Skip to content

Conversation

@anuragthehatter
Copy link

@anuragthehatter anuragthehatter commented Nov 7, 2025

Summary

This PR introduces the test-coverage plugin, a comprehensive tool for analyzing e2e/integration test structure and identifying coverage gaps without running tests.

Key Features

  • Fast E2E Test Analysis: Analyze test structure in seconds without test execution
  • Coverage Gap Identification: Find files and functions without e2e tests
  • Intelligent Priority Detection: Identify high-priority untested code paths
  • Rich HTML Reports: Interactive reports with metrics, charts, and recommendations
  • Framework Support: Works with Ginkgo, pytest, Go testing, and more

Commands Added

  1. /test-coverage:analyze: Analyze e2e test structure and generate comprehensive reports
  2. /test-coverage:gaps: Identify missing test coverage with intelligent gap analysis

Plugin Structure

  • Commands: Two main commands for test analysis and gap detection
  • Skills: Detailed implementation guides for complex analysis workflows
  • Python Utilities: Robust analyzers for test structure and gap reporting
  • Path Handlers: Smart URL and path resolution for various test sources

What's Included

  • Plugin metadata and documentation
  • Command definitions following man page format
  • Skills with detailed implementation steps
  • Python analyzers for test structure and gaps
  • HTML report generators with styling
  • Comprehensive README with examples
  • URL support documentation

Files Changed

  • 26 files added/modified
  • ~7,500 lines of new code
  • Full test coverage analysis framework

Testing

The plugin has been tested with:

  • OpenShift e2e test repositories
  • Ginkgo test suites
  • Python pytest projects
  • Local and remote test sources

🤖 Generated with Claude Code

Co-Authored-By: Claude [email protected]

@openshift-ci openshift-ci bot added the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Nov 7, 2025
@openshift-ci openshift-ci bot requested review from bentito and zaneb November 7, 2025 05:33
@openshift-ci
Copy link

openshift-ci bot commented Nov 7, 2025

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: anuragthehatter
Once this PR has been reviewed and has the lgtm label, please assign bryan-cox for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 7, 2025

Note

.coderabbit.yaml has unrecognized properties

CodeRabbit is using all valid settings from your configuration. Unrecognized properties (listed below) have been ignored and may indicate typos or deprecated fields that can be removed.

⚠️ Parsing warnings (1)
Validation error: Unrecognized key(s) in object: 'tools'
⚙️ Configuration instructions
  • Please see the configuration documentation for more information.
  • You can also validate your configuration using the online YAML validator.
  • 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

Walkthrough

A new Test Coverage Plugin was added including a Claude plugin manifest, extensive documentation, utilities for resolving paths/URLs with caching, Go-focused test-structure and gap analysis Python modules, HTML/JSON/text report generators, package initializers, and CLI entry points. PLUGINS.md was updated (contains a duplicated Test Coverage section).

Changes

Cohort / File(s) Summary
Plugin Registry & Manifest
PLUGINS.md, plugins/test-coverage/.claude-plugin/plugin.json
Added plugin registry entry and a Claude plugin manifest; note: Test Coverage entry appears duplicated in PLUGINS.md.
Top-level Documentation
plugins/test-coverage/README.md, plugins/test-coverage/URL_SUPPORT.md
Added comprehensive README and URL support doc describing commands, URL handling, caching, usage, and examples.
Command Docs
plugins/test-coverage/commands/analyze.md, plugins/test-coverage/commands/gaps.md
Added command reference pages for /test-coverage:analyze and /test-coverage:gaps with arguments, behavior, examples, and prerequisites.
Path/URL Utilities
plugins/test-coverage/utils/__init__.py, plugins/test-coverage/utils/path_handler.py
New PathHandler class and convenience functions (resolve_path, resolve_paths) to normalize local paths vs. URLs, convert GitHub/GitLab blob URLs, download with caching, and manage cache.
Skills Package & Inits
plugins/test-coverage/__init__.py, plugins/test-coverage/skills/__init__.py, plugins/test-coverage/skills/analyze/__init__.py, plugins/test-coverage/skills/gaps/__init__.py, plugins/test-coverage/skills/common/__init__.py
Added package initializers and top-level __version__ = '0.0.1'.
Shared Report Styles
plugins/test-coverage/skills/common/report_styles.py
Added get_common_css() returning shared CSS used by report generators.
Test Structure Skill (analyze)
plugins/test-coverage/skills/analyze/README.md, plugins/test-coverage/skills/analyze/SKILL.md, plugins/test-coverage/skills/analyze/test_structure_analyzer.py, plugins/test-coverage/skills/analyze/test_structure_reports.py, plugins/test-coverage/skills/analyze/test_gap_reports.py
Implemented Go-focused test-structure analyzer (file discovery, parsing, dataclasses, mapping tests→sources, gap identification), and multiple report generators (HTML/JSON/text, comprehensive reports).
Gap Analysis Skill (gaps)
plugins/test-coverage/skills/gaps/README.md, plugins/test-coverage/skills/gaps/SKILL.md, plugins/test-coverage/skills/gaps/gap_analyzer.py, plugins/test-coverage/skills/gaps/reports.py, plugins/test-coverage/skills/gaps/report_template.py
Implemented GapAnalyzer for Ginkgo-style E2E test parsing, multi-category coverage analysis, prioritized gap identification, component-aware scoring, and multi-format report generation.
CLI / Examples / Tests
plugins/test-coverage/skills/analyze/test_gap_reports.py, plugins/test-coverage/skills/analyze/test_structure_analyzer.py (tests/docs within)
Added CLI entry points and modules include example usage, output descriptions, and internal test/report helpers.
OpenShift Docs Update
plugins/openshift/commands/create-cluster.md
Expanded GCP Service Account setup documentation with guided creation/validation and integration into install-config flow.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant PluginCLI
    participant PathHandler
    participant Analyzer as Test Analyzer
    participant ReportGen as Report Generator

    User->>PluginCLI: /test-coverage:analyze [source]
    PluginCLI->>PathHandler: resolve(source)
    PathHandler->>PathHandler: is_url(source)?
    alt URL Input
        PathHandler->>PathHandler: convert_to_raw_url()
        PathHandler->>PathHandler: download_file() + cache
    end
    PathHandler-->>PluginCLI: local_path

    PluginCLI->>Analyzer: discover_files(local_path)
    Analyzer->>Analyzer: parse_test_file() / parse_source_file()
    Analyzer-->>PluginCLI: [test_files, source_files]
    PluginCLI->>Analyzer: map_tests_to_source()
    Analyzer-->>PluginCLI: mapping, gaps
    PluginCLI->>ReportGen: generate_*_report(gaps, output_path)
    ReportGen-->>User: HTML/JSON/text reports
Loading
sequenceDiagram
    participant User
    participant PluginCLI as Plugin CLI
    participant GapAnalyzer
    participant ReportGen as Report Generator

    User->>PluginCLI: /test-coverage:gaps [e2e_test_file]
    PluginCLI->>GapAnalyzer: new GapAnalyzer(file_path)
    GapAnalyzer->>GapAnalyzer: _read_file() / _detect_component_type()
    PluginCLI->>GapAnalyzer: analyze_ginkgo_tests()
    GapAnalyzer->>GapAnalyzer: parse Ginkgo It(...) blocks
    GapAnalyzer->>GapAnalyzer: _identify_*_gaps()
    GapAnalyzer-->>PluginCLI: analysis
    PluginCLI->>GapAnalyzer: calculate_coverage_score(analysis)
    GapAnalyzer-->>PluginCLI: scores
    PluginCLI->>ReportGen: generate_gap_*_report(analysis, scores, output_path)
    ReportGen-->>User: reports + summary
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Key areas needing careful review:
    • plugins/test-coverage/skills/analyze/test_structure_analyzer.py — parsing heuristics, regexes, function-call extraction, mapping logic, and CLI options.
    • plugins/test-coverage/skills/analyze/test_gap_reports.py and plugins/test-coverage/skills/analyze/test_structure_reports.py — complex HTML composition, data formatting, and CSS integration.
    • plugins/test-coverage/skills/gaps/gap_analyzer.py — Ginkgo parsing, component detection, multi-category gap identification, and scoring correctness.
    • plugins/test-coverage/utils/path_handler.py — URL normalization (GitHub/GitLab), caching strategy and file download error handling.
    • Cross-module contracts between analyzers and report generators — ensure expected dict shapes and fields match consumers.

Pre-merge checks and finishing touches

✅ Passed checks (7 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main change: adding test-coverage plugin with structure and gap analysis capabilities.
Docstring Coverage ✅ Passed Docstring coverage is 90.48% which is sufficient. The required threshold is 80.00%.
No Real People Names In Style References ✅ Passed No references to real people's names found in style references, plugin commands, skill documentation, or example prompts throughout the test-coverage plugin.
No Assumed Git Remote Names ✅ Passed Pull request adds test-coverage plugin with documentation and Python modules. No hardcoded git remote names detected in added code or documentation.
Git Push Safety Rules ✅ Passed No git push commands, force pushes, or autonomous git workflow executions found in the PR codebase.
No Untrusted Mcp Servers ✅ Passed The pull request introduces a test-coverage plugin using only Python standard library and built-in functionality with no MCP server installations or untrusted external dependencies.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Comment @coderabbitai help to get the list of available commands and usage tips.

@openshift-ci
Copy link

openshift-ci bot commented Nov 7, 2025

Hi @anuragthehatter. Thanks for your PR.

I'm waiting for a github.com member to verify that this patch is reasonable to test. If it is, they should reply with /ok-to-test on its own line. Until that is done, I will not automatically test new commits in this PR, but the usual testing commands by org members will still work. Regular contributors should join the org to skip this step.

Once the patch is verified, the new status will be reflected by the ok-to-test label.

I understand the commands that are listed here.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@openshift-ci openshift-ci bot added the needs-ok-to-test Indicates a PR that requires an org member to verify it is safe to test. label Nov 7, 2025
Copy link
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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between a50fc18 and fd7a73f.

📒 Files selected for processing (28)
  • PLUGINS.md (2 hunks)
  • plugins/test-coverage/.claude-plugin/plugin.json (1 hunks)
  • plugins/test-coverage/README.md (1 hunks)
  • plugins/test-coverage/URL_SUPPORT.md (1 hunks)
  • plugins/test-coverage/commands/analyze.md (1 hunks)
  • plugins/test-coverage/commands/compare.md (1 hunks)
  • plugins/test-coverage/commands/gaps.md (1 hunks)
  • plugins/test-coverage/skills/analyze/README.md (1 hunks)
  • plugins/test-coverage/skills/analyze/analyze.py (1 hunks)
  • plugins/test-coverage/skills/analyze/coverage_parser.py (1 hunks)
  • plugins/test-coverage/skills/analyze/report_generator.py (1 hunks)
  • plugins/test-coverage/skills/gaps-analyzer/analyze_gaps.py (1 hunks)
  • plugins/test-coverage/skills/test-structure/README.md (1 hunks)
  • plugins/test-coverage/skills/test-structure/README_HTML_REPORTS.md (1 hunks)
  • plugins/test-coverage/skills/test-structure/README_OLD.md (1 hunks)
  • plugins/test-coverage/skills/test-structure/SKILL.md (1 hunks)
  • plugins/test-coverage/skills/test-structure/analyze_test_gaps.py (1 hunks)
  • plugins/test-coverage/skills/test-structure/compare_coverage.py (1 hunks)
  • plugins/test-coverage/skills/test-structure/compare_report_generator.py (1 hunks)
  • plugins/test-coverage/skills/test-structure/coverage_comparator.py (1 hunks)
  • plugins/test-coverage/skills/test-structure/gap_analyzer.py (1 hunks)
  • plugins/test-coverage/skills/test-structure/gap_report_generator.py (1 hunks)
  • plugins/test-coverage/skills/test-structure/generate_networking_report.py (1 hunks)
  • plugins/test-coverage/skills/test-structure/html_report_generator.py (1 hunks)
  • plugins/test-coverage/skills/test-structure/test_structure_analyzer.py (1 hunks)
  • plugins/test-coverage/skills/test-structure/unified_analyzer.py (1 hunks)
  • plugins/test-coverage/utils/__init__.py (1 hunks)
  • plugins/test-coverage/utils/path_handler.py (1 hunks)
🧰 Additional context used
🪛 LanguageTool
plugins/test-coverage/README.md

[uncategorized] ~328-~328: Use a comma before ‘but’ if it connects two independent clauses (unless they are closely connected and short).
Context: ...age python ``` ### Issue: No gaps found but code is clearly untested Solution:...

(COMMA_COMPOUND_SENTENCE_2)


[uncategorized] ~381-~381: Loose punctuation mark.
Context: ...ation. ## Related Plugins - jira: Create bug reports with coverage gap co...

(UNLIKELY_OPENING_PUNCTUATION)

plugins/test-coverage/commands/gaps.md

[uncategorized] ~41-~41: Loose punctuation mark.
Context: ...to archive/file) - --priority <level>: Filter gaps by priority level (optional...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~47-~47: Loose punctuation mark.
Context: ...tters, utilities) - --format <format>: Coverage file format (optional, default...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~50-~50: Loose punctuation mark.
Context: ...orted: go, json - --output <path>: Output directory for gap analysis repor...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~52-~52: Loose punctuation mark.
Context: ...-coverage/gaps/) - --language `: Source code language (optional, default...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~56-~56: Loose punctuation mark.
Context: ...alysis patterns - --exclude <pattern>: Exclude files matching pattern (optiona...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~59-~59: Loose punctuation mark.
Context: ...*" ---complexity-threshold `: Minimum cyclomatic complexity to flag (...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~62-~62: Loose punctuation mark.
Context: ...sts are prioritized - --show-snippets: Include source code snippets of uncover...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~66-~66: Loose punctuation mark.
Context: ...uncovered block - --max-gaps <number>: Limit number of gaps to report (default...

(UNLIKELY_OPENING_PUNCTUATION)

plugins/test-coverage/skills/test-structure/README.md

[uncategorized] ~3-~3: Possible missing comma found.
Context: ...gaps logic Comprehensive test coverage analysis combining structural analysis and gap d...

(AI_HYDRA_LEO_MISSING_COMMA)


[uncategorized] ~53-~53: Possible missing comma found.
Context: ...s the recommended tool for most use cases as it combines analyze and gaps logic t...

(AI_HYDRA_LEO_MISSING_COMMA)

plugins/test-coverage/skills/test-structure/README_OLD.md

[uncategorized] ~207-~207: A comma may be missing after the conjunctive/linking adverb ‘Currently’.
Context: ...precise coverage ### Language Support Currently supports Go, Python, Java, JavaScript, ...

(SENT_START_CONJUNCTIVE_LINKING_ADVERB_COMMA)

plugins/test-coverage/commands/analyze.md

[uncategorized] ~28-~28: Loose punctuation mark.
Context: ...g. ## Arguments - <source-directory>: Path or URL to source code directory/fi...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~36-~36: Loose punctuation mark.
Context: ...-coverage/cache/ ---language `: Programming language (optional, auto-de...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~39-~39: Loose punctuation mark.
Context: ...ript, typescript ---output `: Output directory for generated reports ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~42-~42: Loose punctuation mark.
Context: ...and text summary - --priority <level>: Filter results by priority (optional) ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~46-~46: Loose punctuation mark.
Context: ... Default: all - --exclude <pattern>: Exclude files matching pattern from ana...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~46-~46: It seems likely that a singular genitive (’s) apostrophe is missing.
Context: ...all - --exclude <pattern>: Exclude files matching pattern from analysis (optiona...

(AI_HYDRA_LEO_APOSTROPHE_S_XS)


[uncategorized] ~50-~50: Loose punctuation mark.
Context: ...de "/test/" ---include-test-utils`: Include test utility/helper files in an...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~55-~55: Loose punctuation mark.
Context: ...structure code - --include-unit-tests: Include unit tests in analysis (optiona...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~63-~63: Loose punctuation mark.
Context: ...or Python) - --test-pattern <pattern>: Custom test file pattern (optional) -...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~66-~66: Loose punctuation mark.
Context: .../Test*.java" ---test-structure-only`: Analyze only test file structure, skip ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~289-~289: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ... Example 2: Analyze test structure with high priority filter ``` /test-coverage:analyze ./pk...

(EN_COMPOUND_ADJECTIVE_INTERNAL)


[duplication] ~381-~381: Possible typo: you repeated a word.
Context: ... - URLs are automatically detected and downloaded - Downloaded files are cached in `.work/test-coverag...

(ENGLISH_WORD_REPEAT_RULE)

plugins/test-coverage/URL_SUPPORT.md

[uncategorized] ~225-~225: Possible missing preposition found.
Context: ...eports HTTP error codes and reasons - Network errors: Reports connection issues wit...

(AI_HYDRA_LEO_MISSING_OF)

plugins/test-coverage/skills/analyze/README.md

[style] ~151-~151: As an alternative to the over-used intensifier ‘very’, consider replacing this phrase.
Context: ...lxml ``` ### Large Coverage Files For very large coverage files, the tool may take some ...

(EN_WEAK_ADJECTIVE)

plugins/test-coverage/commands/compare.md

[uncategorized] ~41-~41: Loose punctuation mark.
Context: ...wnloaded and cached - --output <path>: Output directory for comparison reports...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~43-~43: Loose punctuation mark.
Context: ...erage/compare/) - --fail-on-decrease`: Exit with error if coverage decreases ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~47-~47: Loose punctuation mark.
Context: ...ic control - --threshold <percentage>: Maximum acceptable coverage decrease (d...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~51-~51: Loose punctuation mark.
Context: ...-decreaseis set ---format `: Coverage format for both files (optiona...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~55-~55: Loose punctuation mark.
Context: ....jsonfor JSON) ---ignore-new-files`: Don't count new files in coverage delta...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~59-~59: Loose punctuation mark.
Context: ...g files only - --ignore-removed-files: Don't count removed files in coverage d...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~62-~62: Loose punctuation mark.
Context: ...min-coverage-for-new-files `: Require new files to meet minimum cover...

(UNLIKELY_OPENING_PUNCTUATION)


[grammar] ~86-~86: It seems that a pronoun is missing.
Context: ...coverage:analyze), parse directly - If Go coverage format (.out`), parse usin...

(IF_VB)


[uncategorized] ~193-~193: When ‘Show-specific’ is used as a modifier, it is usually spelled with a hyphen.
Context: ... - Files with decreased coverage - Show specific lines that lost coverage - Priorit...

(SPECIFIC_HYPHEN)


[grammar] ~281-~281: Using ‘plenty’ without ‘of’ is considered to be informal.
Context: ...ed: - Allow decrease up to threshold amount - Example: threshold 2.0 allows decrease from 80%...

(PLENTY_OF_NOUNS)

plugins/test-coverage/skills/test-structure/SKILL.md

[duplication] ~217-~217: Possible typo: you repeated a word.
Context: ...t → function): - TestHandleRequest tests HandleRequest - test_parse_xml tests parse_xml 3. *Import-based mapping...

(ENGLISH_WORD_REPEAT_RULE)

🪛 markdownlint-cli2 (0.18.1)
plugins/test-coverage/commands/gaps.md

10-10: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


300-300: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


379-379: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


424-424: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


432-432: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


440-440: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


448-448: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


456-456: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


464-464: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


472-472: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


480-480: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


488-488: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

plugins/test-coverage/skills/test-structure/README_OLD.md

10-10: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

plugins/test-coverage/commands/analyze.md

10-10: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


51-51: Spaces inside emphasis markers

(MD037, no-space-in-emphasis)


247-247: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


283-283: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


291-291: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


299-299: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


307-307: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


315-315: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


323-323: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


337-337: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


345-345: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


353-353: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


363-363: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

plugins/test-coverage/skills/analyze/README.md

22-22: Heading levels should only increment by one level at a time
Expected: h2; Actual: h3

(MD001, heading-increment)

plugins/test-coverage/commands/compare.md

206-206: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


294-294: Bare URL used

(MD034, no-bare-urls)

plugins/test-coverage/skills/test-structure/SKILL.md

365-365: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


410-410: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🪛 Ruff (0.14.3)
plugins/test-coverage/skills/test-structure/compare_coverage.py

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

(EXE001)


111-111: Loop control variable i not used within loop body

Rename unused i to _i

(B007)


118-118: Loop control variable i not used within loop body

Rename unused i to _i

(B007)

plugins/test-coverage/skills/test-structure/compare_report_generator.py

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

(EXE001)

plugins/test-coverage/skills/test-structure/gap_report_generator.py

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

(EXE001)

plugins/test-coverage/skills/test-structure/html_report_generator.py

30-30: Local variable partially_tested is assigned to but never used

Remove assignment to unused variable partially_tested

(F841)


572-572: Unused function argument: summary

(ARG001)


575-575: Local variable untested_funcs is assigned to but never used

Remove assignment to unused variable untested_funcs

(F841)


989-989: Local variable structure is assigned to but never used

Remove assignment to unused variable structure

(F841)

plugins/test-coverage/skills/test-structure/analyze_test_gaps.py

105-105: f-string without any placeholders

Remove extraneous f prefix

(F541)

plugins/test-coverage/skills/test-structure/coverage_comparator.py

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

(EXE001)

plugins/test-coverage/utils/path_handler.py

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

(EXE001)


118-118: Probable use of insecure hash functions in hashlib: md5

(S324)


157-157: Audit URL open for permitted schemes. Allowing use of file: or custom schemes is often unexpected.

(S310)


159-159: Audit URL open for permitted schemes. Allowing use of file: or custom schemes is often unexpected.

(S310)


182-182: Do not catch blind exception: Exception

(BLE001)

plugins/test-coverage/skills/analyze/report_generator.py

18-18: Unused static method argument: baseline

(ARG004)


433-524: f-string without any placeholders

Remove extraneous f prefix

(F541)


706-706: Do not catch blind exception: Exception

(BLE001)

plugins/test-coverage/skills/test-structure/gap_analyzer.py

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

(EXE001)

plugins/test-coverage/skills/analyze/analyze.py

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

(TRY003)


242-242: Do not catch blind exception: Exception

(BLE001)


295-295: Consider moving this statement to an else block

(TRY300)


297-297: Do not catch blind exception: Exception

(BLE001)

plugins/test-coverage/skills/test-structure/generate_networking_report.py

20-20: Local variable test_tags is assigned to but never used

Remove assignment to unused variable test_tags

(F841)


108-108: f-string without any placeholders

Remove extraneous f prefix

(F541)

plugins/test-coverage/skills/test-structure/unified_analyzer.py

37-37: Loop control variable dirs not used within loop body

Rename unused dirs to _dirs

(B007)


65-65: Do not use bare except

(E722)


65-66: try-except-continue detected, consider logging the exception

(S112)


75-75: f-string without any placeholders

Remove extraneous f prefix

(F541)


144-144: Do not catch blind exception: Exception

(BLE001)


151-151: Do not catch blind exception: Exception

(BLE001)


203-203: Loop control variable dirs not used within loop body

Rename unused dirs to _dirs

(B007)


224-224: Do not use bare except

(E722)


224-225: try-except-continue detected, consider logging the exception

(S112)


266-266: Loop control variable dirs not used within loop body

Rename unused dirs to _dirs

(B007)


282-282: Do not use bare except

(E722)


282-283: try-except-continue detected, consider logging the exception

(S112)


307-307: Loop control variable dirs not used within loop body

Rename unused dirs to _dirs

(B007)


347-347: Do not use bare except

(E722)


347-348: try-except-continue detected, consider logging the exception

(S112)


369-369: Loop control variable dirs not used within loop body

Rename unused dirs to _dirs

(B007)


379-379: Do not use bare except

(E722)


379-380: try-except-continue detected, consider logging the exception

(S112)


455-455: Unused method argument: characteristics

(ARG002)


455-455: Unused method argument: quality_metrics

(ARG002)


564-564: Do not catch blind exception: Exception

(BLE001)


637-637: Local variable output_path is assigned to but never used

Remove assignment to unused variable output_path

(F841)


643-643: Consider moving this statement to an else block

(TRY300)


645-645: Do not catch blind exception: Exception

(BLE001)

plugins/test-coverage/skills/test-structure/test_structure_analyzer.py

124-124: Loop control variable root not used within loop body

Rename unused root to _root

(B007)


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

(TRY003)


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

(TRY003)


167-167: PEP 484 prohibits implicit Optional

Convert to T | None

(RUF013)


285-285: Do not catch blind exception: Exception

(BLE001)


504-504: Local variable source_by_path is assigned to but never used

Remove assignment to unused variable source_by_path

(F841)


541-541: Unused function argument: file_path

(ARG001)


761-761: Do not catch blind exception: Exception

(BLE001)


771-771: Do not catch blind exception: Exception

(BLE001)


823-823: Do not catch blind exception: Exception

(BLE001)


837-837: Consider moving this statement to an else block

(TRY300)


839-839: Do not catch blind exception: Exception

(BLE001)

plugins/test-coverage/skills/gaps-analyzer/analyze_gaps.py

314-314: Local variable first_uncovered is assigned to but never used

Remove assignment to unused variable first_uncovered

(F841)


427-427: Loop control variable i not used within loop body

(B007)


633-633: f-string without any placeholders

Remove extraneous f prefix

(F541)


643-643: f-string without any placeholders

Remove extraneous f prefix

(F541)

plugins/test-coverage/skills/analyze/coverage_parser.py

156-156: Do not use bare except

(E722)


156-157: try-except-pass detected, consider logging the exception

(S110)


158-158: Do not catch blind exception: Exception

(BLE001)


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

(TRY003)


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

(TRY003)


194-194: Using xml to parse untrusted data is known to be vulnerable to XML attacks; use defusedxml equivalents

(S314)


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

(TRY003)


355-355: Local variable num_stmt is assigned to but never used

Remove assignment to unused variable num_stmt

(F841)


366-366: Ambiguous variable name: l

(E741)


378-378: Ambiguous variable name: l

(E741)


391-391: Using xml to parse untrusted data is known to be vulnerable to XML attacks; use defusedxml equivalents

(S314)


428-428: Local variable mi is assigned to but never used

Remove assignment to unused variable mi

(F841)


449-449: Using xml to parse untrusted data is known to be vulnerable to XML attacks; use defusedxml equivalents

(S314)


552-552: Do not catch blind exception: Exception

(BLE001)

🔇 Additional comments (1)
plugins/test-coverage/skills/test-structure/README_OLD.md (1)

1-280: Comprehensive and well-structured documentation.

The README provides clear, practical guidance for using the Test Structure Analyzer tool. The progression from quick start through advanced usage, along with multiple concrete examples, will help users understand both basic and sophisticated use cases. The limitations section appropriately sets expectations for what the tool can and cannot do.

Copy link
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: 3

♻️ Duplicate comments (12)
plugins/test-coverage/skills/test-structure/README_OLD.md (1)

133-133: Add language identifier to fenced code block (MD040).

Line 133 code block is missing a language identifier. Apply this diff:

-```
+```bash
 usage: test_structure_analyzer.py [-h] [--language {go,python,java,javascript,typescript}]
                                    [--priority {all,high,medium,low}] [--output OUTPUT]
                                    [--exclude EXCLUDE_PATTERNS]
                                    source_dir

 Arguments:
   source_dir            Source directory to analyze

 Options:
   --language LANG       Programming language (auto-detected if not specified)
   --priority LEVEL      Filter gaps by priority: all, high, medium, low
   --output DIR          Output directory for reports (default: .work/test-coverage/structure)
   --exclude PATTERN     Exclude patterns (can be repeated)
-```
+```
plugins/test-coverage/commands/compare.md (1)

51-64: Remove unsupported flag descriptions.
compare_coverage.py does not expose --format, --ignore-new-files, or --ignore-removed-files; only --output, --fail-on-decrease, --threshold, and --min-coverage-for-new-files are parsed (Lines 27-37). Re-listing the unsupported switches here will keep tripping users—this was flagged earlier and is still unresolved. Please align the docs with the actual parser or add the missing options.

plugins/test-coverage/skills/test-structure/compare_coverage.py (1)

146-151: Return non-zero exit when checks fail.
When threshold checks fail without --fail-on-decrease/--min-coverage-for-new-files, we print “FAILED” but still return 0, so CI treats the run as success. This was already highlighted and remains unfixed. Please return 1 in that final branch.

-        else:
-            return 0
+        else:
+            return 1
plugins/test-coverage/skills/analyze/report_generator.py (1)

363-507: Pass the event object into filterByCoverage.
Every button calls filterByCoverage('low') etc., but inside the function we access event.target. In browsers without a global event, that throws a ReferenceError and the coverage filters stop working—the same issue noted previously. Please pass the event and use event.currentTarget.

-                <button class="filter-btn active" onclick="filterByCoverage('all')">All Files</button>
-                <button class="filter-btn" onclick="filterByCoverage('low')">Low (&lt;50%)</button>
-                <button class="filter-btn" onclick="filterByCoverage('medium')">Medium (50-80%)</button>
-                <button class="filter-btn" onclick="filterByCoverage('high')">High (&gt;80%)</button>
+                <button class="filter-btn active" onclick="filterByCoverage(event, 'all')">All Files</button>
+                <button class="filter-btn" onclick="filterByCoverage(event, 'low')">Low (&lt;50%)</button>
+                <button class="filter-btn" onclick="filterByCoverage(event, 'medium')">Medium (50-80%)</button>
+                <button class="filter-btn" onclick="filterByCoverage(event, 'high')">High (&gt;80%)</button>
@@
-        function filterByCoverage(level) {
+        function filterByCoverage(event, level) {
@@
-            event.target.classList.add('active');
+            event.currentTarget.classList.add('active');
plugins/test-coverage/skills/test-structure/compare_report_generator.py (1)

321-337: Pass event into switchTab to avoid ReferenceError (still outstanding).

This handler still depends on the non-standard global event, so clicking any tab throws ReferenceError in browsers like Firefox and Safari, leaving the UI stuck on the default pane. Please accept the DOM event argument and forward it from every onclick, then use evt.currentTarget. (Previous review already requested this.)

-        function switchTab(tabName) {
+        function switchTab(evt, tabName) {
@@
-            event.target.classList.add('active');
+            evt.currentTarget.classList.add('active');
         }

Remember to update each button:

-                <button class="tab active" onclick="switchTab('improved-tab')">
+                <button class="tab active" onclick="switchTab(event, 'improved-tab')">
                 Improved ({file_changes['improved_files']})
                 </button>
-                <button class="tab" onclick="switchTab('regressed-tab')">
+                <button class="tab" onclick="switchTab(event, 'regressed-tab')">
                 Regressed ({file_changes['regressed_files']})
                 </button>
-                <button class="tab" onclick="switchTab('new-tab')">
+                <button class="tab" onclick="switchTab(event, 'new-tab')">
                 New Files ({file_changes['new_files']})
                 </button>
-                <button class="tab" onclick="switchTab('all-tab')">
+                <button class="tab" onclick="switchTab(event, 'all-tab')">
                 All Changes
                 </button>
plugins/test-coverage/skills/test-structure/html_report_generator.py (1)

1183-1188: Fix tab handler to accept the event (still broken).

showTab continues to rely on the implicit global event, so tab clicks throw ReferenceError in Firefox/Safari and the content never swaps. Pass the event from each onclick and use the received argument inside the function.

-                <button class="tab active" onclick="showTab('overview')">Overview</button>
-                <button class="tab" onclick="showTab('gaps')">Coverage Gaps</button>
-                <button class="tab" onclick="showTab('features')">Feature Coverage</button>
-                <button class="tab" onclick="showTab('quality')">Code Quality</button>
-                <button class="tab" onclick="showTab('recommendations')">Recommendations</button>
+                <button class="tab active" onclick="showTab(event, 'overview')">Overview</button>
+                <button class="tab" onclick="showTab(event, 'gaps')">Coverage Gaps</button>
+                <button class="tab" onclick="showTab(event, 'features')">Feature Coverage</button>
+                <button class="tab" onclick="showTab(event, 'quality')">Code Quality</button>
+                <button class="tab" onclick="showTab(event, 'recommendations')">Recommendations</button>
@@
-        function showTab(tabName) {
+        function showTab(evt, tabName) {
@@
-            document.getElementById(tabName).classList.add('active');
-            event.target.classList.add('active');
+            document.getElementById(tabName).classList.add('active');
+            evt.currentTarget.classList.add('active');
         }

Also applies to: 1219-1227

plugins/test-coverage/skills/test-structure/coverage_comparator.py (2)

39-65: Realign summary counts with GapAnalyzer schema.

This block is still pulling total_source_files / untested_*_count, so every comparison fed by test-structure-gaps.json ends up with 0 totals, 0 deltas, and thresholds that never trigger. Please switch to the documented files_with_tests, files_without_tests, tested_functions, and untested_functions payload and fall back only when those are absent. Otherwise we keep shipping false “100 % coverage” reports.

-        total_files = summary.get('total_source_files', 0)
-        untested_files = summary.get('untested_files_count', 0)
-        total_functions = 0
-        untested_functions = summary.get('untested_functions_count', 0)
-
-        # Count total functions from gaps
-        for file_gap in gaps.get('untested_files', []):
-            total_functions += file_gap.get('total_functions', 0)
-        for file_gap in gaps.get('partially_tested_files', []):
-            total_functions += file_gap.get('total_functions', 0)
-
-        tested_functions = total_functions - untested_functions
-        tested_files = total_files - untested_files
+        def _as_count(value):
+            if isinstance(value, list):
+                return len(value)
+            return value or 0
+
+        files_with_tests = _as_count(summary.get('files_with_tests'))
+        untested_files = _as_count(summary.get('files_without_tests',
+                                               summary.get('untested_files_count', 0)))
+
+        total_files = summary.get('total_source_files')
+        if total_files is None:
+            total_files = files_with_tests + untested_files
+
+        tested_files = files_with_tests if files_with_tests else max(total_files - untested_files, 0)
+
+        tested_functions = _as_count(summary.get('tested_functions'))
+        untested_functions = _as_count(summary.get('untested_functions',
+                                                   summary.get('untested_functions_count', 0)))
+
+        total_functions = summary.get('total_functions')
+        if total_functions is None:
+            total_functions = tested_functions + untested_functions
+        if total_functions == 0:
+            for file_gap in gaps.get('untested_files', []):
+                total_functions += file_gap.get('total_functions', file_gap.get('functions', 0))
+            for file_gap in gaps.get('partially_tested_files', []):
+                total_functions += file_gap.get(
+                    'total_functions',
+                    file_gap.get('tested_functions', 0) + file_gap.get('untested_functions', 0)
+                )
+        if tested_functions == 0 and total_functions:
+            tested_functions = max(total_functions - untested_functions, 0)

71-89: Stop hard-coding legacy gap keys in per-file coverage.

The per-file coverage map has the same problem: total_functions is often missing and the data now ships functions, tested_functions, untested_functions. Today we silently record totals as 0, so regressions in partially tested files vanish. Please consume the new keys and keep the zero guards.

-        for file_gap in gaps.get('untested_files', []):
-            file_coverage[file_gap['file']] = {
-                'coverage': 0.0,
-                'total_functions': file_gap.get('total_functions', 0),
-                'tested_functions': 0
-            }
+        for file_gap in gaps.get('untested_files', []):
+            total = file_gap.get('total_functions', file_gap.get('functions', 0))
+            file_coverage[file_gap['file']] = {
+                'coverage': 0.0,
+                'total_functions': total,
+                'tested_functions': 0
+            }
@@
-        for file_gap in gaps.get('partially_tested_files', []):
-            total = file_gap.get('total_functions', 0)
-            tested = file_gap.get('tested_functions', 0)
-            coverage = (tested / total * 100) if total > 0 else 0
+        for file_gap in gaps.get('partially_tested_files', []):
+            tested = file_gap.get('tested_functions', 0)
+            untested = file_gap.get('untested_functions', 0)
+            total = file_gap.get('total_functions', tested + untested)
+            coverage = (tested / total * 100) if total > 0 else 0
plugins/test-coverage/skills/test-structure/generate_networking_report.py (1)

66-137: Guard percentage math before the report crashes.

When total_tests or total_files is 0 this script still divides by them, so the CLI dies exactly in the “empty dataset” scenario it’s meant to analyse. Please pre-compute guarded percentages and reuse them in the strings/metrics to keep the report resilient.

     total_tests = sum(test_counts.values())
     total_files = len([f for f in os.listdir(test_dir) if f.endswith('.go')])
+    files_with_tests = len(test_counts)
+    disruptive_pct = (characteristics['Disruptive'] / total_tests * 100) if total_tests else 0.0
+    serial_pct = (characteristics['Serial'] / total_tests * 100) if total_tests else 0.0
+    test_file_pct = (files_with_tests / total_files * 100) if total_files else 0.0
@@
-        f'{characteristics["Disruptive"] / total_tests * 100:.1f}% of tests are Disruptive - testing critical failure scenarios',
-        f'{characteristics["Serial"] / total_tests * 100:.1f}% of tests are Serial - proper handling of resource conflicts',
+        f'{disruptive_pct:.1f}% of tests are Disruptive - testing critical failure scenarios',
+        f'{serial_pct:.1f}% of tests are Serial - proper handling of resource conflicts',
@@
-        ('Test File Coverage', f'{len(test_counts)}/{total_files} ({len(test_counts)/total_files*100:.0f}%)', 'Good'),
+        ('Test File Coverage',
+         f'{files_with_tests}/{total_files} ({test_file_pct:.0f}%)' if total_files else '0/0 (0%)',
+         'Good' if total_files else 'Info'),
@@
-        ('Disruptive Test Ratio', f'{characteristics["Disruptive"] / total_tests * 100:.1f}%', 'Good'),
+        ('Disruptive Test Ratio', f'{disruptive_pct:.1f}%', 'Good'),
plugins/test-coverage/skills/test-structure/test_structure_analyzer.py (2)

315-336: Fix Java test name extraction to stop the runtime crash.

match.group(2) still raises IndexError for Java because the regex only captures one group, so every Java test file is skipped. Select the last available capture dynamically so all languages keep working.

-            test_name = match.group(1) if language in ['go', 'python'] else match.group(2)
+            if language in ['go', 'python']:
+                test_name = match.group(1)
+            else:
+                last_index = match.lastindex or 0
+                test_name = match.group(last_index) if last_index else match.group(0)

734-752: Apply the --exclude globs to discovered files.

The CLI still advertises --exclude, but we never drop those paths from the discovery results, so generated/vendor code keeps polluting the reports. Filter both test and source lists with the provided patterns right after discovery so the flag finally works.

-            test_files_paths, source_files_paths = discover_files(source_dir, language, e2e_only=e2e_only)
+            test_files_paths, source_files_paths = discover_files(source_dir, language, e2e_only=e2e_only)
+
+        exclude_patterns = args.exclude_patterns or []
+        if exclude_patterns:
+            from fnmatch import fnmatch
+
+            def _is_excluded(path: str) -> bool:
+                normalized = path.replace('\\', '/')
+                rel_path = os.path.relpath(path, start=source_dir).replace('\\', '/')
+                return any(fnmatch(normalized, pattern) or fnmatch(rel_path, pattern)
+                           for pattern in exclude_patterns)
+
+            test_files_paths = [p for p in test_files_paths if not _is_excluded(p)]
+            source_files_paths = [p for p in source_files_paths if not _is_excluded(p)]
plugins/test-coverage/skills/test-structure/unified_analyzer.py (1)

107-126: [Critical] Summary generation still reads stale data.

This is the same issue previously flagged: _generate_summary() is called while self.results is being constructed, causing it to read either empty data (first run) or stale data from a previous run. The summary will not reflect the current analysis.

As previously recommended, pass the fresh data directly to _generate_summary():

+        summary = self._generate_summary(structure_results, gaps)
+
         self.results = {
             'metadata': {
                 'source_dir': self.source_dir,
                 'language': self.language,
                 'test_framework': self.test_framework,
                 'generated_at': datetime.now().isoformat()
             },
             'structure': structure_results,
             'characteristics': characteristics,
             'feature_coverage': feature_coverage,
             'quality_metrics': quality_metrics,
             'platform_coverage': platform_coverage,
             'gaps': gaps,
             'recommendations': recommendations,
             'strengths': strengths,
-            'summary': self._generate_summary()
+            'summary': summary
         }
🧹 Nitpick comments (19)
plugins/test-coverage/skills/analyze/README.md (2)

63-63: Add language identifiers to fenced code blocks (MD040).

Three code blocks are missing language specifications. While functional, this violates markdown linting standards and reduces syntax highlighting in documentation viewers.

Apply these diffs:

-```
+```bash
 analyze/
 ├── analyze.py              # Main entry point
 ├── coverage_parser.py      # Coverage file parsers
 ├── report_generator.py     # Report generators
 └── README.md              # This file
-```
+```
-```
+```bash
 /test-coverage:analyze coverage.out --threshold 80
-```
+```
-```
+```
 ================================================================================
 Code Coverage Analysis Complete
 ================================================================================

Also applies to: 112-112, 150-150


143-143: Consider alternative phrasing for "very large".

Line 143 uses "very large" as an intensifier. Consider more specific language like "extremely large," "massive," or provide context with actual file size thresholds.

plugins/test-coverage/README.md (2)

10-10: Add language identifiers to fenced code blocks (MD040).

Multiple code blocks lack language specifications. Apply language identifiers to the following locations:

  • Lines 10, 49, 51: bash (example commands)
  • Lines 230, 266, 274, 282, 290, 298: bash (example commands)
  • Lines 312, 320, 328, 338: bash (example commands)

Example fix:

-```
+```bash
 /test-coverage:analyze ./pkg/

Also applies to: 49-49, 51-51, 230-230, 266-266, 274-274, 282-282, 290-290, 298-298, 312-312, 320-320, 328-328, 338-338


195-195: Fix punctuation in test markers list.

Line 195 has inconsistent punctuation between two code element lists. The dash after backticks breaks the flow.

Current:

- `[Longduration]`, `[ConnectedOnly]`, `[NonPreRelease]` - `g.Describe(`, `g.Context(`, `g.It(`

Apply this diff to use consistent punctuation:

-  - `[Longduration]`, `[ConnectedOnly]`, `[NonPreRelease]` - `g.Describe(`, `g.Context(`, `g.It(`
+  - `[Longduration]`, `[ConnectedOnly]`, `[NonPreRelease]`
+  - `g.Describe(`, `g.Context(`, `g.It(`
plugins/test-coverage/commands/gaps.md (1)

10-10: Add language identifiers to fenced code blocks (MD040).

Multiple fenced code blocks lack language specifications. Apply language identifiers:

  • Lines 10, 133, 175, 230, 254, 266, 290: bash or plain (example commands/output)
  • Lines 300, 379: plain or text (output examples)
  • Lines 424, 433, 441, 449, 457, 465, 473, 481, 489: bash (example commands)

Example:

-```
+```bash
 /test-coverage:gaps coverage.xml ./src/

Also applies to: 133-133, 175-175, 230-230, 254-254, 266-266, 290-290, 300-300, 379-379, 424-424, 433-433, 441-441, 449-449, 457-457, 465-465, 473-473, 481-481, 489-489

plugins/test-coverage/skills/test-structure/README_HTML_REPORTS.md (1)

10-10: Add language identifiers to fenced code blocks (MD040).

Seven fenced code blocks are missing language specifications. Apply identifiers:

  • Lines 10, 51: bash (example commands)
  • Lines 230, 266, 274, 282, 290: bash (example commands/paths)

Example:

-```
+```bash
 cd /home/anusaxen/git/ai-helpers/plugins/test-coverage/skills/test-structure

Also applies to: 51-51, 230-230, 266-266, 274-274, 282-282, 290-290

plugins/test-coverage/commands/analyze.md (1)

10-10: Add language identifiers to fenced code blocks (MD040).

Multiple fenced code blocks lack language specifications. Apply identifiers to lines:

  • Lines 10, 51, 230, 266, 274, 282, 290, 298, 312, 320, 328, 338: bash (example commands/output)

Example:

-```
+```bash
 /test-coverage:analyze ./pkg/

Also applies to: 51-51, 230-230, 266-266, 274-274, 282-282, 290-290, 298-298, 312-312, 320-320, 328-328, 338-338

plugins/test-coverage/URL_SUPPORT.md (1)

10-10: Add language identifiers to fenced code blocks (MD040).

Three fenced code blocks lack language specifications:

  • Line 10: bash or plain
  • Line 51: bash (example command)
  • Line 230: bash (example commands)

Example:

-```
+```bash
 https://github.com/owner/repo/blob/main/test/file_test.go

Also applies to: 51-51, 230-230

plugins/test-coverage/skills/gaps-analyzer/analyze_gaps.py (4)

213-214: Consider preserving relative path to avoid filename collisions.

Using only the basename (file_path.split('/')[-1]) discards directory information, which could cause confusion when multiple files share the same name in different directories.

Consider keeping a relative path:

+            # Get relative path from source_dir if possible
+            try:
+                rel_path = str(Path(file_path).relative_to(Path(self.source_dir)))
+            except ValueError:
+                rel_path = file_path.split('/')[-1]
+
             gap = Gap(
-                file=file_path.split('/')[-1],
+                file=rel_path,

427-439: Remove unused loop variable.

The loop variable i from enumerate() is not used in this iteration.

Apply this diff:

-    for i, gap in enumerate([g for g in gaps if g.priority == 'high']):
+    for gap in [g for g in gaps if g.priority == 'high']:
         lines_str = f"{gap.lines[0]}-{gap.lines[-1]}" if len(gap.lines) > 1 else str(gap.lines[0])

497-499: Move import to module level for consistency.

The datetime import should be at the top of the file with other imports rather than inside the function.

Move this import to the top of the file:

+from datetime import datetime
 import re
 import json
 import os

And remove from the function:

 def generate_json_report(gaps: List[Gap], coverage_file: str, source_dir: str, output_path: str):
     """Generate JSON report"""
-    from datetime import datetime
-
     total_gaps = len(gaps)

633-643: Remove unnecessary f-string prefixes.

Lines 633 and 643 use f-string prefixes but have no placeholders.

Apply this diff:

-    print(f"\nReports generated:")
+    print("\nReports generated:")
     print(f"  HTML: {html_path}")
     print(f"  JSON: {json_path}")
     print(f"  Text: {text_path}")
 
     # Print summary
-    print(f"\nSummary:")
+    print("\nSummary:")
     print(f"  High Priority:   {high_gaps}")
plugins/test-coverage/skills/test-structure/unified_analyzer.py (7)

34-68: Replace bare except with specific exception handling.

The bare except at line 65 catches all exceptions including system errors. Consider catching specific exceptions related to file operations.

Apply this diff:

                 try:
                     with open(filepath, 'r', encoding='utf-8', errors='ignore') as f:
                         content = f.read()
 
                         # Go frameworks
                         if self.language == 'go':
                             if 'ginkgo' in content.lower() or 'g.Describe' in content or 'g.It(' in content:
                                 return 'ginkgo'
                             elif 'func Test' in content:
                                 return 'testing'
 
                         # Python frameworks
                         elif self.language == 'python':
                             if 'pytest' in content or '@pytest' in content:
                                 return 'pytest'
                             elif 'unittest' in content:
                                 return 'unittest'
 
                         # JavaScript frameworks
                         elif self.language in ['javascript', 'typescript']:
                             if 'jest' in content or 'describe(' in content:
                                 return 'jest'
                             elif 'mocha' in content:
                                 return 'mocha'
 
-                except:
+                except (OSError, UnicodeDecodeError):
                     continue

203-225: Improve error handling and fix unused variable.

The loop variable dirs is unused, and the bare except should catch specific exceptions.

Apply this diff:

-        for root, dirs, files in os.walk(self.source_dir):
+        for root, _dirs, files in os.walk(self.source_dir):
             for file in files:
                 if file.endswith(('.go', '.py', '.java', '.js', '.ts')):
                     filepath = os.path.join(root, file)
                     try:
                         with open(filepath, 'r', encoding='utf-8', errors='ignore') as f:
                             content = f.read()
 
                             # Count test tags
                             for tag_name, pattern in tag_patterns.items():
                                 count = len(re.findall(pattern, content))
                                 if count > 0:
                                     characteristics['test_tags'][tag_name] += count
 
                             # Cleanup patterns
                             characteristics['cleanup_patterns']['defer'] += len(re.findall(r'\bdefer\b', content))
                             characteristics['cleanup_patterns']['AfterEach'] += len(re.findall(r'AfterEach', content))
                             characteristics['cleanup_patterns']['BeforeEach'] += len(re.findall(r'BeforeEach', content))
                             characteristics['cleanup_patterns']['setUp'] += len(re.findall(r'def setUp', content))
                             characteristics['cleanup_patterns']['tearDown'] += len(re.findall(r'def tearDown', content))
 
-                    except:
+                    except (OSError, UnicodeDecodeError):
                         continue

266-283: Improve error handling and fix unused variable.

Same issues as previous methods: unused dirs variable and bare except.

Apply this diff:

-        for root, dirs, files in os.walk(self.source_dir):
+        for root, _dirs, files in os.walk(self.source_dir):
             for file in files:
                 if file.endswith(('.go', '.py', '.java', '.js', '.ts')):
                     filepath = os.path.join(root, file)
 
                     # Count tests in this file
                     test_count = 0
                     try:
                         with open(filepath, 'r', encoding='utf-8', errors='ignore') as f:
                             content = f.read()
                             if self.test_framework == 'ginkgo':
                                 test_count = len(re.findall(r'g\.It\(', content))
                             elif self.language == 'python':
                                 test_count = len(re.findall(r'def test_', content))
                             else:
                                 test_count = len(re.findall(r'func Test', content))
-                    except:
+                    except (OSError, UnicodeDecodeError):
                         continue

307-348: Improve error handling and fix unused variable.

Consistent with previous methods: unused dirs and bare except.

Apply this diff:

-        for root, dirs, files in os.walk(self.source_dir):
+        for root, _dirs, files in os.walk(self.source_dir):
             for file in files:
                 if file.endswith(('.go', '.py', '.java', '.js', '.ts')):
                     filepath = os.path.join(root, file)
                     is_test = 'test' in file.lower()
 
                     try:
                         with open(filepath, 'r', encoding='utf-8', errors='ignore') as f:
                             content = f.read()
                             lines = content.split('\n')
 
                             # Count lines
                             if is_test:
                                 quality_metrics['test_lines_of_code'] += len(lines)
                             else:
                                 quality_metrics['lines_of_code'] += len(lines)
 
                             # Assertions
                             if self.language == 'go':
                                 quality_metrics['assertions'] += len(re.findall(r'o\.Expect\(', content))
                                 quality_metrics['assertions'] += len(re.findall(r'assert\.(Equal|NotEqual|True|False)', content))
                             elif self.language == 'python':
                                 quality_metrics['assertions'] += len(re.findall(r'assert ', content))
 
                             # Error handling
                             if self.language == 'go':
                                 quality_metrics['error_handling'] += len(re.findall(r'if err != nil', content))
                             elif self.language == 'python':
                                 quality_metrics['error_handling'] += len(re.findall(r'try:', content))
                                 quality_metrics['error_handling'] += len(re.findall(r'except', content))
 
                             # Comments
                             quality_metrics['comments'] += len(re.findall(r'^\s*#', content, re.MULTILINE))
                             quality_metrics['comments'] += len(re.findall(r'^\s*//', content, re.MULTILINE))
 
                             # Complexity
                             quality_metrics['complexity_indicators']['if_statements'] += len(re.findall(r'\bif\b', content))
                             quality_metrics['complexity_indicators']['for_loops'] += len(re.findall(r'\bfor\b', content))
                             quality_metrics['complexity_indicators']['while_loops'] += len(re.findall(r'\bwhile\b', content))
 
-                    except:
+                    except (OSError, UnicodeDecodeError):
                         continue

369-380: Improve error handling and fix unused variable.

Same pattern: unused dirs and bare except.

Apply this diff:

-        for root, dirs, files in os.walk(self.source_dir):
+        for root, _dirs, files in os.walk(self.source_dir):
             for file in files:
                 if file.endswith(('.go', '.py', '.java', '.js', '.ts')):
                     filepath = os.path.join(root, file)
                     try:
                         with open(filepath, 'r', encoding='utf-8', errors='ignore') as f:
                             content = f.read()
                             for platform_name, patterns in platforms.items():
                                 for pattern in patterns:
                                     platform_refs[platform_name] += len(re.findall(pattern, content))
-                    except:
+                    except (OSError, UnicodeDecodeError):
                         continue

455-479: Remove unused parameters if not needed.

The characteristics and quality_metrics parameters are not used in the method body. If they're placeholders for future functionality, consider commenting on their intended use.

If not needed, apply this diff:

-    def _generate_recommendations(self, gaps, characteristics, quality_metrics) -> List[Tuple]:
+    def _generate_recommendations(self, gaps) -> List[Tuple]:
         """Generate prioritized recommendations"""

And update the call site:

         # 7. Generate Recommendations
-        recommendations = self._generate_recommendations(gaps, characteristics, quality_metrics)
+        recommendations = self._generate_recommendations(gaps)

609-642: Remove unused variable and unnecessary f-string.

The output_path variable at line 637 is assigned but never used. Also, line 75 uses an f-string without placeholders.

Apply this diff:

     try:
         # Create analyzer
         analyzer = UnifiedAnalyzer(args.source_dir, args.language, args.framework)
 
         # Run analysis
         print("=" * 70)
         print("UNIFIED TEST COVERAGE ANALYSIS")
         print("=" * 70)
-        print(f"Starting unified analysis...")
+        print("Starting unified analysis...")
         print(f"  Language: {self.language}")

And:

         # Save results
-        output_path = analyzer.save_results(args.output)
+        analyzer.save_results(args.output)
 
         print()
         print(f"✅ Analysis complete! Reports saved to: {args.output}")
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between fd7a73f and bc63771.

📒 Files selected for processing (28)
  • PLUGINS.md (2 hunks)
  • plugins/test-coverage/.claude-plugin/plugin.json (1 hunks)
  • plugins/test-coverage/README.md (1 hunks)
  • plugins/test-coverage/URL_SUPPORT.md (1 hunks)
  • plugins/test-coverage/commands/analyze.md (1 hunks)
  • plugins/test-coverage/commands/compare.md (1 hunks)
  • plugins/test-coverage/commands/gaps.md (1 hunks)
  • plugins/test-coverage/skills/analyze/README.md (1 hunks)
  • plugins/test-coverage/skills/analyze/analyze.py (1 hunks)
  • plugins/test-coverage/skills/analyze/coverage_parser.py (1 hunks)
  • plugins/test-coverage/skills/analyze/report_generator.py (1 hunks)
  • plugins/test-coverage/skills/gaps-analyzer/analyze_gaps.py (1 hunks)
  • plugins/test-coverage/skills/test-structure/README.md (1 hunks)
  • plugins/test-coverage/skills/test-structure/README_HTML_REPORTS.md (1 hunks)
  • plugins/test-coverage/skills/test-structure/README_OLD.md (1 hunks)
  • plugins/test-coverage/skills/test-structure/SKILL.md (1 hunks)
  • plugins/test-coverage/skills/test-structure/analyze_test_gaps.py (1 hunks)
  • plugins/test-coverage/skills/test-structure/compare_coverage.py (1 hunks)
  • plugins/test-coverage/skills/test-structure/compare_report_generator.py (1 hunks)
  • plugins/test-coverage/skills/test-structure/coverage_comparator.py (1 hunks)
  • plugins/test-coverage/skills/test-structure/gap_analyzer.py (1 hunks)
  • plugins/test-coverage/skills/test-structure/gap_report_generator.py (1 hunks)
  • plugins/test-coverage/skills/test-structure/generate_networking_report.py (1 hunks)
  • plugins/test-coverage/skills/test-structure/html_report_generator.py (1 hunks)
  • plugins/test-coverage/skills/test-structure/test_structure_analyzer.py (1 hunks)
  • plugins/test-coverage/skills/test-structure/unified_analyzer.py (1 hunks)
  • plugins/test-coverage/utils/__init__.py (1 hunks)
  • plugins/test-coverage/utils/path_handler.py (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • plugins/test-coverage/.claude-plugin/plugin.json
  • PLUGINS.md
  • plugins/test-coverage/utils/init.py
🧰 Additional context used
🪛 LanguageTool
plugins/test-coverage/skills/test-structure/README_OLD.md

[uncategorized] ~207-~207: A comma may be missing after the conjunctive/linking adverb ‘Currently’.
Context: ...precise coverage ### Language Support Currently supports Go, Python, Java, JavaScript, ...

(SENT_START_CONJUNCTIVE_LINKING_ADVERB_COMMA)

plugins/test-coverage/README.md

[typographical] ~195-~195: Two consecutive commas
Context: ..., [Longduration], [ConnectedOnly], [NonPreRelease]-g.Describe(, g.Context(, g.It(` Note: To inc...

(DOUBLE_PUNCTUATION)


[uncategorized] ~313-~313: Use a comma before ‘but’ if it connects two independent clauses (unless they are closely connected and short).
Context: ...ude "*.js" ``` ### Issue: No gaps found but code is clearly untested Solution:...

(COMMA_COMPOUND_SENTENCE_2)


[uncategorized] ~366-~366: Loose punctuation mark.
Context: ...ation. ## Related Plugins - jira: Create bug reports with coverage gap co...

(UNLIKELY_OPENING_PUNCTUATION)

plugins/test-coverage/URL_SUPPORT.md

[uncategorized] ~225-~225: Possible missing preposition found.
Context: ...eports HTTP error codes and reasons - Network errors: Reports connection issues wit...

(AI_HYDRA_LEO_MISSING_OF)

plugins/test-coverage/commands/analyze.md

[uncategorized] ~28-~28: Loose punctuation mark.
Context: ...g. ## Arguments - <source-directory>: Path or URL to source code directory/fi...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~36-~36: Loose punctuation mark.
Context: ...-coverage/cache/ ---language `: Programming language (optional, default...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~39-~39: Loose punctuation mark.
Context: ... - Supported: go - --output <path>: Output directory for generated reports ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~42-~42: Loose punctuation mark.
Context: ...and text summary - --priority <level>: Filter results by priority (optional) ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~46-~46: Loose punctuation mark.
Context: ... Default: all - --exclude <pattern>: Exclude files matching pattern from ana...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~46-~46: It seems likely that a singular genitive (’s) apostrophe is missing.
Context: ...all - --exclude <pattern>: Exclude files matching pattern from analysis (optiona...

(AI_HYDRA_LEO_APOSTROPHE_S_XS)


[uncategorized] ~50-~50: Loose punctuation mark.
Context: ...de "/test/" ---include-test-utils`: Include test utility/helper files in an...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~55-~55: Loose punctuation mark.
Context: ...structure code - --include-unit-tests: Include unit tests in analysis (optiona...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~63-~63: Loose punctuation mark.
Context: ...or Python) - --test-pattern <pattern>: Custom test file pattern (optional) -...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~66-~66: Loose punctuation mark.
Context: .../Test*.java" ---test-structure-only`: Analyze only test file structure, skip ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~272-~272: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ... Example 2: Analyze test structure with high priority filter ``` /test-coverage:analyze ./pk...

(EN_COMPOUND_ADJECTIVE_INTERNAL)


[duplication] ~356-~356: Possible typo: you repeated a word.
Context: ... - URLs are automatically detected and downloaded - Downloaded files are cached in `.work/test-coverag...

(ENGLISH_WORD_REPEAT_RULE)

plugins/test-coverage/commands/compare.md

[uncategorized] ~41-~41: Loose punctuation mark.
Context: ...wnloaded and cached - --output <path>: Output directory for comparison reports...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~43-~43: Loose punctuation mark.
Context: ...erage/compare/) - --fail-on-decrease`: Exit with error if coverage decreases ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~47-~47: Loose punctuation mark.
Context: ...ic control - --threshold <percentage>: Maximum acceptable coverage decrease (d...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~51-~51: Loose punctuation mark.
Context: ...-decreaseis set ---format `: Coverage format for both files (optiona...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~55-~55: Loose punctuation mark.
Context: ... (.out for Go) - --ignore-new-files: Don't count new files in coverage delta...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~59-~59: Loose punctuation mark.
Context: ...g files only - --ignore-removed-files: Don't count removed files in coverage d...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~62-~62: Loose punctuation mark.
Context: ...min-coverage-for-new-files `: Require new files to meet minimum cover...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~192-~192: When ‘Show-specific’ is used as a modifier, it is usually spelled with a hyphen.
Context: ... - Files with decreased coverage - Show specific lines that lost coverage - Priorit...

(SPECIFIC_HYPHEN)


[grammar] ~280-~280: Using ‘plenty’ without ‘of’ is considered to be informal.
Context: ...ed: - Allow decrease up to threshold amount - Example: threshold 2.0 allows decrease from 80%...

(PLENTY_OF_NOUNS)

plugins/test-coverage/commands/gaps.md

[uncategorized] ~41-~41: Loose punctuation mark.
Context: ...to archive/file) - --priority <level>: Filter gaps by priority level (optional...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~47-~47: Loose punctuation mark.
Context: ...tters, utilities) - --format <format>: Coverage file format (optional, default...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~50-~50: Loose punctuation mark.
Context: ...est -coverprofile) - --output `: Output directory for gap analysis repor...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~52-~52: Loose punctuation mark.
Context: ...-coverage/gaps/) - --language `: Source code language (optional, default...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~56-~56: Loose punctuation mark.
Context: ...alysis patterns - --exclude <pattern>: Exclude files matching pattern (optiona...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~59-~59: Loose punctuation mark.
Context: ...*" ---complexity-threshold `: Minimum cyclomatic complexity to flag (...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~62-~62: Loose punctuation mark.
Context: ...sts are prioritized - --show-snippets: Include source code snippets of uncover...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~66-~66: Loose punctuation mark.
Context: ...uncovered block - --max-gaps <number>: Limit number of gaps to report (default...

(UNLIKELY_OPENING_PUNCTUATION)

plugins/test-coverage/skills/analyze/README.md

[style] ~143-~143: As an alternative to the over-used intensifier ‘very’, consider replacing this phrase.
Context: ...lxml ``` ### Large Coverage Files For very large coverage files, the tool may take some ...

(EN_WEAK_ADJECTIVE)

plugins/test-coverage/skills/test-structure/README.md

[uncategorized] ~3-~3: Possible missing comma found.
Context: ...gaps logic Comprehensive test coverage analysis combining structural analysis and gap d...

(AI_HYDRA_LEO_MISSING_COMMA)


[uncategorized] ~53-~53: Possible missing comma found.
Context: ...s the recommended tool for most use cases as it combines analyze and gaps logic t...

(AI_HYDRA_LEO_MISSING_COMMA)

plugins/test-coverage/skills/test-structure/SKILL.md

[duplication] ~217-~217: Possible typo: you repeated a word.
Context: ...t → function): - TestHandleRequest tests HandleRequest - test_parse_xml tests parse_xml 3. *Import-based mapping...

(ENGLISH_WORD_REPEAT_RULE)

🪛 markdownlint-cli2 (0.18.1)
plugins/test-coverage/skills/test-structure/README_OLD.md

10-10: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


51-51: Spaces inside emphasis markers

(MD037, no-space-in-emphasis)


230-230: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


266-266: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


274-274: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


282-282: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

plugins/test-coverage/skills/test-structure/README_HTML_REPORTS.md

10-10: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


51-51: Spaces inside emphasis markers

(MD037, no-space-in-emphasis)


230-230: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


266-266: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


274-274: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


282-282: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


290-290: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

plugins/test-coverage/README.md

10-10: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


51-51: Spaces inside emphasis markers

(MD037, no-space-in-emphasis)


230-230: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


266-266: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


274-274: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


282-282: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


290-290: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


298-298: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


312-312: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


320-320: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


328-328: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


338-338: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

plugins/test-coverage/URL_SUPPORT.md

10-10: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


51-51: Spaces inside emphasis markers

(MD037, no-space-in-emphasis)


230-230: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

plugins/test-coverage/commands/analyze.md

10-10: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


51-51: Spaces inside emphasis markers

(MD037, no-space-in-emphasis)


230-230: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


266-266: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


274-274: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


282-282: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


290-290: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


298-298: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


312-312: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


320-320: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


328-328: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


338-338: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

plugins/test-coverage/commands/compare.md

10-10: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


239-239: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


311-311: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


350-350: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


358-358: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


366-366: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


374-374: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


382-382: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


391-391: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


399-399: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


407-407: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


416-416: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

plugins/test-coverage/skills/analyze/README.md

63-63: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


112-112: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


150-150: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

plugins/test-coverage/skills/test-structure/SKILL.md

10-10: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


300-300: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


379-379: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


424-424: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


432-432: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


440-440: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


448-448: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


456-456: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


464-464: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


472-472: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


480-480: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


488-488: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🪛 Ruff (0.14.3)
plugins/test-coverage/skills/test-structure/html_report_generator.py

30-30: Local variable partially_tested is assigned to but never used

Remove assignment to unused variable partially_tested

(F841)


572-572: Unused function argument: summary

(ARG001)


575-575: Local variable untested_funcs is assigned to but never used

Remove assignment to unused variable untested_funcs

(F841)


989-989: Local variable structure is assigned to but never used

Remove assignment to unused variable structure

(F841)

plugins/test-coverage/utils/path_handler.py

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

(EXE001)


118-118: Probable use of insecure hash functions in hashlib: md5

(S324)


157-157: Audit URL open for permitted schemes. Allowing use of file: or custom schemes is often unexpected.

(S310)


159-159: Audit URL open for permitted schemes. Allowing use of file: or custom schemes is often unexpected.

(S310)


182-182: Do not catch blind exception: Exception

(BLE001)

plugins/test-coverage/skills/analyze/analyze.py

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

(TRY003)


242-242: Do not catch blind exception: Exception

(BLE001)


295-295: Consider moving this statement to an else block

(TRY300)


297-297: Do not catch blind exception: Exception

(BLE001)

plugins/test-coverage/skills/test-structure/coverage_comparator.py

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

(EXE001)

plugins/test-coverage/skills/analyze/report_generator.py

18-18: Unused static method argument: baseline

(ARG004)


433-524: f-string without any placeholders

Remove extraneous f prefix

(F541)


706-706: Do not catch blind exception: Exception

(BLE001)

plugins/test-coverage/skills/test-structure/test_structure_analyzer.py

124-124: Loop control variable root not used within loop body

Rename unused root to _root

(B007)


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

(TRY003)


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

(TRY003)


167-167: PEP 484 prohibits implicit Optional

Convert to T | None

(RUF013)


285-285: Do not catch blind exception: Exception

(BLE001)


504-504: Local variable source_by_path is assigned to but never used

Remove assignment to unused variable source_by_path

(F841)


541-541: Unused function argument: file_path

(ARG001)


761-761: Do not catch blind exception: Exception

(BLE001)


771-771: Do not catch blind exception: Exception

(BLE001)


823-823: Do not catch blind exception: Exception

(BLE001)


837-837: Consider moving this statement to an else block

(TRY300)


839-839: Do not catch blind exception: Exception

(BLE001)

plugins/test-coverage/skills/test-structure/gap_analyzer.py

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

(EXE001)

plugins/test-coverage/skills/test-structure/compare_coverage.py

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

(EXE001)


111-111: Loop control variable i not used within loop body

Rename unused i to _i

(B007)


118-118: Loop control variable i not used within loop body

Rename unused i to _i

(B007)

plugins/test-coverage/skills/test-structure/gap_report_generator.py

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

(EXE001)

plugins/test-coverage/skills/test-structure/generate_networking_report.py

20-20: Local variable test_tags is assigned to but never used

Remove assignment to unused variable test_tags

(F841)


108-108: f-string without any placeholders

Remove extraneous f prefix

(F541)

plugins/test-coverage/skills/test-structure/unified_analyzer.py

37-37: Loop control variable dirs not used within loop body

Rename unused dirs to _dirs

(B007)


65-65: Do not use bare except

(E722)


65-66: try-except-continue detected, consider logging the exception

(S112)


75-75: f-string without any placeholders

Remove extraneous f prefix

(F541)


144-144: Do not catch blind exception: Exception

(BLE001)


151-151: Do not catch blind exception: Exception

(BLE001)


203-203: Loop control variable dirs not used within loop body

Rename unused dirs to _dirs

(B007)


224-224: Do not use bare except

(E722)


224-225: try-except-continue detected, consider logging the exception

(S112)


266-266: Loop control variable dirs not used within loop body

Rename unused dirs to _dirs

(B007)


282-282: Do not use bare except

(E722)


282-283: try-except-continue detected, consider logging the exception

(S112)


307-307: Loop control variable dirs not used within loop body

Rename unused dirs to _dirs

(B007)


347-347: Do not use bare except

(E722)


347-348: try-except-continue detected, consider logging the exception

(S112)


369-369: Loop control variable dirs not used within loop body

Rename unused dirs to _dirs

(B007)


379-379: Do not use bare except

(E722)


379-380: try-except-continue detected, consider logging the exception

(S112)


455-455: Unused method argument: characteristics

(ARG002)


455-455: Unused method argument: quality_metrics

(ARG002)


564-564: Do not catch blind exception: Exception

(BLE001)


637-637: Local variable output_path is assigned to but never used

Remove assignment to unused variable output_path

(F841)


643-643: Consider moving this statement to an else block

(TRY300)


645-645: Do not catch blind exception: Exception

(BLE001)

plugins/test-coverage/skills/analyze/coverage_parser.py

156-156: Do not use bare except

(E722)


156-157: try-except-pass detected, consider logging the exception

(S110)


158-158: Do not catch blind exception: Exception

(BLE001)


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

(TRY003)


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

(TRY003)


194-194: Using xml to parse untrusted data is known to be vulnerable to XML attacks; use defusedxml equivalents

(S314)


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

(TRY003)


355-355: Local variable num_stmt is assigned to but never used

Remove assignment to unused variable num_stmt

(F841)


366-366: Ambiguous variable name: l

(E741)


378-378: Ambiguous variable name: l

(E741)


391-391: Using xml to parse untrusted data is known to be vulnerable to XML attacks; use defusedxml equivalents

(S314)


428-428: Local variable mi is assigned to but never used

Remove assignment to unused variable mi

(F841)


449-449: Using xml to parse untrusted data is known to be vulnerable to XML attacks; use defusedxml equivalents

(S314)


552-552: Do not catch blind exception: Exception

(BLE001)

plugins/test-coverage/skills/test-structure/analyze_test_gaps.py

105-105: f-string without any placeholders

Remove extraneous f prefix

(F541)

plugins/test-coverage/skills/test-structure/compare_report_generator.py

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

(EXE001)

plugins/test-coverage/skills/gaps-analyzer/analyze_gaps.py

314-314: Local variable first_uncovered is assigned to but never used

Remove assignment to unused variable first_uncovered

(F841)


427-427: Loop control variable i not used within loop body

(B007)


633-633: f-string without any placeholders

Remove extraneous f prefix

(F541)


643-643: f-string without any placeholders

Remove extraneous f prefix

(F541)

🔇 Additional comments (12)
plugins/test-coverage/skills/test-structure/README.md (1)

1-276: File quality is high; no material issues identified.

This README provides comprehensive documentation for the unified analyzer and related tools, with clear examples, feature matrices, and troubleshooting. The static analysis hints about missing commas are false positives (the sentences are grammatically correct).

plugins/test-coverage/skills/gaps-analyzer/analyze_gaps.py (5)

17-45: LGTM: Well-structured data models.

The CoverageBlock and Gap dataclasses are clean and appropriately use the @property decorator for computed fields.


47-79: LGTM: Clean coverage file parser.

The regex pattern correctly parses the Go coverage format, and the implementation appropriately skips the mode line and empty lines.


143-170: LGTM: Well-organized orchestration logic.

The gap analysis workflow is clean, with appropriate grouping by file and priority-based sorting.


229-306: LGTM: Well-designed categorization and prioritization logic.

The gap categorization, priority scoring, and recommendation generation provide a comprehensive framework for analyzing coverage gaps. The weighted scoring system appropriately considers complexity, visibility, and gap type.


542-599: LGTM: Clear and informative text report.

The text report provides a good summary with actionable recommendations and a practical testing roadmap.

plugins/test-coverage/skills/test-structure/unified_analyzer.py (6)

17-32: LGTM: Clean initialization with flexible configuration.

The class initialization appropriately handles optional language and test framework parameters with auto-detection fallback.


140-152: Exception handling is appropriate for parsing multiple files.

While static analysis flags catching broad Exception, this is acceptable here since the code needs to continue processing other files even when parsing fails. The warnings are properly logged.


384-453: LGTM: Comprehensive gap identification with good severity classification.

The gap identification logic appropriately considers structural gaps, cleanup patterns, quality metrics, and feature coverage with reasonable severity thresholds.


481-516: LGTM: Good practice to identify strengths alongside gaps.

The strength identification provides balanced feedback with reasonable thresholds for what constitutes good test coverage.


533-569: LGTM: Robust save logic with graceful HTML generation fallback.

The method appropriately handles HTML generation failures while ensuring JSON output always succeeds. The broad exception handling is acceptable for the optional HTML feature.


571-591: LGTM: Well-formatted metrics for HTML display.

The metrics formatting provides clear status indicators with appropriate thresholds.

Copy link
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: 7

🧹 Nitpick comments (16)
plugins/test-coverage/skills/test-structure/README_HTML_REPORTS.md (5)

247-251: Raise Python minimum version; confirm dependency statement

Python 3.6/3.7 are EOL. Recommend 3.8+ minimum; keep “stdlib only” if accurate.

-- Python 3.6+
+- Python 3.8+ (3.6/3.7 are EOL)
 - No external dependencies (uses only Python standard library)

Please confirm that all referenced scripts (e.g., html_report_generator.py, analyzers) indeed use only the standard library. If not, enumerate minimal deps here.


264-268: Prefer python invocation or add shebangs; chmod alone is misleading

chmod +x without shebangs won’t allow direct execution; current examples already use python3.

-# Make scripts executable
-chmod +x html_report_generator.py
-chmod +x generate_networking_report.py
-chmod +x test_structure_analyzer.py
+# Preferred: run via Python
+python3 generate_networking_report.py --help
+python3 test_structure_analyzer.py --help
+# Optional: to run directly, add a shebang to each script then chmod:
+#   #!/usr/bin/env python3
+#   chmod +x *.py

12-17: Document unified HTML generator (if available) for completeness

If html_report_generator.py exposes generate_unified_html and there’s a unified analyzer, add them here for discoverability and keep examples consistent.

 - `html_report_generator.py` - Core HTML report generation functions
+- `unified_analyzer.py` - Unified analysis across structure and gaps (HTML via generate_unified_html)
-from html_report_generator import generate_test_gaps_html, generate_test_structure_html
+from html_report_generator import (
+    generate_test_gaps_html,
+    generate_test_structure_html,
+    generate_unified_html,
+)
@@
-# For test structure report
+# For test structure report
@@
-generate_test_structure_html(structure_data, 'custom_structure.html')
+generate_test_structure_html(structure_data, 'custom_structure.html')
+
+# For unified report
+unified_data = {'structure': structure_data, 'gaps': gaps_data}
+generate_unified_html(unified_data, 'custom_unified.html')

Also applies to: 88-134


170-183: Create output directories in examples to prevent write errors

Ensure parent directories exist before generating outputs.

 # 1. Navigate to skills directory
 cd /home/anusaxen/git/ai-helpers/plugins/test-coverage/skills/test-structure
+# 1a. Ensure output folder exists
+mkdir -p ../../.work/test-coverage
@@
-  ../../.work/test-coverage/networking_gaps.html
+  ../../.work/test-coverage/networking_gaps.html
@@
 # 1. Navigate to skills directory
 cd /home/anusaxen/git/ai-helpers/plugins/test-coverage/skills/test-structure
+# 1a. Ensure output folder exists
+mkdir -p ../../.work/test-coverage/myproject

Also applies to: 187-200


179-183: Cross‑platform “open in browser” commands

Add macOS and Windows equivalents for convenience.

 firefox ../../.work/test-coverage/networking_gaps.html
 # or
 xdg-open ../../.work/test-coverage/networking_gaps.html
+# macOS
+open ../../.work/test-coverage/networking_gaps.html
+# Windows (PowerShell)
+start "" ../../.work/test-coverage/networking_gaps.html
plugins/test-coverage/README.md (2)

215-219: Verify gocyclo install instruction

You list two different sources for gocyclo. Keep only the supported one to prevent confusion.

Suggested change:

-  go install golang.org/x/tools/cmd/gocyclo@latest
   go install github.com/fzipp/gocyclo/cmd/gocyclo@latest

313-315: Fix bare URLs (MD034)

Convert bare URLs to links to satisfy markdownlint.

- - **Issues**: https://github.com/openshift-eng/ai-helpers/issues
- - **Documentation**: https://github.com/openshift-eng/ai-helpers
+ - **Issues**: <https://github.com/openshift-eng/ai-helpers/issues>
+ - **Documentation**: <https://github.com/openshift-eng/ai-helpers>
plugins/test-coverage/commands/gaps.md (3)

116-121: Go terminology fixes (remove non‑Go constructs)

Replace “try/catch” and “class constructors” with Go‑appropriate language.

-  - Lines in catch blocks
-  - Panic/throw statements
+  - Lines in error return branches (`if err != nil { ... }`)
+  - Panic/recover paths
@@
-  - Public class constructors
+  - Exported constructors (`NewXxx` functions)

Also applies to: 123-126


10-12: Add languages to fenced code blocks (MD040)

Specify languages to satisfy markdownlint and improve rendering.

-```
+```bash
 /test-coverage:gaps <coverage-file-or-url> <source-directory-or-url> [...]

@@
- +text
Coverage Gap Analysis
...

@@
-```
+```bash
/test-coverage:gaps coverage.xml ./src/

@@
- +bash
/test-coverage:gaps coverage.xml ./src/ --priority high

@@
-```
+```bash
/test-coverage:gaps coverage.xml ./src/ --show-snippets

@@
- +bash
/test-coverage:gaps coverage.xml ./src/ --complexity-threshold 15

@@
-```
+```bash
/test-coverage:gaps coverage.xml ./src/ --priority high --max-gaps 10

@@
- +bash
/test-coverage:gaps coverage.out ./pkg/ --language go --format go

@@
-```
+```bash
/test-coverage:gaps https://example.com/ci-artifacts/coverage.xml ./src/

@@
- +bash
/test-coverage:gaps https://example.com/coverage.out https://github.com/owner/repo/archive/refs/heads/main.zip

@@
-```
+```bash
/test-coverage:gaps https://raw.githubusercontent.com/owner/repo/main/coverage.out https://github.com/owner/repo/blob/main/pkg/


Also applies to: 300-361, 379-414, 424-466, 472-494, 480-486, 488-493

---

`505-508`: **Align Python version requirement**

This page says Python 3.8+. Ensure the same minimum version is stated across all plugin docs.

</blockquote></details>
<details>
<summary>plugins/test-coverage/skills/analyze/README.md (2)</summary><blockquote>

`137-139`: **Remove optional lxml note (if Go‑only) and unify Python version**

If the tool is Go‑only, XML parsing and `lxml` aren’t relevant. Also, set a single Python minimum (recommend 3.8+) and use it everywhere.


```diff
- pip install lxml
- - **Python 3.7+** (uses standard library only, no external packages required)
+ - **Python 3.8+** (uses standard library only, no external packages required)

Also applies to: 73-75


63-69: Add languages to fenced code blocks (MD040)

Add explicit languages for better rendering.

-```
+```text
 analyze/
 ├── analyze.py              # Main entry point
 ...
-```
+```bash
 /test-coverage:analyze coverage.out --threshold 80
-```
+```text
 ================================================================================
 Code Coverage Analysis Complete
 ...

Also applies to: 112-115, 150-175

plugins/test-coverage/commands/analyze.md (4)

61-62: Language scope drift

Detection hints mention Python markers, but Supported languages list only Go. Either scope the hints to Go or document explicit multi‑language support.

-    - Test markers (e.g., [Serial], [Disruptive] for Ginkgo, @pytest.mark.integration for Python)
+    - Test markers (e.g., [Serial], [Disruptive] for Ginkgo)

231-256: Add languages to fenced code blocks (MD040)

Label terminal snippets as text or bash for linting and readability.

-```
+```text
 Test Structure Analysis Complete
 ...
-```
+```bash
 /test-coverage:analyze ./pkg/
-```
+```bash
 /test-coverage:analyze ./pkg/ --exclude "*/generated/*"
-```
+```bash
 /test-coverage:analyze ./test/extended/networking/infw.go --test-structure-only
-```
+```bash
 /test-coverage:analyze https://github.com/openshift/origin/blob/master/test/extended/networking/infw.go --test-structure-only
-```
+```bash
 rm -rf .work/test-coverage/cache/
 /test-coverage:analyze https://github.com/user/repo/blob/main/test/file_test.go --test-structure-only

Also applies to: 266-276, 282-294, 298-314, 320-333, 338-341


351-352: Unify Python version check

Standardize to a single minimum version (recommend 3.8+) across all docs.

- The command will automatically check for Python 3.6+ and provide installation instructions if missing.
+ The command will automatically check for Python 3.8+ and provide installation instructions if missing.

319-333: Optional: angle‑bracket bare URLs in examples

To avoid MD034 in some linters, wrap example URLs in angle brackets.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between bc63771 and 70d9c62.

📒 Files selected for processing (7)
  • PLUGINS.md (2 hunks)
  • plugins/test-coverage/README.md (1 hunks)
  • plugins/test-coverage/URL_SUPPORT.md (1 hunks)
  • plugins/test-coverage/commands/analyze.md (1 hunks)
  • plugins/test-coverage/commands/gaps.md (1 hunks)
  • plugins/test-coverage/skills/analyze/README.md (1 hunks)
  • plugins/test-coverage/skills/test-structure/README_HTML_REPORTS.md (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • plugins/test-coverage/URL_SUPPORT.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • PLUGINS.md
🧰 Additional context used
🪛 LanguageTool
plugins/test-coverage/commands/analyze.md

[grammar] ~272-~272: Use a hyphen to join words.
Context: ...mple 2: Analyze test structure with high priority filter ``` /test-coverage:anal...

(QB_NEW_EN_HYPHEN)

plugins/test-coverage/commands/gaps.md

[uncategorized] ~41-~41: Loose punctuation mark.
Context: ...to archive/file) - --priority <level>: Filter gaps by priority level (optional...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~47-~47: Loose punctuation mark.
Context: ...tters, utilities) - --format <format>: Coverage file format (optional, default...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~50-~50: Loose punctuation mark.
Context: ...est -coverprofile) - --output `: Output directory for gap analysis repor...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~52-~52: Loose punctuation mark.
Context: ...-coverage/gaps/) - --language `: Source code language (optional, default...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~56-~56: Loose punctuation mark.
Context: ...alysis patterns - --exclude <pattern>: Exclude files matching pattern (optiona...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~59-~59: Loose punctuation mark.
Context: ...*" ---complexity-threshold `: Minimum cyclomatic complexity to flag (...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~62-~62: Loose punctuation mark.
Context: ...sts are prioritized - --show-snippets: Include source code snippets of uncover...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~66-~66: Loose punctuation mark.
Context: ...uncovered block - --max-gaps <number>: Limit number of gaps to report (default...

(UNLIKELY_OPENING_PUNCTUATION)

plugins/test-coverage/skills/analyze/README.md

[grammar] ~1-~1: Ensure spelling is correct
Context: # Coverage Analyze Skill This skill provides comprehensiv...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)


[style] ~143-~143: As an alternative to the over-used intensifier ‘very’, consider replacing this phrase.
Context: ...lxml ``` ### Large Coverage Files For very large coverage files, the tool may take some ...

(EN_WEAK_ADJECTIVE)

🪛 markdownlint-cli2 (0.18.1)
plugins/test-coverage/skills/test-structure/README_HTML_REPORTS.md

206-206: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


294-294: Bare URL used

(MD034, no-bare-urls)

plugins/test-coverage/README.md

313-313: Bare URL used

(MD034, no-bare-urls)


314-314: Bare URL used

(MD034, no-bare-urls)

plugins/test-coverage/commands/analyze.md

206-206: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


294-294: Bare URL used

(MD034, no-bare-urls)

plugins/test-coverage/commands/gaps.md

10-10: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


300-300: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


379-379: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


424-424: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


432-432: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


440-440: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


448-448: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


456-456: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


464-464: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


472-472: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


480-480: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


488-488: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

plugins/test-coverage/skills/analyze/README.md

63-63: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


112-112: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


150-150: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🔇 Additional comments (2)
plugins/test-coverage/skills/test-structure/README_HTML_REPORTS.md (1)

50-54: No changes needed—--language and --priority flags are present in test_structure_analyzer.py, and the example CLI usage is accurate.

plugins/test-coverage/commands/gaps.md (1)

224-237: “All three reports” guarantee: verify implementation

Docs mark all three outputs as REQUIRED and a failure if any is missing. Confirm the implementation enforces this behavior and error codes.

Also applies to: 253-261, 299-361, 363-373

Copy link
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)
plugins/test-coverage/README.md (2)

208-215: ** Standardize Python version across documentation.**

Line 212 still specifies "Python 3.6+" which conflicts with other docs. Align to a consistent minimum (recommend "Python 3.8+") and update all related docs.

Apply this diff to fix:

- **Python 3.6+** (uses standard library only, no external packages required)
+ **Python 3.8+** (uses standard library only, no external packages required)

301-307: ** Replace Java patterns with Go test patterns.**

Line 306 shows Java test patterns (*Spec.java, IT*.java) but the plugin is Go-only (see line 161). Replace with Go-specific patterns for consistency.

Apply this diff:

- /test-coverage:analyze ./src/ --test-pattern "**/*Spec.java,**/IT*.java"
+ /test-coverage:analyze ./pkg/ --test-pattern "**/*_test.go,**/*e2e*_test.go,**/*integration*_test.go"
plugins/test-coverage/commands/gaps.md (2)

30-35: ** Align coverage format examples with supported formats.**

Lines 31–32 reference coverage.xml files, but line 33 states only "Go coverage (.out) or JSON" are supported. Remove XML examples or explicitly add XML as a supported format.

Apply this diff to align with Go-only support:

- - **Local path**: `./coverage.out`, `/path/to/coverage.xml`
- - **URL**: `https://example.com/coverage.xml`, `https://raw.githubusercontent.com/owner/repo/main/coverage.out`
+ - **Local path**: `./coverage.out`, `/path/to/coverage.out`
+ - **URL**: `https://raw.githubusercontent.com/owner/repo/main/coverage.out`
- - Supports: Go coverage (`.out`) or JSON from `/test-coverage:analyze`
+ - Supports: Go coverage (`.out`) or JSON from `/test-coverage:analyze`

420-483: Update all example commands to use supported coverage formats.

Examples throughout the file reference coverage.xml (lines 423, 431, 439, 447, 455, 463, 471, 479), but only .out (Go format) or JSON are supported. Update all examples to use Go coverage format.

Apply diffs to each example. For instance:

- /test-coverage:gaps coverage.xml ./src/
+ /test-coverage:gaps coverage.out ./src/
- /test-coverage:gaps https://example.com/coverage.xml ./src/
+ /test-coverage:gaps https://raw.githubusercontent.com/owner/repo/main/coverage.out ./src/
- /test-coverage:gaps coverage.xml ./src/ --priority high
+ /test-coverage:gaps coverage.out ./src/ --priority high

(Apply similar changes to all remaining examples at lines 423, 431, 439, 447, 455, 463, 471, 479.)

plugins/test-coverage/skills/test-structure/test_structure_analyzer.py (2)

318-318: Fix Java test name extraction to avoid runtime failure.

Line 318 uses match.group(2) for non-Go/Python languages (including Java), but the Java regex pattern at line 53 defines only one capture group. This causes an IndexError that is silently caught, meaning Java test files are always skipped.

Apply this diff to handle variable capture group counts:

-            test_name = match.group(1) if language in ['go', 'python'] else match.group(2)
+            if language in ['go', 'python']:
+                test_name = match.group(1)
+            elif match.lastindex and match.lastindex >= 1:
+                test_name = match.group(match.lastindex)
+            else:
+                test_name = match.group(0)

693-694: The --exclude option is still not wired up.

Despite the past review comment being marked as addressed, the CLI accepts --exclude patterns via args.exclude_patterns (lines 693-694), but this value is never used to filter the discovered files. Users expecting to exclude vendor/generated files will find the flag has no effect.

Apply this diff after line 739:

         test_files_paths, source_files_paths = discover_files(source_dir, language, e2e_only=e2e_only)
+
+        # Apply exclusion patterns if provided
+        exclude_patterns = args.exclude_patterns or []
+        if exclude_patterns:
+            from fnmatch import fnmatch
+            
+            def is_excluded(path):
+                return any(fnmatch(path, pattern) for pattern in exclude_patterns)
+            
+            test_files_paths = [p for p in test_files_paths if not is_excluded(p)]
+            source_files_paths = [p for p in source_files_paths if not is_excluded(p)]
 
         # Filter out utility files unless flag is set (but not in single file mode)

Also applies to: 733-750

plugins/test-coverage/skills/test-structure/unified_analyzer.py (1)

107-127: Fix summary generation to use current analysis data.

_generate_summary() at line 123 reads self.results, but it's called while building self.results. On the first run, the summary will have zeros, and on subsequent runs it will show previous data. This breaks all downstream consumers expecting accurate statistics.

Apply this diff:

+        # Generate summary from fresh data
+        summary = {
+            'total_source_files': structure_results.get('total_source_files', 0),
+            'total_test_files': structure_results.get('total_test_files', 0),
+            'total_tests': structure_results.get('total_tests', 0),
+            'total_gaps_identified': len(gaps),
+            'high_priority_gaps': len([g for g in gaps if g['severity'] == 'HIGH']),
+            'medium_priority_gaps': len([g for g in gaps if g['severity'] == 'MEDIUM']),
+            'low_priority_gaps': len([g for g in gaps if g['severity'] == 'LOW']),
+        }
+
         self.results = {
             'metadata': {
                 'source_dir': self.source_dir,
                 'language': self.language,
                 'test_framework': self.test_framework,
                 'generated_at': datetime.now().isoformat()
             },
             'structure': structure_results,
             'characteristics': characteristics,
             'feature_coverage': feature_coverage,
             'quality_metrics': quality_metrics,
             'platform_coverage': platform_coverage,
             'gaps': gaps,
             'recommendations': recommendations,
             'strengths': strengths,
-            'summary': self._generate_summary()
+            'summary': summary
         }

Then remove or refactor _generate_summary() method since it's no longer needed.

Also applies to: 518-531

🧹 Nitpick comments (12)
plugins/test-coverage/README.md (2)

315-318: Wrap bare URLs in markdown link syntax.

Lines 315–318 contain bare URLs which should be wrapped in markdown syntax for consistency and better readability.

Apply this diff:

- - **Issues**: https://github.com/openshift-eng/ai-helpers/issues
- - **Documentation**: https://github.com/openshift-eng/ai-helpers
- - **Examples**: See `examples/` directory in the repository
+ - **Issues**: [Report Issues](https://github.com/openshift-eng/ai-helpers/issues)
+ - **Documentation**: [View Docs](https://github.com/openshift-eng/ai-helpers)
+ - **Examples**: See `examples/` directory in the repository

195-206: Clarify command mixing in Workflow 3.

The "Code Review Integration" workflow mentions analyze but references gaps command output. Either clarify this is for the gaps command or adjust the workflow description.

The workflow would be clearer if you explicitly note which command generates which output:

- # Review JSON output for CI/CD integration
- cat /tmp/review-gaps/test-structure-gaps.json
+ # Review JSON output from analyze command for CI/CD integration
+ cat /tmp/review-gaps/test-structure-gaps.json
+ 
+ # For gaps analysis output, see the /test-coverage:gaps command documentation
plugins/test-coverage/commands/gaps.md (2)

10-12: Add language specification to fenced code blocks.

Fenced code blocks should specify the language for syntax highlighting. Line 10 and others lack language tags (e.g., ```bash instead of ```).

Apply this diff to line 10 and similar blocks throughout the file:

- ```
+ ```bash
 /test-coverage:gaps <coverage-file-or-url> <source-directory-or-url> [--priority <high|medium|low>] [--format <format>] [--output <path>]
- ```
+ ```

(Apply similar changes to code blocks at lines 298, 377, 422, 430, 438, 446, 454, 462, 470, 478.)


444-450: Apply hyphen to compound adjective.

Line 444 uses "high complexity code" which should be hyphenated as "high-complexity code" when used as a compound adjective.

Apply this diff:

- ### Example 4: Focus on high complexity code
+ ### Example 4: Focus on high-complexity code
plugins/test-coverage/commands/analyze.md (3)

10-12: Add language specification to fenced code blocks (analyze.md).

Fenced code blocks should specify language for syntax highlighting. Lines 10, 50, 227, 263, 271, 279, 287, 295, 309, 317, 325, 335 lack language tags.

Apply this diff to line 10 and similar blocks:

- ```
+ ```bash
 /test-coverage:analyze <path-or-url> [--output <path>] [--priority <level>] [--test-structure-only]
- ```
+ ```

(Apply similar changes with appropriate language tags (bash, json, text, etc.) to all other code blocks in the file.)


49-52: Fix emphasis marker spacing on line 50.

Line 50 has unnecessary spaces inside emphasis markers. Use inline code formatting for file patterns instead.

Apply this diff:

- - `--include-test-utils`: Include test utility/helper files in analysis (optional)
-   - By default, utility files are excluded (*_util.go, *_utils.go, *_helper.go, helpers.go, etc.)
+ - `--include-test-utils`: Include test utility/helper files in analysis (optional)
+   - By default, utility files are excluded (`*_util.go`, `*_utils.go`, `*_helper.go`, `helpers.go`, etc.)

269-275: Apply hyphen to compound adjective.

Line 269 uses "high priority filter" which should be hyphenated as "high-priority filter" when used as a compound adjective.

Apply this diff:

- ### Example 2: Analyze test structure with high priority filter
+ ### Example 2: Analyze test structure with high-priority filter
plugins/test-coverage/skills/test-structure/README.md (1)

40-40: Consider grammar improvements for consistency.

The static analysis tool suggests hyphenating compound modifiers ("file-/function-level") and flagged the phrase "combines analyze and gaps." While the meaning is clear, you could rephrase for better readability: "combines analysis and gap detection" or "combines structural analysis and gap identification."

Also applies to: 53-53

plugins/test-coverage/skills/test-structure/analyze_test_gaps.py (1)

103-103: Remove unnecessary f-string prefix.

Line 103 uses an f-string but contains no placeholders. Remove the f prefix for consistency.

Apply this diff:

-    print(f"  Add 5-7 test cases to address high-priority gaps")
+    print("  Add 5-7 test cases to address high-priority gaps")
plugins/test-coverage/skills/test-structure/test_structure_analyzer.py (1)

504-504: Remove unused variable.

source_by_path is assigned but never used in this function. Remove it to clean up the code.

Apply this diff:

-    # Create lookup for source files
-    source_by_path = {sf.path: sf for sf in source_files}
-
     # Map each source file
plugins/test-coverage/skills/test-structure/unified_analyzer.py (2)

28-30: Remove unused language parameter.

The __init__ method accepts a language parameter but always overrides it to 'go' on line 30. This is confusing for API users. Either remove the parameter or use it when provided.

Apply this diff:

-    def __init__(self, source_dir: str, language: Optional[str] = None, test_framework: Optional[str] = None):
+    def __init__(self, source_dir: str, test_framework: Optional[str] = None):
         self.source_dir = source_dir
         self.language = 'go'  # Only Go is supported

455-479: Consider using or removing unused parameters.

The _generate_recommendations method accepts characteristics and quality_metrics parameters but never uses them. Either use these parameters to generate additional recommendations, or remove them from the signature.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 70d9c62 and bb5f9fe.

📒 Files selected for processing (9)
  • plugins/test-coverage/README.md (1 hunks)
  • plugins/test-coverage/commands/analyze.md (1 hunks)
  • plugins/test-coverage/commands/gaps.md (1 hunks)
  • plugins/test-coverage/skills/test-structure/README.md (1 hunks)
  • plugins/test-coverage/skills/test-structure/README_HTML_REPORTS.md (1 hunks)
  • plugins/test-coverage/skills/test-structure/SKILL.md (1 hunks)
  • plugins/test-coverage/skills/test-structure/analyze_test_gaps.py (1 hunks)
  • plugins/test-coverage/skills/test-structure/test_structure_analyzer.py (1 hunks)
  • plugins/test-coverage/skills/test-structure/unified_analyzer.py (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • plugins/test-coverage/skills/test-structure/SKILL.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • plugins/test-coverage/skills/test-structure/README_HTML_REPORTS.md
🧰 Additional context used
🪛 LanguageTool
plugins/test-coverage/skills/test-structure/README.md

[grammar] ~40-~40: Use a hyphen to join words.
Context: ...e_analyzer.py` Focused on file/function level test-to-source mapping. **When to...

(QB_NEW_EN_HYPHEN)


[grammar] ~53-~53: Ensure spelling is correct
Context: ... tool for most use cases as it combines analyze and gaps logic together. ### Usage ``...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)


[grammar] ~252-~252: Ensure spelling is correct
Context: ...mary The unified analyzer combines analyze and gaps logic into one comprehensive t...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

plugins/test-coverage/commands/analyze.md

[grammar] ~269-~269: Use a hyphen to join words.
Context: ...mple 2: Analyze test structure with high priority filter ``` /test-coverage:anal...

(QB_NEW_EN_HYPHEN)

plugins/test-coverage/commands/gaps.md

[grammar] ~444-~444: Use a hyphen to join words.
Context: ...he report. ### Example 4: Focus on high complexity code ``` /test-coverage:gaps...

(QB_NEW_EN_HYPHEN)

🪛 markdownlint-cli2 (0.18.1)
plugins/test-coverage/README.md

315-315: Bare URL used

(MD034, no-bare-urls)


316-316: Bare URL used

(MD034, no-bare-urls)

plugins/test-coverage/commands/analyze.md

10-10: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


50-50: Spaces inside emphasis markers

(MD037, no-space-in-emphasis)


227-227: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


263-263: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


271-271: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


279-279: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


287-287: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


295-295: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


309-309: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


317-317: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


325-325: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


335-335: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

plugins/test-coverage/commands/gaps.md

10-10: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


298-298: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


377-377: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


422-422: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


430-430: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


438-438: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


446-446: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


454-454: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


462-462: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


470-470: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


478-478: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🪛 Ruff (0.14.3)
plugins/test-coverage/skills/test-structure/test_structure_analyzer.py

124-124: Loop control variable root not used within loop body

Rename unused root to _root

(B007)


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

(TRY003)


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

(TRY003)


167-167: PEP 484 prohibits implicit Optional

Convert to T | None

(RUF013)


285-285: Do not catch blind exception: Exception

(BLE001)


504-504: Local variable source_by_path is assigned to but never used

Remove assignment to unused variable source_by_path

(F841)


541-541: Unused function argument: file_path

(ARG001)


759-759: Do not catch blind exception: Exception

(BLE001)


769-769: Do not catch blind exception: Exception

(BLE001)


821-821: Do not catch blind exception: Exception

(BLE001)


835-835: Consider moving this statement to an else block

(TRY300)


837-837: Do not catch blind exception: Exception

(BLE001)

plugins/test-coverage/skills/test-structure/unified_analyzer.py

28-28: Unused method argument: language

(ARG002)


37-37: Loop control variable dirs not used within loop body

Rename unused dirs to _dirs

(B007)


65-65: Do not use bare except

(E722)


65-66: try-except-continue detected, consider logging the exception

(S112)


75-75: f-string without any placeholders

Remove extraneous f prefix

(F541)


144-144: Do not catch blind exception: Exception

(BLE001)


151-151: Do not catch blind exception: Exception

(BLE001)


203-203: Loop control variable dirs not used within loop body

Rename unused dirs to _dirs

(B007)


224-224: Do not use bare except

(E722)


224-225: try-except-continue detected, consider logging the exception

(S112)


266-266: Loop control variable dirs not used within loop body

Rename unused dirs to _dirs

(B007)


282-282: Do not use bare except

(E722)


282-283: try-except-continue detected, consider logging the exception

(S112)


307-307: Loop control variable dirs not used within loop body

Rename unused dirs to _dirs

(B007)


347-347: Do not use bare except

(E722)


347-348: try-except-continue detected, consider logging the exception

(S112)


369-369: Loop control variable dirs not used within loop body

Rename unused dirs to _dirs

(B007)


379-379: Do not use bare except

(E722)


379-380: try-except-continue detected, consider logging the exception

(S112)


455-455: Unused method argument: characteristics

(ARG002)


455-455: Unused method argument: quality_metrics

(ARG002)


564-564: Do not catch blind exception: Exception

(BLE001)


635-635: Local variable output_path is assigned to but never used

Remove assignment to unused variable output_path

(F841)


641-641: Consider moving this statement to an else block

(TRY300)


643-643: Do not catch blind exception: Exception

(BLE001)

plugins/test-coverage/skills/test-structure/analyze_test_gaps.py

103-103: f-string without any placeholders

Remove extraneous f prefix

(F541)

🔇 Additional comments (1)
plugins/test-coverage/skills/test-structure/test_structure_analyzer.py (1)

20-81: Clarify language support scope.

The code includes comprehensive configuration for Go, Python, Java, JavaScript, and TypeScript, but the documentation and other files state "Go only." If multi-language support is planned but not yet ready, consider adding a comment explaining which languages are fully tested and supported.

Copy link
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: 3

♻️ Duplicate comments (2)
plugins/test-coverage/skills/test-structure/README_OLD.md (1)

133-147: Add language specification to fenced code block (MD040).

The usage documentation block is missing a language identifier for the fenced code block.

Apply this diff to add a language identifier:

-```
+```bash
 usage: test_structure_analyzer.py [-h] [--language {go,python,java,javascript,typescript}]
                                    [--priority {all,high,medium,low}] [--output OUTPUT]
                                    [--exclude EXCLUDE_PATTERNS]
                                    source_dir
 
 Arguments:
   source_dir            Source directory to analyze
 
 Options:
   --language LANG       Programming language (auto-detected if not specified)
   --priority LEVEL      Filter gaps by priority: all, high, medium, low
   --output DIR          Output directory for reports (default: .work/test-coverage/structure)
   --exclude PATTERN     Exclude patterns (can be repeated)
-```
+```

This issue was previously flagged in an earlier review. Please ensure it is fixed.

plugins/test-coverage/skills/analyze/report_generator.py (1)

10-10: Fix import to use the module’s package path.

When this module is imported via plugins.test-coverage.skills.analyze.report_generator, Python looks for a top-level coverage_parser and raises ModuleNotFoundError. Please use a relative import so it resolves inside the package.

-from coverage_parser import CoverageReport, FileCoverage
+from .coverage_parser import CoverageReport, FileCoverage
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 1a69720 and 5a7f3fd.

📒 Files selected for processing (6)
  • docs/data.json (1 hunks)
  • plugins/test-coverage/skills/analyze/report_generator.py (1 hunks)
  • plugins/test-coverage/skills/test-structure/README_OLD.md (1 hunks)
  • plugins/test-coverage/skills/test-structure/generate_networking_report.py (1 hunks)
  • plugins/test-coverage/skills/test-structure/html_report_generator.py (1 hunks)
  • plugins/test-coverage/skills/test-structure/test_structure_analyzer.py (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • docs/data.json
🧰 Additional context used
🪛 markdownlint-cli2 (0.18.1)
plugins/test-coverage/skills/test-structure/README_OLD.md

98-98: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🪛 Ruff (0.14.3)
plugins/test-coverage/skills/analyze/report_generator.py

18-18: Unused static method argument: baseline

(ARG004)


433-524: f-string without any placeholders

Remove extraneous f prefix

(F541)


706-706: Do not catch blind exception: Exception

(BLE001)

plugins/test-coverage/skills/test-structure/generate_networking_report.py

20-20: Local variable test_tags is assigned to but never used

Remove assignment to unused variable test_tags

(F841)


114-114: f-string without any placeholders

Remove extraneous f prefix

(F541)

plugins/test-coverage/skills/test-structure/test_structure_analyzer.py

124-124: Loop control variable root not used within loop body

Rename unused root to _root

(B007)


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

(TRY003)


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

(TRY003)


167-167: PEP 484 prohibits implicit Optional

Convert to T | None

(RUF013)


241-241: PEP 484 prohibits implicit Optional

Convert to T | None

(RUF013)


294-294: Do not catch blind exception: Exception

(BLE001)


516-516: Local variable source_by_path is assigned to but never used

Remove assignment to unused variable source_by_path

(F841)


553-553: Unused function argument: file_path

(ARG001)


773-773: Do not catch blind exception: Exception

(BLE001)


783-783: Do not catch blind exception: Exception

(BLE001)


835-835: Do not catch blind exception: Exception

(BLE001)


849-849: Consider moving this statement to an else block

(TRY300)


851-851: Do not catch blind exception: Exception

(BLE001)

plugins/test-coverage/skills/test-structure/html_report_generator.py

30-30: Local variable partially_tested is assigned to but never used

Remove assignment to unused variable partially_tested

(F841)


572-572: Unused function argument: summary

(ARG001)


575-575: Local variable untested_funcs is assigned to but never used

Remove assignment to unused variable untested_funcs

(F841)


989-989: Local variable structure is assigned to but never used

Remove assignment to unused variable structure

(F841)

Copy link
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 (2)
plugins/test-coverage/commands/gaps.md (1)

69-72: Coverage format inconsistency persists—align examples with documented support.

Lines 70–71 reference coverage.xml examples, but line 72 explicitly states only Go (.out) or JSON are supported. This mismatch was flagged in prior review; update examples to use supported formats only.

- - **Local path**: `./coverage.out`, `/path/to/coverage.xml`
+ - **Local path**: `./coverage.out`
- - **URL**: `https://example.com/coverage.xml`, `https://raw.githubusercontent.com/owner/repo/main/coverage.out`
+ - **URL**: `https://raw.githubusercontent.com/owner/repo/main/coverage.out`
plugins/test-coverage/skills/test-structure/test_structure_analyzer.py (1)

827-829: CRITICAL: Language is still hard-coded to Go despite previous review.

A past review comment flagged this exact issue and marked it as addressed, but the code still shows language = 'go'. This means Python, Java, JavaScript, and TypeScript projects will be analyzed with Go patterns, causing file discovery and parsing to fail completely.

Apply this diff to fix:

-        language = 'go'
+        language = detect_language(source_dir)
         print(f"Language: {language}")
         print()

This is marked as "✅ Addressed in commit bc63771" in the past review comments, but the fix is not present in the current code.

🧹 Nitpick comments (16)
plugins/test-coverage/commands/gaps.md (2)

10-10: Add language specifiers to fenced code blocks (markdown best practice).

Fenced code blocks should declare their language for syntax highlighting and accessibility. Apply language identifiers:

  • Shell examples (lines 10, 34, 48, 569, 579, 587, 595, 607, 615, 623, 631, 639, 647): Use ```bash
  • JSON output (line 397): Use ```json
  • Terminal output (lines 443, 522): Use ```text

Example:

- ```
+ ```bash
  /test-coverage:gaps <test-file.go>
- ```
+ ```

Also applies to: 34-34, 48-48, 443-443, 522-522, 569-569, 579-579, 587-587, 595-595, 607-607, 615-615, 623-623, 631-631, 639-639, 647-647


577-577: Hyphenate compound adjectives.

"High priority" used as a modifier should be hyphenated: "high-priority filter".

- ### Example 2: Analyze e2e test with high priority filter
+ ### Example 2: Analyze e2e test with high-priority filter

Also verify other similar usage patterns (e.g., "high priority gaps" at line 449, 550) and apply hyphenation consistently.

plugins/test-coverage/skills/test-structure/html_report_generator.py (6)

21-24: Consider removing unused variables.

The variables source_dir and analyzed_file are extracted from the data dictionary but never used in the function body.

Apply this diff to remove the unused assignments:

     language = data.get('language', 'unknown')
-    source_dir = data.get('source_dir', '')
     test_file_details = data.get('test_file_details', {})
-    analyzed_file = data.get('analyzed_file', '')

362-366: Consider removing unused variable.

The variable partially_tested is computed but never used in this function.

Apply this diff:

     total_source = summary.get('total_source_files', 0)
     total_tests = summary.get('total_test_files', 0)
     untested_files = len(gaps.get('untested_files', []))
     untested_funcs = len(gaps.get('untested_functions', []))
-    partially_tested = len(gaps.get('partially_tested_files', []))

908-916: Consider removing unused parameter and variable.

The summary parameter is declared but never used, and untested_funcs is computed but never referenced in the function.

Apply this diff:

-def _generate_recommendations_section(gaps: Dict, summary: Dict) -> str:
+def _generate_recommendations_section(gaps: Dict) -> str:
     """Generate recommendations section"""
     untested_files = len(gaps.get('untested_files', []))
-    untested_funcs = len(gaps.get('untested_functions', []))
     partially_tested = len(gaps.get('partially_tested_files', []))
 
     high_priority_files = len([f for f in gaps.get('untested_files', []) if f.get('priority') == 'high'])

Also update the call site at line 676:

-        {_generate_recommendations_section(gaps, summary)}
+        {_generate_recommendations_section(gaps)}

1196-1244: Avoid showing placeholder data in production reports.

The functions _generate_gaps_section and _generate_strengths_section_gaps generate example/placeholder data when the input is empty. This could mislead users into thinking these are real findings.

Consider showing an empty state message instead or omitting these sections entirely when there's no data.

For example, update _generate_gaps_section:

 def _generate_gaps_section(gaps: List[Dict]) -> str:
     """Generate gaps section for HTML"""
     if not gaps:
-        gaps = [
-            {'area': 'Example Gap', 'severity': 'HIGH', 'finding': 'Example finding', 'recommendation': 'Example recommendation'}
-        ]
+        return """
+        <div class="section">
+            <h2>✅ Coverage Gaps</h2>
+            <div style="text-align: center; padding: 40px; color: #10b981;">
+                <div style="font-size: 3em;">🎉</div>
+                <p>No coverage gaps identified!</p>
+            </div>
+        </div>
+        """

Similarly update _generate_strengths_section_gaps to handle empty data more gracefully.


1287-1313: Avoid placeholder metrics in production reports.

The _generate_metrics_summary function also falls back to example data when metrics are empty, which could be misleading.

Consider returning an empty state or a message indicating no metrics are available:

 def _generate_metrics_summary(metrics: List[tuple]) -> str:
     """Generate metrics summary section"""
     if not metrics:
-        metrics = [('Example Metric', 'Value', 'Good')]
+        return """
+        <div class="section">
+            <h2>📈 Coverage Metrics Summary</h2>
+            <p style="text-align: center; padding: 40px; color: #6b7280;">No metrics data available.</p>
+        </div>
+        """

1324-1325: Remove unused variable.

The variable structure is retrieved from the data dictionary but never used in the function.

Apply this diff:

     metadata = data.get('metadata', {})
-    structure = data.get('structure', {})
     characteristics = data.get('characteristics', {})
plugins/test-coverage/skills/test-structure/test_structure_analyzer.py (8)

124-130: Unused loop variable root.

The root variable from os.walk() is not used in the loop body. Per PEP 8 conventions, prefix it with an underscore to indicate it's intentionally unused.

-    for root, dirs, files in os.walk(source_dir):
+    for _root, dirs, files in os.walk(source_dir):
         dirs[:] = [d for d in dirs if d not in ['.git', 'node_modules', 'vendor']]

167-167: Make Optional type hint explicit.

PEP 484 prohibits implicit Optional. The content parameter should be explicitly annotated as str | None or Optional[str].

-def is_e2e_test_file(file_path: str, language: str, content: str = None) -> bool:
+def is_e2e_test_file(file_path: str, language: str, content: Optional[str] = None) -> bool:

241-241: Make Optional type hint explicit.

The exclude_patterns parameter should be explicitly annotated as List[str] | None or Optional[List[str]].

-def discover_files(source_dir: str, language: str, e2e_only: bool = True, exclude_patterns: List[str] = None) -> Tuple[List[str], List[str]]:
+def discover_files(source_dir: str, language: str, e2e_only: bool = True, exclude_patterns: Optional[List[str]] = None) -> Tuple[List[str], List[str]]:

363-372: Remove unused base_indent variable.

The base_indent variable is calculated but never used. If it was intended for indentation-based brace matching logic, that logic is incomplete. Otherwise, remove it.

                 # Find end of It block (look for closing brace at same or lower indent)
                 line_end = i + 1
-                base_indent = len(line) - len(line.lstrip())
                 brace_count = line.count('{') - line.count('}')

386-391: Remove unused context_name variable.

The context_name is extracted but never used. The comment suggests it could be used to show test hierarchy, but currently it's dead code.

             # Also track Describe/Context blocks for context
             describe_match = re.search(ginkgo_describe_pattern, line)
             if describe_match and not it_match:  # Don't count lines that are both
-                context_name = describe_match.group(1)
                 # Note: We're not adding these as tests, just tracking them
                 # Could be enhanced to show test hierarchy
+                pass  # Could be enhanced to show test hierarchy with describe_match.group(1)

564-565: Remove unused source_by_path lookup.

This dictionary is created but never used. Remove it to reduce confusion.

-    # Create lookup for source files
-    source_by_path = {sf.path: sf for sf in source_files}
-
     # Map each source file

601-625: Remove unused file_path parameter.

The file_path parameter is never used in the function body. Remove it from the signature and update all call sites.

-def calculate_priority(file_path: str, file_data: Dict) -> str:
+def calculate_priority(file_data: Dict) -> str:
     """Calculate priority for testing a file/function"""

Update the call site at line 637:

-        priority = calculate_priority(source_file, data)
+        priority = calculate_priority(data)

990-999: Handle optional HTML report gracefully.

The HTML report generation is wrapped in a try-except, but the exception handling could be more specific. Consider catching ImportError separately from other exceptions to provide clearer diagnostics.

         # HTML report
         html_path = os.path.join(args.output, 'test-structure-report.html')
         try:
             from html_report_generator import generate_test_structure_html
             with open(json_path, 'r') as f:
                 json_data = json.load(f)
             generate_test_structure_html(json_data, html_path)
         except ImportError:
             print("Warning: html_report_generator not found, skipping HTML report")
-        except Exception as e:
-            print(f"Warning: Failed to generate HTML report: {e}")
+        except FileNotFoundError as e:
+            print(f"Warning: Could not read JSON file for HTML report: {e}")
+        except Exception as e:
+            print(f"Warning: Failed to generate HTML report: {e}")
+            import traceback
+            traceback.print_exc(file=sys.stderr)
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 5a7f3fd and 6bd1a06.

📒 Files selected for processing (3)
  • plugins/test-coverage/commands/gaps.md (1 hunks)
  • plugins/test-coverage/skills/test-structure/html_report_generator.py (1 hunks)
  • plugins/test-coverage/skills/test-structure/test_structure_analyzer.py (1 hunks)
🧰 Additional context used
🪛 LanguageTool
plugins/test-coverage/commands/gaps.md

[uncategorized] ~577-~577: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: .... ### Example 2: Analyze e2e test with high priority filter ``` /test-coverage:gaps ./test/...

(EN_COMPOUND_ADJECTIVE_INTERNAL)

🪛 markdownlint-cli2 (0.18.1)
plugins/test-coverage/commands/gaps.md

10-10: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


34-34: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


48-48: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


235-235: Multiple headings with the same content

(MD024, no-duplicate-heading)


443-443: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


522-522: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


569-569: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


579-579: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


587-587: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


595-595: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


607-607: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


615-615: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


623-623: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


631-631: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


639-639: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


647-647: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🪛 Ruff (0.14.3)
plugins/test-coverage/skills/test-structure/html_report_generator.py

22-22: Local variable source_dir is assigned to but never used

Remove assignment to unused variable source_dir

(F841)


24-24: Local variable analyzed_file is assigned to but never used

Remove assignment to unused variable analyzed_file

(F841)


324-324: String contains ambiguous (INFORMATION SOURCE). Did you mean i (LATIN SMALL LETTER I)?

(RUF001)


366-366: Local variable partially_tested is assigned to but never used

Remove assignment to unused variable partially_tested

(F841)


908-908: Unused function argument: summary

(ARG001)


911-911: Local variable untested_funcs is assigned to but never used

Remove assignment to unused variable untested_funcs

(F841)


1325-1325: Local variable structure is assigned to but never used

Remove assignment to unused variable structure

(F841)

plugins/test-coverage/skills/test-structure/test_structure_analyzer.py

124-124: Loop control variable root not used within loop body

Rename unused root to _root

(B007)


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

(TRY003)


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

(TRY003)


167-167: PEP 484 prohibits implicit Optional

Convert to T | None

(RUF013)


241-241: PEP 484 prohibits implicit Optional

Convert to T | None

(RUF013)


294-294: Do not catch blind exception: Exception

(BLE001)


363-363: Local variable base_indent is assigned to but never used

Remove assignment to unused variable base_indent

(F841)


388-388: Local variable context_name is assigned to but never used

Remove assignment to unused variable context_name

(F841)


564-564: Local variable source_by_path is assigned to but never used

Remove assignment to unused variable source_by_path

(F841)


601-601: Unused function argument: file_path

(ARG001)


853-853: Do not catch blind exception: Exception

(BLE001)


907-907: Do not catch blind exception: Exception

(BLE001)


918-918: Do not catch blind exception: Exception

(BLE001)


997-997: Do not catch blind exception: Exception

(BLE001)


1011-1011: Consider moving this statement to an else block

(TRY300)


1013-1013: Do not catch blind exception: Exception

(BLE001)

🔇 Additional comments (2)
plugins/test-coverage/skills/test-structure/html_report_generator.py (1)

1519-1523: Event handler correctly implemented.

The tab navigation now correctly passes the event parameter to showTab(event, tabName) and uses evt.currentTarget to mark the active tab. This addresses the previous ReferenceError issue.

Also applies to: 1555-1563

plugins/test-coverage/skills/test-structure/test_structure_analyzer.py (1)

871-883: The exclude pattern filtering logic is working correctly.

The verification test confirmed that files matching exclude patterns (*/vendor/* and vendor/*) are properly filtered out. The implementation uses fnmatch for pattern matching and correctly applies the any() logic to check if a path matches any exclude pattern. No edge cases were found during testing—the filtering operates as designed.

@anuragthehatter
Copy link
Author

/coderabbit restart

@anuragthehatter
Copy link
Author

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 7, 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
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 (2)
plugins/test-coverage/skills/analyze/README.md (1)

16-33: Format support inconsistency between examples and documentation.

The README examples and narrative reference coverage.xml, Cobertura format, and lxml dependencies (lines 16-33, 106-107, 114-115, 137), but the Supported Format table (line 48) only lists Go coverage .out. This creates confusion about actual capabilities.

Also applies to: 48-48, 106-107, 114-115, 137-137

plugins/test-coverage/commands/analyze.md (1)

344-348: Update Python version requirement to match project standard.

Lines 344 and 348 reference "Python 3.6+" which should be updated to "Python 3.8+" to align with the standardized minimum version used across other documentation files in this PR.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 6bd1a06 and a10b4ca.

📒 Files selected for processing (22)
  • .claude-plugin/marketplace.json (1 hunks)
  • PLUGINS.md (2 hunks)
  • docs/data.json (1 hunks)
  • plugins/test-coverage/.claude-plugin/plugin.json (1 hunks)
  • plugins/test-coverage/README.md (1 hunks)
  • plugins/test-coverage/URL_SUPPORT.md (1 hunks)
  • plugins/test-coverage/commands/analyze.md (1 hunks)
  • plugins/test-coverage/commands/gaps.md (1 hunks)
  • plugins/test-coverage/skills/analyze/README.md (1 hunks)
  • plugins/test-coverage/skills/analyze/SKILL.md (1 hunks)
  • plugins/test-coverage/skills/analyze/analyze.py (1 hunks)
  • plugins/test-coverage/skills/analyze/coverage_parser.py (1 hunks)
  • plugins/test-coverage/skills/analyze/coverage_reports.py (1 hunks)
  • plugins/test-coverage/skills/analyze/test_gap_reports.py (1 hunks)
  • plugins/test-coverage/skills/analyze/test_structure_analyzer.py (1 hunks)
  • plugins/test-coverage/skills/analyze/test_structure_reports.py (1 hunks)
  • plugins/test-coverage/skills/gaps/README.md (1 hunks)
  • plugins/test-coverage/skills/gaps/SKILL.md (1 hunks)
  • plugins/test-coverage/skills/gaps/gap_analyzer.py (1 hunks)
  • plugins/test-coverage/skills/gaps/reports.py (1 hunks)
  • plugins/test-coverage/utils/__init__.py (1 hunks)
  • plugins/test-coverage/utils/path_handler.py (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • plugins/test-coverage/skills/gaps/README.md
🚧 Files skipped from review as they are similar to previous changes (4)
  • plugins/test-coverage/.claude-plugin/plugin.json
  • .claude-plugin/marketplace.json
  • plugins/test-coverage/README.md
  • PLUGINS.md
🧰 Additional context used
🪛 LanguageTool
plugins/test-coverage/commands/analyze.md

[grammar] ~269-~269: Use a hyphen to join words.
Context: ...mple 2: Analyze test structure with high priority filter ``` /test-coverage:anal...

(QB_NEW_EN_HYPHEN)

plugins/test-coverage/commands/gaps.md

[uncategorized] ~219-~219: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...I drivers. ### Example 3: Analyze with high priority filter ``` /test-coverage:gaps ./test/...

(EN_COMPOUND_ADJECTIVE_INTERNAL)

plugins/test-coverage/skills/analyze/README.md

[grammar] ~1-~1: Ensure spelling is correct
Context: # Coverage Analyze Skill This skill provides comprehensiv...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)


[style] ~119-~119: As an alternative to the over-used intensifier ‘very’, consider replacing this phrase.
Context: ...lxml ``` ### Large Coverage Files For very large coverage files, the tool may take some ...

(EN_WEAK_ADJECTIVE)

🪛 markdownlint-cli2 (0.18.1)
plugins/test-coverage/URL_SUPPORT.md

17-17: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


22-22: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


28-28: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


35-35: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


40-40: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


47-47: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

plugins/test-coverage/commands/analyze.md

10-10: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


50-50: Spaces inside emphasis markers

(MD037, no-space-in-emphasis)


227-227: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


263-263: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


271-271: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


279-279: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


287-287: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


295-295: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


309-309: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


317-317: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


325-325: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


335-335: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

plugins/test-coverage/commands/gaps.md

10-10: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


138-138: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


171-171: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


201-201: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


211-211: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


221-221: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


229-229: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


237-237: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

plugins/test-coverage/skills/analyze/README.md

52-52: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


126-126: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

plugins/test-coverage/skills/gaps/SKILL.md

364-364: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


409-409: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🪛 Ruff (0.14.3)
plugins/test-coverage/skills/gaps/reports.py

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

(EXE001)

plugins/test-coverage/skills/analyze/analyze.py

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

(TRY003)


242-242: Do not catch blind exception: Exception

(BLE001)


295-295: Consider moving this statement to an else block

(TRY300)


297-297: Do not catch blind exception: Exception

(BLE001)

plugins/test-coverage/skills/gaps/gap_analyzer.py

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

(EXE001)


627-627: f-string without any placeholders

Remove extraneous f prefix

(F541)

plugins/test-coverage/skills/analyze/test_gap_reports.py

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

(EXE001)


796-796: Local variable source_dir is assigned to but never used

Remove assignment to unused variable source_dir

(F841)


798-798: Local variable analyzed_file is assigned to but never used

Remove assignment to unused variable analyzed_file

(F841)


906-906: String contains ambiguous (INFORMATION SOURCE). Did you mean i (LATIN SMALL LETTER I)?

(RUF001)


1109-1109: Unused function argument: summary

(ARG001)

plugins/test-coverage/skills/analyze/coverage_reports.py

18-18: Unused static method argument: baseline

(ARG004)


433-524: f-string without any placeholders

Remove extraneous f prefix

(F541)


706-706: Do not catch blind exception: Exception

(BLE001)

plugins/test-coverage/skills/analyze/test_structure_analyzer.py

78-78: Unused function argument: language

(ARG001)


84-84: Unused function argument: language

(ARG001)


84-84: PEP 484 prohibits implicit Optional

Convert to T | None

(RUF013)


126-126: Unused function argument: language

(ARG001)


158-158: PEP 484 prohibits implicit Optional

Convert to T | None

(RUF013)


211-211: Do not catch blind exception: Exception

(BLE001)


280-280: Local variable base_indent is assigned to but never used

Remove assignment to unused variable base_indent

(F841)


305-305: Local variable context_name is assigned to but never used

Remove assignment to unused variable context_name

(F841)


330-330: Unused function argument: language

(ARG001)


382-382: Unused function argument: language

(ARG001)


405-405: Unused function argument: language

(ARG001)


425-425: Local variable source_by_path is assigned to but never used

Remove assignment to unused variable source_by_path

(F841)


462-462: Unused function argument: file_path

(ARG001)


690-690: f-string without any placeholders

Remove extraneous f prefix

(F541)


714-714: Do not catch blind exception: Exception

(BLE001)


768-768: Do not catch blind exception: Exception

(BLE001)


779-779: Do not catch blind exception: Exception

(BLE001)


858-858: Do not catch blind exception: Exception

(BLE001)


872-872: Consider moving this statement to an else block

(TRY300)


874-874: Do not catch blind exception: Exception

(BLE001)

plugins/test-coverage/skills/analyze/coverage_parser.py

156-156: Do not use bare except

(E722)


156-157: try-except-pass detected, consider logging the exception

(S110)


158-158: Do not catch blind exception: Exception

(BLE001)


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

(TRY003)


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

(TRY003)


194-194: Using xml to parse untrusted data is known to be vulnerable to XML attacks; use defusedxml equivalents

(S314)


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

(TRY003)


355-355: Local variable num_stmt is assigned to but never used

Remove assignment to unused variable num_stmt

(F841)


366-366: Ambiguous variable name: l

(E741)


378-378: Ambiguous variable name: l

(E741)


391-391: Using xml to parse untrusted data is known to be vulnerable to XML attacks; use defusedxml equivalents

(S314)


428-428: Local variable mi is assigned to but never used

Remove assignment to unused variable mi

(F841)


449-449: Using xml to parse untrusted data is known to be vulnerable to XML attacks; use defusedxml equivalents

(S314)


552-552: Do not catch blind exception: Exception

(BLE001)

plugins/test-coverage/skills/analyze/test_structure_reports.py

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

(EXE001)


358-358: Local variable source_dir is assigned to but never used

Remove assignment to unused variable source_dir

(F841)


360-360: Local variable analyzed_file is assigned to but never used

Remove assignment to unused variable analyzed_file

(F841)


468-468: String contains ambiguous (INFORMATION SOURCE). Did you mean i (LATIN SMALL LETTER I)?

(RUF001)


671-671: Unused function argument: summary

(ARG001)

plugins/test-coverage/utils/path_handler.py

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

(EXE001)


118-118: Probable use of insecure hash functions in hashlib: md5

(S324)


157-157: Audit URL open for permitted schemes. Allowing use of file: or custom schemes is often unexpected.

(S310)


159-159: Audit URL open for permitted schemes. Allowing use of file: or custom schemes is often unexpected.

(S310)


182-182: Do not catch blind exception: Exception

(BLE001)

🔇 Additional comments (10)
plugins/test-coverage/URL_SUPPORT.md (1)

1-234: LGTM - Clear and comprehensive URL support documentation.

The documentation clearly explains URL resolution, caching, and integration with test-coverage commands. The examples are helpful and the implementation details provide good context.

plugins/test-coverage/skills/analyze/SKILL.md (1)

1-539: Excellent comprehensive SKILL documentation.

The documentation provides clear guidance on when to use the skill, prerequisites (correctly specifying Python 3.8+), detailed implementation steps with code examples, and proper error handling guidance. The scope is clearly defined (Go coverage format support).

docs/data.json (1)

607-638: LGTM - Proper plugin registry entry.

The test-coverage plugin entry is well-structured and consistent with other plugin definitions. Commands and skills are properly documented with appropriate synopses and argument hints.

plugins/test-coverage/utils/__init__.py (1)

1-9: LGTM - Clean package initialization.

The package properly exports the PathHandler utility and helper functions with appropriate docstring. Standard Python package structure.

plugins/test-coverage/skills/gaps/SKILL.md (1)

1-694: Excellent comprehensive SKILL documentation with clear requirements.

The documentation provides thorough guidance on component-aware gap analysis, correctly specifies Python 3.8+ requirement, and properly emphasizes critical requirements (e.g., generating all three report formats). The implementation steps are detailed and examples are clear.

plugins/test-coverage/skills/gaps/reports.py (2)

329-404: Handle non-networking coverage shapes before rendering scores

GapAnalyzer.analyze_ginkgo_tests() only populates analysis['coverage']['protocols'] and scores['protocol_coverage'] when component_type == 'networking'. Storage components expose coverage['storage_classes']/['volume_modes'] with scores like storage_class_coverage, and generic components omit both sections entirely. As written, the HTML renderer will raise KeyError as soon as it tries to render the score grid or the protocol/service-type tables for any storage or generic file, so the new reporting flow crashes outside the networking happy path. Please branch on analysis['component_type'] (or probe the keys) and only render the sections that exist, mapping to the correct score keys for each type.

Also applies to: 418-480


648-705: Guard text report against missing protocol/service metrics

The text report repeats the networking-only assumptions (scores['protocol_coverage'], coverage['protocols'], etc.). For storage and generic analyses those keys do not exist, so calling this function raises immediately. Mirror whatever branching you add for the HTML renderer so that the text summary emits storage-specific metrics (or skips them) instead of crashing.

plugins/test-coverage/skills/gaps/gap_analyzer.py (1)

595-600: Avoid KeyError when summarizing non-networking scores

calculate_coverage_score() only supplies protocol_coverage and service_type_coverage for networking components; storage and generic components return different keys. The summary print block assumes the networking schema and will raise KeyError for any other component type, so running the CLI on a storage test file exits after report generation. Please gate these print lines (and any downstream logic) on analysis['component_type'] and use the matching score names for each type.

plugins/test-coverage/skills/analyze/test_gap_reports.py (2)

342-525: Replicate component-aware scoring logic here too

This copy of the gap HTML generator has the same networking-only assumptions (coverage['protocols'], scores['protocol_coverage'], etc.) discussed in skills/gaps/reports.py. Without the same guards or branching, rendering storage/generic analyses raises KeyError. Align this implementation with the component-aware handling you add in the gaps module.


682-756: Text report needs the same component-aware safeguards

Just like the HTML path, the text renderer dereferences networking-only keys and crashes for other component types. Reuse the component-type branching so storage/generic reports succeed.

Copy link
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: 15

♻️ Duplicate comments (4)
plugins/test-coverage/skills/analyze/README.md (1)

16-144: Document supported formats consistently

Usage, troubleshooting, and the sample output still tell readers to run python analyze.py coverage.xml, reference Cobertura XML, and even show “Coverage Data: COBERTURA”, yet the Supported Format table (and the “Go only” positioning) claim we only handle Go .out. This disconnect will push users toward commands the tool can’t satisfy. Please either (a) update the README to stick with Go coverage everywhere or (b) formally document the additional formats (and their dependencies) that are actually implemented.

- python analyze.py coverage.xml
+ python analyze.py coverage.out
@@
- Coverage Data:  COBERTURA
+ Coverage Data:  GO
plugins/test-coverage/skills/analyze/test_structure_analyzer.py (1)

839-848: Fix HTML report import target

generate_test_structure_html is defined in test_structure_reports, not test_gap_reports, so this import throws and we always skip HTML output. Please point the import at the correct module (with the existing fallback for script execution) so HTML reports are produced again.

-        from test_gap_reports import generate_test_structure_html
+        try:
+            from .test_structure_reports import generate_test_structure_html
+        except ImportError:
+            from test_structure_reports import generate_test_structure_html
plugins/test-coverage/commands/analyze.md (1)

336-336: Update Python version requirement to 3.8+.

Line 336 states "Python 3.6+" but should be "Python 3.8+" to match the standardized requirement across all test-coverage documentation (gaps.md line 246, SKILL.md files, etc.).

Apply this diff:

-The command will automatically check for Python 3.6+ and provide installation instructions if missing.
+The command will automatically check for Python 3.8+ and provide installation instructions if missing.
plugins/test-coverage/README.md (1)

214-214: Update Python version requirement to 3.8+.

Line 214 states "Python 3.6+" but other documentation files in this PR (analyze.md line 246, gaps.md line 246, SKILL.md files) specify Python 3.8+. Standardize to Python 3.8+ for consistency.

Apply this diff:

-- **Python 3.6+** (uses standard library only, no external packages required)
+- **Python 3.8+** (uses standard library only, no external packages required)
🧹 Nitpick comments (7)
plugins/test-coverage/README.md (1)

317-318: Format bare URLs as markdown links.

Lines 317-318 contain bare URLs which should be formatted as proper markdown links for better readability and accessibility.

Apply this diff:

-- **Issues**: https://github.com/openshift-eng/ai-helpers/issues
-- **Documentation**: https://github.com/openshift-eng/ai-helpers
+- **Issues**: [https://github.com/openshift-eng/ai-helpers/issues](https://github.com/openshift-eng/ai-helpers/issues)
+- **Documentation**: [https://github.com/openshift-eng/ai-helpers](https://github.com/openshift-eng/ai-helpers)
plugins/test-coverage/commands/analyze.md (1)

46-46: Fix markdown emphasis spacing.

Line 46 has spaces inside emphasis markers which may cause rendering issues in some markdown parsers.

Apply this diff:

-  - By default, utility files are excluded (*_util.go, *_utils.go, *_helper.go, helpers.go, etc.)
+  - By default, utility files are excluded (`*_util.go`, `*_utils.go`, `*_helper.go`, `helpers.go`, etc.)

Using backticks for code/filenames is more appropriate than emphasis markers.

plugins/test-coverage/skills/gaps/reports.py (1)

1-1: Make script executable or remove shebang.

The file has a shebang (#!/usr/bin/env python3) but is not marked as executable. Either add execute permissions or remove the shebang if this module is only intended to be imported.

To make executable:

chmod +x plugins/test-coverage/skills/gaps/reports.py

Or remove the shebang if it's not meant to be executed directly:

-#!/usr/bin/env python3
 """
 E2E Test Gap Analysis Report Generator
plugins/test-coverage/skills/gaps/gap_analyzer.py (3)

19-28: Consider logging encoding errors instead of silently ignoring them.

The errors='ignore' parameter silently discards encoding errors, which could mask issues with malformed files. Consider using errors='replace' or logging a warning when encoding issues are encountered.

Apply this diff to improve error visibility:

     def _read_file(self) -> str:
         """Read the test file content"""
-        with open(self.file_path, 'r', encoding='utf-8', errors='ignore') as f:
+        with open(self.file_path, 'r', encoding='utf-8', errors='replace') as f:
             return f.read()

278-464: Consider extracting gap definitions to a configuration structure.

The gap identification methods contain repetitive logic and hardcoded priority/impact/recommendation strings. Consider extracting these into a configuration structure (e.g., a dict or dataclass) to improve maintainability and make it easier to add or modify gap definitions.

Example structure:

GAP_DEFINITIONS = {
    'protocols': [
        {'name': 'TCP', 'priority': 'high', 'impact': 'Most common protocol not tested', 'recommendation': 'Add TCP protocol tests'},
        {'name': 'UDP', 'priority': 'high', 'impact': 'Common protocol for DNS, streaming not tested', 'recommendation': 'Add UDP protocol tests'},
        # ...
    ],
    'platforms': [
        {'name': 'Azure', 'pattern': r'azure', 'priority': 'high', 'impact': 'Major cloud provider - production blocker', 'recommendation': 'Add Azure platform-specific tests'},
        # ...
    ],
}

627-627: Remove unnecessary f-string prefix.

Line 627 uses an f-string but contains no placeholders. Remove the f prefix for clarity.

Apply this diff:

-    print(f"  Add 5-7 test cases to address high-priority gaps")
+    print("  Add 5-7 test cases to address high-priority gaps")
plugins/test-coverage/skills/analyze/test_gap_reports.py (1)

906-906: Consider using ASCII alternative for information icon.

Line 906 uses the Unicode character ℹ️ which could cause display issues in some terminals or environments. Consider using a simpler ASCII alternative like [i] or Info:.

Apply this diff:

-            <h2>ℹ️ Note</h2>
+            <h2>ℹ Info</h2>
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between a10b4ca and 2455b3f.

📒 Files selected for processing (22)
  • .claude-plugin/marketplace.json (1 hunks)
  • PLUGINS.md (2 hunks)
  • docs/data.json (1 hunks)
  • plugins/test-coverage/.claude-plugin/plugin.json (1 hunks)
  • plugins/test-coverage/README.md (1 hunks)
  • plugins/test-coverage/URL_SUPPORT.md (1 hunks)
  • plugins/test-coverage/commands/analyze.md (1 hunks)
  • plugins/test-coverage/commands/gaps.md (1 hunks)
  • plugins/test-coverage/skills/analyze/README.md (1 hunks)
  • plugins/test-coverage/skills/analyze/SKILL.md (1 hunks)
  • plugins/test-coverage/skills/analyze/analyze.py (1 hunks)
  • plugins/test-coverage/skills/analyze/coverage_parser.py (1 hunks)
  • plugins/test-coverage/skills/analyze/coverage_reports.py (1 hunks)
  • plugins/test-coverage/skills/analyze/test_gap_reports.py (1 hunks)
  • plugins/test-coverage/skills/analyze/test_structure_analyzer.py (1 hunks)
  • plugins/test-coverage/skills/analyze/test_structure_reports.py (1 hunks)
  • plugins/test-coverage/skills/gaps/README.md (1 hunks)
  • plugins/test-coverage/skills/gaps/SKILL.md (1 hunks)
  • plugins/test-coverage/skills/gaps/gap_analyzer.py (1 hunks)
  • plugins/test-coverage/skills/gaps/reports.py (1 hunks)
  • plugins/test-coverage/utils/__init__.py (1 hunks)
  • plugins/test-coverage/utils/path_handler.py (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • plugins/test-coverage/.claude-plugin/plugin.json
🚧 Files skipped from review as they are similar to previous changes (2)
  • plugins/test-coverage/skills/gaps/README.md
  • docs/data.json
🧰 Additional context used
🪛 LanguageTool
plugins/test-coverage/commands/analyze.md

[grammar] ~265-~265: Use a hyphen to join words.
Context: ...mple 2: Analyze test structure with high priority filter ``` /test-coverage:anal...

(QB_NEW_EN_HYPHEN)

plugins/test-coverage/commands/gaps.md

[uncategorized] ~219-~219: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...I drivers. ### Example 3: Analyze with high priority filter ``` /test-coverage:gaps ./test/...

(EN_COMPOUND_ADJECTIVE_INTERNAL)

plugins/test-coverage/skills/analyze/README.md

[grammar] ~1-~1: Ensure spelling is correct
Context: # Coverage Analyze Skill This skill provides comprehensiv...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)


[style] ~113-~113: As an alternative to the over-used intensifier ‘very’, consider replacing this phrase.
Context: ...lxml ``` ### Large Coverage Files For very large coverage files, the tool may take some ...

(EN_WEAK_ADJECTIVE)

🪛 markdownlint-cli2 (0.18.1)
plugins/test-coverage/README.md

317-317: Bare URL used

(MD034, no-bare-urls)


318-318: Bare URL used

(MD034, no-bare-urls)

plugins/test-coverage/URL_SUPPORT.md

17-17: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


22-22: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


28-28: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


35-35: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


40-40: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


47-47: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

plugins/test-coverage/commands/analyze.md

10-10: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


46-46: Spaces inside emphasis markers

(MD037, no-space-in-emphasis)


223-223: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


259-259: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


267-267: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


275-275: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


283-283: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


297-297: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


305-305: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


313-313: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


323-323: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

plugins/test-coverage/skills/analyze/README.md

49-49: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


119-119: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

plugins/test-coverage/skills/analyze/SKILL.md

58-58: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


306-306: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

plugins/test-coverage/skills/gaps/SKILL.md

364-364: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


409-409: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🪛 Ruff (0.14.3)
plugins/test-coverage/skills/gaps/reports.py

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

(EXE001)

plugins/test-coverage/skills/gaps/gap_analyzer.py

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

(EXE001)


627-627: f-string without any placeholders

Remove extraneous f prefix

(F541)

plugins/test-coverage/skills/analyze/analyze.py

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

(TRY003)


95-95: Unused function argument: exclude_patterns

(ARG001)


235-235: Do not catch blind exception: Exception

(BLE001)


286-286: Consider moving this statement to an else block

(TRY300)


288-288: Do not catch blind exception: Exception

(BLE001)

plugins/test-coverage/skills/analyze/coverage_parser.py

156-156: Do not use bare except

(E722)


156-157: try-except-pass detected, consider logging the exception

(S110)


158-158: Do not catch blind exception: Exception

(BLE001)


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

(TRY003)


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

(TRY003)


194-194: Using xml to parse untrusted data is known to be vulnerable to XML attacks; use defusedxml equivalents

(S314)


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

(TRY003)


355-355: Local variable num_stmt is assigned to but never used

Remove assignment to unused variable num_stmt

(F841)


366-366: Ambiguous variable name: l

(E741)


378-378: Ambiguous variable name: l

(E741)


391-391: Using xml to parse untrusted data is known to be vulnerable to XML attacks; use defusedxml equivalents

(S314)


428-428: Local variable mi is assigned to but never used

Remove assignment to unused variable mi

(F841)


449-449: Using xml to parse untrusted data is known to be vulnerable to XML attacks; use defusedxml equivalents

(S314)


552-552: Do not catch blind exception: Exception

(BLE001)

plugins/test-coverage/utils/path_handler.py

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

(EXE001)


118-118: Probable use of insecure hash functions in hashlib: md5

(S324)


157-157: Audit URL open for permitted schemes. Allowing use of file: or custom schemes is often unexpected.

(S310)


159-159: Audit URL open for permitted schemes. Allowing use of file: or custom schemes is often unexpected.

(S310)


182-182: Do not catch blind exception: Exception

(BLE001)

plugins/test-coverage/skills/analyze/test_gap_reports.py

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

(EXE001)


796-796: Local variable source_dir is assigned to but never used

Remove assignment to unused variable source_dir

(F841)


798-798: Local variable analyzed_file is assigned to but never used

Remove assignment to unused variable analyzed_file

(F841)


906-906: String contains ambiguous (INFORMATION SOURCE). Did you mean i (LATIN SMALL LETTER I)?

(RUF001)


1109-1109: Unused function argument: summary

(ARG001)

plugins/test-coverage/skills/analyze/coverage_reports.py

18-18: Unused static method argument: baseline

(ARG004)


433-524: f-string without any placeholders

Remove extraneous f prefix

(F541)


706-706: Do not catch blind exception: Exception

(BLE001)

plugins/test-coverage/skills/analyze/test_structure_analyzer.py

78-78: Unused function argument: language

(ARG001)


84-84: Unused function argument: language

(ARG001)


84-84: PEP 484 prohibits implicit Optional

Convert to T | None

(RUF013)


126-126: Unused function argument: language

(ARG001)


202-202: Do not catch blind exception: Exception

(BLE001)


271-271: Local variable base_indent is assigned to but never used

Remove assignment to unused variable base_indent

(F841)


296-296: Local variable context_name is assigned to but never used

Remove assignment to unused variable context_name

(F841)


321-321: Unused function argument: language

(ARG001)


373-373: Unused function argument: language

(ARG001)


396-396: Unused function argument: language

(ARG001)


416-416: Local variable source_by_path is assigned to but never used

Remove assignment to unused variable source_by_path

(F841)


453-453: Unused function argument: file_path

(ARG001)


679-679: f-string without any placeholders

Remove extraneous f prefix

(F541)


703-703: Do not catch blind exception: Exception

(BLE001)


757-757: Do not catch blind exception: Exception

(BLE001)


768-768: Do not catch blind exception: Exception

(BLE001)


847-847: Do not catch blind exception: Exception

(BLE001)


861-861: Consider moving this statement to an else block

(TRY300)


863-863: Do not catch blind exception: Exception

(BLE001)

plugins/test-coverage/skills/analyze/test_structure_reports.py

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

(EXE001)


358-358: Local variable source_dir is assigned to but never used

Remove assignment to unused variable source_dir

(F841)


360-360: Local variable analyzed_file is assigned to but never used

Remove assignment to unused variable analyzed_file

(F841)


468-468: String contains ambiguous (INFORMATION SOURCE). Did you mean i (LATIN SMALL LETTER I)?

(RUF001)


671-671: Unused function argument: summary

(ARG001)

🔇 Additional comments (21)
plugins/test-coverage/commands/gaps.md (1)

1-290: LGTM!

The documentation is comprehensive and well-structured. It clearly describes the component-aware gap analysis functionality, including auto-detection, supported components, implementation steps, examples, and prerequisites.

plugins/test-coverage/URL_SUPPORT.md (1)

1-234: LGTM!

The URL support documentation is clear and comprehensive, covering GitHub, GitLab, and generic HTTP(S) URLs, caching behavior, implementation details, and usage examples. The fenced code blocks showing URL examples don't need language specifiers as they're illustrative text.

plugins/test-coverage/skills/analyze/SKILL.md (1)

1-504: LGTM!

The Coverage Analysis Skill documentation is thorough and well-structured, covering when to use it, prerequisites (Python 3.8+), detailed workflow steps, implementation guidance, error handling, and integration examples. The documentation accurately describes Go coverage parsing and report generation.

plugins/test-coverage/skills/gaps/SKILL.md (1)

1-694: LGTM!

The Component-Aware Test Gap Analysis Skill documentation is comprehensive and well-structured. It appropriately emphasizes the critical requirement to execute the gap analyzer script (lines 22-34) and provides detailed workflow steps, examples, and error handling guidance. The Python 3.8+ requirement is correctly specified.

PLUGINS.md (1)

18-18: LGTM!

The Test Coverage Plugin entry is well-integrated into the plugins list, following the established documentation pattern. The navigation link and plugin section are properly formatted with appropriate command descriptions and README link.

Also applies to: 176-184

plugins/test-coverage/skills/gaps/reports.py (1)

17-291: LGTM!

The report generation module is well-structured with clear separation of concerns:

  • get_common_css() provides shared styling
  • generate_gap_html_report() creates interactive HTML with visual indicators
  • generate_gap_json_report() produces machine-readable output
  • generate_gap_text_report() generates terminal-friendly summaries

The HTML generation uses modern CSS with gradients, progress bars, and responsive design. The component-specific handling (networking, storage, generic) is appropriately implemented.

Also applies to: 298-826

plugins/test-coverage/skills/gaps/gap_analyzer.py (2)

141-276: LGTM - Coverage analysis methods.

The coverage analysis methods use regex pattern matching to identify tested features. While this approach may produce some false positives (e.g., matching keywords in comments), it's appropriate for a gap analysis tool where conservative estimates are acceptable.


62-77: Now let me check the actual codebase to understand what the Python analyzer is looking for:

Based on my verification, the original review comment identifies a legitimate pattern coverage concern, but requires clarification about the codebase's actual testing conventions.

Verify Ginkgo test pattern coverage and project's import style.

Ginkgo's Describe, Context, and When blocks are functionally equivalent container nodes, and It and Specify are subject nodes that hold assertions. The pattern g\.It\("([^"]+)" targets tests using a named import alias (where g is an imported package reference). However, this pattern may not capture tests if the codebase uses dot-imports, which place Ginkgo functions into the test's top-level namespace, allowing bare It() calls instead of g.It().

Before accepting this concern, verify:

  1. Whether the codebase uses dot-import style (import . "ginkgo") or named imports (import g "ginkgo")
  2. Whether any test files use Describe(), Context(), or standalone It() without the g. prefix
  3. If the pattern needs expansion to handle both import styles
plugins/test-coverage/skills/analyze/coverage_reports.py (3)

529-574: LGTM - JSON report generation.

The JSON report generation is well-structured and includes all relevant metrics. The baseline comparison is properly integrated when provided.


575-675: LGTM - Text report generation.

The text report generation provides a good terminal-friendly summary with visual progress bars. The use of Unicode characters for progress visualization is appropriate for modern terminals.


677-710: LGTM - CLI entry point with appropriate error handling.

The CLI entry point properly handles errors and provides clear feedback to users. The broad exception catch on Line 706 is appropriate for a CLI tool where all errors should be reported gracefully.

plugins/test-coverage/skills/analyze/analyze.py (3)

23-42: LGTM - Coverage file discovery.

The file discovery logic appropriately handles various coverage file formats and uses keyword filtering to avoid false positives.


81-88: Verify merge strategy for branches and functions.

The merge logic uses max() for branches and functions (Lines 82-87), which could undercount coverage if different reports cover different branches/functions. Using max() assumes the reports are redundant rather than complementary.

Consider whether summing (like with line hits) would be more appropriate:

# Current approach (takes max):
existing.branches_covered = max(existing.branches_covered, file_cov.branches_covered)

# Alternative (sums coverage):
existing.branches_covered = existing.branches_covered + file_cov.branches_covered

The choice depends on whether multiple reports represent:

  • Redundant runs of the same tests (use max)
  • Complementary runs of different tests (use sum)

If complementary, using max could significantly underreport coverage.


228-242: LGTM - Appropriate exception handling for file parsing.

The exception handling allows the tool to continue processing other coverage files even if one fails to parse. The warning is properly logged to stderr with the specific file and error message.

plugins/test-coverage/skills/analyze/test_gap_reports.py (2)

19-334: LGTM - Comprehensive CSS styling.

The CSS provides modern, responsive styling for the HTML reports. While large, keeping it inline ensures the reports are self-contained and portable.


669-771: LGTM - Gap report JSON and text generation.

The JSON and text report generators provide appropriate alternative formats for gap analysis results.

plugins/test-coverage/skills/analyze/coverage_parser.py (4)

23-105: LGTM - Well-designed data models.

The dataclass-based models provide a clean, type-safe structure for coverage data with appropriate calculated properties for percentages.


188-248: XML parsing security consideration.

Line 194 uses xml.etree.ElementTree which is vulnerable to XML attacks (XXE, billion laughs). For coverage files from trusted sources (your own test runs), this is acceptable. If parsing untrusted coverage files, consider using defusedxml instead.

For now, the current implementation is fine for trusted coverage data. Document this assumption or add validation if files come from untrusted sources.


250-323: LGTM - LCOV parser implementation.

The LCOV parser correctly handles the line-based format with appropriate state tracking for file boundaries.


493-556: LGTM - SimpleCov parser and CLI.

The SimpleCov parser appropriately handles the flexible JSON format, and the CLI provides clear error reporting.

plugins/test-coverage/skills/analyze/test_structure_reports.py (1)

700-844: LGTM - Comprehensive report generation logic.

The comprehensive HTML generation logic is well-structured, though it suffers from the same code duplication issues noted earlier in the file.

Copy link
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: 6

♻️ Duplicate comments (8)
plugins/test-coverage/skills/analyze/README.md (1)

16-30: Format inconsistency remains unresolved.

The examples and troubleshooting sections still reference coverage.xml, Cobertura format, and lxml, but the Supported Format table (lines 43-45) only lists Go .out files. This makes the documentation confusing and inconsistent.

Also applies to: 55-60, 100-109, 130-130

plugins/test-coverage/README.md (1)

214-214: Python version inconsistency remains.

Line 214 states "Python 3.6+" but other documentation files reference 3.7+ or 3.8+. This inconsistency was flagged in previous reviews but remains unaddressed.

plugins/test-coverage/commands/analyze.md (1)

336-336: Python version requirement inconsistency.

Line 336 references "Python 3.6+" but this should be standardized to match the project-wide minimum version (recommend 3.8+) as flagged in previous reviews.

plugins/test-coverage/skills/analyze/test_structure_analyzer.py (1)

839-848: Fix HTML report import path

Line 841 still imports generate_test_structure_html from test_gap_reports, but the function lives in test_structure_reports. In practice this raises ImportError, so HTML output is silently skipped. Point the import at the correct module (with a fallback for script execution) and update the warning message accordingly.

-        from test_gap_reports import generate_test_structure_html
+        try:
+            from .test_structure_reports import generate_test_structure_html
+        except ImportError:
+            from test_structure_reports import generate_test_structure_html
plugins/test-coverage/skills/analyze/test_gap_reports.py (3)

795-799: Drop unused locals in the test-only report generator.

source_dir and analyzed_file are assigned but never read, so they only add noise. Please remove the dead assignments.

-    language = data.get('language', 'unknown')
-    source_dir = data.get('source_dir', '')
-    test_file_details = data.get('test_file_details', {})
-    analyzed_file = data.get('analyzed_file', '')
+    language = data.get('language', 'unknown')
+    test_file_details = data.get('test_file_details', {})

992-995: Remove unused summary parameter in the recommendations helper.

The helper never references summary, yet every caller must supply it. Please drop the parameter and adjust the call site.

-            {_generate_recommendations_section(gaps, summary)}
+            {_generate_recommendations_section(gaps)}
@@
-def _generate_recommendations_section(gaps: Dict, summary: Dict) -> str:
+def _generate_recommendations_section(gaps: Dict) -> str:

Also applies to: 1109-1131


427-567: Guard against missing coverage dimensions before rendering.

generate_gap_html_report is invoked for every component type, but storage/generic analyses don’t populate coverage['protocols'], coverage['service_types'], etc. Directly indexing those keys raises KeyError, aborting HTML generation for those components. Please null-check each dimension (protocols, platforms, service types) before iterating, and skip whole sections when the data is absent.

-    tested_protocols = coverage['protocols']['tested']
-    not_tested_protocols = coverage['protocols']['not_tested']
+    protocols = coverage.get('protocols') or {'tested': [], 'not_tested': []}
+    tested_protocols = protocols.get('tested', [])
+    not_tested_protocols = protocols.get('not_tested', [])

Apply the same defensive pattern for platforms and service types so the report degrades gracefully instead of crashing.

plugins/test-coverage/skills/analyze/test_structure_reports.py (1)

17-333: Factor CSS/template duplication into a shared helper.

This block duplicates the same CSS that lives in test_gap_reports.py. Maintaining two copies invites drift every time styles or layout change. Please extract the CSS (and any other shared HTML scaffolding) into a common module so both generators import the same source.

🧹 Nitpick comments (5)
plugins/test-coverage/README.md (1)

317-318: Consider formatting bare URLs.

The URLs on lines 317-318 could be formatted as markdown links for better presentation.

Apply this diff:

-- **Issues**: https://github.com/openshift-eng/ai-helpers/issues
-- **Documentation**: https://github.com/openshift-eng/ai-helpers
+- **Issues**: [GitHub Issues](https://github.com/openshift-eng/ai-helpers/issues)
+- **Documentation**: [Repository](https://github.com/openshift-eng/ai-helpers)
plugins/test-coverage/commands/analyze.md (1)

10-11: Add language identifiers to code blocks.

Several code blocks lack language identifiers, which would improve syntax highlighting and readability.

For example, the Synopsis block could specify bash:

-```
+```bash
 /test-coverage:analyze <path-or-url> [--output <path>] [--priority <level>] [--test-structure-only]

Apply similar changes to other command example blocks throughout the file.


Also applies to: 223-224, 259-260, 267-268

</blockquote></details>
<details>
<summary>plugins/test-coverage/commands/gaps.md (1)</summary><blockquote>

`10-11`: **Add language identifiers to code blocks.**

Multiple code blocks lack language identifiers for syntax highlighting.



Apply this pattern:

```diff
-```
+```bash
 /test-coverage:gaps <test-file-or-url> [--priority <high|medium|low>] [--output <path>]

Apply to all command example blocks for consistency.


Also applies to: 138-139, 171-172, 201-202

</blockquote></details>
<details>
<summary>plugins/test-coverage/utils/path_handler.py (2)</summary><blockquote>

`176-184`: **Refine exception handling specificity.**

Line 182 catches a bare `Exception`, which is too broad. Consider catching specific exceptions or at least logging the full traceback for debugging.



Apply this diff:

```diff
         except urllib.error.HTTPError as e:
             print(f"HTTP Error {e.code}: {e.reason} when downloading {url}", file=sys.stderr)
             return False
         except urllib.error.URLError as e:
             print(f"URL Error: {e.reason} when downloading {url}", file=sys.stderr)
             return False
-        except Exception as e:
-            print(f"Error downloading {url}: {e}", file=sys.stderr)
+        except (OSError, IOError) as e:
+            print(f"I/O Error downloading {url}: {e}", file=sys.stderr)
+            return False
+        except Exception as e:
+            import traceback
+            print(f"Unexpected error downloading {url}: {e}", file=sys.stderr)
+            traceback.print_exc()
             return False

72-78: GitLab URL detection is too broad.

Line 78 checks if 'gitlab' is anywhere in the URL (case-insensitive), which could match non-GitLab URLs like https://example.com/my-gitlab-docs/. Consider checking for gitlab.com or a more specific pattern.

     def is_gitlab_url(self, url):
         """Check if URL is from GitLab."""
-        return 'gitlab' in url.lower()
+        # Match gitlab.com or self-hosted GitLab instances
+        return 'gitlab.com' in url.lower() or '/-/blob/' in url or '/-/raw/' in url
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 2455b3f and db36564.

📒 Files selected for processing (22)
  • .claude-plugin/marketplace.json (1 hunks)
  • PLUGINS.md (2 hunks)
  • docs/data.json (1 hunks)
  • plugins/test-coverage/.claude-plugin/plugin.json (1 hunks)
  • plugins/test-coverage/README.md (1 hunks)
  • plugins/test-coverage/URL_SUPPORT.md (1 hunks)
  • plugins/test-coverage/commands/analyze.md (1 hunks)
  • plugins/test-coverage/commands/gaps.md (1 hunks)
  • plugins/test-coverage/skills/analyze/README.md (1 hunks)
  • plugins/test-coverage/skills/analyze/SKILL.md (1 hunks)
  • plugins/test-coverage/skills/analyze/analyze.py (1 hunks)
  • plugins/test-coverage/skills/analyze/coverage_parser.py (1 hunks)
  • plugins/test-coverage/skills/analyze/coverage_reports.py (1 hunks)
  • plugins/test-coverage/skills/analyze/test_gap_reports.py (1 hunks)
  • plugins/test-coverage/skills/analyze/test_structure_analyzer.py (1 hunks)
  • plugins/test-coverage/skills/analyze/test_structure_reports.py (1 hunks)
  • plugins/test-coverage/skills/gaps/README.md (1 hunks)
  • plugins/test-coverage/skills/gaps/SKILL.md (1 hunks)
  • plugins/test-coverage/skills/gaps/gap_analyzer.py (1 hunks)
  • plugins/test-coverage/skills/gaps/reports.py (1 hunks)
  • plugins/test-coverage/utils/__init__.py (1 hunks)
  • plugins/test-coverage/utils/path_handler.py (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
  • plugins/test-coverage/skills/gaps/README.md
  • plugins/test-coverage/.claude-plugin/plugin.json
  • .claude-plugin/marketplace.json
  • plugins/test-coverage/URL_SUPPORT.md
  • plugins/test-coverage/skills/analyze/SKILL.md
🧰 Additional context used
🪛 LanguageTool
plugins/test-coverage/commands/analyze.md

[grammar] ~265-~265: Use a hyphen to join words.
Context: ...mple 2: Analyze test structure with high priority filter ``` /test-coverage:anal...

(QB_NEW_EN_HYPHEN)

plugins/test-coverage/commands/gaps.md

[uncategorized] ~219-~219: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...I drivers. ### Example 3: Analyze with high priority filter ``` /test-coverage:gaps ./test/...

(EN_COMPOUND_ADJECTIVE_INTERNAL)

plugins/test-coverage/skills/analyze/README.md

[grammar] ~1-~1: Ensure spelling is correct
Context: # Coverage Analyze Skill This skill provides comprehensiv...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)


[style] ~113-~113: As an alternative to the over-used intensifier ‘very’, consider replacing this phrase.
Context: ...lxml ``` ### Large Coverage Files For very large coverage files, the tool may take some ...

(EN_WEAK_ADJECTIVE)

🪛 markdownlint-cli2 (0.18.1)
plugins/test-coverage/README.md

317-317: Bare URL used

(MD034, no-bare-urls)


318-318: Bare URL used

(MD034, no-bare-urls)

plugins/test-coverage/commands/analyze.md

10-10: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


46-46: Spaces inside emphasis markers

(MD037, no-space-in-emphasis)


223-223: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


259-259: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


267-267: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


275-275: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


283-283: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


297-297: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


305-305: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


313-313: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


323-323: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

plugins/test-coverage/commands/gaps.md

10-10: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


138-138: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


171-171: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


201-201: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


211-211: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


221-221: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


229-229: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


237-237: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

plugins/test-coverage/skills/analyze/README.md

58-58: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

plugins/test-coverage/skills/gaps/SKILL.md

317-317: Bare URL used

(MD034, no-bare-urls)


318-318: Bare URL used

(MD034, no-bare-urls)

🪛 Ruff (0.14.3)
plugins/test-coverage/skills/analyze/test_gap_reports.py

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

(EXE001)


796-796: Local variable source_dir is assigned to but never used

Remove assignment to unused variable source_dir

(F841)


798-798: Local variable analyzed_file is assigned to but never used

Remove assignment to unused variable analyzed_file

(F841)


906-906: String contains ambiguous (INFORMATION SOURCE). Did you mean i (LATIN SMALL LETTER I)?

(RUF001)


1109-1109: Unused function argument: summary

(ARG001)

plugins/test-coverage/skills/gaps/reports.py

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

(EXE001)

plugins/test-coverage/skills/analyze/analyze.py

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

(TRY003)


235-235: Do not catch blind exception: Exception

(BLE001)


285-285: Consider moving this statement to an else block

(TRY300)


287-287: Do not catch blind exception: Exception

(BLE001)

plugins/test-coverage/utils/path_handler.py

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

(EXE001)


118-118: Probable use of insecure hash functions in hashlib: md5

(S324)


157-157: Audit URL open for permitted schemes. Allowing use of file: or custom schemes is often unexpected.

(S310)


159-159: Audit URL open for permitted schemes. Allowing use of file: or custom schemes is often unexpected.

(S310)


182-182: Do not catch blind exception: Exception

(BLE001)

plugins/test-coverage/skills/gaps/gap_analyzer.py

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

(EXE001)


639-639: f-string without any placeholders

Remove extraneous f prefix

(F541)

plugins/test-coverage/skills/analyze/coverage_reports.py

18-18: Unused static method argument: baseline

(ARG004)


433-524: f-string without any placeholders

Remove extraneous f prefix

(F541)


706-706: Do not catch blind exception: Exception

(BLE001)

plugins/test-coverage/skills/analyze/coverage_parser.py

158-158: Do not catch blind exception: Exception

(BLE001)


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

(TRY003)


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

(TRY003)


194-194: Using xml to parse untrusted data is known to be vulnerable to XML attacks; use defusedxml equivalents

(S314)


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

(TRY003)


365-365: Ambiguous variable name: l

(E741)


377-377: Ambiguous variable name: l

(E741)


390-390: Using xml to parse untrusted data is known to be vulnerable to XML attacks; use defusedxml equivalents

(S314)


447-447: Using xml to parse untrusted data is known to be vulnerable to XML attacks; use defusedxml equivalents

(S314)


550-550: Do not catch blind exception: Exception

(BLE001)

plugins/test-coverage/skills/analyze/test_structure_reports.py

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

(EXE001)


466-466: String contains ambiguous (INFORMATION SOURCE). Did you mean i (LATIN SMALL LETTER I)?

(RUF001)

plugins/test-coverage/skills/analyze/test_structure_analyzer.py

78-78: Unused function argument: language

(ARG001)


84-84: Unused function argument: language

(ARG001)


84-84: PEP 484 prohibits implicit Optional

Convert to T | None

(RUF013)


126-126: Unused function argument: language

(ARG001)


202-202: Do not catch blind exception: Exception

(BLE001)


271-271: Local variable base_indent is assigned to but never used

Remove assignment to unused variable base_indent

(F841)


296-296: Local variable context_name is assigned to but never used

Remove assignment to unused variable context_name

(F841)


321-321: Unused function argument: language

(ARG001)


373-373: Unused function argument: language

(ARG001)


396-396: Unused function argument: language

(ARG001)


416-416: Local variable source_by_path is assigned to but never used

Remove assignment to unused variable source_by_path

(F841)


453-453: Unused function argument: file_path

(ARG001)


679-679: f-string without any placeholders

Remove extraneous f prefix

(F541)


703-703: Do not catch blind exception: Exception

(BLE001)


757-757: Do not catch blind exception: Exception

(BLE001)


768-768: Do not catch blind exception: Exception

(BLE001)


847-847: Do not catch blind exception: Exception

(BLE001)


861-861: Consider moving this statement to an else block

(TRY300)


863-863: Do not catch blind exception: Exception

(BLE001)

🔇 Additional comments (8)
plugins/test-coverage/README.md (1)

306-309: Test pattern example is now Go-specific.

Good fix! The example now correctly uses Go test patterns (**/*_test.go,**/*e2e*_test.go,**/*integration*_test.go) instead of Java patterns, which aligns with the plugin's Go-only scope.

plugins/test-coverage/commands/gaps.md (1)

34-36: Examples correctly aligned with Go-only support.

The examples now consistently show Go test files (.go extensions), which properly aligns with the stated "Language Support: This command currently supports Go projects only" on line 27.

plugins/test-coverage/utils/__init__.py (1)

1-9: Clean package initialization.

The __init__.py follows Python best practices with a clear module docstring and explicit __all__ declaration for the public API. The re-exports provide convenient package-level access to the path handling utilities.

PLUGINS.md (1)

18-18: Test Coverage plugin documentation added correctly.

The navigation link and plugin section are well-structured and consistent with other plugin entries in the document. The commands are clearly documented with proper synopsis and argument hints.

Also applies to: 176-185

docs/data.json (1)

607-638: Plugin metadata well-structured.

The test-coverage plugin entry in data.json is properly formatted and includes all required fields: name, description, version, commands (with synopsis and argument hints), skills, and has_readme flag. The structure is consistent with other plugin entries in the file.

plugins/test-coverage/utils/path_handler.py (3)

118-118: MD5 usage is appropriate for cache key generation.

The use of MD5 on line 118 is for generating cache filenames, not cryptographic purposes. This is an acceptable use case where collision resistance for a small key space is sufficient.


33-44: Cache directory initialization is clean.

The __init__ method properly sets up the cache directory with a sensible default (.work/test-coverage/cache/) and ensures it exists. The use of os.makedirs(..., exist_ok=True) prevents race conditions.


268-297: Convenience functions provide clean API.

The module-level resolve_path() and resolve_paths() functions provide a convenient interface without requiring explicit PathHandler instantiation, following a common Python pattern.

Copy link
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: 3

♻️ Duplicate comments (8)
plugins/test-coverage/skills/analyze/test_structure_analyzer.py (1)

838-848: Fix HTML generator import path.

The import at line 841 still references test_gap_reports instead of test_structure_reports, causing HTML generation to fail. This issue was flagged in a previous review but remains unresolved.

Apply this diff:

         html_path = os.path.join(args.output, 'test-structure-report.html')
         try:
-            from test_gap_reports import generate_test_structure_html
+            try:
+                from test_structure_reports import generate_test_structure_html
+            except ImportError:
+                from .test_structure_reports import generate_test_structure_html
             with open(json_path, 'r') as f:
                 json_data = json.load(f)
             generate_test_structure_html(json_data, html_path)
         except ImportError:
-            print("Warning: report_generator not found, skipping HTML report")
+            print("Warning: test_structure_reports not found, skipping HTML report")
         except Exception as e:
             print(f"Warning: Failed to generate HTML report: {e}")
plugins/test-coverage/skills/analyze/README.md (1)

16-30: Fix format inconsistency throughout documentation.

The README claims Go-only support (line 45) but examples use coverage.xml (lines 17, 20, 23, 29). This contradicts the "Supported Format" table showing only Go .out files. Either add Cobertura support or change all examples to use coverage.out.

For Go-only, apply this diff pattern throughout:

 # Analyze single coverage file
-python analyze.py coverage.xml
+python analyze.py coverage.out

 # Analyze with custom output directory
-python analyze.py coverage.xml --output reports/coverage/
+python analyze.py coverage.out --output reports/coverage/

 # Analyze with threshold
-python analyze.py coverage.xml --threshold 80
+python analyze.py coverage.out --threshold 80

 # Analyze specific files only
-python analyze.py coverage.xml --include-only "pkg/*" --include-only "cmd/*"
+python analyze.py coverage.out --include-only "pkg/*" --include-only "cmd/*"

Also update lines 100, 108 (remove lxml references) and line 130 (change "COBERTURA" to "GO").

plugins/test-coverage/README.md (1)

217-232: Standardize minimum Python version across all documentation.

Line 221 states "Python 3.6+" but other documentation in this PR requires 3.8+. Standardize to Python 3.8+ for consistency.

Apply this diff:

 ### Required
 
-- **Python 3.6+**
+- **Python 3.8+**
 - **Go toolchain** (for generating coverage files with `go test -coverprofile`)

Also update line 312 to match:

-Ensure Python 3.6+ is installed:
+Ensure Python 3.8+ is installed:
 ```bash
 python3 --version
-# If not installed: sudo apt install python3  # Ubuntu/Debian
+# Should be 3.8 or higher

</blockquote></details>
<details>
<summary>plugins/test-coverage/commands/analyze.md (1)</summary><blockquote>

`328-337`: **Update Python version requirement to match project standard.**

Line 336 states "Python 3.6+" but should be "Python 3.8+" to match the standardized minimum across the project.




Apply this diff:

```diff
 ### Checking Prerequisites
 
-The command will automatically check for Python 3.6+ and provide installation instructions if missing.
+The command will automatically check for Python 3.8+ and provide installation instructions if missing.

Also update line 332 for consistency:

-The command uses Python for parsing and report generation. No external packages are required - only standard library modules are used.
+The command uses Python 3.8+ for parsing and report generation. No external packages are required - only standard library modules are used.
plugins/test-coverage/skills/analyze/test_gap_reports.py (3)

795-799: Drop unused locals in test-only renderer.

source_dir and analyzed_file are still assigned but never consumed. Please remove these dead assignments to keep the helper tidy.

-    language = data.get('language', 'unknown')
-    source_dir = data.get('source_dir', '')
-    test_file_details = data.get('test_file_details', {})
-    analyzed_file = data.get('analyzed_file', '')
+    language = data.get('language', 'unknown')
+    test_file_details = data.get('test_file_details', {})

1109-1132: Remove unused summary parameter.

summary is never referenced inside _generate_recommendations_section, yet the call site still passes it. Please trim the signature and invocation as previously requested.

-def _generate_recommendations_section(gaps: Dict, summary: Dict) -> str:
+def _generate_recommendations_section(gaps: Dict) -> str:
@@
-            {_generate_recommendations_section(gaps, summary)}
+            {_generate_recommendations_section(gaps)}

427-579: Guard against missing coverage buckets before rendering.

Directly indexing coverage['protocols'], coverage['platforms'], coverage['service_types'], and the corresponding gaps[...] collections will crash with KeyError when the analysis payload comes from storage or “generic” components that don’t populate those networking-only buckets. This is the same failure mode I highlighted earlier and it’s still reachable from gap_analyzer.py, where we dispatch on component type but always call this renderer. Please gate each section with .get lookups (and skip rendering when the bucket is absent) so the report degrades gracefully instead of blowing up.

-    tested_protocols = coverage['protocols']['tested']
-    not_tested_protocols = coverage['protocols']['not_tested']
+    protocol_section = coverage.get('protocols', {})
+    tested_protocols = protocol_section.get('tested', [])
+    not_tested_protocols = protocol_section.get('not_tested', [])
@@
-    tested_platforms = coverage['platforms']['tested']
+    platform_section = coverage.get('platforms', {})
+    tested_platforms = platform_section.get('tested', [])
@@
-    tested_services = coverage['service_types']['tested']
+    service_section = coverage.get('service_types', {})
+    tested_services = service_section.get('tested', [])
@@
-    if gaps['platforms']:
+    if gaps.get('platforms'):
@@
-        for gap in gaps['platforms']:
+        for gap in gaps.get('platforms', []):
@@
-    if gaps['service_types']:
+    if gaps.get('service_types'):
@@
-        for gap in gaps['service_types']:
+        for gap in gaps.get('service_types', []):
@@
-    if gaps['scenarios']:
+    if gaps.get('scenarios'):
@@
-        for gap in gaps['scenarios']:
+        for gap in gaps.get('scenarios', []):
plugins/test-coverage/skills/analyze/test_structure_reports.py (1)

17-333: Deduplicate shared CSS/report helpers.

This entire CSS template and surrounding helpers are byte-for-byte identical to the ones in test_gap_reports.py. Please extract them into a shared module (e.g., report_common.py) so we only maintain them in one place.

🧹 Nitpick comments (2)
plugins/test-coverage/skills/gaps/SKILL.md (2)

364-404: Add language identifier to fenced code block.

Static analysis correctly flags this code block as missing a language identifier. Add text or plaintext to improve rendering and accessibility.

Apply this diff:

-```
+```text
 Simulated Coverage Report (based on test structure)
 ═══════════════════════════════════════════════════

409-424: Add language identifier to fenced code block.

This code block should specify text as the language for proper rendering.

Apply this diff:

-```
+```text
 Simulated Coverage Report (based on test structure)
 ═══════════════════════════════════════════════════
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between db36564 and bb87992.

📒 Files selected for processing (25)
  • .claude-plugin/marketplace.json (1 hunks)
  • PLUGINS.md (2 hunks)
  • docs/data.json (1 hunks)
  • plugins/test-coverage/.claude-plugin/plugin.json (1 hunks)
  • plugins/test-coverage/README.md (1 hunks)
  • plugins/test-coverage/URL_SUPPORT.md (1 hunks)
  • plugins/test-coverage/commands/analyze.md (1 hunks)
  • plugins/test-coverage/commands/gaps.md (1 hunks)
  • plugins/test-coverage/skills/__init__.py (1 hunks)
  • plugins/test-coverage/skills/analyze/README.md (1 hunks)
  • plugins/test-coverage/skills/analyze/SKILL.md (1 hunks)
  • plugins/test-coverage/skills/analyze/__init__.py (1 hunks)
  • plugins/test-coverage/skills/analyze/analyze.py (1 hunks)
  • plugins/test-coverage/skills/analyze/coverage_parser.py (1 hunks)
  • plugins/test-coverage/skills/analyze/coverage_reports.py (1 hunks)
  • plugins/test-coverage/skills/analyze/test_gap_reports.py (1 hunks)
  • plugins/test-coverage/skills/analyze/test_structure_analyzer.py (1 hunks)
  • plugins/test-coverage/skills/analyze/test_structure_reports.py (1 hunks)
  • plugins/test-coverage/skills/gaps/README.md (1 hunks)
  • plugins/test-coverage/skills/gaps/SKILL.md (1 hunks)
  • plugins/test-coverage/skills/gaps/__init__.py (1 hunks)
  • plugins/test-coverage/skills/gaps/gap_analyzer.py (1 hunks)
  • plugins/test-coverage/skills/gaps/reports.py (1 hunks)
  • plugins/test-coverage/utils/__init__.py (1 hunks)
  • plugins/test-coverage/utils/path_handler.py (1 hunks)
✅ Files skipped from review due to trivial changes (3)
  • plugins/test-coverage/skills/gaps/init.py
  • plugins/test-coverage/skills/init.py
  • plugins/test-coverage/skills/analyze/init.py
🚧 Files skipped from review as they are similar to previous changes (6)
  • .claude-plugin/marketplace.json
  • plugins/test-coverage/skills/gaps/README.md
  • plugins/test-coverage/.claude-plugin/plugin.json
  • plugins/test-coverage/skills/analyze/SKILL.md
  • PLUGINS.md
  • plugins/test-coverage/utils/init.py
🧰 Additional context used
🪛 LanguageTool
plugins/test-coverage/commands/analyze.md

[grammar] ~265-~265: Use a hyphen to join words.
Context: ...mple 2: Analyze test structure with high priority filter ``` /test-coverage:anal...

(QB_NEW_EN_HYPHEN)

plugins/test-coverage/commands/gaps.md

[uncategorized] ~225-~225: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...I drivers. ### Example 3: Analyze with high priority filter ``` /test-coverage:gaps ./test/...

(EN_COMPOUND_ADJECTIVE_INTERNAL)

plugins/test-coverage/skills/analyze/README.md

[grammar] ~1-~1: Ensure spelling is correct
Context: # Coverage Analyze Skill This skill provides comprehensiv...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)


[style] ~113-~113: As an alternative to the over-used intensifier ‘very’, consider replacing this phrase.
Context: ...lxml ``` ### Large Coverage Files For very large coverage files, the tool may take some ...

(EN_WEAK_ADJECTIVE)

🪛 markdownlint-cli2 (0.18.1)
plugins/test-coverage/URL_SUPPORT.md

17-17: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


22-22: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


28-28: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


35-35: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


40-40: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


47-47: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

plugins/test-coverage/README.md

332-332: Bare URL used

(MD034, no-bare-urls)


333-333: Bare URL used

(MD034, no-bare-urls)

plugins/test-coverage/commands/analyze.md

10-10: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


144-144: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


177-177: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


207-207: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


217-217: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


227-227: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


235-235: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


243-243: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

plugins/test-coverage/commands/gaps.md

10-10: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


144-144: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


177-177: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


207-207: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


217-217: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


227-227: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


235-235: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


243-243: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

plugins/test-coverage/skills/analyze/README.md

49-49: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


119-119: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

plugins/test-coverage/skills/gaps/SKILL.md

364-364: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


409-409: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🪛 Ruff (0.14.3)
plugins/test-coverage/skills/analyze/coverage_reports.py

21-21: Unused static method argument: baseline

(ARG004)


436-527: f-string without any placeholders

Remove extraneous f prefix

(F541)


709-709: Do not catch blind exception: Exception

(BLE001)

plugins/test-coverage/skills/gaps/gap_analyzer.py

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

(EXE001)


567-567: f-string without any placeholders

Remove extraneous f prefix

(F541)

plugins/test-coverage/skills/analyze/coverage_parser.py

163-163: Do not catch blind exception: Exception

(BLE001)


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

(TRY003)


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

(TRY003)


199-199: Using xml to parse untrusted data is known to be vulnerable to XML attacks; use defusedxml equivalents

(S314)


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

(TRY003)


370-370: Ambiguous variable name: l

(E741)


382-382: Ambiguous variable name: l

(E741)


395-395: Using xml to parse untrusted data is known to be vulnerable to XML attacks; use defusedxml equivalents

(S314)


452-452: Using xml to parse untrusted data is known to be vulnerable to XML attacks; use defusedxml equivalents

(S314)


555-555: Do not catch blind exception: Exception

(BLE001)

plugins/test-coverage/skills/analyze/test_gap_reports.py

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

(EXE001)


796-796: Local variable source_dir is assigned to but never used

Remove assignment to unused variable source_dir

(F841)


798-798: Local variable analyzed_file is assigned to but never used

Remove assignment to unused variable analyzed_file

(F841)


906-906: String contains ambiguous (INFORMATION SOURCE). Did you mean i (LATIN SMALL LETTER I)?

(RUF001)


1109-1109: Unused function argument: summary

(ARG001)

plugins/test-coverage/utils/path_handler.py

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

(EXE001)


116-116: Probable use of insecure hash functions in hashlib: md5

(S324)


161-161: Audit URL open for permitted schemes. Allowing use of file: or custom schemes is often unexpected.

(S310)


163-163: Audit URL open for permitted schemes. Allowing use of file: or custom schemes is often unexpected.

(S310)


186-186: Do not catch blind exception: Exception

(BLE001)

plugins/test-coverage/skills/analyze/analyze.py

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

(TRY003)


239-239: Do not catch blind exception: Exception

(BLE001)


289-289: Consider moving this statement to an else block

(TRY300)


291-291: Do not catch blind exception: Exception

(BLE001)

plugins/test-coverage/skills/analyze/test_structure_analyzer.py

78-78: Unused function argument: language

(ARG001)


84-84: Unused function argument: language

(ARG001)


84-84: PEP 484 prohibits implicit Optional

Convert to T | None

(RUF013)


126-126: Unused function argument: language

(ARG001)


202-202: Do not catch blind exception: Exception

(BLE001)


271-271: Local variable base_indent is assigned to but never used

Remove assignment to unused variable base_indent

(F841)


296-296: Local variable context_name is assigned to but never used

Remove assignment to unused variable context_name

(F841)


321-321: Unused function argument: language

(ARG001)


373-373: Unused function argument: language

(ARG001)


396-396: Unused function argument: language

(ARG001)


416-416: Local variable source_by_path is assigned to but never used

Remove assignment to unused variable source_by_path

(F841)


453-453: Unused function argument: file_path

(ARG001)


679-679: f-string without any placeholders

Remove extraneous f prefix

(F541)


703-703: Do not catch blind exception: Exception

(BLE001)


757-757: Do not catch blind exception: Exception

(BLE001)


768-768: Do not catch blind exception: Exception

(BLE001)


847-847: Do not catch blind exception: Exception

(BLE001)


861-861: Consider moving this statement to an else block

(TRY300)


863-863: Do not catch blind exception: Exception

(BLE001)

plugins/test-coverage/skills/analyze/test_structure_reports.py

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

(EXE001)


466-466: String contains ambiguous (INFORMATION SOURCE). Did you mean i (LATIN SMALL LETTER I)?

(RUF001)

plugins/test-coverage/skills/gaps/reports.py

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

(EXE001)

🔇 Additional comments (1)
plugins/test-coverage/utils/path_handler.py (1)

148-152: LGTM! URL scheme validation properly implemented.

The explicit scheme validation at urlopen call-site prevents file:// and other insecure schemes, addressing the security concern. The dual validation (in is_url() and download_file()) provides defense in depth.

Copy link
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: 3

♻️ Duplicate comments (5)
plugins/test-coverage/README.md (1)

310-315: Replace Java patterns with Go examples for consistency.

This example uses Java test patterns (**/*Spec.java,**/IT*.java), but the plugin documentation clearly states it "Currently supports Go projects only" (line 170) and the language support table (lines 172-174) lists only Go patterns. This creates confusion for users.

Replace with Go-appropriate patterns:

-/test-coverage:analyze ./src/ --test-pattern "**/*Spec.java,**/IT*.java"
+/test-coverage:analyze ./pkg/ --test-pattern "**/*_test.go,**/e2e/*_test.go"
plugins/test-coverage/commands/analyze.md (1)

336-336: Update Python version requirement to 3.8+ for consistency.

This line states "Python 3.6+" but all other documentation files consistently require "Python 3.8+":

  • plugins/test-coverage/README.md (line 221)
  • plugins/test-coverage/skills/analyze/README.md (line 59)
  • plugins/test-coverage/skills/gaps/README.md (line 46)

Apply this update:

-The command will automatically check for Python 3.6+ and provide installation instructions if missing.
+The command will automatically check for Python 3.8+ and provide installation instructions if missing.
plugins/test-coverage/URL_SUPPORT.md (1)

121-124: Correct URL support description.
PathHandler.is_url only accepts HTTP(S) inputs; FTP and file schemes are intentionally rejected for security. Please update this bullet to say “Identifies HTTP(S) URLs only (FTP/file are excluded)” so the doc matches the actual behavior.

-- **URL detection**: Identifies HTTP(S), FTP, and file:// URLs
+- **URL detection**: Identifies HTTP(S) URLs only (FTP and file:// are excluded for security)
plugins/test-coverage/skills/analyze/test_gap_reports.py (2)

795-799: Drop the unused locals.

source_dir and analyzed_file are reintroduced but never referenced, triggering Ruff F841 again. Please delete the dead assignments to keep the report generator lint-clean.

-    language = data.get('language', 'unknown')
-    source_dir = data.get('source_dir', '')
-    test_file_details = data.get('test_file_details', {})
-    analyzed_file = data.get('analyzed_file', '')
+    language = data.get('language', 'unknown')
+    test_file_details = data.get('test_file_details', {})

994-995: Remove the unused summary argument.

_generate_recommendations_section still accepts summary but never touches it, and the caller passes the extra dict only to satisfy the dead parameter. This keeps tripping Ruff ARG001. Please drop the parameter and simplify the call.

-            {_generate_recommendations_section(gaps, summary)}
+            {_generate_recommendations_section(gaps)}
@@
-def _generate_recommendations_section(gaps: Dict, summary: Dict) -> str:
+def _generate_recommendations_section(gaps: Dict) -> str:

Also applies to: 1109-1132

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between bb87992 and 64b12b1.

📒 Files selected for processing (22)
  • .claude-plugin/marketplace.json (1 hunks)
  • PLUGINS.md (2 hunks)
  • docs/data.json (1 hunks)
  • plugins/test-coverage/.claude-plugin/plugin.json (1 hunks)
  • plugins/test-coverage/README.md (1 hunks)
  • plugins/test-coverage/URL_SUPPORT.md (1 hunks)
  • plugins/test-coverage/commands/analyze.md (1 hunks)
  • plugins/test-coverage/commands/gaps.md (1 hunks)
  • plugins/test-coverage/skills/__init__.py (1 hunks)
  • plugins/test-coverage/skills/analyze/README.md (1 hunks)
  • plugins/test-coverage/skills/analyze/SKILL.md (1 hunks)
  • plugins/test-coverage/skills/analyze/__init__.py (1 hunks)
  • plugins/test-coverage/skills/analyze/test_gap_reports.py (1 hunks)
  • plugins/test-coverage/skills/analyze/test_structure_analyzer.py (1 hunks)
  • plugins/test-coverage/skills/analyze/test_structure_reports.py (1 hunks)
  • plugins/test-coverage/skills/gaps/README.md (1 hunks)
  • plugins/test-coverage/skills/gaps/SKILL.md (1 hunks)
  • plugins/test-coverage/skills/gaps/__init__.py (1 hunks)
  • plugins/test-coverage/skills/gaps/gap_analyzer.py (1 hunks)
  • plugins/test-coverage/skills/gaps/reports.py (1 hunks)
  • plugins/test-coverage/utils/__init__.py (1 hunks)
  • plugins/test-coverage/utils/path_handler.py (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
  • plugins/test-coverage/utils/init.py
  • plugins/test-coverage/skills/gaps/init.py
  • .claude-plugin/marketplace.json
  • plugins/test-coverage/skills/init.py
  • plugins/test-coverage/skills/analyze/init.py
🧰 Additional context used
🪛 LanguageTool
plugins/test-coverage/commands/gaps.md

[uncategorized] ~225-~225: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...I drivers. ### Example 3: Analyze with high priority filter ``` /test-coverage:gaps ./test/...

(EN_COMPOUND_ADJECTIVE_INTERNAL)

plugins/test-coverage/README.md

[typographical] ~161-~161: Two consecutive commas
Context: ..., [Longduration], [ConnectedOnly], [NonPreRelease]-g.Describe(, g.Context(, g.It(` Note: To inc...

(DOUBLE_PUNCTUATION)


[uncategorized] ~170-~170: A comma may be missing after the conjunctive/linking adverb ‘Currently’.
Context: ...` flag. --- ## Supported Languages Currently supports Go projects only. | Languag...

(SENT_START_CONJUNCTIVE_LINKING_ADVERB_COMMA)


[uncategorized] ~280-~280: Use a comma before ‘but’ if it connects two independent clauses (unless they are closely connected and short).
Context: ...ude "*.js" ``` ### Issue: No gaps found but code is clearly untested Solution:...

(COMMA_COMPOUND_SENTENCE_2)


[uncategorized] ~333-~333: Loose punctuation mark.
Context: ...ation. ## Related Plugins - jira: Create bug reports with coverage gap co...

(UNLIKELY_OPENING_PUNCTUATION)

plugins/test-coverage/commands/analyze.md

[grammar] ~265-~265: Use a hyphen to join words.
Context: ...mple 2: Analyze test structure with high priority filter ``` /test-coverage:anal...

(QB_NEW_EN_HYPHEN)

plugins/test-coverage/skills/analyze/README.md

[uncategorized] ~79-~79: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...files without tests ### Example 2: High Priority Gaps Only bash # Analyze only high-...

(EN_COMPOUND_ADJECTIVE_INTERNAL)

🪛 markdownlint-cli2 (0.18.1)
plugins/test-coverage/commands/gaps.md

10-10: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


144-144: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


177-177: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


207-207: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


217-217: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


227-227: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


235-235: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


243-243: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

plugins/test-coverage/URL_SUPPORT.md

17-17: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


22-22: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


27-27: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


34-34: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


39-39: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


46-46: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

plugins/test-coverage/commands/analyze.md

10-10: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


46-46: Spaces inside emphasis markers

(MD037, no-space-in-emphasis)


223-223: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


259-259: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


267-267: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


275-275: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


283-283: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


297-297: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


305-305: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


313-313: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


323-323: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

plugins/test-coverage/skills/analyze/README.md

48-48: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


95-95: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

plugins/test-coverage/skills/analyze/SKILL.md

292-292: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

plugins/test-coverage/skills/gaps/SKILL.md

364-364: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


409-409: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🪛 Ruff (0.14.3)
plugins/test-coverage/skills/gaps/gap_analyzer.py

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

(EXE001)


567-567: f-string without any placeholders

Remove extraneous f prefix

(F541)

plugins/test-coverage/skills/gaps/reports.py

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

(EXE001)

plugins/test-coverage/skills/analyze/test_structure_reports.py

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

(EXE001)


466-466: String contains ambiguous (INFORMATION SOURCE). Did you mean i (LATIN SMALL LETTER I)?

(RUF001)

plugins/test-coverage/skills/analyze/test_gap_reports.py

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

(EXE001)


796-796: Local variable source_dir is assigned to but never used

Remove assignment to unused variable source_dir

(F841)


798-798: Local variable analyzed_file is assigned to but never used

Remove assignment to unused variable analyzed_file

(F841)


906-906: String contains ambiguous (INFORMATION SOURCE). Did you mean i (LATIN SMALL LETTER I)?

(RUF001)


1109-1109: Unused function argument: summary

(ARG001)

plugins/test-coverage/skills/analyze/test_structure_analyzer.py

78-78: Unused function argument: language

(ARG001)


84-84: Unused function argument: language

(ARG001)


84-84: PEP 484 prohibits implicit Optional

Convert to T | None

(RUF013)


126-126: Unused function argument: language

(ARG001)


202-202: Do not catch blind exception: Exception

(BLE001)


271-271: Local variable base_indent is assigned to but never used

Remove assignment to unused variable base_indent

(F841)


296-296: Local variable context_name is assigned to but never used

Remove assignment to unused variable context_name

(F841)


321-321: Unused function argument: language

(ARG001)


373-373: Unused function argument: language

(ARG001)


396-396: Unused function argument: language

(ARG001)


416-416: Local variable source_by_path is assigned to but never used

Remove assignment to unused variable source_by_path

(F841)


453-453: Unused function argument: file_path

(ARG001)


679-679: f-string without any placeholders

Remove extraneous f prefix

(F541)


703-703: Do not catch blind exception: Exception

(BLE001)


757-757: Do not catch blind exception: Exception

(BLE001)


768-768: Do not catch blind exception: Exception

(BLE001)


847-847: Do not catch blind exception: Exception

(BLE001)


861-861: Consider moving this statement to an else block

(TRY300)


863-863: Do not catch blind exception: Exception

(BLE001)

plugins/test-coverage/utils/path_handler.py

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

(EXE001)


116-116: Probable use of insecure hash functions in hashlib: md5

(S324)


161-161: Audit URL open for permitted schemes. Allowing use of file: or custom schemes is often unexpected.

(S310)


163-163: Audit URL open for permitted schemes. Allowing use of file: or custom schemes is often unexpected.

(S310)


186-186: Do not catch blind exception: Exception

(BLE001)

🔇 Additional comments (6)
plugins/test-coverage/skills/analyze/README.md (1)

1-128: LGTM! Clear and consistent documentation.

The README effectively documents the Test Structure Analysis skill with accurate examples, clear feature descriptions, and proper Go-only focus. The content is well-organized and provides useful guidance for users.

plugins/test-coverage/skills/gaps/README.md (1)

1-65: LGTM! Concise and accurate documentation.

The gap analysis README is well-structured with clear descriptions of features, usage, and requirements. Python version (3.8+) and language support (Go only) are correctly documented and consistent with other files.

plugins/test-coverage/.claude-plugin/plugin.json (1)

1-8: LGTM! Valid plugin manifest.

The plugin.json is well-formed with appropriate metadata for the test-coverage plugin.

PLUGINS.md (1)

176-185: LGTM! Proper plugin documentation entry.

The Test Coverage plugin is correctly added to the plugins list with appropriate command descriptions and a link to the detailed README.

plugins/test-coverage/utils/path_handler.py (1)

1-328: LGTM! Secure and well-implemented path handling utility.

The PathHandler class provides robust handling of both local paths and remote URLs with proper security measures:

  • URL scheme restricted to HTTP(S) only (lines 59-62, 148-152)
  • Comprehensive error handling with informative messages
  • Caching mechanism for efficient re-use
  • Clear documentation and examples

The static analysis warnings (MD5 hash, urlopen) are false positives given the context - MD5 is used only for cache filenames, and urlopen is called after explicit scheme validation.

plugins/test-coverage/skills/analyze/SKILL.md (1)

1-418: LGTM! Comprehensive and well-structured skill guide.

This SKILL.md provides excellent detailed documentation for AI agents implementing the test structure analysis feature. The content is thorough, well-organized, and consistent:

  • Correct Python 3.8+ requirement (line 24)
  • Clear Go-only focus (line 39)
  • Detailed step-by-step workflows with code examples
  • Proper JSON examples showing data structures
  • Comprehensive error handling guidance

Copy link
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: 6

♻️ Duplicate comments (2)
plugins/test-coverage/URL_SUPPORT.md (1)

123-123: Remove incorrect FTP/file:// reference.

The documentation claims PathHandler supports "FTP, and file:// URLs" but path_handler.py explicitly restricts to HTTP(S) only for security (lines 59-62, 148-152 in path_handler.py). This was flagged in a previous review but appears unaddressed.

Apply this diff:

-- **URL detection**: Identifies HTTP(S), FTP, and file:// URLs
+- **URL detection**: Identifies HTTP(S) URLs only (file:// and FTP excluded for security)

Based on past review comments.

plugins/test-coverage/skills/gaps/gap_analyzer.py (1)

563-576: CLI summary still ignores storage/service gaps.

all_gaps only aggregates platforms and scenarios, so high-priority service_type/storage_class/volume_mode gaps never show up in the console output. This matches the earlier feedback; please extend the aggregation to include every gap category returned by the analyzer.

🧹 Nitpick comments (16)
plugins/test-coverage/skills/analyze/README.md (2)

48-55: Add language identifier to fenced code block.

The file structure code block should specify a language for proper rendering and to satisfy markdown linting requirements.

Apply this diff:

 ## File Structure
 
-```
+```text
 analyze/
 ├── test_structure_analyzer.py  # Main test structure analyzer
 ├── test_structure_reports.py   # Report generators
 ├── test_gap_reports.py         # Gap report generators
 ├── SKILL.md                    # Detailed implementation guide
 └── README.md                   # This file

---

`95-123`: **Add language identifier to output example block.**

The output example code block should specify a language (or 'text') for proper rendering and to satisfy markdown linting requirements.


Apply this diff:

```diff
 ## Output Example
 
-```
+```text
 ================================================================================
 Test Structure Analysis Complete
 ================================================================================
plugins/test-coverage/commands/analyze.md (4)

10-12: Add language identifier to synopsis code block.

Add bash as the language identifier to improve rendering and satisfy markdown linting.

Apply this diff:

 ## Synopsis
-```
+```bash
 /test-coverage:analyze <path-or-url> [--output <path>] [--priority <level>] [--test-structure-only]

---

`223-249`: **Add language identifier to return value example.**

Add `text` as the language identifier to improve rendering and satisfy markdown linting.


Apply this diff:

```diff
 **Terminal Output:**
-```
+```text
 Test Structure Analysis Complete

259-326: Add language identifiers to all example code blocks.

All command example blocks should use bash as the language identifier for proper syntax highlighting and to satisfy markdown linting requirements.

Apply this diff for each example block (showing one instance):

 ### Example 1: Analyze e2e test structure without running tests (Go project)
 
-```
+```bash
 /test-coverage:analyze ./pkg/

Repeat for all example blocks at lines 259, 267, 275, 283, 297, 305, 313, and 323.

---

`46-46`: **Fix spacing in emphasis markers.**

Remove extra spaces inside the emphasis markers around `*_util.go`.


Apply this diff:

```diff
-- By default, utility files are excluded (*_util.go, *_utils.go, *_helper.go, helpers.go, etc.)
+- By default, utility files are excluded (`*_util.go`, `*_utils.go`, `*_helper.go`, `helpers.go`, etc.)
plugins/test-coverage/skills/gaps/README.md (1)

39-43: Consider adding comma for clarity.

While optional, adding a comma after "Currently" improves readability per style guidelines.

Apply this diff:

 ## Language Support
 
-Currently supports Go test files only:
+Currently, supports Go test files only:
plugins/test-coverage/utils/path_handler.py (1)

186-188: Narrow exception handling for better error diagnosis.

Catching bare Exception can mask unexpected errors. Consider catching specific exceptions or at minimum logging the exception type.

Apply this diff:

         except urllib.error.URLError as e:
             print(f"URL Error: {e.reason} when downloading {url}", file=sys.stderr)
             return False
-        except Exception as e:
-            print(f"Error downloading {url}: {e}", file=sys.stderr)
+        except OSError as e:
+            print(f"File system error when saving {url}: {e}", file=sys.stderr)
+            return False
+        except Exception as e:
+            print(f"Unexpected error downloading {url}: {type(e).__name__}: {e}", file=sys.stderr)
             return False
plugins/test-coverage/URL_SUPPORT.md (1)

17-49: Add language identifiers to URL example blocks.

All URL example code blocks should specify a language (use text or url) for proper rendering and to satisfy markdown linting requirements.

Apply this diff to each block (showing representative examples):

 **Blob URLs** (automatically converted to raw URLs):
-```
+```text
 https://github.com/owner/repo/blob/main/test/file_test.go

Raw URLs (used directly):
- +text
https://raw.githubusercontent.com/owner/repo/main/test/file_test.go

Apply to blocks at lines 17, 22, 27, 34, 39, and 46.

plugins/test-coverage/README.md (2)

161-162: Fix double comma formatting.

Static analysis detected double consecutive commas in the test markers list.

Apply this diff:

-- `[Serial]`, `[Disruptive]`, `[Longduration]`, `[ConnectedOnly]`, `[NonPreRelease]`
+- `[Serial]`, `[Disruptive]`, `[Longduration]`, `[ConnectedOnly]`, `[NonPreRelease]`

323-324: Convert bare URLs to markdown links.

Bare URLs should be formatted as proper markdown links for better rendering.

Apply this diff:

 ## Support
 
-- **Issues**: https://github.com/openshift-eng/ai-helpers/issues
-- **Documentation**: https://github.com/openshift-eng/ai-helpers
+- **Issues**: [github.com/openshift-eng/ai-helpers/issues](https://github.com/openshift-eng/ai-helpers/issues)
+- **Documentation**: [github.com/openshift-eng/ai-helpers](https://github.com/openshift-eng/ai-helpers)
plugins/test-coverage/commands/gaps.md (3)

10-12: Add language identifier to synopsis block.

Add bash as the language identifier to improve rendering and satisfy markdown linting.

Apply this diff:

 ## Synopsis
-```bash
+```bash
 /test-coverage:gaps <test-file-or-url> [--priority <level>] [--output <path>]

(Note: The diff shows the language is already present in the annotated code. If this is an error in the linting tool, this comment can be skipped.)

---

`144-174`: **Add language identifier to output examples.**

The terminal output example blocks should use `text` as the language identifier for proper rendering.


Apply this diff:

```diff
 **Terminal Output (Networking Component Example):**
-```text
+```text
 Detected component: networking

Both output examples at lines 144 and 176 already appear to have text specified in the annotated code, so this may be a false positive from the linter.

Also applies to: 176-198


207-247: Add language identifiers to example blocks.

All command example blocks should use bash as the language identifier.

Apply bash language identifier to code blocks at lines 207, 217, 227, 235, and 243 if not already present.

plugins/test-coverage/skills/analyze/test_gap_reports.py (2)

795-799: Drop unused locals in _generate_test_only_html.

source_dir and analyzed_file are assigned but never read, which just adds noise and trips Ruff (F841). Please remove the dead assignments.

-    source_dir = data.get('source_dir', '')
     test_file_details = data.get('test_file_details', {})
-    analyzed_file = data.get('analyzed_file', '')

1109-1132: Remove the unused summary parameter.

_generate_recommendations_section no longer touches summary, so keeping it around only confuses readers and invites ARG001. Drop the parameter and update the caller accordingly.

-def _generate_recommendations_section(gaps: Dict, summary: Dict) -> str:
+def _generate_recommendations_section(gaps: Dict) -> str:
@@
-            {_generate_recommendations_section(gaps, summary)}
+            {_generate_recommendations_section(gaps)}
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 64b12b1 and e6a2574.

📒 Files selected for processing (22)
  • .claude-plugin/marketplace.json (1 hunks)
  • PLUGINS.md (2 hunks)
  • docs/data.json (1 hunks)
  • plugins/test-coverage/.claude-plugin/plugin.json (1 hunks)
  • plugins/test-coverage/README.md (1 hunks)
  • plugins/test-coverage/URL_SUPPORT.md (1 hunks)
  • plugins/test-coverage/commands/analyze.md (1 hunks)
  • plugins/test-coverage/commands/gaps.md (1 hunks)
  • plugins/test-coverage/skills/__init__.py (1 hunks)
  • plugins/test-coverage/skills/analyze/README.md (1 hunks)
  • plugins/test-coverage/skills/analyze/SKILL.md (1 hunks)
  • plugins/test-coverage/skills/analyze/__init__.py (1 hunks)
  • plugins/test-coverage/skills/analyze/test_gap_reports.py (1 hunks)
  • plugins/test-coverage/skills/analyze/test_structure_analyzer.py (1 hunks)
  • plugins/test-coverage/skills/analyze/test_structure_reports.py (1 hunks)
  • plugins/test-coverage/skills/gaps/README.md (1 hunks)
  • plugins/test-coverage/skills/gaps/SKILL.md (1 hunks)
  • plugins/test-coverage/skills/gaps/__init__.py (1 hunks)
  • plugins/test-coverage/skills/gaps/gap_analyzer.py (1 hunks)
  • plugins/test-coverage/skills/gaps/reports.py (1 hunks)
  • plugins/test-coverage/utils/__init__.py (1 hunks)
  • plugins/test-coverage/utils/path_handler.py (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (7)
  • .claude-plugin/marketplace.json
  • plugins/test-coverage/skills/analyze/init.py
  • plugins/test-coverage/skills/init.py
  • plugins/test-coverage/.claude-plugin/plugin.json
  • plugins/test-coverage/utils/init.py
  • plugins/test-coverage/skills/gaps/init.py
  • docs/data.json
🧰 Additional context used
🪛 LanguageTool
plugins/test-coverage/commands/analyze.md

[uncategorized] ~30-~30: Loose punctuation mark.
Context: ...g. ## Arguments - <source-directory>: Path or URL to source code directory/fi...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~38-~38: Loose punctuation mark.
Context: ...st-coverage/cache/ ---output `: Output directory for generated reports ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~41-~41: Loose punctuation mark.
Context: ...and text summary - --priority <level>: Filter results by priority (optional) ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~45-~45: Loose punctuation mark.
Context: ...Default: all - --include-test-utils: Include test utility/helper files in an...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~50-~50: Loose punctuation mark.
Context: ...structure code - --include-unit-tests: Include unit tests in analysis (optiona...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~58-~58: Loose punctuation mark.
Context: ...or Python) - --test-pattern <pattern>: Custom test file pattern (optional) -...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~61-~61: Loose punctuation mark.
Context: .../Test*.java" ---test-structure-only`: Analyze only test file structure, skip ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~265-~265: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ... Example 2: Analyze test structure with high priority filter ``` /test-coverage:analyze ./pk...

(EN_COMPOUND_ADJECTIVE_INTERNAL)


[duplication] ~341-~341: Possible typo: you repeated a word.
Context: ... - URLs are automatically detected and downloaded - Downloaded files are cached in `.work/test-coverag...

(ENGLISH_WORD_REPEAT_RULE)

plugins/test-coverage/README.md

[typographical] ~161-~161: Two consecutive commas
Context: ..., [Longduration], [ConnectedOnly], [NonPreRelease]-g.Describe(, g.Context(, g.It(` Note: To inc...

(DOUBLE_PUNCTUATION)


[uncategorized] ~170-~170: A comma may be missing after the conjunctive/linking adverb ‘Currently’.
Context: ...` flag. --- ## Supported Languages Currently supports Go projects only. | Languag...

(SENT_START_CONJUNCTIVE_LINKING_ADVERB_COMMA)


[uncategorized] ~280-~280: Use a comma before ‘but’ if it connects two independent clauses (unless they are closely connected and short).
Context: ...ude "*.js" ``` ### Issue: No gaps found but code is clearly untested Solution:...

(COMMA_COMPOUND_SENTENCE_2)


[uncategorized] ~333-~333: Loose punctuation mark.
Context: ...ation. ## Related Plugins - jira: Create bug reports with coverage gap co...

(UNLIKELY_OPENING_PUNCTUATION)

plugins/test-coverage/URL_SUPPORT.md

[uncategorized] ~196-~196: Possible missing preposition found.
Context: ...eports HTTP error codes and reasons - Network errors: Reports connection issues wit...

(AI_HYDRA_LEO_MISSING_OF)


[duplication] ~231-~231: Possible typo: you repeated a word.
Context: ...# See Also - /test-coverage:analyze command - /test-coverage:gaps command - [Path Handler Util...

(ENGLISH_WORD_REPEAT_RULE)

plugins/test-coverage/commands/gaps.md

[uncategorized] ~48-~48: Loose punctuation mark.
Context: ...tional Arguments - --priority <level>: Filter gaps by priority level (optional...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~54-~54: Loose punctuation mark.
Context: ...dge case scenarios) - --output <path>: Output directory for gap analysis repor...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~225-~225: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...I drivers. ### Example 3: Analyze with high priority filter ```bash /test-coverage:gaps ./t...

(EN_COMPOUND_ADJECTIVE_INTERNAL)

plugins/test-coverage/skills/analyze/README.md

[uncategorized] ~79-~79: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...files without tests ### Example 2: High Priority Gaps Only bash # Analyze only high-...

(EN_COMPOUND_ADJECTIVE_INTERNAL)

plugins/test-coverage/skills/gaps/README.md

[uncategorized] ~39-~39: A comma may be missing after the conjunctive/linking adverb ‘Currently’.
Context: ...output

] ``` ## Language Support Currently supports Go test files only: - Ginkgo B...

(SENT_START_CONJUNCTIVE_LINKING_ADVERB_COMMA)

plugins/test-coverage/skills/gaps/SKILL.md

[duplication] ~216-~216: Possible typo: you repeated a word.
Context: ...t → function): - TestHandleRequest tests HandleRequest - TestParseXML tests ParseXML 3. Import-based mapping...

(ENGLISH_WORD_REPEAT_RULE)

🪛 markdownlint-cli2 (0.18.1)
plugins/test-coverage/skills/analyze/SKILL.md

292-292: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

plugins/test-coverage/commands/analyze.md

10-10: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


46-46: Spaces inside emphasis markers

(MD037, no-space-in-emphasis)


223-223: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


259-259: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


267-267: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


275-275: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


283-283: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


297-297: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


305-305: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


313-313: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


323-323: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

plugins/test-coverage/README.md

323-323: Bare URL used

(MD034, no-bare-urls)


324-324: Bare URL used

(MD034, no-bare-urls)

plugins/test-coverage/URL_SUPPORT.md

17-17: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


22-22: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


27-27: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


34-34: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


39-39: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


46-46: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

plugins/test-coverage/skills/analyze/README.md

48-48: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


95-95: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

plugins/test-coverage/skills/gaps/SKILL.md

364-364: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


409-409: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🪛 Ruff (0.14.4)
plugins/test-coverage/skills/gaps/reports.py

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

(EXE001)

plugins/test-coverage/skills/analyze/test_structure_reports.py

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

(EXE001)


466-466: String contains ambiguous (INFORMATION SOURCE). Did you mean i (LATIN SMALL LETTER I)?

(RUF001)

plugins/test-coverage/skills/analyze/test_structure_analyzer.py

78-78: Unused function argument: language

(ARG001)


84-84: Unused function argument: language

(ARG001)


84-84: PEP 484 prohibits implicit Optional

Convert to T | None

(RUF013)


126-126: Unused function argument: language

(ARG001)


202-202: Do not catch blind exception: Exception

(BLE001)


271-271: Local variable base_indent is assigned to but never used

Remove assignment to unused variable base_indent

(F841)


296-296: Local variable context_name is assigned to but never used

Remove assignment to unused variable context_name

(F841)


321-321: Unused function argument: language

(ARG001)


373-373: Unused function argument: language

(ARG001)


396-396: Unused function argument: language

(ARG001)


416-416: Local variable source_by_path is assigned to but never used

Remove assignment to unused variable source_by_path

(F841)


453-453: Unused function argument: file_path

(ARG001)


679-679: f-string without any placeholders

Remove extraneous f prefix

(F541)


703-703: Do not catch blind exception: Exception

(BLE001)


757-757: Do not catch blind exception: Exception

(BLE001)


768-768: Do not catch blind exception: Exception

(BLE001)


847-847: Do not catch blind exception: Exception

(BLE001)


861-861: Consider moving this statement to an else block

(TRY300)


863-863: Do not catch blind exception: Exception

(BLE001)

plugins/test-coverage/skills/gaps/gap_analyzer.py

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

(EXE001)


585-585: f-string without any placeholders

Remove extraneous f prefix

(F541)

plugins/test-coverage/utils/path_handler.py

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

(EXE001)


116-116: Probable use of insecure hash functions in hashlib: md5

(S324)


161-161: Audit URL open for permitted schemes. Allowing use of file: or custom schemes is often unexpected.

(S310)


163-163: Audit URL open for permitted schemes. Allowing use of file: or custom schemes is often unexpected.

(S310)


186-186: Do not catch blind exception: Exception

(BLE001)

plugins/test-coverage/skills/analyze/test_gap_reports.py

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

(EXE001)


796-796: Local variable source_dir is assigned to but never used

Remove assignment to unused variable source_dir

(F841)


798-798: Local variable analyzed_file is assigned to but never used

Remove assignment to unused variable analyzed_file

(F841)


906-906: String contains ambiguous (INFORMATION SOURCE). Did you mean i (LATIN SMALL LETTER I)?

(RUF001)


1109-1109: Unused function argument: summary

(ARG001)

🔇 Additional comments (1)
PLUGINS.md (1)

176-184: LGTM! Test Coverage plugin entry is well-structured.

The new Test Coverage plugin entry follows the established format and includes:

  • Clear description
  • Two properly documented commands with arguments
  • Link to detailed documentation

The formatting is consistent with other plugin entries in the file.

Copy link
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: 8

♻️ Duplicate comments (5)
plugins/test-coverage/URL_SUPPORT.md (1)

117-128: Verify FTP reference removal.

The past review comment indicated line 124 incorrectly claimed FTP support. While marked as addressed, please confirm the line now correctly states "HTTP(S) URLs only" without mentioning FTP or file://.

Based on past review at line 124.

plugins/test-coverage/README.md (2)

309-315: Verify Go-specific test patterns.

Past reviews indicated line 314 contained Java patterns (**/*Spec.java,**/IT*.java) in a Go-only plugin. While marked as addressed in commit bb5f9fe, please confirm the example now uses Go patterns like **/*_test.go or **/*e2e*_test.go.


300-307: Update Python version requirement for consistency.

Line 303 should state "Python 3.8+" to match the requirement specified at line 221 and align with other documentation.

Apply this diff:

-Ensure Python 3.8+ is installed:
+Ensure Python 3.8+ is installed:

Note: Based on past review comments, this line may currently state "Python 3.6+" and needs to be updated to "Python 3.8+" for consistency across all documentation.

plugins/test-coverage/skills/gaps/gap_analyzer.py (1)

587-600: Surface every high-priority gap in the CLI summary.

Lines 587-595 only scan platforms and scenarios, so high-priority protocol gaps (e.g., missing UDP) and every storage-specific gap never reach the console output. This regression defeats the point of the component-aware analysis that the docs promise. Please iterate all gap categories and resolve the label lookups so every high-priority item is surfaced. For example:

-    all_gaps = []
-    for key in ('platforms', 'scenarios'):
-        all_gaps.extend(analysis['gaps'].get(key, []))
+    all_gaps = []
+    for key in ('platforms', 'protocols', 'service_types', 'storage_classes', 'volume_modes', 'scenarios'):
+        all_gaps.extend(analysis['gaps'].get(key, []))
@@
-            name = gap.get('platform') or gap.get('scenario')
+            name = (
+                gap.get('platform')
+                or gap.get('protocol')
+                or gap.get('service_type')
+                or gap.get('storage_class')
+                or gap.get('volume_mode')
+                or gap.get('scenario')
+            )

This aligns the CLI output with what calculate_coverage_score and the docs already treat as first-class metrics.

plugins/test-coverage/skills/analyze/test_structure_analyzer.py (1)

841-848: Fix HTML generator import path.

Line 841 imports generate_test_structure_html from test_gap_reports, but that function is defined in test_structure_reports.py. This causes an ImportError, and HTML report generation is silently skipped (exception caught on Line 847), so users never see the HTML output.

Apply this diff to correct the import:

         # HTML report
         html_path = os.path.join(args.output, 'test-structure-report.html')
         try:
-            from test_gap_reports import generate_test_structure_html
+            try:
+                from .test_structure_reports import generate_test_structure_html
+            except ImportError:
+                from test_structure_reports import generate_test_structure_html
             with open(json_path, 'r') as f:
                 json_data = json.load(f)
             generate_test_structure_html(json_data, html_path)
         except ImportError:
-            print("Warning: report_generator not found, skipping HTML report")
+            print("Warning: test_structure_reports module not found, skipping HTML report")
         except Exception as e:
             print(f"Warning: Failed to generate HTML report: {e}")
🧹 Nitpick comments (7)
plugins/test-coverage/utils/path_handler.py (1)

186-188: Consider more specific exception handling.

The broad Exception catch on line 186 is a last-resort handler, but could be more specific to avoid masking unexpected errors.

Consider catching only expected exceptions:

-        except Exception as e:
-            print(f"Error downloading {url}: {e}", file=sys.stderr)
-            return False
+        except (OSError, TimeoutError) as e:
+            print(f"Error downloading {url}: {e}", file=sys.stderr)
+            return False
plugins/test-coverage/URL_SUPPORT.md (1)

17-49: Add language identifiers to fenced code blocks.

Multiple fenced code blocks (lines 17-19, 22-24, 27-29, 34-36, 39-41, 46-49) lack language identifiers, which triggers markdown linting warnings and reduces syntax highlighting clarity.

Add text identifier to URL example blocks:

-```
+```text
 https://github.com/owner/repo/blob/main/test/file_test.go

Apply similar changes to all URL example blocks in this section.

</blockquote></details>
<details>
<summary>plugins/test-coverage/skills/analyze/README.md (1)</summary><blockquote>

`48-55`: **Add language identifier to code block.**

The file structure diagram (lines 48-55) uses an unlabeled fenced code block, triggering markdown linting.


Apply this diff:

```diff
-```
+```text
 analyze/
 ├── test_structure_analyzer.py  # Main test structure analyzer
 ...

</blockquote></details>
<details>
<summary>plugins/test-coverage/skills/gaps/reports.py (1)</summary><blockquote>

`1-1`: **Consider making the file executable.**

The shebang is present but the file is not executable. If this script is intended to be run directly, make it executable with `chmod +x`.

</blockquote></details>
<details>
<summary>plugins/test-coverage/skills/analyze/test_structure_reports.py (1)</summary><blockquote>

`1-1`: **Consider making the file executable.**

The shebang is present but the file is not executable. If this script is intended to be run directly, make it executable with `chmod +x`.

</blockquote></details>
<details>
<summary>plugins/test-coverage/skills/analyze/test_structure_analyzer.py (2)</summary><blockquote>

`271-271`: **Remove unused local variables.**

Three local variables are assigned but never used:
- Line 271: `base_indent` 
- Line 296: `context_name`
- Line 416: `source_by_path`



Apply this diff:

```diff
                 # Find end of It block (look for closing brace at same or lower indent)
                 line_end = i + 1
-                base_indent = len(line) - len(line.lstrip())
                 brace_count = line.count('{') - line.count('}')
             # Also track Describe/Context blocks for context
             describe_match = re.search(ginkgo_describe_pattern, line)
             if describe_match and not it_match:  # Don't count lines that are both
-                context_name = describe_match.group(1)
                 # Note: We're not adding these as tests, just tracking them
                 # Could be enhanced to show test hierarchy
     mapping = {}

     # Create lookup for source files
-    source_by_path = {sf.path: sf for sf in source_files}

     # Map each source file

Also applies to: 296-296, 416-416


1-1: Make the file executable.

This script has a CLI entry point and shebang but isn't executable. Make it executable with chmod +x.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between e6a2574 and a3b8aed.

📒 Files selected for processing (22)
  • .claude-plugin/marketplace.json (1 hunks)
  • PLUGINS.md (2 hunks)
  • docs/data.json (1 hunks)
  • plugins/test-coverage/.claude-plugin/plugin.json (1 hunks)
  • plugins/test-coverage/README.md (1 hunks)
  • plugins/test-coverage/URL_SUPPORT.md (1 hunks)
  • plugins/test-coverage/commands/analyze.md (1 hunks)
  • plugins/test-coverage/commands/gaps.md (1 hunks)
  • plugins/test-coverage/skills/__init__.py (1 hunks)
  • plugins/test-coverage/skills/analyze/README.md (1 hunks)
  • plugins/test-coverage/skills/analyze/SKILL.md (1 hunks)
  • plugins/test-coverage/skills/analyze/__init__.py (1 hunks)
  • plugins/test-coverage/skills/analyze/test_gap_reports.py (1 hunks)
  • plugins/test-coverage/skills/analyze/test_structure_analyzer.py (1 hunks)
  • plugins/test-coverage/skills/analyze/test_structure_reports.py (1 hunks)
  • plugins/test-coverage/skills/gaps/README.md (1 hunks)
  • plugins/test-coverage/skills/gaps/SKILL.md (1 hunks)
  • plugins/test-coverage/skills/gaps/__init__.py (1 hunks)
  • plugins/test-coverage/skills/gaps/gap_analyzer.py (1 hunks)
  • plugins/test-coverage/skills/gaps/reports.py (1 hunks)
  • plugins/test-coverage/utils/__init__.py (1 hunks)
  • plugins/test-coverage/utils/path_handler.py (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • plugins/test-coverage/.claude-plugin/plugin.json
🚧 Files skipped from review as they are similar to previous changes (5)
  • plugins/test-coverage/skills/gaps/init.py
  • docs/data.json
  • .claude-plugin/marketplace.json
  • plugins/test-coverage/skills/analyze/init.py
  • PLUGINS.md
🧰 Additional context used
🪛 LanguageTool
plugins/test-coverage/skills/gaps/README.md

[uncategorized] ~39-~39: A comma may be missing after the conjunctive/linking adverb ‘Currently’.
Context: ...output

] ``` ## Language Support Currently supports Go test files only: - Ginkgo B...

(SENT_START_CONJUNCTIVE_LINKING_ADVERB_COMMA)

plugins/test-coverage/README.md

[typographical] ~161-~161: Two consecutive commas
Context: ..., [Longduration], [ConnectedOnly], [NonPreRelease]-g.Describe(, g.Context(, g.It(` Note: To inc...

(DOUBLE_PUNCTUATION)


[uncategorized] ~170-~170: A comma may be missing after the conjunctive/linking adverb ‘Currently’.
Context: ...` flag. --- ## Supported Languages Currently supports Go projects only. | Languag...

(SENT_START_CONJUNCTIVE_LINKING_ADVERB_COMMA)


[uncategorized] ~280-~280: Use a comma before ‘but’ if it connects two independent clauses (unless they are closely connected and short).
Context: ...ude "*.js" ``` ### Issue: No gaps found but code is clearly untested Solution:...

(COMMA_COMPOUND_SENTENCE_2)


[uncategorized] ~333-~333: Loose punctuation mark.
Context: ...ation. ## Related Plugins - jira: Create bug reports with coverage gap co...

(UNLIKELY_OPENING_PUNCTUATION)

plugins/test-coverage/URL_SUPPORT.md

[uncategorized] ~196-~196: Possible missing preposition found.
Context: ...eports HTTP error codes and reasons - Network errors: Reports connection issues wit...

(AI_HYDRA_LEO_MISSING_OF)


[duplication] ~231-~231: Possible typo: you repeated a word.
Context: ...# See Also - /test-coverage:analyze command - /test-coverage:gaps command - [Path Handler Util...

(ENGLISH_WORD_REPEAT_RULE)

plugins/test-coverage/commands/analyze.md

[uncategorized] ~30-~30: Loose punctuation mark.
Context: ...g. ## Arguments - <source-directory>: Path or URL to source code directory/fi...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~38-~38: Loose punctuation mark.
Context: ...st-coverage/cache/ ---output `: Output directory for generated reports ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~41-~41: Loose punctuation mark.
Context: ...and text summary - --priority <level>: Filter results by priority (optional) ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~45-~45: Loose punctuation mark.
Context: ...Default: all - --include-test-utils: Include test utility/helper files in an...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~50-~50: Loose punctuation mark.
Context: ...structure code - --include-unit-tests: Include unit tests in analysis (optiona...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~58-~58: Loose punctuation mark.
Context: ...or Python) - --test-pattern <pattern>: Custom test file pattern (optional) -...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~61-~61: Loose punctuation mark.
Context: .../Test*.java" ---test-structure-only`: Analyze only test file structure, skip ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~265-~265: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ... Example 2: Analyze test structure with high priority filter ``` /test-coverage:analyze ./pk...

(EN_COMPOUND_ADJECTIVE_INTERNAL)


[duplication] ~341-~341: Possible typo: you repeated a word.
Context: ... - URLs are automatically detected and downloaded - Downloaded files are cached in `.work/test-coverag...

(ENGLISH_WORD_REPEAT_RULE)

plugins/test-coverage/commands/gaps.md

[uncategorized] ~48-~48: Loose punctuation mark.
Context: ...tional Arguments - --priority <level>: Filter gaps by priority level (optional...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~54-~54: Loose punctuation mark.
Context: ...dge case scenarios) - --output <path>: Output directory for gap analysis repor...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~225-~225: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...I drivers. ### Example 3: Analyze with high priority filter ```bash /test-coverage:gaps ./t...

(EN_COMPOUND_ADJECTIVE_INTERNAL)

plugins/test-coverage/skills/analyze/README.md

[uncategorized] ~79-~79: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...files without tests ### Example 2: High Priority Gaps Only bash # Analyze only high-...

(EN_COMPOUND_ADJECTIVE_INTERNAL)

plugins/test-coverage/skills/gaps/SKILL.md

[duplication] ~172-~172: Possible typo: you repeated a word.
Context: ...age, service type/volume mode, scenario coverage - Coverage matrices: Visual tables showing what ...

(ENGLISH_WORD_REPEAT_RULE)


[uncategorized] ~175-~175: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ... - Priority indicators: High/medium/low priority badges for each gap - **Test cases list...

(EN_COMPOUND_ADJECTIVE_INTERNAL)

🪛 markdownlint-cli2 (0.18.1)
plugins/test-coverage/README.md

323-323: Bare URL used

(MD034, no-bare-urls)


324-324: Bare URL used

(MD034, no-bare-urls)

plugins/test-coverage/URL_SUPPORT.md

17-17: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


22-22: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


27-27: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


34-34: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


39-39: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


46-46: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

plugins/test-coverage/skills/analyze/README.md

48-48: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


95-95: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

plugins/test-coverage/skills/analyze/SKILL.md

292-292: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

plugins/test-coverage/skills/gaps/SKILL.md

10-10: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


46-46: Spaces inside emphasis markers

(MD037, no-space-in-emphasis)


223-223: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


259-259: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


267-267: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


275-275: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


283-283: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


297-297: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


305-305: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


313-313: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


323-323: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🪛 Ruff (0.14.4)
plugins/test-coverage/skills/gaps/gap_analyzer.py

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

(EXE001)


609-609: f-string without any placeholders

Remove extraneous f prefix

(F541)

plugins/test-coverage/skills/gaps/reports.py

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

(EXE001)

plugins/test-coverage/skills/analyze/test_structure_reports.py

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

(EXE001)


466-466: String contains ambiguous (INFORMATION SOURCE). Did you mean i (LATIN SMALL LETTER I)?

(RUF001)

plugins/test-coverage/utils/path_handler.py

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

(EXE001)


116-116: Probable use of insecure hash functions in hashlib: md5

(S324)


161-161: Audit URL open for permitted schemes. Allowing use of file: or custom schemes is often unexpected.

(S310)


163-163: Audit URL open for permitted schemes. Allowing use of file: or custom schemes is often unexpected.

(S310)


186-186: Do not catch blind exception: Exception

(BLE001)

plugins/test-coverage/skills/analyze/test_structure_analyzer.py

78-78: Unused function argument: language

(ARG001)


84-84: Unused function argument: language

(ARG001)


84-84: PEP 484 prohibits implicit Optional

Convert to T | None

(RUF013)


126-126: Unused function argument: language

(ARG001)


202-202: Do not catch blind exception: Exception

(BLE001)


271-271: Local variable base_indent is assigned to but never used

Remove assignment to unused variable base_indent

(F841)


296-296: Local variable context_name is assigned to but never used

Remove assignment to unused variable context_name

(F841)


321-321: Unused function argument: language

(ARG001)


373-373: Unused function argument: language

(ARG001)


396-396: Unused function argument: language

(ARG001)


416-416: Local variable source_by_path is assigned to but never used

Remove assignment to unused variable source_by_path

(F841)


453-453: Unused function argument: file_path

(ARG001)


679-679: f-string without any placeholders

Remove extraneous f prefix

(F541)


703-703: Do not catch blind exception: Exception

(BLE001)


757-757: Do not catch blind exception: Exception

(BLE001)


768-768: Do not catch blind exception: Exception

(BLE001)


847-847: Do not catch blind exception: Exception

(BLE001)


861-861: Consider moving this statement to an else block

(TRY300)


863-863: Do not catch blind exception: Exception

(BLE001)

plugins/test-coverage/skills/analyze/test_gap_reports.py

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

(EXE001)


796-796: Local variable source_dir is assigned to but never used

Remove assignment to unused variable source_dir

(F841)


798-798: Local variable analyzed_file is assigned to but never used

Remove assignment to unused variable analyzed_file

(F841)


906-906: String contains ambiguous (INFORMATION SOURCE). Did you mean i (LATIN SMALL LETTER I)?

(RUF001)


1109-1109: Unused function argument: summary

(ARG001)

🔇 Additional comments (13)
plugins/test-coverage/skills/__init__.py (1)

1-1: LGTM!

Clean package initializer with appropriate docstring.

plugins/test-coverage/commands/gaps.md (1)

1-296: LGTM!

Comprehensive command documentation with clear structure, examples, and implementation details. All previously identified issues have been addressed.

plugins/test-coverage/utils/path_handler.py (1)

1-328: LGTM! Security concerns addressed.

The implementation correctly restricts URL schemes to HTTP(S) only and validates before calling urlopen. MD5 usage for cache keys is appropriate (non-cryptographic). All previously identified security issues have been resolved.

plugins/test-coverage/utils/__init__.py (1)

1-9: LGTM!

Clean package initialization with well-defined public API exports.

plugins/test-coverage/skills/analyze/README.md (1)

1-128: Documentation is clear and consistent.

The README accurately documents Go-only support with appropriate examples and usage instructions. All examples use Go file paths and patterns.

plugins/test-coverage/README.md (1)

1-342: Comprehensive plugin documentation.

The README provides thorough coverage of the test-coverage plugin's capabilities, installation, usage, and troubleshooting. The structure is clear and examples are practical.

plugins/test-coverage/skills/gaps/reports.py (3)

17-291: LGTM!

The CSS template is well-structured and provides comprehensive styling for all report elements.


619-629: LGTM!

JSON report generation is straightforward and correctly includes all analysis data, scores, and timestamp.


695-754: LGTM!

The text report now correctly includes all gap categories (platforms, protocols, service_types, storage_classes, volume_modes, scenarios), addressing the past review concern about missing storage/service gaps.

plugins/test-coverage/skills/analyze/test_structure_reports.py (3)

354-479: LGTM!

The test-only HTML generation correctly handles single test file analysis and provides clear messaging about the analysis mode limitations.


482-563: LGTM!

Full structure HTML generation is well-implemented, correctly integrating gap analysis sections and recommendations.


698-842: LGTM!

The comprehensive HTML report effectively combines structure and gap analysis with proper organization and styling.

plugins/test-coverage/skills/analyze/test_structure_analyzer.py (1)

720-738: The exclude filtering is already implemented and working correctly.

Your review comment is based on an incorrect premise. There is no --exclude_patterns CLI argument, and that's not needed—exclude filtering is already applied in the discover_files() function. At line 32, exclude_dirs is defined in the GO_CONFIG dict with default values ['vendor', 'testdata', '.git']. During file discovery, at line 186, the code filters directories during the os.walk traversal: dirs[:] = [d for d in dirs if d not in exclude_dirs]. This effectively excludes vendor and generated paths from both test and source file discovery. The filtering is working as intended.

Likely an incorrect or invalid review comment.

Copy link
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: 0

♻️ Duplicate comments (8)
plugins/test-coverage/README.md (1)

312-315: Replace Java test patterns with Go examples.

Line 314 shows Java test patterns (**/*Spec.java, **/IT*.java), but the plugin documentation consistently states "Currently supports Go projects only" (line 170). This contradicts the stated scope and may confuse users.

Apply this diff to use Go-specific patterns:

-/test-coverage:analyze ./src/ --test-pattern "**/*Spec.java,**/IT*.java"
+/test-coverage:analyze ./pkg/ --test-pattern "**/*e2e*_test.go,**/*integration*_test.go"
plugins/test-coverage/skills/analyze/test_structure_analyzer.py (2)

841-845: Fix the HTML report import path.

We still import generate_test_structure_html from test_gap_reports, which raises ImportError because the function lives in test_structure_reports. That means HTML output is silently skipped every run. Please import from the correct module (with the relative/absolute fallback for script execution).

Apply this diff:

-        from test_gap_reports import generate_test_structure_html
+        try:
+            from .test_structure_reports import generate_test_structure_html
+        except ImportError:
+            from test_structure_reports import generate_test_structure_html

121-124: Don't default every _test.go to e2e coverage.

Right now is_e2e_test_file returns True when none of the e2e heuristics hit, so any regular Go unit test ends up being treated as e2e. In directory mode with the default --include-unit-tests flag unset, you still slurp in the entire unit-test suite, making the default filter a no-op and skewing the structure/gap analysis. Please flip the fallback so only files that positively match the naming/dir/content heuristics are tagged as e2e (and therefore included when e2e_only is true).

Apply this diff:

-    # Default: if it's a test file but not in unit dir and not explicitly e2e,
-    # assume it could be e2e (inclusive approach)
-    return True
+    # Default: require positive evidence to classify as e2e
+    return False
plugins/test-coverage/URL_SUPPORT.md (1)

123-127: Fix the documented URL support to match PathHandler.

PathHandler.is_url() only accepts HTTP(S), so advertising FTP/file support is inaccurate (and could encourage unsafe assumptions). Please update the bullet to reflect HTTP(S)-only detection.

-- **URL detection**: Identifies HTTP(S), FTP, and file:// URLs
+- **URL detection**: Identifies HTTP(S) URLs (FTP and file:// are intentionally excluded for security)
plugins/test-coverage/skills/analyze/test_gap_reports.py (2)

705-708: Drop the unused locals.

source_dir and analyzed_file aren’t referenced, triggering Ruff F841. Please remove them.

-    source_dir = data.get('source_dir', '')
     test_file_details = data.get('test_file_details', {})
-    analyzed_file = data.get('analyzed_file', '')

1019-1041: Remove the dead summary parameter.

_generate_recommendations_section never touches summary, so Ruff flags ARG001. Simplify the signature and call site.

-def _generate_recommendations_section(gaps: Dict, summary: Dict) -> str:
+def _generate_recommendations_section(gaps: Dict) -> str:
@@
-            {_generate_recommendations_section(gaps, summary)}
+            {_generate_recommendations_section(gaps)}
docs/data.json (1)

615-623: Fix /test-coverage:gaps synopsis & args.

gap_analyzer.py exposes only <test-file-or-url> and --output. The current metadata (“bash”, --priority) is wrong and will frustrate users.

-          "synopsis": "bash",
-          "argument_hint": "<test-file-or-url> [--priority <level>] [--output <path>]"
+          "synopsis": "/test-coverage:gaps <test-file-or-url> [--output <path>]",
+          "argument_hint": "<test-file-or-url> [--output <path>]"
plugins/test-coverage/skills/gaps/gap_analyzer.py (1)

587-593: Summaries must include component-specific gaps.

Right now all_gaps only collects platforms/scenarios, so networking protocols/service-types and storage class/volume gaps never appear in the “High Priority Gaps” list. That hides the very findings the analyzer produces.

-    all_gaps = []
-    for key in ('platforms', 'scenarios'):
-        all_gaps.extend(analysis['gaps'].get(key, []))
+    if component == 'networking':
+        summary_keys = ('platforms', 'protocols', 'service_types', 'scenarios')
+    elif component == 'storage':
+        summary_keys = ('platforms', 'storage_classes', 'volume_modes', 'scenarios')
+    else:
+        summary_keys = ('platforms', 'scenarios')
+
+    all_gaps = []
+    for key in summary_keys:
+        all_gaps.extend(analysis['gaps'].get(key, []))
🧹 Nitpick comments (2)
plugins/test-coverage/utils/path_handler.py (1)

186-188: Consider narrowing the exception handler.

Catching Exception on line 186 may mask unexpected errors (e.g., KeyboardInterrupt or system issues). Consider catching specific exceptions or at least logging the exception type for debugging.

Apply this diff to narrow the exception scope:

-        except Exception as e:
-            print(f"Error downloading {url}: {e}", file=sys.stderr)
+        except (OSError, IOError, RuntimeError) as e:
+            print(f"Error downloading {url}: {e}", file=sys.stderr)
+        except Exception as e:
+            print(f"Unexpected error downloading {url}: {type(e).__name__}: {e}", file=sys.stderr)
             return False

Alternatively, if broad exception handling is intentional for robustness, add a comment explaining the design choice.

plugins/test-coverage/skills/analyze/SKILL.md (1)

74-102: Add language hints to fenced code blocks.

Explicit languages (e.g., go, json, ```bash) silence MD040 and keep rendered snippets highlighted/readable. Could you annotate the Go/JSON/Bash blocks accordingly?

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between a3b8aed and 7282ac9.

📒 Files selected for processing (24)
  • .claude-plugin/marketplace.json (1 hunks)
  • PLUGINS.md (2 hunks)
  • docs/data.json (1 hunks)
  • plugins/test-coverage/.claude-plugin/plugin.json (1 hunks)
  • plugins/test-coverage/README.md (1 hunks)
  • plugins/test-coverage/URL_SUPPORT.md (1 hunks)
  • plugins/test-coverage/commands/analyze.md (1 hunks)
  • plugins/test-coverage/commands/gaps.md (1 hunks)
  • plugins/test-coverage/skills/__init__.py (1 hunks)
  • plugins/test-coverage/skills/analyze/README.md (1 hunks)
  • plugins/test-coverage/skills/analyze/SKILL.md (1 hunks)
  • plugins/test-coverage/skills/analyze/__init__.py (1 hunks)
  • plugins/test-coverage/skills/analyze/test_gap_reports.py (1 hunks)
  • plugins/test-coverage/skills/analyze/test_structure_analyzer.py (1 hunks)
  • plugins/test-coverage/skills/analyze/test_structure_reports.py (1 hunks)
  • plugins/test-coverage/skills/common/__init__.py (1 hunks)
  • plugins/test-coverage/skills/common/report_styles.py (1 hunks)
  • plugins/test-coverage/skills/gaps/README.md (1 hunks)
  • plugins/test-coverage/skills/gaps/SKILL.md (1 hunks)
  • plugins/test-coverage/skills/gaps/__init__.py (1 hunks)
  • plugins/test-coverage/skills/gaps/gap_analyzer.py (1 hunks)
  • plugins/test-coverage/skills/gaps/reports.py (1 hunks)
  • plugins/test-coverage/utils/__init__.py (1 hunks)
  • plugins/test-coverage/utils/path_handler.py (1 hunks)
✅ Files skipped from review due to trivial changes (2)
  • plugins/test-coverage/skills/analyze/init.py
  • plugins/test-coverage/skills/common/init.py
🚧 Files skipped from review as they are similar to previous changes (5)
  • plugins/test-coverage/.claude-plugin/plugin.json
  • plugins/test-coverage/skills/gaps/init.py
  • plugins/test-coverage/skills/init.py
  • PLUGINS.md
  • plugins/test-coverage/utils/init.py
🧰 Additional context used
🪛 LanguageTool
plugins/test-coverage/commands/gaps.md

[uncategorized] ~48-~48: Loose punctuation mark.
Context: ...tional Arguments - --priority <level>: Filter gaps by priority level (optional...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~54-~54: Loose punctuation mark.
Context: ...dge case scenarios) - --output <path>: Output directory for gap analysis repor...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~225-~225: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...I drivers. ### Example 3: Analyze with high priority filter ```bash /test-coverage:gaps ./t...

(EN_COMPOUND_ADJECTIVE_INTERNAL)

plugins/test-coverage/commands/analyze.md

[uncategorized] ~30-~30: Loose punctuation mark.
Context: ...g. ## Arguments - <source-directory>: Path or URL to source code directory/fi...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~38-~38: Loose punctuation mark.
Context: ...st-coverage/cache/ ---output `: Output directory for generated reports ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~41-~41: Loose punctuation mark.
Context: ...and text summary - --priority <level>: Filter results by priority (optional) ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~45-~45: Loose punctuation mark.
Context: ...Default: all - --include-test-utils: Include test utility/helper files in an...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~50-~50: Loose punctuation mark.
Context: ...structure code - --include-unit-tests: Include unit tests in analysis (optiona...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~58-~58: Loose punctuation mark.
Context: ...or Python) - --test-pattern <pattern>: Custom test file pattern (optional) -...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~61-~61: Loose punctuation mark.
Context: .../Test*.java" ---test-structure-only`: Analyze only test file structure, skip ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~265-~265: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ... Example 2: Analyze test structure with high priority filter ``` /test-coverage:analyze ./pk...

(EN_COMPOUND_ADJECTIVE_INTERNAL)

plugins/test-coverage/skills/analyze/README.md

[uncategorized] ~79-~79: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...files without tests ### Example 2: High Priority Gaps Only bash # Analyze only high-...

(EN_COMPOUND_ADJECTIVE_INTERNAL)

plugins/test-coverage/README.md

[uncategorized] ~170-~170: A comma may be missing after the conjunctive/linking adverb ‘Currently’.
Context: ...` flag. --- ## Supported Languages Currently supports Go projects only. | Languag...

(SENT_START_CONJUNCTIVE_LINKING_ADVERB_COMMA)


[uncategorized] ~280-~280: Use a comma before ‘but’ if it connects two independent clauses (unless they are closely connected and short).
Context: ...ude "*.js" ``` ### Issue: No gaps found but code is clearly untested Solution:...

(COMMA_COMPOUND_SENTENCE_2)


[uncategorized] ~333-~333: Loose punctuation mark.
Context: ...ation. ## Related Plugins - jira: Create bug reports with coverage gap co...

(UNLIKELY_OPENING_PUNCTUATION)

plugins/test-coverage/URL_SUPPORT.md

[uncategorized] ~196-~196: Possible missing preposition found.
Context: ...eports HTTP error codes and reasons - Network errors: Reports connection issues wit...

(AI_HYDRA_LEO_MISSING_OF)


[duplication] ~231-~231: Possible typo: you repeated a word.
Context: ...# See Also - /test-coverage:analyze command - /test-coverage:gaps command - [Path Handler Util...

(ENGLISH_WORD_REPEAT_RULE)

plugins/test-coverage/skills/gaps/README.md

[uncategorized] ~41-~41: A comma may be missing after the conjunctive/linking adverb ‘Currently’.
Context: ...ntly implemented. ## Language Support Currently supports Go test files only: - Ginkgo B...

(SENT_START_CONJUNCTIVE_LINKING_ADVERB_COMMA)

plugins/test-coverage/skills/gaps/SKILL.md

[duplication] ~172-~172: Possible typo: you repeated a word.
Context: ...age, service type/volume mode, scenario coverage - Coverage matrices: Visual tables showing what ...

(ENGLISH_WORD_REPEAT_RULE)


[uncategorized] ~175-~175: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ... - Priority indicators: High/medium/low priority badges for each gap - **Test cases list...

(EN_COMPOUND_ADJECTIVE_INTERNAL)

🪛 markdownlint-cli2 (0.18.1)
plugins/test-coverage/commands/analyze.md

213-213: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

plugins/test-coverage/skills/analyze/SKILL.md

48-48: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


95-95: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

plugins/test-coverage/skills/gaps/SKILL.md

213-213: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🪛 Ruff (0.14.4)
plugins/test-coverage/skills/gaps/gap_analyzer.py

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

(EXE001)


609-609: f-string without any placeholders

Remove extraneous f prefix

(F541)

plugins/test-coverage/skills/gaps/reports.py

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

(EXE001)

plugins/test-coverage/skills/common/report_styles.py

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

(EXE001)

plugins/test-coverage/skills/analyze/test_structure_reports.py

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

(EXE001)


150-150: String contains ambiguous (INFORMATION SOURCE). Did you mean i (LATIN SMALL LETTER I)?

(RUF001)

plugins/test-coverage/utils/path_handler.py

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

(EXE001)


116-116: Probable use of insecure hash functions in hashlib: md5

(S324)


161-161: Audit URL open for permitted schemes. Allowing use of file: or custom schemes is often unexpected.

(S310)


163-163: Audit URL open for permitted schemes. Allowing use of file: or custom schemes is often unexpected.

(S310)


186-186: Do not catch blind exception: Exception

(BLE001)

plugins/test-coverage/skills/analyze/test_gap_reports.py

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

(EXE001)


706-706: Local variable source_dir is assigned to but never used

Remove assignment to unused variable source_dir

(F841)


708-708: Local variable analyzed_file is assigned to but never used

Remove assignment to unused variable analyzed_file

(F841)


816-816: String contains ambiguous (INFORMATION SOURCE). Did you mean i (LATIN SMALL LETTER I)?

(RUF001)


1019-1019: Unused function argument: summary

(ARG001)

plugins/test-coverage/skills/analyze/test_structure_analyzer.py

78-78: Unused function argument: language

(ARG001)


84-84: Unused function argument: language

(ARG001)


84-84: PEP 484 prohibits implicit Optional

Convert to T | None

(RUF013)


126-126: Unused function argument: language

(ARG001)


202-202: Do not catch blind exception: Exception

(BLE001)


271-271: Local variable base_indent is assigned to but never used

Remove assignment to unused variable base_indent

(F841)


296-296: Local variable context_name is assigned to but never used

Remove assignment to unused variable context_name

(F841)


321-321: Unused function argument: language

(ARG001)


373-373: Unused function argument: language

(ARG001)


396-396: Unused function argument: language

(ARG001)


416-416: Local variable source_by_path is assigned to but never used

Remove assignment to unused variable source_by_path

(F841)


453-453: Unused function argument: file_path

(ARG001)


679-679: f-string without any placeholders

Remove extraneous f prefix

(F541)


703-703: Do not catch blind exception: Exception

(BLE001)


757-757: Do not catch blind exception: Exception

(BLE001)


768-768: Do not catch blind exception: Exception

(BLE001)


847-847: Do not catch blind exception: Exception

(BLE001)


861-861: Consider moving this statement to an else block

(TRY300)


863-863: Do not catch blind exception: Exception

(BLE001)

@anuragthehatter
Copy link
Author

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 10, 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
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 (5)
plugins/test-coverage/URL_SUPPORT.md (1)

121-128: Correct URL detection claim to match implementation.

Line 123 states "Identifies HTTP(S), FTP, and file:// URLs", but according to the path_handler.py implementation (lines 59-62), only HTTP(S) URLs are supported for security reasons. The FTP and file:// schemes were removed in commit bb87992.

Apply this fix:

-- **URL detection**: Identifies HTTP(S), FTP, and file:// URLs
+- **URL detection**: Identifies HTTP(S) URLs only (file:// and FTP excluded for security)
plugins/test-coverage/README.md (1)

309-315: Remove Java pattern example - conflicts with Go-only scope.

Line 314 shows a Java test pattern example (**/*Spec.java,**/IT*.java), but the plugin documentation states it "Currently supports Go projects only" (line 170). This contradicts the documented scope and could mislead users.

Either document multi-language support or replace with a Go-specific example:

-/test-coverage:analyze ./src/ --test-pattern "**/*Spec.java,**/IT*.java"
+/test-coverage:analyze ./pkg/ --test-pattern "**/*_test.go,**/*e2e*_test.go"
plugins/test-coverage/skills/gaps/gap_analyzer.py (1)

772-781: Expose every gap type in the console summary.
The summary still only aggregates platforms and scenarios, so protocol/service/storage/IP-stack/topology gaps never show up at the console—exactly the issue called out earlier. Please aggregate every category returned by analyze_ginkgo_tests() so users see all high-priority findings.

Apply this diff:

-    all_gaps = []
-    for key in ('platforms', 'scenarios'):
-        all_gaps.extend(analysis['gaps'].get(key, []))
+    all_gaps = []
+    for key in (
+        'platforms',
+        'protocols',
+        'service_types',
+        'storage_classes',
+        'volume_modes',
+        'ip_stacks',
+        'topologies',
+        'scenarios',
+    ):
+        all_gaps.extend(analysis['gaps'].get(key, []))
docs/data.json (1)

608-623: Fix the /test-coverage:gaps command metadata.
The new entry points synopsis to "bash" and lists --priority, but the actual CLI (see gap_analyzer.py) only accepts --output. Anyone using these docs will get runtime errors.

Apply this diff:

-        {
-          "name": "gaps",
-          "description": "Identify E2E test scenario gaps in OpenShift/Kubernetes tests (component-agnostic)",
-          "synopsis": "bash",
-          "argument_hint": "<test-file-or-url> [--priority <level>] [--output <path>]"
-        }
+        {
+          "name": "gaps",
+          "description": "Identify E2E test scenario gaps in OpenShift/Kubernetes tests (component-agnostic)",
+          "synopsis": "/test-coverage:gaps <test-file-or-url> [--output <path>]",
+          "argument_hint": "<test-file-or-url> [--output <path>]"
+        }
plugins/test-coverage/skills/analyze/test_structure_analyzer.py (1)

845-854: Import HTML report generator from the new module

We now have test_structure_reports.py dedicated to the HTML output, but main() still imports generate_test_structure_html from test_gap_reports. As soon as we remove the duplicated definitions discussed above, this import will break and the CLI will stop emitting HTML. Please switch the import (with the same relative/absolute fallback) to point at test_structure_reports. Concretely:

-        try:
-            from test_gap_reports import generate_test_structure_html
+        try:
+            from .test_structure_reports import generate_test_structure_html
+        except ImportError:
+            from test_structure_reports import generate_test_structure_html

Keep the existing error handling for the actual rendering call. This ensures the analyzer exercises the new shared implementation and lets us delete the stale copy in test_gap_reports.py.

🧹 Nitpick comments (1)
plugins/test-coverage/commands/analyze.md (1)

10-12: Optional: Add language tag to code fence.

The synopsis code block (line 10) lacks a language specifier, which triggers markdownlint MD040. While not critical, adding bash would improve syntax highlighting:

-```
+```bash
 /test-coverage:analyze <path-or-url> [--output <path>] [--priority <level>] [--test-structure-only]
-```
+```

This same pattern applies to other code blocks throughout the file (lines 223, 259, 267, 275, 283, 297, 305, 313, 323).

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 7282ac9 and 9044dda.

📒 Files selected for processing (26)
  • .claude-plugin/marketplace.json (1 hunks)
  • PLUGINS.md (2 hunks)
  • docs/data.json (1 hunks)
  • plugins/test-coverage/.claude-plugin/plugin.json (1 hunks)
  • plugins/test-coverage/README.md (1 hunks)
  • plugins/test-coverage/URL_SUPPORT.md (1 hunks)
  • plugins/test-coverage/__init__.py (1 hunks)
  • plugins/test-coverage/commands/analyze.md (1 hunks)
  • plugins/test-coverage/commands/gaps.md (1 hunks)
  • plugins/test-coverage/skills/__init__.py (1 hunks)
  • plugins/test-coverage/skills/analyze/README.md (1 hunks)
  • plugins/test-coverage/skills/analyze/SKILL.md (1 hunks)
  • plugins/test-coverage/skills/analyze/__init__.py (1 hunks)
  • plugins/test-coverage/skills/analyze/test_gap_reports.py (1 hunks)
  • plugins/test-coverage/skills/analyze/test_structure_analyzer.py (1 hunks)
  • plugins/test-coverage/skills/analyze/test_structure_reports.py (1 hunks)
  • plugins/test-coverage/skills/common/__init__.py (1 hunks)
  • plugins/test-coverage/skills/common/report_styles.py (1 hunks)
  • plugins/test-coverage/skills/gaps/README.md (1 hunks)
  • plugins/test-coverage/skills/gaps/SKILL.md (1 hunks)
  • plugins/test-coverage/skills/gaps/__init__.py (1 hunks)
  • plugins/test-coverage/skills/gaps/gap_analyzer.py (1 hunks)
  • plugins/test-coverage/skills/gaps/report_template.py (1 hunks)
  • plugins/test-coverage/skills/gaps/reports.py (1 hunks)
  • plugins/test-coverage/utils/__init__.py (1 hunks)
  • plugins/test-coverage/utils/path_handler.py (1 hunks)
✅ Files skipped from review due to trivial changes (2)
  • plugins/test-coverage/init.py
  • plugins/test-coverage/skills/analyze/init.py
🚧 Files skipped from review as they are similar to previous changes (4)
  • plugins/test-coverage/skills/init.py
  • plugins/test-coverage/.claude-plugin/plugin.json
  • plugins/test-coverage/skills/gaps/init.py
  • plugins/test-coverage/utils/init.py
🧰 Additional context used
🪛 LanguageTool
plugins/test-coverage/skills/analyze/README.md

[uncategorized] ~79-~79: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...files without tests ### Example 2: High Priority Gaps Only bash # Analyze only high-...

(EN_COMPOUND_ADJECTIVE_INTERNAL)

plugins/test-coverage/README.md

[uncategorized] ~170-~170: A comma may be missing after the conjunctive/linking adverb ‘Currently’.
Context: ...` flag. --- ## Supported Languages Currently supports Go projects only. | Languag...

(SENT_START_CONJUNCTIVE_LINKING_ADVERB_COMMA)


[uncategorized] ~280-~280: Use a comma before ‘but’ if it connects two independent clauses (unless they are closely connected and short).
Context: ...ude "*.js" ``` ### Issue: No gaps found but code is clearly untested Solution:...

(COMMA_COMPOUND_SENTENCE_2)


[uncategorized] ~333-~333: Loose punctuation mark.
Context: ...ation. ## Related Plugins - jira: Create bug reports with coverage gap co...

(UNLIKELY_OPENING_PUNCTUATION)

plugins/test-coverage/URL_SUPPORT.md

[uncategorized] ~196-~196: Possible missing preposition found.
Context: ...eports HTTP error codes and reasons - Network errors: Reports connection issues wit...

(AI_HYDRA_LEO_MISSING_OF)


[duplication] ~231-~231: Possible typo: you repeated a word.
Context: ...# See Also - /test-coverage:analyze command - /test-coverage:gaps command - [Path Handler Util...

(ENGLISH_WORD_REPEAT_RULE)

plugins/test-coverage/commands/analyze.md

[uncategorized] ~30-~30: Loose punctuation mark.
Context: ...g. ## Arguments - <source-directory>: Path or URL to source code directory/fi...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~38-~38: Loose punctuation mark.
Context: ...st-coverage/cache/ ---output `: Output directory for generated reports ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~41-~41: Loose punctuation mark.
Context: ...and text summary - --priority <level>: Filter results by priority (optional) ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~45-~45: Loose punctuation mark.
Context: ...Default: all - --include-test-utils: Include test utility/helper files in an...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~50-~50: Loose punctuation mark.
Context: ...structure code - --include-unit-tests: Include unit tests in analysis (optiona...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~58-~58: Loose punctuation mark.
Context: ...or Python) - --test-pattern <pattern>: Custom test file pattern (optional) -...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~61-~61: Loose punctuation mark.
Context: .../Test*.java" ---test-structure-only`: Analyze only test file structure, skip ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~265-~265: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ... Example 2: Analyze test structure with high priority filter ``` /test-coverage:analyze ./pk...

(EN_COMPOUND_ADJECTIVE_INTERNAL)

plugins/test-coverage/commands/gaps.md

[uncategorized] ~48-~48: Loose punctuation mark.
Context: ...tional Arguments - --priority <level>: Filter gaps by priority level (optional...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~54-~54: Loose punctuation mark.
Context: ...dge case scenarios) - --output <path>: Output directory for gap analysis repor...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~225-~225: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...I drivers. ### Example 3: Analyze with high priority filter ```bash /test-coverage:gaps ./t...

(EN_COMPOUND_ADJECTIVE_INTERNAL)

plugins/test-coverage/skills/gaps/README.md

[uncategorized] ~41-~41: A comma may be missing after the conjunctive/linking adverb ‘Currently’.
Context: ...ntly implemented. ## Language Support Currently supports Go test files only: - Ginkgo B...

(SENT_START_CONJUNCTIVE_LINKING_ADVERB_COMMA)

plugins/test-coverage/skills/gaps/SKILL.md

[duplication] ~172-~172: Possible typo: you repeated a word.
Context: ...age, service type/volume mode, scenario coverage - Coverage matrices: Visual tables showing what ...

(ENGLISH_WORD_REPEAT_RULE)


[uncategorized] ~175-~175: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ... - Priority indicators: High/medium/low priority badges for each gap - **Test cases list...

(EN_COMPOUND_ADJECTIVE_INTERNAL)

🪛 markdownlint-cli2 (0.18.1)
plugins/test-coverage/skills/analyze/README.md

48-48: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


95-95: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

plugins/test-coverage/skills/analyze/SKILL.md

292-292: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

plugins/test-coverage/README.md

22-22: Heading levels should only increment by one level at a time
Expected: h2; Actual: h3

(MD001, heading-increment)

plugins/test-coverage/URL_SUPPORT.md

22-22: Heading levels should only increment by one level at a time
Expected: h2; Actual: h3

(MD001, heading-increment)

plugins/test-coverage/commands/analyze.md

10-10: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


46-46: Spaces inside emphasis markers

(MD037, no-space-in-emphasis)


223-223: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


259-259: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


267-267: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


275-275: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


283-283: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


297-297: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


305-305: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


313-313: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


323-323: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

plugins/test-coverage/skills/gaps/SKILL.md

213-213: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🪛 Ruff (0.14.4)
plugins/test-coverage/skills/gaps/reports.py

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

(EXE001)

plugins/test-coverage/skills/common/report_styles.py

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

(EXE001)

plugins/test-coverage/skills/gaps/gap_analyzer.py

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

(EXE001)


624-624: Local variable gaps is assigned to but never used

Remove assignment to unused variable gaps

(F841)


794-794: f-string without any placeholders

Remove extraneous f prefix

(F541)

plugins/test-coverage/skills/analyze/test_gap_reports.py

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

(EXE001)


709-709: Local variable source_dir is assigned to but never used

Remove assignment to unused variable source_dir

(F841)


711-711: Local variable analyzed_file is assigned to but never used

Remove assignment to unused variable analyzed_file

(F841)


819-819: String contains ambiguous (INFORMATION SOURCE). Did you mean i (LATIN SMALL LETTER I)?

(RUF001)


1022-1022: Unused function argument: summary

(ARG001)

plugins/test-coverage/skills/gaps/report_template.py

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

(EXE001)


46-46: Multiple statements on one line (colon)

(E701)


47-47: Multiple statements on one line (colon)

(E701)


48-48: Multiple statements on one line (colon)

(E701)


49-49: Multiple statements on one line (colon)

(E701)


258-258: Unused function argument: component_type

(ARG001)


306-306: Function definition does not bind loop variable no_stack_specified

(B023)


311-311: Function definition does not bind loop variable has_dualstack

(B023)


313-313: Function definition does not bind loop variable has_ipv6

(B023)


315-315: Function definition does not bind loop variable has_ipv4

(B023)


354-354: Unused function argument: component_type

(ARG001)


373-373: Do not assign a lambda expression, use a def

Rewrite ipv4_only as a def

(E731)


446-446: Unused function argument: scores

(ARG001)

plugins/test-coverage/skills/analyze/test_structure_reports.py

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

(EXE001)


150-150: String contains ambiguous (INFORMATION SOURCE). Did you mean i (LATIN SMALL LETTER I)?

(RUF001)

plugins/test-coverage/utils/path_handler.py

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

(EXE001)


116-116: Probable use of insecure hash functions in hashlib: md5

(S324)


161-161: Audit URL open for permitted schemes. Allowing use of file: or custom schemes is often unexpected.

(S310)


163-163: Audit URL open for permitted schemes. Allowing use of file: or custom schemes is often unexpected.

(S310)


186-186: Do not catch blind exception: Exception

(BLE001)

plugins/test-coverage/skills/analyze/test_structure_analyzer.py

84-84: Unused function argument: language

(ARG001)


90-90: Unused function argument: language

(ARG001)


90-90: PEP 484 prohibits implicit Optional

Convert to T | None

(RUF013)


132-132: Unused function argument: language

(ARG001)


208-208: Do not catch blind exception: Exception

(BLE001)


277-277: Local variable base_indent is assigned to but never used

Remove assignment to unused variable base_indent

(F841)


302-302: Local variable context_name is assigned to but never used

Remove assignment to unused variable context_name

(F841)


327-327: Unused function argument: language

(ARG001)


379-379: Unused function argument: language

(ARG001)


402-402: Unused function argument: language

(ARG001)


422-422: Local variable source_by_path is assigned to but never used

Remove assignment to unused variable source_by_path

(F841)


459-459: Unused function argument: file_path

(ARG001)


685-685: f-string without any placeholders

Remove extraneous f prefix

(F541)


709-709: Do not catch blind exception: Exception

(BLE001)


763-763: Do not catch blind exception: Exception

(BLE001)


774-774: Do not catch blind exception: Exception

(BLE001)


853-853: Do not catch blind exception: Exception

(BLE001)


867-867: Consider moving this statement to an else block

(TRY300)


869-869: Do not catch blind exception: Exception

(BLE001)

🔇 Additional comments (7)
plugins/test-coverage/skills/common/__init__.py (1)

1-3: LGTM!

Clean package initialization with clear documentation. The docstring appropriately describes the shared utilities purpose.

plugins/test-coverage/commands/gaps.md (1)

1-296: LGTM! Comprehensive command documentation.

The gaps command documentation is thorough and well-structured. Past review issues (fenced code block languages, duplicate headings, format inconsistencies) have been properly addressed.

plugins/test-coverage/skills/gaps/SKILL.md (1)

55-163: LGTM! Clear scope and limitations.

The documentation now clearly states:

  • Go-only support (line 55)
  • Current implementation scope (lines 57-61)
  • Explicit limitations section (lines 151-163)

This properly sets expectations and avoids misleading users about capabilities.

plugins/test-coverage/utils/path_handler.py (2)

46-68: LGTM! Secure URL validation.

The is_url() method correctly restricts to HTTP(S) only (lines 59-62), excluding potentially dangerous file:// and ftp:// schemes. This addresses the security concern from previous reviews.


136-189: LGTM! Proper security validation in download.

The download_file() method includes explicit scheme validation (lines 148-152) before calling urlopen(), providing defense in depth. The timeout (line 163) prevents hanging, and error handling appropriately catches HTTP and URL errors.

Note: Ruff warnings S310 and BLE001 are false positives here - the URL scheme is validated before use, and the broad exception catch is appropriate for a CLI utility.

plugins/test-coverage/commands/analyze.md (1)

330-345: LGTM! Prerequisites section is accurate.

Python version requirement correctly states 3.8+ (line 336), and the URL support description (line 341) is clear without repetition. Past review issues have been properly addressed.

plugins/test-coverage/skills/analyze/README.md (1)

1-128: LGTM! Consistent Go-focused documentation.

The README clearly documents Go-only support (lines 40-44) and all examples are appropriate for test structure analysis. No XML/Cobertura references found - the documentation is internally consistent.

Copy link
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: 5

♻️ Duplicate comments (2)
plugins/test-coverage/URL_SUPPORT.md (1)

123-127: Fix PathHandler URL claim

PathHandler.is_url() only accepts HTTP(S); documenting FTP/file schemes misleads users and contradicts the implementation. Please update the bullet to say it detects HTTP(S) URLs only.citeturn0past_comment0

Apply this diff:

-- **URL detection**: Identifies HTTP(S), FTP, and file:// URLs
+- **URL detection**: Identifies HTTP(S) URLs only (FTP/file:// are rejected for security)
plugins/test-coverage/skills/analyze/test_structure_analyzer.py (1)

847-854: Fix HTML generator import so the report actually writes.
test_structure_analyzer still tries from test_gap_reports import generate_test_structure_html, but that module sits under analyze/test_structure_reports. At runtime we always hit the ImportError branch and skip HTML generation entirely. Import from the correct package (with a fallback for script execution) so the CLI produces the HTML artifact.

-        from test_gap_reports import generate_test_structure_html
+        try:
+            from .test_structure_reports import generate_test_structure_html
+        except ImportError:
+            from analyze.test_structure_reports import generate_test_structure_html
🧹 Nitpick comments (5)
plugins/test-coverage/commands/analyze.md (2)

10-12: Add language identifier to code block for better rendering.

The synopsis code block would benefit from a language identifier for proper syntax highlighting in documentation renderers.

Apply this diff:

-```
+```bash
 /test-coverage:analyze <path-or-url> [--output <path>] [--priority <level>] [--test-structure-only]

---

`46-46`: **Fix markdown emphasis markers.**

Line 46 has spaces inside emphasis markers which may not render correctly. Use backticks instead for code literals.



Apply this diff:

```diff
-- By default, utility files are excluded (*_util.go, *_utils.go, *_helper.go, helpers.go, etc.)
+- By default, utility files are excluded (`*_util.go`, `*_utils.go`, `*_helper.go`, `helpers.go`, etc.)
plugins/test-coverage/utils/path_handler.py (1)

186-188: Consider more specific exception handling.

The bare Exception catch is very broad. While it ensures all errors are reported, it may hide unexpected issues. Consider catching only expected exceptions or at least re-raising after logging for debugging purposes.

Example refinement:

except Exception as e:
    print(f"Error downloading {url}: {e}", file=sys.stderr)
    # Optionally: import traceback; traceback.print_exc()
    return False

Or be more specific about what exceptions are expected here beyond the already-handled HTTPError and URLError.

plugins/test-coverage/README.md (1)

323-324: Format URLs as proper markdown links.

The bare URLs should use proper markdown link syntax for better rendering and accessibility.

Apply this diff:

-- **Issues**: https://github.com/openshift-eng/ai-helpers/issues
-- **Documentation**: https://github.com/openshift-eng/ai-helpers
+- **Issues**: [https://github.com/openshift-eng/ai-helpers/issues](https://github.com/openshift-eng/ai-helpers/issues)
+- **Documentation**: [https://github.com/openshift-eng/ai-helpers](https://github.com/openshift-eng/ai-helpers)
plugins/test-coverage/URL_SUPPORT.md (1)

17-50: Tag fenced code blocks with languages

Markdownlint (MD040) is tripping on the unlabeled fences. Please add language hints (bash, python, text, etc.) to every code block so docs lint passes.citeturn0static_summary0

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 9044dda and a9dde63.

📒 Files selected for processing (26)
  • .claude-plugin/marketplace.json (1 hunks)
  • PLUGINS.md (2 hunks)
  • docs/data.json (1 hunks)
  • plugins/test-coverage/.claude-plugin/plugin.json (1 hunks)
  • plugins/test-coverage/README.md (1 hunks)
  • plugins/test-coverage/URL_SUPPORT.md (1 hunks)
  • plugins/test-coverage/__init__.py (1 hunks)
  • plugins/test-coverage/commands/analyze.md (1 hunks)
  • plugins/test-coverage/commands/gaps.md (1 hunks)
  • plugins/test-coverage/skills/__init__.py (1 hunks)
  • plugins/test-coverage/skills/analyze/README.md (1 hunks)
  • plugins/test-coverage/skills/analyze/SKILL.md (1 hunks)
  • plugins/test-coverage/skills/analyze/__init__.py (1 hunks)
  • plugins/test-coverage/skills/analyze/test_gap_reports.py (1 hunks)
  • plugins/test-coverage/skills/analyze/test_structure_analyzer.py (1 hunks)
  • plugins/test-coverage/skills/analyze/test_structure_reports.py (1 hunks)
  • plugins/test-coverage/skills/common/__init__.py (1 hunks)
  • plugins/test-coverage/skills/common/report_styles.py (1 hunks)
  • plugins/test-coverage/skills/gaps/README.md (1 hunks)
  • plugins/test-coverage/skills/gaps/SKILL.md (1 hunks)
  • plugins/test-coverage/skills/gaps/__init__.py (1 hunks)
  • plugins/test-coverage/skills/gaps/gap_analyzer.py (1 hunks)
  • plugins/test-coverage/skills/gaps/report_template.py (1 hunks)
  • plugins/test-coverage/skills/gaps/reports.py (1 hunks)
  • plugins/test-coverage/utils/__init__.py (1 hunks)
  • plugins/test-coverage/utils/path_handler.py (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (7)
  • .claude-plugin/marketplace.json
  • plugins/test-coverage/skills/init.py
  • plugins/test-coverage/skills/analyze/SKILL.md
  • plugins/test-coverage/utils/init.py
  • plugins/test-coverage/skills/gaps/init.py
  • plugins/test-coverage/init.py
  • plugins/test-coverage/skills/analyze/init.py
🧰 Additional context used
🪛 LanguageTool
plugins/test-coverage/commands/analyze.md

[uncategorized] ~30-~30: Loose punctuation mark.
Context: ...g. ## Arguments - <source-directory>: Path or URL to source code directory/fi...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~38-~38: Loose punctuation mark.
Context: ...st-coverage/cache/ ---output `: Output directory for generated reports ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~41-~41: Loose punctuation mark.
Context: ...and text summary - --priority <level>: Filter results by priority (optional) ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~45-~45: Loose punctuation mark.
Context: ...Default: all - --include-test-utils: Include test utility/helper files in an...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~50-~50: Loose punctuation mark.
Context: ...structure code - --include-unit-tests: Include unit tests in analysis (optiona...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~58-~58: Loose punctuation mark.
Context: ...or Python) - --test-pattern <pattern>: Custom test file pattern (optional) -...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~61-~61: Loose punctuation mark.
Context: .../Test*.java" ---test-structure-only`: Analyze only test file structure, skip ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~265-~265: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ... Example 2: Analyze test structure with high priority filter ``` /test-coverage:analyze ./pk...

(EN_COMPOUND_ADJECTIVE_INTERNAL)

plugins/test-coverage/skills/gaps/README.md

[uncategorized] ~41-~41: A comma may be missing after the conjunctive/linking adverb ‘Currently’.
Context: ...ntly implemented. ## Language Support Currently supports Go test files only: - Ginkgo B...

(SENT_START_CONJUNCTIVE_LINKING_ADVERB_COMMA)

plugins/test-coverage/README.md

[uncategorized] ~170-~170: A comma may be missing after the conjunctive/linking adverb ‘Currently’.
Context: ...` flag. --- ## Supported Languages Currently supports Go projects only. | Languag...

(SENT_START_CONJUNCTIVE_LINKING_ADVERB_COMMA)


[uncategorized] ~280-~280: Use a comma before ‘but’ if it connects two independent clauses (unless they are closely connected and short).
Context: ...ude "*.js" ``` ### Issue: No gaps found but code is clearly untested Solution:...

(COMMA_COMPOUND_SENTENCE_2)


[uncategorized] ~333-~333: Loose punctuation mark.
Context: ...ation. ## Related Plugins - jira: Create bug reports with coverage gap co...

(UNLIKELY_OPENING_PUNCTUATION)

plugins/test-coverage/URL_SUPPORT.md

[uncategorized] ~196-~196: Possible missing preposition found.
Context: ...eports HTTP error codes and reasons - Network errors: Reports connection issues wit...

(AI_HYDRA_LEO_MISSING_OF)


[duplication] ~231-~231: Possible typo: you repeated a word.
Context: ...# See Also - /test-coverage:analyze command - /test-coverage:gaps command - [Path Handler Util...

(ENGLISH_WORD_REPEAT_RULE)

plugins/test-coverage/commands/gaps.md

[uncategorized] ~48-~48: Loose punctuation mark.
Context: ... Optional Arguments - --output <path>: Output directory for gap analysis repor...

(UNLIKELY_OPENING_PUNCTUATION)

plugins/test-coverage/skills/analyze/README.md

[uncategorized] ~79-~79: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...files without tests ### Example 2: High Priority Gaps Only bash # Analyze only high-...

(EN_COMPOUND_ADJECTIVE_INTERNAL)

plugins/test-coverage/skills/gaps/SKILL.md

[duplication] ~172-~172: Possible typo: you repeated a word.
Context: ...age, service type/volume mode, scenario coverage - Coverage matrices: Visual tables showing what ...

(ENGLISH_WORD_REPEAT_RULE)


[uncategorized] ~175-~175: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ... - Priority indicators: High/medium/low priority badges for each gap - **Test cases list...

(EN_COMPOUND_ADJECTIVE_INTERNAL)

🪛 markdownlint-cli2 (0.18.1)
plugins/test-coverage/commands/analyze.md

10-10: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


46-46: Spaces inside emphasis markers

(MD037, no-space-in-emphasis)


223-223: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


259-259: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


267-267: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


275-275: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


283-283: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


297-297: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


305-305: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


313-313: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


323-323: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

plugins/test-coverage/README.md

323-323: Bare URL used

(MD034, no-bare-urls)


324-324: Bare URL used

(MD034, no-bare-urls)

plugins/test-coverage/URL_SUPPORT.md

17-17: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


22-22: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


27-27: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


34-34: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


39-39: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


46-46: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

plugins/test-coverage/skills/gaps/SKILL.md

17-17: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


22-22: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


27-27: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


34-34: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


39-39: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


46-46: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🪛 Ruff (0.14.4)
plugins/test-coverage/skills/gaps/reports.py

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

(EXE001)

plugins/test-coverage/skills/gaps/report_template.py

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

(EXE001)


46-46: Multiple statements on one line (colon)

(E701)


47-47: Multiple statements on one line (colon)

(E701)


48-48: Multiple statements on one line (colon)

(E701)


49-49: Multiple statements on one line (colon)

(E701)


258-258: Unused function argument: component_type

(ARG001)


306-306: Function definition does not bind loop variable no_stack_specified

(B023)


311-311: Function definition does not bind loop variable has_dualstack

(B023)


313-313: Function definition does not bind loop variable has_ipv6

(B023)


315-315: Function definition does not bind loop variable has_ipv4

(B023)


354-354: Unused function argument: component_type

(ARG001)


373-373: Do not assign a lambda expression, use a def

Rewrite ipv4_only as a def

(E731)


446-446: Unused function argument: scores

(ARG001)

plugins/test-coverage/skills/analyze/test_gap_reports.py

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

(EXE001)

plugins/test-coverage/utils/path_handler.py

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

(EXE001)


116-116: Probable use of insecure hash functions in hashlib: md5

(S324)


161-161: Audit URL open for permitted schemes. Allowing use of file: or custom schemes is often unexpected.

(S310)


163-163: Audit URL open for permitted schemes. Allowing use of file: or custom schemes is often unexpected.

(S310)


186-186: Do not catch blind exception: Exception

(BLE001)

plugins/test-coverage/skills/gaps/gap_analyzer.py

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

(EXE001)


624-624: Local variable gaps is assigned to but never used

Remove assignment to unused variable gaps

(F841)


794-794: f-string without any placeholders

Remove extraneous f prefix

(F541)

plugins/test-coverage/skills/analyze/test_structure_reports.py

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

(EXE001)


150-150: String contains ambiguous (INFORMATION SOURCE). Did you mean i (LATIN SMALL LETTER I)?

(RUF001)

plugins/test-coverage/skills/analyze/test_structure_analyzer.py

84-84: Unused function argument: language

(ARG001)


90-90: Unused function argument: language

(ARG001)


90-90: PEP 484 prohibits implicit Optional

Convert to T | None

(RUF013)


132-132: Unused function argument: language

(ARG001)


208-208: Do not catch blind exception: Exception

(BLE001)


277-277: Local variable base_indent is assigned to but never used

Remove assignment to unused variable base_indent

(F841)


302-302: Local variable context_name is assigned to but never used

Remove assignment to unused variable context_name

(F841)


327-327: Unused function argument: language

(ARG001)


379-379: Unused function argument: language

(ARG001)


402-402: Unused function argument: language

(ARG001)


422-422: Local variable source_by_path is assigned to but never used

Remove assignment to unused variable source_by_path

(F841)


459-459: Unused function argument: file_path

(ARG001)


685-685: f-string without any placeholders

Remove extraneous f prefix

(F541)


709-709: Do not catch blind exception: Exception

(BLE001)


763-763: Do not catch blind exception: Exception

(BLE001)


774-774: Do not catch blind exception: Exception

(BLE001)


853-853: Do not catch blind exception: Exception

(BLE001)


867-867: Consider moving this statement to an else block

(TRY300)


869-869: Do not catch blind exception: Exception

(BLE001)

plugins/test-coverage/skills/common/report_styles.py

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

(EXE001)

🔇 Additional comments (5)
plugins/test-coverage/skills/common/__init__.py (1)

1-3: LGTM!

Clean package initializer with clear documentation.

plugins/test-coverage/skills/analyze/README.md (1)

1-128: LGTM!

The documentation is clear and consistent. Examples properly demonstrate Go test structure analysis without any Cobertura/XML references.

plugins/test-coverage/skills/gaps/README.md (1)

1-67: LGTM!

Clear documentation that accurately reflects the current implementation, including the explicit note about URL support limitations.

plugins/test-coverage/.claude-plugin/plugin.json (1)

1-8: LGTM!

Clean and properly structured plugin manifest with all required fields.

PLUGINS.md (1)

181-182: Command documentation looks accurate.

The command signatures properly document the available options and align with the actual implementation.

docs/data.json Outdated
Comment on lines 621 to 622
"synopsis": "bash",
"argument_hint": "<test-file-or-url> [--output <path>]"
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Correct gaps command synopsis

The synopsis is set to "bash", so marketplace metadata can’t show or validate the actual invocation. Please replace it with the real command string (e.g. /test-coverage:gaps <test-file-or-url> [--output <path>]).citeturn0pr_objectives0

🤖 Prompt for AI Agents
In docs/data.json around lines 621-622, the "synopsis" field is incorrectly set
to "bash"; replace that value with the actual command invocation string so
marketplace metadata can validate and display it correctly (for example use
"/test-coverage:gaps <test-file-or-url> [--output <path>]" or the exact command
your tool exposes). Ensure you keep the synopsis as a single string matching the
real CLI entry (including any subcommand or prefix) and preserve JSON
escaping/quoting.

Copy link
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: 3

♻️ Duplicate comments (6)
plugins/test-coverage/README.md (1)

309-315: Java patterns contradict Go-only scope.

Line 314 shows a Java test pattern example (**/*Spec.java,**/IT*.java), but line 170 clearly states "Currently supports Go projects only." This inconsistency will confuse users.

Apply this diff to use Go patterns:

-/test-coverage:analyze ./src/ --test-pattern "**/*Spec.java,**/IT*.java"
+/test-coverage:analyze ./pkg/ --test-pattern "**/*_test.go,**/*e2e*_test.go"

Note: This issue was previously marked as addressed in commit bb5f9fe but appears to have been reintroduced.

PLUGINS.md (1)

176-184: Remove duplicate Test Coverage Plugin section.

The AI summary indicates that PLUGINS.md contains two identical Test Coverage Plugin sections. Please search the file and remove the redundant entry.

Run this script to locate all occurrences:

#!/bin/bash
# Find all Test Coverage Plugin section headers
rg -n "^### Test Coverage Plugin" PLUGINS.md
plugins/test-coverage/skills/analyze/test_structure_analyzer.py (1)

845-854: Fix HTML generator import.

The analyzer still imports generate_test_structure_html from test_gap_reports, so every run trips the ImportError branch and silently skips HTML output. Point the import at the new test_structure_reports module (with the usual relative/absolute fallback) so we actually emit the HTML report again.

-        try:
-            from test_gap_reports import generate_test_structure_html
+        try:
+            from .test_structure_reports import generate_test_structure_html
+        except ImportError:
+            from test_structure_reports import generate_test_structure_html
         with open(json_path, 'r') as f:
             json_data = json.load(f)
         generate_test_structure_html(json_data, html_path)
-        except ImportError:
-            print("Warning: report_generator not found, skipping HTML report")
+        except ImportError:
+            print("Warning: test_structure_reports module not found, skipping HTML report")
plugins/test-coverage/URL_SUPPORT.md (1)

123-124: Align docs with actual URL validation.

The PathHandler now rejects FTP and file:// schemes, so this bullet is misleading and repeats the earlier concern. Please update it to describe HTTP(S)-only support.

Apply this diff:

- - **URL detection**: Identifies HTTP(S), FTP, and file:// URLs
+ - **URL detection**: Identifies HTTP(S) URLs only (FTP and file:// are intentionally excluded)
plugins/test-coverage/skills/gaps/gap_analyzer.py (2)

379-404: Add gap detection for every tracked platform.

Coverage bookkeeping reports vSphere, ROSA, AWS, Azure, GCP, and Bare Metal, but this block only emits gaps for Azure/GCP/Bare Metal. Missing AWS/ROSA/vSphere coverage therefore never surfaces in HTML/JSON/text, hiding critical production gaps.

Apply this diff:

-        if not re.search(r'azure', self.content, re.IGNORECASE):
-            gaps.append({
-                'platform': 'Azure',
-                'priority': 'high',
-                'impact': 'Major cloud provider - production blocker',
-                'recommendation': 'Add Azure platform-specific tests'
-            })
-
-        if not re.search(r'\bGCP\b|google.*cloud', self.content, re.IGNORECASE):
-            gaps.append({
-                'platform': 'GCP',
-                'priority': 'high',
-                'impact': 'Major cloud provider - production blocker',
-                'recommendation': 'Add GCP platform-specific tests'
-            })
-
-        if not re.search(r'baremetal|bare.metal', self.content, re.IGNORECASE):
-            gaps.append({
-                'platform': 'Bare Metal',
-                'priority': 'medium',
-                'impact': 'Edge/on-premise deployments',
-                'recommendation': 'Add bare metal platform tests'
-            })
+        platform_specs = {
+            'vSphere': {
+                'pattern': r'vsphere',
+                'priority': 'medium',
+                'impact': 'On-prem virtualization path not covered',
+                'recommendation': 'Add vSphere platform-specific tests'
+            },
+            'ROSA': {
+                'pattern': r'\bROSA\b',
+                'priority': 'medium',
+                'impact': 'Managed OpenShift on AWS not validated',
+                'recommendation': 'Add ROSA platform-specific tests'
+            },
+            'AWS': {
+                'pattern': r'\bAWS\b|amazon\s+web\s+services',
+                'priority': 'high',
+                'impact': 'Most common production cloud not tested',
+                'recommendation': 'Add AWS platform-specific tests'
+            },
+            'Azure': {
+                'pattern': r'azure',
+                'priority': 'high',
+                'impact': 'Major cloud provider - production blocker',
+                'recommendation': 'Add Azure platform-specific tests'
+            },
+            'GCP': {
+                'pattern': r'\bGCP\b|google.*cloud',
+                'priority': 'high',
+                'impact': 'Major cloud provider - production blocker',
+                'recommendation': 'Add GCP platform-specific tests'
+            },
+            'Bare Metal': {
+                'pattern': r'baremetal|bare\.metal',
+                'priority': 'medium',
+                'impact': 'Edge/on-premise deployments',
+                'recommendation': 'Add bare metal platform tests'
+            },
+        }
+
+        for name, spec in platform_specs.items():
+            if not re.search(spec['pattern'], self.content, re.IGNORECASE):
+                gaps.append({
+                    'platform': name,
+                    'priority': spec['priority'],
+                    'impact': spec['impact'],
+                    'recommendation': spec['recommendation']
+                })

772-785: CLI summary hides networking/storage gaps.

all_gaps only collects platforms and scenarios, so high-priority protocol/service/storage/IP-stack/topology gaps never reach the console output. That makes the CLI disagree with the HTML/JSON reports.

Apply this diff:

-    all_gaps = []
-    for key in ('platforms', 'scenarios'):
-        all_gaps.extend(analysis['gaps'].get(key, []))
+    all_gaps = [
+        gap
+        for gap_list in analysis['gaps'].values()
+        if isinstance(gap_list, list)
+        for gap in gap_list
+    ]
@@
-            name = gap.get('platform') or gap.get('scenario')
+            name = (
+                gap.get('platform')
+                or gap.get('protocol')
+                or gap.get('service_type')
+                or gap.get('storage_class')
+                or gap.get('volume_mode')
+                or gap.get('ip_stack')
+                or gap.get('topology')
+                or gap.get('scenario')
+            )
🧹 Nitpick comments (1)
plugins/test-coverage/skills/common/report_styles.py (1)

1-1: Remove unnecessary shebang from library module.

This module is a pure library that only exports get_common_css() and has no CLI entry point. The shebang is unnecessary and triggers static analysis warnings.

Apply this diff:

-#!/usr/bin/env python3
 """
 Shared CSS styles for HTML reports across all test coverage skills
 """

Based on static analysis hints.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between a9dde63 and 3714192.

📒 Files selected for processing (26)
  • .claude-plugin/marketplace.json (1 hunks)
  • PLUGINS.md (2 hunks)
  • docs/data.json (1 hunks)
  • plugins/test-coverage/.claude-plugin/plugin.json (1 hunks)
  • plugins/test-coverage/README.md (1 hunks)
  • plugins/test-coverage/URL_SUPPORT.md (1 hunks)
  • plugins/test-coverage/__init__.py (1 hunks)
  • plugins/test-coverage/commands/analyze.md (1 hunks)
  • plugins/test-coverage/commands/gaps.md (1 hunks)
  • plugins/test-coverage/skills/__init__.py (1 hunks)
  • plugins/test-coverage/skills/analyze/README.md (1 hunks)
  • plugins/test-coverage/skills/analyze/SKILL.md (1 hunks)
  • plugins/test-coverage/skills/analyze/__init__.py (1 hunks)
  • plugins/test-coverage/skills/analyze/test_gap_reports.py (1 hunks)
  • plugins/test-coverage/skills/analyze/test_structure_analyzer.py (1 hunks)
  • plugins/test-coverage/skills/analyze/test_structure_reports.py (1 hunks)
  • plugins/test-coverage/skills/common/__init__.py (1 hunks)
  • plugins/test-coverage/skills/common/report_styles.py (1 hunks)
  • plugins/test-coverage/skills/gaps/README.md (1 hunks)
  • plugins/test-coverage/skills/gaps/SKILL.md (1 hunks)
  • plugins/test-coverage/skills/gaps/__init__.py (1 hunks)
  • plugins/test-coverage/skills/gaps/gap_analyzer.py (1 hunks)
  • plugins/test-coverage/skills/gaps/report_template.py (1 hunks)
  • plugins/test-coverage/skills/gaps/reports.py (1 hunks)
  • plugins/test-coverage/utils/__init__.py (1 hunks)
  • plugins/test-coverage/utils/path_handler.py (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • plugins/test-coverage/skills/analyze/init.py
🚧 Files skipped from review as they are similar to previous changes (7)
  • plugins/test-coverage/skills/init.py
  • plugins/test-coverage/skills/gaps/init.py
  • plugins/test-coverage/skills/common/init.py
  • .claude-plugin/marketplace.json
  • docs/data.json
  • plugins/test-coverage/.claude-plugin/plugin.json
  • plugins/test-coverage/utils/init.py
🧰 Additional context used
🪛 LanguageTool
plugins/test-coverage/skills/analyze/README.md

[uncategorized] ~79-~79: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...files without tests ### Example 2: High Priority Gaps Only bash # Analyze only high-...

(EN_COMPOUND_ADJECTIVE_INTERNAL)

plugins/test-coverage/commands/analyze.md

[uncategorized] ~30-~30: Loose punctuation mark.
Context: ...g. ## Arguments - <source-directory>: Path or URL to source code directory/fi...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~38-~38: Loose punctuation mark.
Context: ...st-coverage/cache/ ---output `: Output directory for generated reports ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~41-~41: Loose punctuation mark.
Context: ...and text summary - --priority <level>: Filter results by priority (optional) ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~45-~45: Loose punctuation mark.
Context: ...Default: all - --include-test-utils: Include test utility/helper files in an...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~50-~50: Loose punctuation mark.
Context: ...structure code - --include-unit-tests: Include unit tests in analysis (optiona...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~58-~58: Loose punctuation mark.
Context: ...or Python) - --test-pattern <pattern>: Custom test file pattern (optional) -...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~61-~61: Loose punctuation mark.
Context: .../Test*.java" ---test-structure-only`: Analyze only test file structure, skip ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~265-~265: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ... Example 2: Analyze test structure with high priority filter ``` /test-coverage:analyze ./pk...

(EN_COMPOUND_ADJECTIVE_INTERNAL)

plugins/test-coverage/skills/gaps/README.md

[uncategorized] ~41-~41: A comma may be missing after the conjunctive/linking adverb ‘Currently’.
Context: ...ntly implemented. ## Language Support Currently supports Go test files only: - Ginkgo B...

(SENT_START_CONJUNCTIVE_LINKING_ADVERB_COMMA)

plugins/test-coverage/README.md

[uncategorized] ~170-~170: A comma may be missing after the conjunctive/linking adverb ‘Currently’.
Context: ...` flag. --- ## Supported Languages Currently supports Go projects only. | Languag...

(SENT_START_CONJUNCTIVE_LINKING_ADVERB_COMMA)


[uncategorized] ~280-~280: Use a comma before ‘but’ if it connects two independent clauses (unless they are closely connected and short).
Context: ...ude "*.js" ``` ### Issue: No gaps found but code is clearly untested Solution:...

(COMMA_COMPOUND_SENTENCE_2)


[uncategorized] ~333-~333: Loose punctuation mark.
Context: ...ation. ## Related Plugins - jira: Create bug reports with coverage gap co...

(UNLIKELY_OPENING_PUNCTUATION)

plugins/test-coverage/URL_SUPPORT.md

[uncategorized] ~196-~196: Possible missing preposition found.
Context: ...eports HTTP error codes and reasons - Network errors: Reports connection issues wit...

(AI_HYDRA_LEO_MISSING_OF)


[duplication] ~231-~231: Possible typo: you repeated a word.
Context: ...# See Also - /test-coverage:analyze command - /test-coverage:gaps command - [Path Handler Util...

(ENGLISH_WORD_REPEAT_RULE)

plugins/test-coverage/commands/gaps.md

[uncategorized] ~48-~48: Loose punctuation mark.
Context: ... Optional Arguments - --output <path>: Output directory for gap analysis repor...

(UNLIKELY_OPENING_PUNCTUATION)

plugins/test-coverage/skills/gaps/SKILL.md

[duplication] ~172-~172: Possible typo: you repeated a word.
Context: ...age, service type/volume mode, scenario coverage - Coverage matrices: Visual tables showing what ...

(ENGLISH_WORD_REPEAT_RULE)


[uncategorized] ~175-~175: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ... - Priority indicators: High/medium/low priority badges for each gap - **Test cases list...

(EN_COMPOUND_ADJECTIVE_INTERNAL)

🪛 markdownlint-cli2 (0.18.1)
plugins/test-coverage/skills/analyze/README.md

48-48: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


95-95: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

plugins/test-coverage/commands/analyze.md

10-10: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


46-46: Spaces inside emphasis markers

(MD037, no-space-in-emphasis)


223-223: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


259-259: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


267-267: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


275-275: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


283-283: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


297-297: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


305-305: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


313-313: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


323-323: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

plugins/test-coverage/README.md

323-323: Bare URL used

(MD034, no-bare-urls)


324-324: Bare URL used

(MD034, no-bare-urls)

plugins/test-coverage/URL_SUPPORT.md

17-17: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


22-22: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


27-27: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


34-34: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


39-39: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


46-46: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

plugins/test-coverage/skills/analyze/SKILL.md

292-292: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

plugins/test-coverage/skills/gaps/SKILL.md

213-213: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🪛 Ruff (0.14.4)
plugins/test-coverage/skills/analyze/test_gap_reports.py

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

(EXE001)

plugins/test-coverage/skills/gaps/reports.py

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

(EXE001)

plugins/test-coverage/skills/analyze/test_structure_reports.py

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

(EXE001)


150-150: String contains ambiguous (INFORMATION SOURCE). Did you mean i (LATIN SMALL LETTER I)?

(RUF001)

plugins/test-coverage/skills/gaps/report_template.py

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

(EXE001)


46-46: Multiple statements on one line (colon)

(E701)


47-47: Multiple statements on one line (colon)

(E701)


48-48: Multiple statements on one line (colon)

(E701)


49-49: Multiple statements on one line (colon)

(E701)


258-258: Unused function argument: component_type

(ARG001)


306-306: Function definition does not bind loop variable no_stack_specified

(B023)


311-311: Function definition does not bind loop variable has_dualstack

(B023)


313-313: Function definition does not bind loop variable has_ipv6

(B023)


315-315: Function definition does not bind loop variable has_ipv4

(B023)


354-354: Unused function argument: component_type

(ARG001)


373-373: Do not assign a lambda expression, use a def

Rewrite ipv4_only as a def

(E731)


446-446: Unused function argument: scores

(ARG001)

plugins/test-coverage/skills/analyze/test_structure_analyzer.py

84-84: Unused function argument: language

(ARG001)


90-90: Unused function argument: language

(ARG001)


90-90: PEP 484 prohibits implicit Optional

Convert to T | None

(RUF013)


132-132: Unused function argument: language

(ARG001)


208-208: Do not catch blind exception: Exception

(BLE001)


277-277: Local variable base_indent is assigned to but never used

Remove assignment to unused variable base_indent

(F841)


302-302: Local variable context_name is assigned to but never used

Remove assignment to unused variable context_name

(F841)


327-327: Unused function argument: language

(ARG001)


379-379: Unused function argument: language

(ARG001)


402-402: Unused function argument: language

(ARG001)


422-422: Local variable source_by_path is assigned to but never used

Remove assignment to unused variable source_by_path

(F841)


459-459: Unused function argument: file_path

(ARG001)


685-685: f-string without any placeholders

Remove extraneous f prefix

(F541)


709-709: Do not catch blind exception: Exception

(BLE001)


763-763: Do not catch blind exception: Exception

(BLE001)


774-774: Do not catch blind exception: Exception

(BLE001)


853-853: Do not catch blind exception: Exception

(BLE001)


867-867: Consider moving this statement to an else block

(TRY300)


869-869: Do not catch blind exception: Exception

(BLE001)

plugins/test-coverage/skills/common/report_styles.py

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

(EXE001)

plugins/test-coverage/skills/gaps/gap_analyzer.py

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

(EXE001)


624-624: Local variable gaps is assigned to but never used

Remove assignment to unused variable gaps

(F841)


794-794: f-string without any placeholders

Remove extraneous f prefix

(F541)

plugins/test-coverage/utils/path_handler.py

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

(EXE001)


116-116: Probable use of insecure hash functions in hashlib: md5

(S324)


161-161: Audit URL open for permitted schemes. Allowing use of file: or custom schemes is often unexpected.

(S310)


163-163: Audit URL open for permitted schemes. Allowing use of file: or custom schemes is often unexpected.

(S310)


186-186: Do not catch blind exception: Exception

(BLE001)

Copy link
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 (6)
plugins/test-coverage/skills/gaps/gap_analyzer.py (2)

772-776: Surface every high-priority gap in the CLI summary.

Line [774] only aggregates platforms and scenarios, so networking protocol gaps, storage-class gaps, volume-mode gaps, etc., vanish from the console even when marked priority: 'high' in the JSON/HTML outputs. Users running just the CLI never see the main red flags. Please gather every gap list before filtering by priority.

-    all_gaps = []
-    for key in ('platforms', 'scenarios'):
-        all_gaps.extend(analysis['gaps'].get(key, []))
+    all_gaps = [
+        gap
+        for gap_list in analysis['gaps'].values()
+        if isinstance(gap_list, list)
+        for gap in gap_list
+    ]

379-403: Emit gaps for every tracked platform.

Line [379] only appends Azure, GCP, and Bare Metal entries. Yet _analyze_platforms() classifies AWS, vSphere, and ROSA as well, so those providers never appear in analysis['gaps'] even when not_tested marks them missing. That hides real coverage holes from the JSON/HTML/CLI outputs and contradicts the “Major cloud providers” guidance. Please iterate over every platform you track so the gap list stays in sync with coverage.

-        if not re.search(r'azure', self.content, re.IGNORECASE):
-            gaps.append({
-                'platform': 'Azure',
-                'priority': 'high',
-                'impact': 'Major cloud provider - production blocker',
-                'recommendation': 'Add Azure platform-specific tests'
-            })
-
-        if not re.search(r'\bGCP\b|google.*cloud', self.content, re.IGNORECASE):
-            gaps.append({
-                'platform': 'GCP',
-                'priority': 'high',
-                'impact': 'Major cloud provider - production blocker',
-                'recommendation': 'Add GCP platform-specific tests'
-            })
-
-        if not re.search(r'baremetal|bare.metal', self.content, re.IGNORECASE):
-            gaps.append({
-                'platform': 'Bare Metal',
-                'priority': 'medium',
-                'impact': 'Edge/on-premise deployments',
-                'recommendation': 'Add bare metal platform tests'
-            })
+        platform_specs = {
+            'AWS': {
+                'pattern': r'\bAWS\b|amazon\s+web\s+services|aws.*platform',
+                'priority': 'high',
+                'impact': 'Most commonly deployed cloud not tested',
+                'recommendation': 'Add AWS platform-specific tests'
+            },
+            'Azure': {
+                'pattern': r'azure',
+                'priority': 'high',
+                'impact': 'Major cloud provider - production blocker',
+                'recommendation': 'Add Azure platform-specific tests'
+            },
+            'GCP': {
+                'pattern': r'\bGCP\b|google.*cloud',
+                'priority': 'high',
+                'impact': 'Major cloud provider - production blocker',
+                'recommendation': 'Add GCP platform-specific tests'
+            },
+            'vSphere': {
+                'pattern': r'vsphere',
+                'priority': 'medium',
+                'impact': 'On-prem virtualization path not covered',
+                'recommendation': 'Add vSphere platform-specific tests'
+            },
+            'ROSA': {
+                'pattern': r'\bROSA\b',
+                'priority': 'medium',
+                'impact': 'Managed OpenShift on AWS not validated',
+                'recommendation': 'Add ROSA platform-specific tests'
+            },
+            'Bare Metal': {
+                'pattern': r'baremetal|bare.metal',
+                'priority': 'medium',
+                'impact': 'Edge/on-premise deployments',
+                'recommendation': 'Add bare metal platform tests'
+            },
+        }
+
+        for name, spec in platform_specs.items():
+            if not re.search(spec['pattern'], self.content, re.IGNORECASE):
+                gaps.append({
+                    'platform': name,
+                    'priority': spec['priority'],
+                    'impact': spec['impact'],
+                    'recommendation': spec['recommendation']
+                })
plugins/test-coverage/skills/analyze/test_structure_analyzer.py (1)

844-853: Fix the HTML report import so reports generate.

Line [846] imports generate_test_structure_html from test_gap_reports, but that function lives in test_structure_reports.py. At runtime we hit ImportError and skip HTML generation, so the promised “Rich Reports” (README) never materialize. Please import from the correct module with a package-aware fallback.

-        from test_gap_reports import generate_test_structure_html
+        try:
+            from .test_structure_reports import generate_test_structure_html
+        except ImportError:
+            from test_structure_reports import generate_test_structure_html
@@
-        except ImportError:
-            print("Warning: report_generator not found, skipping HTML report")
+        except ImportError:
+            print("Warning: test_structure_reports not found, skipping HTML report")
plugins/test-coverage/URL_SUPPORT.md (1)

123-123: Remove FTP and file:// protocol references.

Line 123 claims support for "HTTP(S), FTP, and file:// URLs" but the actual implementation (path_handler.py) only supports HTTP(S) for security reasons. A past review flagged this but the text remains unchanged.

Apply this diff:

-- **URL detection**: Identifies HTTP(S), FTP, and file:// URLs
+- **URL detection**: Identifies HTTP(S) URLs only (file:// and FTP excluded for security)
docs/data.json (1)

618-623: Fix gaps command synopsis.

Line 621 has "synopsis": "bash" which is incorrect metadata. This should be the actual command invocation string.

Apply this diff:

         {
           "name": "gaps",
           "description": "Identify E2E test scenario gaps in OpenShift/Kubernetes tests (component-agnostic)",
-          "synopsis": "bash",
+          "synopsis": "/test-coverage:gaps <test-file-or-url> [--output <path>]",
           "argument_hint": "<test-file-or-url> [--output <path>]"
         }
plugins/test-coverage/README.md (1)

309-315: Java patterns contradict Go-only scope.

Line 314 shows a Java test pattern example (**/*Spec.java,**/IT*.java), but this plugin only supports Go projects. Although a past review marked this as addressed, the Java example remains.

Apply this diff to align with Go-only support:

-/test-coverage:analyze ./src/ --test-pattern "**/*Spec.java,**/IT*.java"
+/test-coverage:analyze ./pkg/ --test-pattern "**/*_test.go,**/e2e/*_test.go"
🧹 Nitpick comments (7)
plugins/test-coverage/README.md (1)

323-324: Wrap bare URLs in angle brackets.

Bare URLs should be enclosed in angle brackets for proper Markdown formatting.

Apply this diff:

-- **Issues**: https://github.com/openshift-eng/ai-helpers/issues
-- **Documentation**: https://github.com/openshift-eng/ai-helpers
+- **Issues**: <https://github.com/openshift-eng/ai-helpers/issues>
+- **Documentation**: <https://github.com/openshift-eng/ai-helpers>
plugins/test-coverage/skills/analyze/SKILL.md (1)

292-317: Add language identifier to fenced code block.

The text summary example should specify text as the language identifier for proper rendering.

Apply this diff:

-```
+```text
 Test Structure Analysis
 ═══════════════════════════════════════════════════
plugins/test-coverage/skills/common/report_styles.py (1)

1-1: Make file executable or remove shebang.

The shebang is present but the file is not marked as executable. Either add execute permissions or remove the shebang if this module is only meant to be imported.

To make executable:

chmod +x plugins/test-coverage/skills/common/report_styles.py

Or remove the shebang if it's library code only:

-#!/usr/bin/env python3
 """
 Shared CSS styles for HTML reports across all test coverage skills
 """
plugins/test-coverage/URL_SUPPORT.md (1)

17-48: Add language identifiers to URL example blocks.

The URL examples in fenced code blocks should specify a language identifier (e.g., text or url) for consistent rendering.

Example:

-```
+```text
 https://github.com/owner/repo/blob/main/test/file_test.go

Apply to all similar blocks at lines 17-18, 22-23, 27-28, 34-35, 39-40, and 46-48.

</blockquote></details>
<details>
<summary>plugins/test-coverage/commands/analyze.md (3)</summary><blockquote>

`10-12`: **Add language identifier to synopsis block.**

The synopsis should specify `bash` as the language identifier.



Apply this diff:

```diff
-```
+```bash
 /test-coverage:analyze <path-or-url> [--output <path>] [--priority <level>] [--test-structure-only]

---

`46-46`: **Fix spacing in emphasis markers.**

Remove spaces inside the emphasis markers around file patterns.



Apply this diff:

```diff
-  - By default, utility files are excluded (*_util.go, *_utils.go, *_helper.go, helpers.go, etc.)
+  - By default, utility files are excluded (`*_util.go`, `*_utils.go`, `*_helper.go`, `helpers.go`, etc.)

223-249: Add language identifiers to remaining code blocks.

Multiple example and output blocks are missing language identifiers. Add text for output examples and bash for command examples at lines 223-249 and 259-326.

Also applies to: 259-326

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 3714192 and ff6781d.

📒 Files selected for processing (26)
  • .claude-plugin/marketplace.json (1 hunks)
  • PLUGINS.md (2 hunks)
  • docs/data.json (1 hunks)
  • plugins/test-coverage/.claude-plugin/plugin.json (1 hunks)
  • plugins/test-coverage/README.md (1 hunks)
  • plugins/test-coverage/URL_SUPPORT.md (1 hunks)
  • plugins/test-coverage/__init__.py (1 hunks)
  • plugins/test-coverage/commands/analyze.md (1 hunks)
  • plugins/test-coverage/commands/gaps.md (1 hunks)
  • plugins/test-coverage/skills/__init__.py (1 hunks)
  • plugins/test-coverage/skills/analyze/README.md (1 hunks)
  • plugins/test-coverage/skills/analyze/SKILL.md (1 hunks)
  • plugins/test-coverage/skills/analyze/__init__.py (1 hunks)
  • plugins/test-coverage/skills/analyze/test_gap_reports.py (1 hunks)
  • plugins/test-coverage/skills/analyze/test_structure_analyzer.py (1 hunks)
  • plugins/test-coverage/skills/analyze/test_structure_reports.py (1 hunks)
  • plugins/test-coverage/skills/common/__init__.py (1 hunks)
  • plugins/test-coverage/skills/common/report_styles.py (1 hunks)
  • plugins/test-coverage/skills/gaps/README.md (1 hunks)
  • plugins/test-coverage/skills/gaps/SKILL.md (1 hunks)
  • plugins/test-coverage/skills/gaps/__init__.py (1 hunks)
  • plugins/test-coverage/skills/gaps/gap_analyzer.py (1 hunks)
  • plugins/test-coverage/skills/gaps/report_template.py (1 hunks)
  • plugins/test-coverage/skills/gaps/reports.py (1 hunks)
  • plugins/test-coverage/utils/__init__.py (1 hunks)
  • plugins/test-coverage/utils/path_handler.py (1 hunks)
✅ Files skipped from review due to trivial changes (3)
  • plugins/test-coverage/.claude-plugin/plugin.json
  • plugins/test-coverage/skills/analyze/init.py
  • PLUGINS.md
🚧 Files skipped from review as they are similar to previous changes (6)
  • plugins/test-coverage/skills/common/init.py
  • plugins/test-coverage/init.py
  • .claude-plugin/marketplace.json
  • plugins/test-coverage/skills/gaps/init.py
  • plugins/test-coverage/skills/init.py
  • plugins/test-coverage/utils/init.py
🧰 Additional context used
🪛 LanguageTool
plugins/test-coverage/skills/gaps/SKILL.md

[duplication] ~172-~172: Possible typo: you repeated a word.
Context: ...age, service type/volume mode, scenario coverage - Coverage matrices: Visual tables showing what ...

(ENGLISH_WORD_REPEAT_RULE)


[uncategorized] ~175-~175: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ... - Priority indicators: High/medium/low priority badges for each gap - **Test cases list...

(EN_COMPOUND_ADJECTIVE_INTERNAL)

plugins/test-coverage/commands/analyze.md

[uncategorized] ~30-~30: Loose punctuation mark.
Context: ...g. ## Arguments - <source-directory>: Path or URL to source code directory/fi...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~38-~38: Loose punctuation mark.
Context: ...st-coverage/cache/ ---output `: Output directory for generated reports ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~41-~41: Loose punctuation mark.
Context: ...and text summary - --priority <level>: Filter results by priority (optional) ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~45-~45: Loose punctuation mark.
Context: ...Default: all - --include-test-utils: Include test utility/helper files in an...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~50-~50: Loose punctuation mark.
Context: ...structure code - --include-unit-tests: Include unit tests in analysis (optiona...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~58-~58: Loose punctuation mark.
Context: ...or Python) - --test-pattern <pattern>: Custom test file pattern (optional) -...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~61-~61: Loose punctuation mark.
Context: .../Test*.java" ---test-structure-only`: Analyze only test file structure, skip ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~265-~265: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ... Example 2: Analyze test structure with high priority filter ``` /test-coverage:analyze ./pk...

(EN_COMPOUND_ADJECTIVE_INTERNAL)

plugins/test-coverage/skills/analyze/README.md

[uncategorized] ~79-~79: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...files without tests ### Example 2: High Priority Gaps Only bash # Analyze only high-...

(EN_COMPOUND_ADJECTIVE_INTERNAL)

plugins/test-coverage/README.md

[uncategorized] ~170-~170: A comma may be missing after the conjunctive/linking adverb ‘Currently’.
Context: ...` flag. --- ## Supported Languages Currently supports Go projects only. | Languag...

(SENT_START_CONJUNCTIVE_LINKING_ADVERB_COMMA)


[uncategorized] ~280-~280: Use a comma before ‘but’ if it connects two independent clauses (unless they are closely connected and short).
Context: ...ude "*.js" ``` ### Issue: No gaps found but code is clearly untested Solution:...

(COMMA_COMPOUND_SENTENCE_2)


[uncategorized] ~333-~333: Loose punctuation mark.
Context: ...ation. ## Related Plugins - jira: Create bug reports with coverage gap co...

(UNLIKELY_OPENING_PUNCTUATION)

plugins/test-coverage/URL_SUPPORT.md

[uncategorized] ~196-~196: Possible missing preposition found.
Context: ...eports HTTP error codes and reasons - Network errors: Reports connection issues wit...

(AI_HYDRA_LEO_MISSING_OF)


[duplication] ~231-~231: Possible typo: you repeated a word.
Context: ...# See Also - /test-coverage:analyze command - /test-coverage:gaps command - [Path Handler Util...

(ENGLISH_WORD_REPEAT_RULE)

plugins/test-coverage/commands/gaps.md

[uncategorized] ~48-~48: Loose punctuation mark.
Context: ... Optional Arguments - --output <path>: Output directory for gap analysis repor...

(UNLIKELY_OPENING_PUNCTUATION)

plugins/test-coverage/skills/gaps/README.md

[uncategorized] ~41-~41: A comma may be missing after the conjunctive/linking adverb ‘Currently’.
Context: ...ntly implemented. ## Language Support Currently supports Go test files only: - Ginkgo B...

(SENT_START_CONJUNCTIVE_LINKING_ADVERB_COMMA)

🪛 markdownlint-cli2 (0.18.1)
plugins/test-coverage/skills/gaps/SKILL.md

213-213: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

plugins/test-coverage/commands/analyze.md

10-10: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


46-46: Spaces inside emphasis markers

(MD037, no-space-in-emphasis)


223-223: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


259-259: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


267-267: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


275-275: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


283-283: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


297-297: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


305-305: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


313-313: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


323-323: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

plugins/test-coverage/skills/analyze/README.md

48-48: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


95-95: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

plugins/test-coverage/README.md

323-323: Bare URL used

(MD034, no-bare-urls)


324-324: Bare URL used

(MD034, no-bare-urls)

plugins/test-coverage/URL_SUPPORT.md

17-17: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


22-22: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


27-27: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


34-34: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


39-39: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


46-46: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

plugins/test-coverage/skills/analyze/SKILL.md

292-292: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🪛 Ruff (0.14.4)
plugins/test-coverage/skills/gaps/reports.py

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

(EXE001)

plugins/test-coverage/skills/analyze/test_gap_reports.py

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

(EXE001)

plugins/test-coverage/skills/gaps/report_template.py

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

(EXE001)


46-46: Multiple statements on one line (colon)

(E701)


47-47: Multiple statements on one line (colon)

(E701)


48-48: Multiple statements on one line (colon)

(E701)


49-49: Multiple statements on one line (colon)

(E701)


258-258: Unused function argument: component_type

(ARG001)


306-306: Function definition does not bind loop variable no_stack_specified

(B023)


311-311: Function definition does not bind loop variable has_dualstack

(B023)


313-313: Function definition does not bind loop variable has_ipv6

(B023)


315-315: Function definition does not bind loop variable has_ipv4

(B023)


354-354: Unused function argument: component_type

(ARG001)


373-373: Do not assign a lambda expression, use a def

Rewrite ipv4_only as a def

(E731)


446-446: Unused function argument: scores

(ARG001)

plugins/test-coverage/skills/analyze/test_structure_reports.py

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

(EXE001)


150-150: String contains ambiguous (INFORMATION SOURCE). Did you mean i (LATIN SMALL LETTER I)?

(RUF001)

plugins/test-coverage/skills/gaps/gap_analyzer.py

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

(EXE001)


624-624: Local variable gaps is assigned to but never used

Remove assignment to unused variable gaps

(F841)


794-794: f-string without any placeholders

Remove extraneous f prefix

(F541)

plugins/test-coverage/skills/analyze/test_structure_analyzer.py

84-84: Unused function argument: language

(ARG001)


90-90: Unused function argument: language

(ARG001)


90-90: PEP 484 prohibits implicit Optional

Convert to T | None

(RUF013)


131-131: Unused function argument: language

(ARG001)


207-207: Do not catch blind exception: Exception

(BLE001)


276-276: Local variable base_indent is assigned to but never used

Remove assignment to unused variable base_indent

(F841)


301-301: Local variable context_name is assigned to but never used

Remove assignment to unused variable context_name

(F841)


326-326: Unused function argument: language

(ARG001)


378-378: Unused function argument: language

(ARG001)


401-401: Unused function argument: language

(ARG001)


421-421: Local variable source_by_path is assigned to but never used

Remove assignment to unused variable source_by_path

(F841)


458-458: Unused function argument: file_path

(ARG001)


684-684: f-string without any placeholders

Remove extraneous f prefix

(F541)


708-708: Do not catch blind exception: Exception

(BLE001)


762-762: Do not catch blind exception: Exception

(BLE001)


773-773: Do not catch blind exception: Exception

(BLE001)


852-852: Do not catch blind exception: Exception

(BLE001)


866-866: Consider moving this statement to an else block

(TRY300)


868-868: Do not catch blind exception: Exception

(BLE001)

plugins/test-coverage/skills/common/report_styles.py

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

(EXE001)

plugins/test-coverage/utils/path_handler.py

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

(EXE001)


118-118: Probable use of insecure hash functions in hashlib: md5

(S324)


163-163: Audit URL open for permitted schemes. Allowing use of file: or custom schemes is often unexpected.

(S310)


165-165: Audit URL open for permitted schemes. Allowing use of file: or custom schemes is often unexpected.

(S310)


188-188: Do not catch blind exception: Exception

(BLE001)

🔇 Additional comments (2)
plugins/test-coverage/skills/gaps/README.md (1)

1-68: Documentation is clear and accurate.

The README correctly documents that the CLI requires local file paths and that URL support is handled at the command level, not the skill level. This aligns with the architectural separation.

plugins/test-coverage/commands/gaps.md (1)

1-282: Comprehensive command documentation.

The gaps command documentation is well-structured, provides clear examples for multiple components (networking, storage, auth, etc.), and properly documents the component-agnostic analysis approach. All report formats are clearly described.

Copy link
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)
plugins/test-coverage/README.md (1)

309-315: Java patterns in Go-only plugin example.

Line 314 shows Java test patterns (**/*Spec.java,**/IT*.java) in the custom test pattern example, which is inconsistent with this plugin's documented Go-only scope (line 170).

Replace with Go-specific patterns:

-/test-coverage:analyze ./src/ --test-pattern "**/*Spec.java,**/IT*.java"
+/test-coverage:analyze ./pkg/ --test-pattern "**/*_test.go,**/*e2e*_test.go"
plugins/test-coverage/URL_SUPPORT.md (1)

117-128: Documentation incorrectly claims FTP and file:// support.

Line 123 states "Identifies HTTP(S), FTP, and file:// URLs" but the actual path_handler.py implementation (lines 59-62) only accepts HTTP(S) URLs for security reasons.

Apply this diff:

-- **URL detection**: Identifies HTTP(S), FTP, and file:// URLs
+- **URL detection**: Identifies HTTP(S) URLs only (file:// and FTP excluded for security)
🧹 Nitpick comments (3)
plugins/test-coverage/skills/analyze/test_structure_analyzer.py (3)

263-304: Remove unused variables in Ginkgo parsing.

Two variables are computed but never used:

  • Line 276: base_indent is calculated but the brace-counting logic doesn't reference it
  • Line 301: context_name is extracted but never used (the comment even acknowledges this)

Apply this diff:

             # Match g.It(...) or It(...)
             it_match = re.search(ginkgo_it_pattern, line)
             if it_match:
                 test_name = it_match.group(1)
 
                 # Find end of It block (look for closing brace at same or lower indent)
                 line_end = i + 1
-                base_indent = len(line) - len(line.lstrip())
                 brace_count = line.count('{') - line.count('}')
 
                 for j in range(i + 1, len(lines)):
                     brace_count += lines[j].count('{') - lines[j].count('}')
                     if brace_count <= 0:
                         line_end = j
                         break
                     if j + 1 == len(lines):
                         line_end = j
 
                 # Extract function calls
                 test_block = '\n'.join(lines[i:line_end + 1])
                 targets = extract_function_calls(test_block, language)
 
                 tests.append(TestFunction(
                     name=f"It: {test_name}",
                     line_start=i + 1,
                     line_end=line_end + 1,
                     targets=targets
                 ))
 
             # Also track Describe/Context blocks for context
             describe_match = re.search(ginkgo_describe_pattern, line)
-            if describe_match and not it_match:  # Don't count lines that are both
-                context_name = describe_match.group(1)
-                # Note: We're not adding these as tests, just tracking them
-                # Could be enhanced to show test hierarchy
+            # Note: Describe/Context tracking could be enhanced to show test hierarchy

416-455: Remove unused lookup dictionary.

Line 421 creates source_by_path but the function never references it—subsequent logic iterates source_files directly.

Apply this diff:

 def map_tests_to_source(test_files: List[TestFile], source_files: List[SourceFile]) -> Dict:
     """Map tests to source files and functions"""
     mapping = {}
 
-    # Create lookup for source files
-    source_by_path = {sf.path: sf for sf in source_files}
-
     # Map each source file
     for source_file in source_files:
         # Find test files that target this source file
         related_tests = [tf for tf in test_files if tf.target_file == source_file.path]

196-210: Tighten exception handling during file discovery.

Lines 207 and 209 catch all exceptions when reading test files, which can hide permission errors, encoding issues, or disk failures. Consider catching specific exceptions and logging warnings so issues don't go unnoticed.

                 if e2e_only:
                     # Read file content to check for e2e markers
                     try:
                         with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
                             content = f.read()
 
                         # Only include if it's identified as an e2e test
                         if is_e2e_test_file(file_path, language, content):
                             test_files.append(file_path)
-                    except Exception:
+                    except (IOError, OSError) as e:
                         # If we can't read the file, use filename/path heuristics only
+                        print(f"Warning: Could not read {file_path}: {e}", file=sys.stderr)
                         if is_e2e_test_file(file_path, language):
                             test_files.append(file_path)
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between ff6781d and 0a122de.

📒 Files selected for processing (25)
  • PLUGINS.md (2 hunks)
  • docs/data.json (1 hunks)
  • plugins/test-coverage/.claude-plugin/plugin.json (1 hunks)
  • plugins/test-coverage/README.md (1 hunks)
  • plugins/test-coverage/URL_SUPPORT.md (1 hunks)
  • plugins/test-coverage/__init__.py (1 hunks)
  • plugins/test-coverage/commands/analyze.md (1 hunks)
  • plugins/test-coverage/commands/gaps.md (1 hunks)
  • plugins/test-coverage/skills/__init__.py (1 hunks)
  • plugins/test-coverage/skills/analyze/README.md (1 hunks)
  • plugins/test-coverage/skills/analyze/SKILL.md (1 hunks)
  • plugins/test-coverage/skills/analyze/__init__.py (1 hunks)
  • plugins/test-coverage/skills/analyze/test_gap_reports.py (1 hunks)
  • plugins/test-coverage/skills/analyze/test_structure_analyzer.py (1 hunks)
  • plugins/test-coverage/skills/analyze/test_structure_reports.py (1 hunks)
  • plugins/test-coverage/skills/common/__init__.py (1 hunks)
  • plugins/test-coverage/skills/common/report_styles.py (1 hunks)
  • plugins/test-coverage/skills/gaps/README.md (1 hunks)
  • plugins/test-coverage/skills/gaps/SKILL.md (1 hunks)
  • plugins/test-coverage/skills/gaps/__init__.py (1 hunks)
  • plugins/test-coverage/skills/gaps/gap_analyzer.py (1 hunks)
  • plugins/test-coverage/skills/gaps/report_template.py (1 hunks)
  • plugins/test-coverage/skills/gaps/reports.py (1 hunks)
  • plugins/test-coverage/utils/__init__.py (1 hunks)
  • plugins/test-coverage/utils/path_handler.py (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
  • plugins/test-coverage/skills/analyze/init.py
  • plugins/test-coverage/skills/common/init.py
  • docs/data.json
  • plugins/test-coverage/utils/init.py
  • plugins/test-coverage/.claude-plugin/plugin.json
🧰 Additional context used
🪛 LanguageTool
plugins/test-coverage/skills/analyze/README.md

[uncategorized] ~79-~79: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...files without tests ### Example 2: High Priority Gaps Only bash # Analyze only high-...

(EN_COMPOUND_ADJECTIVE_INTERNAL)

plugins/test-coverage/README.md

[uncategorized] ~170-~170: A comma may be missing after the conjunctive/linking adverb ‘Currently’.
Context: ...` flag. --- ## Supported Languages Currently supports Go projects only. | Languag...

(SENT_START_CONJUNCTIVE_LINKING_ADVERB_COMMA)


[uncategorized] ~280-~280: Use a comma before ‘but’ if it connects two independent clauses (unless they are closely connected and short).
Context: ...ude "*.js" ``` ### Issue: No gaps found but code is clearly untested Solution:...

(COMMA_COMPOUND_SENTENCE_2)


[uncategorized] ~333-~333: Loose punctuation mark.
Context: ...ation. ## Related Plugins - jira: Create bug reports with coverage gap co...

(UNLIKELY_OPENING_PUNCTUATION)

plugins/test-coverage/URL_SUPPORT.md

[uncategorized] ~196-~196: Possible missing preposition found.
Context: ...eports HTTP error codes and reasons - Network errors: Reports connection issues wit...

(AI_HYDRA_LEO_MISSING_OF)


[duplication] ~231-~231: Possible typo: you repeated a word.
Context: ...# See Also - /test-coverage:analyze command - /test-coverage:gaps command - [Path Handler Util...

(ENGLISH_WORD_REPEAT_RULE)

plugins/test-coverage/commands/analyze.md

[uncategorized] ~30-~30: Loose punctuation mark.
Context: ...g. ## Arguments - <source-directory>: Path or URL to source code directory/fi...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~38-~38: Loose punctuation mark.
Context: ...st-coverage/cache/ ---output `: Output directory for generated reports ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~41-~41: Loose punctuation mark.
Context: ...and text summary - --priority <level>: Filter results by priority (optional) ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~45-~45: Loose punctuation mark.
Context: ...Default: all - --include-test-utils: Include test utility/helper files in an...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~50-~50: Loose punctuation mark.
Context: ...structure code - --include-unit-tests: Include unit tests in analysis (optiona...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~58-~58: Loose punctuation mark.
Context: ...or Python) - --test-pattern <pattern>: Custom test file pattern (optional) -...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~61-~61: Loose punctuation mark.
Context: .../Test*.java" ---test-structure-only`: Analyze only test file structure, skip ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~265-~265: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ... Example 2: Analyze test structure with high priority filter ``` /test-coverage:analyze ./pk...

(EN_COMPOUND_ADJECTIVE_INTERNAL)

plugins/test-coverage/commands/gaps.md

[uncategorized] ~48-~48: Loose punctuation mark.
Context: ... Optional Arguments - --output <path>: Output directory for gap analysis repor...

(UNLIKELY_OPENING_PUNCTUATION)

plugins/test-coverage/skills/gaps/README.md

[uncategorized] ~41-~41: A comma may be missing after the conjunctive/linking adverb ‘Currently’.
Context: ...ntly implemented. ## Language Support Currently supports Go test files only: - Ginkgo B...

(SENT_START_CONJUNCTIVE_LINKING_ADVERB_COMMA)

plugins/test-coverage/skills/gaps/SKILL.md

[duplication] ~172-~172: Possible typo: you repeated a word.
Context: ...age, service type/volume mode, scenario coverage - Coverage matrices: Visual tables showing what ...

(ENGLISH_WORD_REPEAT_RULE)


[uncategorized] ~175-~175: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ... - Priority indicators: High/medium/low priority badges for each gap - **Test cases list...

(EN_COMPOUND_ADJECTIVE_INTERNAL)

🪛 markdownlint-cli2 (0.18.1)
plugins/test-coverage/commands/analyze.md

10-10: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


46-46: Spaces inside emphasis markers

(MD037, no-space-in-emphasis)


223-223: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


259-259: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


267-267: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


275-275: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


283-283: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


297-297: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


305-305: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


313-313: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


323-323: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

plugins/test-coverage/skills/analyze/SKILL.md

292-292: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

plugins/test-coverage/skills/gaps/SKILL.md

17-17: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


22-22: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


27-27: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


34-34: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


39-39: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


46-46: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🪛 Ruff (0.14.4)
plugins/test-coverage/skills/gaps/report_template.py

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

(EXE001)


46-46: Multiple statements on one line (colon)

(E701)


47-47: Multiple statements on one line (colon)

(E701)


48-48: Multiple statements on one line (colon)

(E701)


49-49: Multiple statements on one line (colon)

(E701)


257-257: Unused function argument: component_type

(ARG001)


305-305: Function definition does not bind loop variable no_stack_specified

(B023)


310-310: Function definition does not bind loop variable has_dualstack

(B023)


312-312: Function definition does not bind loop variable has_ipv6

(B023)


314-314: Function definition does not bind loop variable has_ipv4

(B023)


353-353: Unused function argument: component_type

(ARG001)


372-372: Do not assign a lambda expression, use a def

Rewrite ipv4_only as a def

(E731)


445-445: Unused function argument: scores

(ARG001)

plugins/test-coverage/skills/analyze/test_structure_reports.py

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

(EXE001)


153-153: String contains ambiguous (INFORMATION SOURCE). Did you mean i (LATIN SMALL LETTER I)?

(RUF001)

plugins/test-coverage/utils/path_handler.py

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

(EXE001)


118-118: Probable use of insecure hash functions in hashlib: md5

(S324)


163-163: Audit URL open for permitted schemes. Allowing use of file: or custom schemes is often unexpected.

(S310)


165-165: Audit URL open for permitted schemes. Allowing use of file: or custom schemes is often unexpected.

(S310)


188-188: Do not catch blind exception: Exception

(BLE001)

plugins/test-coverage/skills/gaps/gap_analyzer.py

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

(EXE001)


743-743: Local variable gaps is assigned to but never used

Remove assignment to unused variable gaps

(F841)


961-961: f-string without any placeholders

Remove extraneous f prefix

(F541)

plugins/test-coverage/skills/gaps/reports.py

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

(EXE001)

plugins/test-coverage/skills/analyze/test_structure_analyzer.py

84-84: Unused function argument: language

(ARG001)


90-90: Unused function argument: language

(ARG001)


90-90: PEP 484 prohibits implicit Optional

Convert to T | None

(RUF013)


131-131: Unused function argument: language

(ARG001)


207-207: Do not catch blind exception: Exception

(BLE001)


276-276: Local variable base_indent is assigned to but never used

Remove assignment to unused variable base_indent

(F841)


301-301: Local variable context_name is assigned to but never used

Remove assignment to unused variable context_name

(F841)


326-326: Unused function argument: language

(ARG001)


378-378: Unused function argument: language

(ARG001)


401-401: Unused function argument: language

(ARG001)


421-421: Local variable source_by_path is assigned to but never used

Remove assignment to unused variable source_by_path

(F841)


458-458: Unused function argument: file_path

(ARG001)


684-684: f-string without any placeholders

Remove extraneous f prefix

(F541)


708-708: Do not catch blind exception: Exception

(BLE001)


762-762: Do not catch blind exception: Exception

(BLE001)


773-773: Do not catch blind exception: Exception

(BLE001)


852-852: Do not catch blind exception: Exception

(BLE001)


866-866: Consider moving this statement to an else block

(TRY300)


868-868: Do not catch blind exception: Exception

(BLE001)

plugins/test-coverage/skills/analyze/test_gap_reports.py

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

(EXE001)

plugins/test-coverage/skills/common/report_styles.py

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

(EXE001)

🔇 Additional comments (13)
plugins/test-coverage/skills/__init__.py (1)

1-1: LGTM!

Clean package initializer with appropriate docstring.

plugins/test-coverage/commands/gaps.md (1)

1-282: LGTM!

Comprehensive command documentation with clear examples, implementation details, and component-agnostic approach. The documentation properly describes the gaps analysis workflow and all three report formats.

plugins/test-coverage/__init__.py (1)

1-7: LGTM!

Standard Python package initialization with appropriate docstring and version export. The version '0.0.1' aligns with the initial release mentioned in the broader PR context.

plugins/test-coverage/commands/analyze.md (1)

1-361: LGTM!

Excellent command documentation with comprehensive coverage of both analysis modes (full coverage and test-structure-only), clear implementation steps, and diverse examples covering local and remote inputs. The dual-mode design is well-explained and the URL support integration is properly documented.

PLUGINS.md (1)

18-18: LGTM!

Clean integration of the Test Coverage plugin into the plugin index. The navigation entry and plugin section are properly formatted with accurate command synopses that align with the detailed documentation.

Also applies to: 176-184

plugins/test-coverage/utils/path_handler.py (1)

1-330: LGTM! Solid utility implementation.

The PathHandler class is well-designed with:

  • Strong security: Restricts to HTTP(S) only with explicit scheme validation (lines 59-62, 150-154)
  • Smart URL conversion: Properly handles GitHub/GitLab blob URLs while preserving archive URLs (lines 88-96)
  • Robust caching: MD5-based cache naming with collision avoidance (lines 107-136)
  • Comprehensive error handling: Specific exception types with descriptive messages (lines 182-190)
  • Clean API: Convenience functions and CLI for easy integration (lines 274-330)

The static analysis warnings about MD5 (S324) and broad Exception catch (BLE001) are false positives in this context—MD5 is appropriate for cache keys, and the catch-all ensures graceful degradation with proper error reporting.

plugins/test-coverage/skills/analyze/test_structure_reports.py (1)

26-529: LGTM! Clean report generation architecture.

The report generator is well-structured with clear separation between test-only mode, full-structure mode, and comprehensive reports. The multi-fallback import approach for get_common_css ensures compatibility across different execution contexts.

plugins/test-coverage/skills/gaps/__init__.py (1)

1-1: LGTM!

Simple package initializer with appropriate docstring.

plugins/test-coverage/skills/analyze/README.md (1)

1-128: LGTM! Documentation is consistent with Go-only implementation.

The README correctly focuses on Go support throughout, with appropriate examples using _test.go files and Go-specific patterns. The supported language table clearly indicates Go-only support.

plugins/test-coverage/skills/gaps/README.md (1)

1-67: LGTM! Clear documentation of current capabilities.

The README accurately describes the gap analysis tool and explicitly states that URL support is not yet implemented (line 38), setting correct user expectations.

plugins/test-coverage/skills/analyze/SKILL.md (1)

1-414: LGTM! Comprehensive skill documentation.

The SKILL.md provides thorough guidance for implementing test structure analysis, with clear prerequisites, detailed workflow steps, output format specifications, and practical examples. The Go-only scope is explicitly stated.

plugins/test-coverage/skills/common/report_styles.py (1)

7-322: LGTM! Clean CSS provider module.

The module provides a well-structured CSS stylesheet for HTML reports with consistent styling for tables, badges, progress bars, and cards. Single-responsibility design makes it easy to maintain.

plugins/test-coverage/skills/gaps/SKILL.md (1)

1-392: LGTM! Documentation accurately reflects implementation.

The SKILL.md clearly distinguishes between current implementation (single-file regex-based analysis) and future capabilities, with an explicit limitations section (lines 151-163). The Go-only scope is stated upfront, and URL support is correctly marked as not yet implemented.

Copy link
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 (3)
plugins/test-coverage/skills/analyze/test_structure_analyzer.py (1)

642-876: Wire up the --exclude patterns argument.

The CLI parser accepts --exclude-patterns at the argument level (though not visible in annotated code, it's implied by past review context), but the patterns are never applied to filter the discovered files. This means the flag is a no-op, and users cannot exclude vendor/generated paths as documented.

After the discover_files() call (line 736-738), add filtering logic:

             test_files_paths, source_files_paths = discover_files(
                 source_dir, language, e2e_only=e2e_only
             )
+
+            # Apply exclude patterns if specified
+            if hasattr(args, 'exclude_patterns') and args.exclude_patterns:
+                from fnmatch import fnmatch
+                
+                def is_excluded(path):
+                    return any(fnmatch(path, pattern) for pattern in args.exclude_patterns)
+                
+                test_files_paths = [p for p in test_files_paths if not is_excluded(p)]
+                source_files_paths = [p for p in source_files_paths if not is_excluded(p)]

             # If test-structure-only mode, ignore discovered source files
             if test_only_mode:

Note: The argument parsing for --exclude-patterns needs to be added to the parser if not already present. Check the argparse setup around line 649.

plugins/test-coverage/URL_SUPPORT.md (1)

123-124: Fix URL detection claim: HTTP(S) only.

-- **URL detection**: Identifies HTTP(S), FTP, and file:// URLs
+- **URL detection**: Identifies HTTP(S) URLs only (file:// and FTP are not supported)
plugins/test-coverage/skills/gaps/gap_analyzer.py (1)

949-954: Include all gap categories in CLI summary.

-    all_gaps = []
-    for key in ('platforms', 'scenarios'):
-        all_gaps.extend(analysis['gaps'].get(key, []))
+    all_gaps = [
+        gap
+        for gap_list in analysis['gaps'].values()
+        if isinstance(gap_list, list)
+        for gap in gap_list
+    ]
     high_priority = [g for g in all_gaps if g.get('priority') == 'high']
🧹 Nitpick comments (10)
plugins/test-coverage/skills/common/report_styles.py (1)

1-1: Remove shebang from library module.

This file is a library module imported by other scripts, not a standalone executable. The shebang line is unnecessary and triggers static analysis warnings.

Apply this diff:

-#!/usr/bin/env python3
 """
 Shared CSS styles for HTML reports across all test coverage skills
 """
plugins/test-coverage/skills/gaps/SKILL.md (3)

140-148: Align scoring bullets with implementation (include IP stack/topology).

Networking scoring omits IP stack and topology, but the code scores them. Update Step 5 to match behavior.

-**Networking components:**
-- Overall = avg(platform_score, protocol_score, service_type_score, scenario_score)
+**Networking components:**
+- Overall = avg(platform_score, protocol_score, service_type_score, ip_stack_coverage, topology_coverage, scenario_score)

171-176: Hyphenate compound adjective.

Use “high-/medium-/low-priority badges” before the noun.

-- **Priority indicators**: High/medium/low priority badges for each gap
+- **Priority indicators**: high-/medium-/low-priority badges for each gap

375-378: Use a test-file example to reduce confusion.

Ginkgo tests typically live in *_test.go. Recommend adjusting Example 3.

-  /path/to/local/test/extended/networking/egressip.go \
+  /path/to/local/test/extended/networking/egressip_test.go \

If non-* _test.go files are also valid in your repo, please ignore and confirm here.

plugins/test-coverage/URL_SUPPORT.md (1)

51-57: Clarify command-level URL support vs script local-path requirement.

SKILL.md notes the analyzer script consumes local paths. Add a brief note to prevent confusion.

 ## How It Works
+> Note: URL support is provided at the command level via PathHandler. The underlying analyzer script (`skills/gaps/gap_analyzer.py`) currently expects a local file path; commands resolve URLs to local files before invoking it.
plugins/test-coverage/skills/analyze/test_structure_reports.py (1)

1-1: I/O hygiene and minor lint: encoding, shebang, unused import.

-#!/usr/bin/env python3
+# (shebang removed; module is imported, not executed)

-import json
+# import json  # unused; remove if not needed

-    with open(output_path, 'w') as f:
+    with open(output_path, 'w', encoding='utf-8') as f:
         f.write(html)

-    with open(output_path, 'w') as f:
+    with open(output_path, 'w', encoding='utf-8') as f:
         f.write(html)

-    with open(output_path, 'w') as f:
+    with open(output_path, 'w', encoding='utf-8') as f:
         f.write(html)

If you intend to execute this file directly, keep the shebang and mark it executable instead.

Also applies to: 7-7, 165-167, 249-251, 528-529

plugins/test-coverage/skills/gaps/reports.py (1)

1-1: Add UTF‑8 encoding on writes; remove shebang or make file executable.

-#!/usr/bin/env python3
+# (shebang removed; module is imported, not executed)

-    with open(output_path, 'w') as f:
+    with open(output_path, 'w', encoding='utf-8') as f:
         f.write(html)

-    with open(output_path, 'w') as f:
+    with open(output_path, 'w', encoding='utf-8') as f:
         json.dump(report, f, indent=2)

-    with open(output_path, 'w') as f:
+    with open(output_path, 'w', encoding='utf-8') as f:
         f.write('\n'.join(lines))

Also applies to: 404-405, 416-418, 588-589

plugins/test-coverage/skills/gaps/report_template.py (1)

1-1: Resolve Ruff lint (E701, E731, ARG001, B023) and portability.

-#!/usr/bin/env python3
+# (shebang removed; module is imported, not executed)

-from datetime import datetime
-from typing import Dict, List
-import re
+from datetime import datetime
+from typing import Dict, List
+import os
+import re

-    def get_score_class(score):
-        if score >= 80: return 'excellent'
-        elif score >= 60: return 'good'
-        elif score >= 40: return 'fair'
-        else: return 'poor'
+    def get_score_class(score):
+        if score >= 80:
+            return 'excellent'
+        elif score >= 60:
+            return 'good'
+        elif score >= 40:
+            return 'fair'
+        else:
+            return 'poor'

-    file_name = analysis['file'].split('/')[-1]
+    file_name = os.path.basename(analysis['file'])

-def _analyze_feature_coverage(test_cases: List[Dict], component_type: str = 'unknown') -> Dict:
+def _analyze_feature_coverage(test_cases: List[Dict]) -> Dict:

-        def set_ip_stack(feature_name):
+        def set_ip_stack(feature_name, no_stack=no_stack_specified, has_ds=has_dualstack, has_v6=has_ipv6, has_v4=has_ipv4):
             if feature_name in features:
-                if no_stack_specified:
+                if no_stack:
                     # Test doesn't specify stack in name - mark all as tested
                     features[feature_name]['ipv4'] = True
                     features[feature_name]['ipv6'] = True
                     features[feature_name]['dualstack'] = True
-                elif has_dualstack:
+                elif has_ds:
                     features[feature_name]['dualstack'] = True
-                elif has_ipv6:
+                elif has_v6:
                     features[feature_name]['ipv6'] = True
-                elif has_ipv4:
+                elif has_v4:
                     features[feature_name]['ipv4'] = True

-def _analyze_scenario_coverage(test_cases: List[Dict], component_type: str = 'unknown') -> Dict:
+def _analyze_scenario_coverage(test_cases: List[Dict]) -> Dict:

-    ipv4_only = lambda tests: all('ipv4' in t.get('name', '').lower() and 'ipv6' not in t.get('name', '').lower() for t in tests if tests)
+    def ipv4_only(tests):
+        return all('ipv4' in t.get('name', '').lower() and 'ipv6' not in t.get('name', '').lower() for t in tests if tests)

-def _generate_whats_tested_section(coverage: Dict, scores: Dict, test_cases: List[Dict], component_type: str = 'unknown') -> str:
+def _generate_whats_tested_section(coverage: Dict, test_cases: List[Dict], component_type: str = 'unknown') -> str:
@@
-    html += _generate_whats_tested_section(coverage, scores, test_cases, component.lower())
+    html += _generate_whats_tested_section(coverage, test_cases, component.lower())

Rationale: fixes style/lint, removes unused parameters, and avoids closure late-binding surprises without changing behavior.

Also applies to: 44-49, 257-259, 303-316, 353-355, 372-375, 445-446, 14-16

plugins/test-coverage/skills/gaps/gap_analyzer.py (1)

1-1: Minor hygiene: remove unused local and shebang.

-#!/usr/bin/env python3
+# (shebang removed; CLI entry is guarded by __main__)

-        gaps = analysis['gaps']
+        # gaps = analysis['gaps']  # unused; remove

Also applies to: 749-750

plugins/test-coverage/skills/analyze/test_gap_reports.py (1)

1-1: Add UTF‑8 encoding on writes; remove shebang or mark executable.

-#!/usr/bin/env python3
+# (shebang removed; module is imported, not executed)

-    with open(output_path, 'w') as f:
+    with open(output_path, 'w', encoding='utf-8') as f:
         f.write(html)
@@
-    with open(output_path, 'w') as f:
+    with open(output_path, 'w', encoding='utf-8') as f:
         f.write('\n'.join(lines))

Also applies to: 590-592, 805-807

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 0a122de and bde8952.

📒 Files selected for processing (25)
  • PLUGINS.md (2 hunks)
  • plugins/openshift/commands/create-cluster.md (3 hunks)
  • plugins/test-coverage/.claude-plugin/plugin.json (1 hunks)
  • plugins/test-coverage/README.md (1 hunks)
  • plugins/test-coverage/URL_SUPPORT.md (1 hunks)
  • plugins/test-coverage/__init__.py (1 hunks)
  • plugins/test-coverage/commands/analyze.md (1 hunks)
  • plugins/test-coverage/commands/gaps.md (1 hunks)
  • plugins/test-coverage/skills/__init__.py (1 hunks)
  • plugins/test-coverage/skills/analyze/README.md (1 hunks)
  • plugins/test-coverage/skills/analyze/SKILL.md (1 hunks)
  • plugins/test-coverage/skills/analyze/__init__.py (1 hunks)
  • plugins/test-coverage/skills/analyze/test_gap_reports.py (1 hunks)
  • plugins/test-coverage/skills/analyze/test_structure_analyzer.py (1 hunks)
  • plugins/test-coverage/skills/analyze/test_structure_reports.py (1 hunks)
  • plugins/test-coverage/skills/common/__init__.py (1 hunks)
  • plugins/test-coverage/skills/common/report_styles.py (1 hunks)
  • plugins/test-coverage/skills/gaps/README.md (1 hunks)
  • plugins/test-coverage/skills/gaps/SKILL.md (1 hunks)
  • plugins/test-coverage/skills/gaps/__init__.py (1 hunks)
  • plugins/test-coverage/skills/gaps/gap_analyzer.py (1 hunks)
  • plugins/test-coverage/skills/gaps/report_template.py (1 hunks)
  • plugins/test-coverage/skills/gaps/reports.py (1 hunks)
  • plugins/test-coverage/utils/__init__.py (1 hunks)
  • plugins/test-coverage/utils/path_handler.py (1 hunks)
✅ Files skipped from review due to trivial changes (4)
  • plugins/test-coverage/.claude-plugin/plugin.json
  • plugins/test-coverage/skills/gaps/README.md
  • plugins/openshift/commands/create-cluster.md
  • plugins/test-coverage/commands/gaps.md
🚧 Files skipped from review as they are similar to previous changes (6)
  • plugins/test-coverage/skills/init.py
  • plugins/test-coverage/skills/common/init.py
  • plugins/test-coverage/skills/gaps/init.py
  • plugins/test-coverage/utils/init.py
  • PLUGINS.md
  • plugins/test-coverage/skills/analyze/init.py
🧰 Additional context used
🪛 LanguageTool
plugins/test-coverage/commands/analyze.md

[uncategorized] ~265-~265: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ... Example 2: Analyze test structure with high priority filter ``` /test-coverage:analyze ./pk...

(EN_COMPOUND_ADJECTIVE_INTERNAL)

plugins/test-coverage/skills/gaps/SKILL.md

[uncategorized] ~175-~175: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ... - Priority indicators: High/medium/low priority badges for each gap - **Test cases list...

(EN_COMPOUND_ADJECTIVE_INTERNAL)

plugins/test-coverage/skills/analyze/README.md

[uncategorized] ~79-~79: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...files without tests ### Example 2: High Priority Gaps Only bash # Analyze only high-...

(EN_COMPOUND_ADJECTIVE_INTERNAL)

🪛 markdownlint-cli2 (0.18.1)
plugins/test-coverage/URL_SUPPORT.md

213-213: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

plugins/test-coverage/commands/analyze.md

10-10: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


46-46: Spaces inside emphasis markers

(MD037, no-space-in-emphasis)


223-223: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


259-259: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


267-267: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


275-275: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


283-283: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


297-297: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


305-305: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


313-313: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


323-323: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

plugins/test-coverage/skills/gaps/SKILL.md

213-213: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

plugins/test-coverage/README.md

17-17: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


22-22: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


27-27: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


34-34: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


39-39: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


46-46: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

plugins/test-coverage/skills/analyze/README.md

48-48: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


95-95: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

plugins/test-coverage/skills/analyze/SKILL.md

292-292: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🪛 Ruff (0.14.4)
plugins/test-coverage/skills/analyze/test_structure_reports.py

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

(EXE001)


153-153: String contains ambiguous (INFORMATION SOURCE). Did you mean i (LATIN SMALL LETTER I)?

(RUF001)

plugins/test-coverage/utils/path_handler.py

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

(EXE001)


118-118: Probable use of insecure hash functions in hashlib: md5

(S324)


163-163: Audit URL open for permitted schemes. Allowing use of file: or custom schemes is often unexpected.

(S310)


165-165: Audit URL open for permitted schemes. Allowing use of file: or custom schemes is often unexpected.

(S310)


188-188: Do not catch blind exception: Exception

(BLE001)

plugins/test-coverage/skills/analyze/test_gap_reports.py

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

(EXE001)

plugins/test-coverage/skills/analyze/test_structure_analyzer.py

84-84: Unused function argument: language

(ARG001)


90-90: Unused function argument: language

(ARG001)


90-90: PEP 484 prohibits implicit Optional

Convert to T | None

(RUF013)


131-131: Unused function argument: language

(ARG001)


276-276: Local variable base_indent is assigned to but never used

Remove assignment to unused variable base_indent

(F841)


301-301: Local variable context_name is assigned to but never used

Remove assignment to unused variable context_name

(F841)


326-326: Unused function argument: language

(ARG001)


378-378: Unused function argument: language

(ARG001)


401-401: Unused function argument: language

(ARG001)


421-421: Local variable source_by_path is assigned to but never used

Remove assignment to unused variable source_by_path

(F841)


458-458: Unused function argument: file_path

(ARG001)


684-684: f-string without any placeholders

Remove extraneous f prefix

(F541)


852-852: Do not catch blind exception: Exception

(BLE001)


866-866: Consider moving this statement to an else block

(TRY300)


868-868: Do not catch blind exception: Exception

(BLE001)

plugins/test-coverage/skills/gaps/reports.py

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

(EXE001)

plugins/test-coverage/skills/gaps/gap_analyzer.py

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

(EXE001)


749-749: Local variable gaps is assigned to but never used

Remove assignment to unused variable gaps

(F841)


971-971: f-string without any placeholders

Remove extraneous f prefix

(F541)

plugins/test-coverage/skills/common/report_styles.py

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

(EXE001)

plugins/test-coverage/skills/gaps/report_template.py

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

(EXE001)


46-46: Multiple statements on one line (colon)

(E701)


47-47: Multiple statements on one line (colon)

(E701)


48-48: Multiple statements on one line (colon)

(E701)


49-49: Multiple statements on one line (colon)

(E701)


257-257: Unused function argument: component_type

(ARG001)


305-305: Function definition does not bind loop variable no_stack_specified

(B023)


310-310: Function definition does not bind loop variable has_dualstack

(B023)


312-312: Function definition does not bind loop variable has_ipv6

(B023)


314-314: Function definition does not bind loop variable has_ipv4

(B023)


353-353: Unused function argument: component_type

(ARG001)


372-372: Do not assign a lambda expression, use a def

Rewrite ipv4_only as a def

(E731)


445-445: Unused function argument: scores

(ARG001)

🔇 Additional comments (3)
plugins/test-coverage/__init__.py (1)

1-7: LGTM!

Clean module initialization with proper docstring and semantic versioning. The __version__ variable follows Python packaging conventions.

plugins/test-coverage/utils/path_handler.py (1)

1-330: Code looks good overall.

The past review comments have been properly addressed:

  • URL scheme validation restricts to HTTP(S) only for security
  • GitHub blob URL handling preserves archive URLs
  • The shebang is appropriate since this file includes a CLI interface (lines 306-330)

The static analysis hints about MD5 and URL opening are false positives - MD5 is used for cache key generation (not cryptographic security), and URL schemes are explicitly validated before opening.

plugins/test-coverage/skills/analyze/test_structure_analyzer.py (1)

683-683: Language detection is correctly hard-coded to Go.

The code explicitly documents "Go only" support (lines 3, 8, 24, 39, 169, 644) and the analyzer is designed specifically for Go test patterns. Hard-coding language = 'go' is the correct approach since this analyzer doesn't support other languages yet.

The past review comment suggesting to call detect_language() is not applicable here - there is no detect_language() function defined in this file, and the Go-only focus is intentional and well-documented.

Signed-off-by: Anurag Saxena <[email protected]>

add test-coverage structure and gap analysis

Signed-off-by: Anurag Saxena <[email protected]>

keeping go format references only

Signed-off-by: Anurag Saxena <[email protected]>

Removed comapre cmd, holding off for later version if needed

Removed multi-language support but just Go

Removed compare logic across releases

Addresses codeRabbit comments

Removed README_OLD.md

Addressed test structure analyzer fixes and gaps

add test-coverage structure and gap analysis plugin

remove unwanted --exlude-only flag

Addressed corerabbit comments

addressed corerabbit comments

removed running tests option to obtain reports and coderabbit comments

addressed coderabbit comments

addresses code reabbit comments

addressed coderabbit comments

improvements for score cards

coderabbit comments

coderabbit comments

coderabbit comments

addressed coderabbit comments

addressed coderabbit comments

addressed coderabbit comments
@anuragthehatter anuragthehatter changed the title WIP: feat(test-coverage): add test-coverage's structure and gap analysis Add test-coverage plugin for E2E test structure analysis Nov 11, 2025
@openshift-ci openshift-ci bot removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Nov 11, 2025
Copy link
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: 3

♻️ Duplicate comments (2)
plugins/test-coverage/README.md (1)

314-314: Replace Java pattern with Go-specific example.

This example still references Java test patterns (*Spec.java, IT*.java), which contradicts the plugin's documented Go-only scope. A past review flagged this issue and marked it as addressed, but the Java example remains.

Replace with a Go-specific example:

-/test-coverage:analyze ./src/ --test-pattern "**/*Spec.java,**/IT*.java"
+/test-coverage:analyze ./pkg/ --test-pattern "**/*_test.go,**/*e2e*_test.go,**/*integration*_test.go"
plugins/test-coverage/URL_SUPPORT.md (1)

123-123: Remove incorrect FTP and file:// claim.

The documentation states that PathHandler "Identifies HTTP(S), FTP, and file:// URLs" but the implementation in path_handler.py (lines 59-62) only accepts HTTP(S) patterns for security reasons. A past review flagged this issue and marked it as addressed, but the incorrect claim remains.

Apply this diff:

-- **URL detection**: Identifies HTTP(S), FTP, and file:// URLs
+- **URL detection**: Identifies HTTP(S) URLs only (file:// and FTP excluded for security)

Based on learnings

🧹 Nitpick comments (31)
plugins/test-coverage/skills/analyze/SKILL.md (1)

292-317: Add language specifier to fenced code block.

The text summary example block is missing a language identifier. Add text to improve rendering and satisfy linting.

Apply this diff:

-```
+```text
 Test Structure Analysis
 ═══════════════════════════════════════════════════
plugins/test-coverage/README.md (2)

48-78: Add language specifier to usage example.

The code block is missing a language identifier for proper syntax highlighting.

Apply this diff:

 **Usage:**
-```
+```bash
 /test-coverage:analyze <source-directory> [options]

---

`90-129`: **Add language specifier to usage example.**

The code block is missing a language identifier.


Apply this diff:

```diff
 **Usage:**
-```
+```bash
 /test-coverage:gaps <test-file> [options]

</blockquote></details>
<details>
<summary>plugins/test-coverage/skills/analyze/README.md (1)</summary><blockquote>

`79-85`: **Hyphenate the compound adjective.**

“High‑priority gaps” reads better in the heading.


```diff
-### Example 2: High Priority Gaps Only
+### Example 2: High‑priority Gaps Only
plugins/test-coverage/skills/common/report_styles.py (1)

1-1: Remove shebang or make file executable.

Shebang triggers EXE001 since this module isn’t executed directly.

-#!/usr/bin/env python3
plugins/test-coverage/skills/analyze/test_structure_reports.py (6)

7-10: HTML‑escape dynamic content to avoid broken markup.

Escape file/test names before embedding in HTML.

 import json
 import os
+import html
 from datetime import datetime
 from typing import Dict, List

56-81: Escape test names and targets.

Avoid raw insertion into HTML.

-        display_name = test_name.replace("It: ", "")
+        display_name = html.escape(test_name.replace("It: ", ""))
@@
-            targets_list = ', '.join(targets[:10])
+            targets_list = ', '.join(html.escape(t) for t in targets[:10])

88-101: Escape filename in the title/meta.

-    <title>Test Structure Analysis - {file_name}</title>
+    <title>Test Structure Analysis - {html.escape(file_name)}</title>
@@
-                <strong>File:</strong> {file_name} |
+                <strong>File:</strong> {html.escape(file_name)} |

165-166: Write files with UTF‑8 encoding.

-    with open(output_path, 'w') as f:
+    with open(output_path, 'w', encoding='utf-8') as f:
         f.write(html)

249-251: Write files with UTF‑8 encoding.

-    with open(output_path, 'w') as f:
+    with open(output_path, 'w', encoding='utf-8') as f:
         f.write(html)

153-158: Optional: replace the ℹ️ glyph to satisfy linters.

If Ruff RUF001 is enforced, replace “ℹ️ Note” with plain “Note”.

plugins/test-coverage/skills/gaps/report_template.py (4)

45-50: PEP 8: expand one‑line blocks for readability.

-    def get_score_class(score):
-        if score >= 80: return 'excellent'
-        elif score >= 60: return 'good'
-        elif score >= 40: return 'fair'
-        else: return 'poor'
+    def get_score_class(score):
+        if score >= 80:
+            return 'excellent'
+        elif score >= 60:
+            return 'good'
+        elif score >= 40:
+            return 'fair'
+        else:
+            return 'poor'

372-373: Avoid assigning lambdas; use a def.

-    ipv4_only = lambda tests: all('ipv4' in t.get('name', '').lower() and 'ipv6' not in t.get('name', '').lower() for t in tests if tests)
+    def ipv4_only(tests):
+        return all('ipv4' in t.get('name', '').lower() and 'ipv6' not in t.get('name', '').lower() for t in tests) if tests else False

185-186: Drop unused scores parameter from helper.

It’s not referenced inside _generate_whats_tested_section.

-    html += _generate_whats_tested_section(coverage, scores, test_cases, component.lower())
+    html += _generate_whats_tested_section(coverage, test_cases, component.lower())
-def _generate_whats_tested_section(coverage: Dict, scores: Dict, test_cases: List[Dict], component_type: str = 'unknown') -> str:
+def _generate_whats_tested_section(coverage: Dict, test_cases: List[Dict], component_type: str = 'unknown') -> str:

Also applies to: 445-451


290-349: Consider moving set_ip_stack out of the loop to avoid capturing changing loop vars.

Define it to accept the boolean flags as parameters, or inline the assignments.

plugins/test-coverage/skills/gaps/reports.py (4)

404-405: Write HTML with UTF‑8 encoding.

-    with open(output_path, 'w') as f:
+    with open(output_path, 'w', encoding='utf-8') as f:
         f.write(html)

416-418: Write JSON with UTF‑8 encoding.

-    with open(output_path, 'w') as f:
+    with open(output_path, 'w', encoding='utf-8') as f:
         json.dump(report, f, indent=2)

588-589: Write text with UTF‑8 encoding.

-    with open(output_path, 'w') as f:
+    with open(output_path, 'w', encoding='utf-8') as f:
         f.write('\n'.join(lines))

12-23: Prefer package‑relative imports over sys.path surgery.

Rely on from ..common.report_styles import get_common_css and keep one fallback if needed; avoid mutating sys.path.

plugins/test-coverage/skills/gaps/gap_analyzer.py (2)

749-749: Remove unused local (gaps).

-        gaps = analysis['gaps']

971-973: Drop unnecessary f‑string.

-    print(f"  Add 5-7 test cases to address high-priority gaps")
+    print("  Add 5-7 test cases to address high-priority gaps")
plugins/test-coverage/skills/analyze/test_gap_reports.py (3)

590-592: Write HTML with UTF‑8 encoding.

-    with open(output_path, 'w') as f:
+    with open(output_path, 'w', encoding='utf-8') as f:
         f.write(html)

602-604: Write JSON with UTF‑8 encoding.

-    with open(output_path, 'w') as f:
+    with open(output_path, 'w', encoding='utf-8') as f:
         json.dump(report, f, indent=2)

805-806: Write text with UTF‑8 encoding.

-    with open(output_path, 'w') as f:
+    with open(output_path, 'w', encoding='utf-8') as f:
         f.write('\n'.join(lines))
plugins/test-coverage/skills/analyze/test_structure_analyzer.py (7)

684-685: Drop unnecessary f‑string.

-        print(f"Language: Go")
+        print("Language: Go")

831-833: Write JSON with UTF‑8 encoding.

-        with open(json_path, 'w') as f:
+        with open(json_path, 'w', encoding='utf-8') as f:
             json.dump(report_data, f, indent=2)

840-842: Write text with UTF‑8 encoding.

-        with open(text_path, 'w') as f:
+        with open(text_path, 'w', encoding='utf-8') as f:
             f.write(summary)

276-286: Remove unused base_indent.

-                base_indent = len(line) - len(line.lstrip())
                 brace_count = line.count('{') - line.count('}')

301-304: Remove unused context_name.

-                context_name = describe_match.group(1)
-                # Note: We're not adding these as tests, just tracking them
+                _ = describe_match.group(1)
+                # Note: We're not adding these as tests, just tracking them

421-422: Remove unused source_by_path.

-    source_by_path = {sf.path: sf for sf in source_files}

851-853: Clarify warning message (module name).

-        except ImportError:
-            print("Warning: report_generator not found, skipping HTML report")
+        except ImportError:
+            print("Warning: test_structure_reports not found, skipping HTML report")
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between bde8952 and 073d782.

📒 Files selected for processing (24)
  • PLUGINS.md (2 hunks)
  • plugins/test-coverage/.claude-plugin/plugin.json (1 hunks)
  • plugins/test-coverage/README.md (1 hunks)
  • plugins/test-coverage/URL_SUPPORT.md (1 hunks)
  • plugins/test-coverage/__init__.py (1 hunks)
  • plugins/test-coverage/commands/analyze.md (1 hunks)
  • plugins/test-coverage/commands/gaps.md (1 hunks)
  • plugins/test-coverage/skills/__init__.py (1 hunks)
  • plugins/test-coverage/skills/analyze/README.md (1 hunks)
  • plugins/test-coverage/skills/analyze/SKILL.md (1 hunks)
  • plugins/test-coverage/skills/analyze/__init__.py (1 hunks)
  • plugins/test-coverage/skills/analyze/test_gap_reports.py (1 hunks)
  • plugins/test-coverage/skills/analyze/test_structure_analyzer.py (1 hunks)
  • plugins/test-coverage/skills/analyze/test_structure_reports.py (1 hunks)
  • plugins/test-coverage/skills/common/__init__.py (1 hunks)
  • plugins/test-coverage/skills/common/report_styles.py (1 hunks)
  • plugins/test-coverage/skills/gaps/README.md (1 hunks)
  • plugins/test-coverage/skills/gaps/SKILL.md (1 hunks)
  • plugins/test-coverage/skills/gaps/__init__.py (1 hunks)
  • plugins/test-coverage/skills/gaps/gap_analyzer.py (1 hunks)
  • plugins/test-coverage/skills/gaps/report_template.py (1 hunks)
  • plugins/test-coverage/skills/gaps/reports.py (1 hunks)
  • plugins/test-coverage/utils/__init__.py (1 hunks)
  • plugins/test-coverage/utils/path_handler.py (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • plugins/test-coverage/.claude-plugin/plugin.json
🚧 Files skipped from review as they are similar to previous changes (7)
  • plugins/test-coverage/init.py
  • plugins/test-coverage/skills/analyze/init.py
  • plugins/test-coverage/utils/init.py
  • plugins/test-coverage/skills/common/init.py
  • plugins/test-coverage/skills/gaps/README.md
  • plugins/test-coverage/skills/gaps/init.py
  • plugins/test-coverage/skills/init.py
🧰 Additional context used
🪛 LanguageTool
plugins/test-coverage/commands/analyze.md

[grammar] ~265-~265: Use a hyphen to join words.
Context: ...mple 2: Analyze test structure with high priority filter ``` /test-coverage:anal...

(QB_NEW_EN_HYPHEN)

plugins/test-coverage/skills/analyze/README.md

[uncategorized] ~79-~79: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...files without tests ### Example 2: High Priority Gaps Only bash # Analyze only high-...

(EN_COMPOUND_ADJECTIVE_INTERNAL)

plugins/test-coverage/skills/gaps/SKILL.md

[uncategorized] ~175-~175: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ... - Priority indicators: High/medium/low priority badges for each gap - **Test cases list...

(EN_COMPOUND_ADJECTIVE_INTERNAL)

🪛 markdownlint-cli2 (0.18.1)
plugins/test-coverage/README.md

48-48: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


95-95: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

plugins/test-coverage/skills/analyze/SKILL.md

292-292: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🪛 Ruff (0.14.4)
plugins/test-coverage/skills/common/report_styles.py

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

(EXE001)

plugins/test-coverage/skills/gaps/report_template.py

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

(EXE001)


46-46: Multiple statements on one line (colon)

(E701)


47-47: Multiple statements on one line (colon)

(E701)


48-48: Multiple statements on one line (colon)

(E701)


49-49: Multiple statements on one line (colon)

(E701)


257-257: Unused function argument: component_type

(ARG001)


305-305: Function definition does not bind loop variable no_stack_specified

(B023)


310-310: Function definition does not bind loop variable has_dualstack

(B023)


312-312: Function definition does not bind loop variable has_ipv6

(B023)


314-314: Function definition does not bind loop variable has_ipv4

(B023)


353-353: Unused function argument: component_type

(ARG001)


372-372: Do not assign a lambda expression, use a def

Rewrite ipv4_only as a def

(E731)


445-445: Unused function argument: scores

(ARG001)

plugins/test-coverage/skills/gaps/reports.py

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

(EXE001)

plugins/test-coverage/skills/gaps/gap_analyzer.py

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

(EXE001)


749-749: Local variable gaps is assigned to but never used

Remove assignment to unused variable gaps

(F841)


971-971: f-string without any placeholders

Remove extraneous f prefix

(F541)

plugins/test-coverage/utils/path_handler.py

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

(EXE001)


118-118: Probable use of insecure hash functions in hashlib: md5

(S324)


163-163: Audit URL open for permitted schemes. Allowing use of file: or custom schemes is often unexpected.

(S310)


165-165: Audit URL open for permitted schemes. Allowing use of file: or custom schemes is often unexpected.

(S310)


188-188: Do not catch blind exception: Exception

(BLE001)

plugins/test-coverage/skills/analyze/test_gap_reports.py

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

(EXE001)

plugins/test-coverage/skills/analyze/test_structure_reports.py

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

(EXE001)


153-153: String contains ambiguous (INFORMATION SOURCE). Did you mean i (LATIN SMALL LETTER I)?

(RUF001)

plugins/test-coverage/skills/analyze/test_structure_analyzer.py

84-84: Unused function argument: language

(ARG001)


90-90: Unused function argument: language

(ARG001)


90-90: PEP 484 prohibits implicit Optional

Convert to T | None

(RUF013)


131-131: Unused function argument: language

(ARG001)


276-276: Local variable base_indent is assigned to but never used

Remove assignment to unused variable base_indent

(F841)


301-301: Local variable context_name is assigned to but never used

Remove assignment to unused variable context_name

(F841)


326-326: Unused function argument: language

(ARG001)


378-378: Unused function argument: language

(ARG001)


401-401: Unused function argument: language

(ARG001)


421-421: Local variable source_by_path is assigned to but never used

Remove assignment to unused variable source_by_path

(F841)


458-458: Unused function argument: file_path

(ARG001)


684-684: f-string without any placeholders

Remove extraneous f prefix

(F541)


852-852: Do not catch blind exception: Exception

(BLE001)


866-866: Consider moving this statement to an else block

(TRY300)


868-868: Do not catch blind exception: Exception

(BLE001)

Comment on lines +33 to +36
Generates three report formats:
- **HTML Report** (`test-coverage-report.html`) - Interactive web-based report
- **JSON Summary** (`test-structure-gaps.json`) - Machine-readable for CI/CD
- **Text Summary** (`test-structure-summary.txt`) - Terminal-friendly summary
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix output filenames to match the tool.

Analyzer writes “test-structure-report.html”, not “test-coverage-report.html”. Align names to avoid confusion.

Apply:

- - **HTML Report** (`test-coverage-report.html`) - Interactive web-based report
+ - **HTML Report** (`test-structure-report.html`) - Interactive web-based report
📝 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
Generates three report formats:
- **HTML Report** (`test-coverage-report.html`) - Interactive web-based report
- **JSON Summary** (`test-structure-gaps.json`) - Machine-readable for CI/CD
- **Text Summary** (`test-structure-summary.txt`) - Terminal-friendly summary
Generates three report formats:
- **HTML Report** (`test-structure-report.html`) - Interactive web-based report
- **JSON Summary** (`test-structure-gaps.json`) - Machine-readable for CI/CD
- **Text Summary** (`test-structure-summary.txt`) - Terminal-friendly summary
🤖 Prompt for AI Agents
In plugins/test-coverage/skills/analyze/README.md around lines 33 to 36, the
README lists output filenames that do not match the analyzer’s actual outputs;
update the listed filenames so they match the tool (change
test-coverage-report.html to test-structure-report.html and verify the JSON and
text filenames match the analyzer: test-structure-gaps.json and
test-structure-summary.txt), ensuring the three report names are accurate and
consistent with the tool’s outputs.

Comment on lines +114 to +118
Reports Generated:
HTML Report: .work/test-coverage/analyze/test-coverage-report.html
JSON Report: .work/test-coverage/analyze/test-structure-gaps.json
Text Summary: .work/test-coverage/analyze/test-structure-summary.txt

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Update sample output paths to current defaults.

Defaults are “.work/test-coverage/structure/*” (and filenames per analyzer). Update the three lines accordingly.

Proposed:

-  HTML Report:    .work/test-coverage/analyze/test-coverage-report.html
-  JSON Report:    .work/test-coverage/analyze/test-structure-gaps.json
-  Text Summary:   .work/test-coverage/analyze/test-structure-summary.txt
+  HTML Report:    .work/test-coverage/structure/test-structure-report.html
+  JSON Report:    .work/test-coverage/structure/test-structure-gaps.json
+  Text Summary:   .work/test-coverage/structure/test-structure-summary.txt
📝 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
Reports Generated:
HTML Report: .work/test-coverage/analyze/test-coverage-report.html
JSON Report: .work/test-coverage/analyze/test-structure-gaps.json
Text Summary: .work/test-coverage/analyze/test-structure-summary.txt
Reports Generated:
HTML Report: .work/test-coverage/structure/test-structure-report.html
JSON Report: .work/test-coverage/structure/test-structure-gaps.json
Text Summary: .work/test-coverage/structure/test-structure-summary.txt
🤖 Prompt for AI Agents
In plugins/test-coverage/skills/analyze/README.md around lines 114 to 118, the
sample output paths are outdated; update the three report paths to use the
current default directory ".work/test-coverage/structure/". Replace the HTML,
JSON and text paths with
".work/test-coverage/structure/test-coverage-report.html",
".work/test-coverage/structure/test-structure-gaps.json", and
".work/test-coverage/structure/test-structure-summary.txt" respectively so they
reflect the current defaults.

Comment on lines +139 to +141
test_pattern = r'g\.It\("([^"]+)"'
for match in re.finditer(test_pattern, self.content):
test_name = match.group(1)
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Broaden Ginkgo It() match to capture common forms.

Handles g.It/It with single or double quotes and optional whitespace.

-        test_pattern = r'g\.It\("([^"]+)"'
+        test_pattern = r'(?:g\.|o\.)?It\(\s*["\']([^"\']+)["\']'
🤖 Prompt for AI Agents
In plugins/test-coverage/skills/gaps/gap_analyzer.py around lines 139 to 141,
the current regex only matches g.It("...") with double quotes and no extra
whitespace; replace it with a broader pattern that accepts optional "g." prefix,
either single or double quotes, and optional whitespace before the opening
parenthesis/quotes (for example use a pattern like one that matches
(?:g\.)?It\s*\(\s*["']([^"']+)["'] ) so re.finditer still yields the test name
in group(1); update test_pattern accordingly and keep the rest of the loop logic
unchanged.

@anuragthehatter
Copy link
Author

Closing to create a fresh PR with the same changes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-ok-to-test Indicates a PR that requires an org member to verify it is safe to test.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants