diff --git a/.github/workflows/opencode-review.yml b/.github/workflows/opencode-review.yml index 4980e30f..da8c08c2 100644 --- a/.github/workflows/opencode-review.yml +++ b/.github/workflows/opencode-review.yml @@ -638,6 +638,11 @@ jobs: | sort -u } + javascript_test_script_collects_coverage() { + jq -e '(.scripts.test // "") | test("(^|[[:space:]])--coverage([.=[:space:]]|$)|c8([[:space:]]|$)|nyc([[:space:]]|$)")' \ + package.json >/dev/null 2>&1 + } + declared_package_manager() { if [ -f package.json ]; then jq -r '.packageManager // "" | split("@")[0]' package.json 2>/dev/null || true @@ -1388,11 +1393,19 @@ jobs: run_and_capture "JavaScript/TypeScript coverage script" "$package_runner" run coverage javascript_coverage_ran=1 elif jq -e '.scripts.test // empty' package.json >/dev/null; then - case "$package_runner" in - npm) run_and_capture "JavaScript/TypeScript test coverage" npm test -- --coverage ;; - pnpm) run_and_capture "JavaScript/TypeScript test coverage" pnpm test -- --coverage ;; - yarn) run_and_capture "JavaScript/TypeScript test coverage" yarn test --coverage ;; - esac + if javascript_test_script_collects_coverage; then + case "$package_runner" in + npm) run_and_capture "JavaScript/TypeScript test coverage" npm test ;; + pnpm) run_and_capture "JavaScript/TypeScript test coverage" pnpm test ;; + yarn) run_and_capture "JavaScript/TypeScript test coverage" yarn test ;; + esac + else + case "$package_runner" in + npm) run_and_capture "JavaScript/TypeScript test coverage" npm test -- --coverage ;; + pnpm) run_and_capture "JavaScript/TypeScript test coverage" pnpm test -- --coverage ;; + yarn) run_and_capture "JavaScript/TypeScript test coverage" yarn test --coverage ;; + esac + fi javascript_coverage_ran=1 else append "### JavaScript/TypeScript test coverage" diff --git a/tests/test_opencode_agent_contract.py b/tests/test_opencode_agent_contract.py index 8e18d152..fb1b2a55 100644 --- a/tests/test_opencode_agent_contract.py +++ b/tests/test_opencode_agent_contract.py @@ -278,6 +278,27 @@ def test_opencode_coverage_prefers_declared_pnpm_runner_before_npm(): assert "return" in declared_pnpm_block +def test_opencode_coverage_does_not_duplicate_existing_javascript_coverage(): + """An existing coverage flag/tool must run once instead of receiving a duplicate flag.""" + workflow = Path(".github/workflows/opencode-review.yml").read_text(encoding="utf-8") + measure_start = workflow.index(" - name: Measure test and docstring evidence\n") + measure_end = workflow.index("\n - name:", measure_start + 1) + measure_step = workflow[measure_start:measure_end] + + assert "javascript_test_script_collects_coverage()" in measure_step + assert "if javascript_test_script_collects_coverage; then" in measure_step + assert ( + 'npm) run_and_capture "JavaScript/TypeScript test coverage" npm test ;;' + in measure_step + ) + assert ( + 'npm) run_and_capture "JavaScript/TypeScript test coverage" npm test -- --coverage ;;' + in measure_step + ) + assert 'test("(^|[[:space:]])--coverage([.=[:space:]]|$)' in measure_step + assert '|c8([[:space:]]|$)|nyc([[:space:]]|$)")' in measure_step + + def test_opencode_coverage_discovers_changed_nested_javascript_package(tmp_path): """A changed JS file must select its nearest nested package.json for coverage.""" bash = shutil.which("bash")