Skip to content

ci: add ReSharper InspectCode as a parallel required check in pr.yaml #208

Description

@Chris-Wolfgang

Summary

Add a JetBrains ReSharper InspectCode step to the PR pipeline as a new parallel job in pr.yaml. Findings upload to GitHub Code Scanning (Security → Code scanning alerts) and inline-annotate the PR diff. The job is a required status check so PRs cannot merge while findings remain.

Why

The current static-analysis stack (Meziantou, SonarAnalyzer.CSharp, Roslynator, AsyncFixer, Microsoft.VisualStudio.Threading.Analyzers, BannedApiAnalyzers, .NET SDK analyzers, CodeQL, DevSkim) is comprehensive but exclusively Roslyn-based. ReSharper InspectCode runs a different ruleset — including data-flow analysis, dead-code detection, and naming/structural rules that Roslyn analyzers don't cover — and routinely surfaces issues the existing pipeline misses. Running it in CI catches them before they ship.

InspectCode is free for OSS / CI use (JetBrains.ReSharper.GlobalTools NuGet package).

What needs to be done

1. Canonical workflow change (do this in repo-template first)

Add a new inspectcode job to .github/workflows/pr.yaml, parallel to the test stages (no needs: dependency). Job sketch:

  inspectcode:
    name: ReSharper InspectCode
    runs-on: ubuntu-latest
    permissions:
      contents: read
      security-events: write   # required for upload-sarif
    steps:
      - uses: actions/checkout@v6
        with: { persist-credentials: false }
      - uses: actions/setup-dotnet@v5
        with: { dotnet-version: '10.0.x' }
      - name: Restore + Build (Release)
        run: |
          dotnet restore
          dotnet build -c Release --no-restore
      - name: Install JetBrains.ReSharper.GlobalTools
        run: dotnet tool install -g JetBrains.ReSharper.GlobalTools
      - name: Run InspectCode
        run: |
          SLN=$(ls *.slnx 2>/dev/null | head -1)
          jb inspectcode "$SLN" \
            --output=inspect.sarif \
            --format=sarif \
            --severity=WARNING \
            --no-build
      - uses: github/codeql-action/upload-sarif@v3
        with: { sarif_file: inspect.sarif }
      - name: Gate on errors
        run: |
          count=$(jq '[.runs[].results[] | select(.level=="error")] | length' inspect.sarif)
          if [ "$count" -gt 0 ]; then
            echo "::error::$count InspectCode error(s) — see Security → Code scanning"
            exit 1
          fi

2. Tune the noise floor

A .DotSettings file at the repo root that silences InspectCode rules already covered by the existing Roslyn analyzers (avoid double-reporting). Canonical baseline lives in repo-template; downstream repos sync via template-sync.

Starter list of categories to silence:

  • Style/formatting (.editorconfig + Roslynator already enforce)
  • Async/await rules (AsyncFixer + VSTHRD cover them)
  • Nullability (built-in Roslyn nullable annotations)
  • Naming conventions duplicated by IDE1006

The goal is 0 noise findings on a clean main, so the first error after the workflow lands is always actionable.

3. Branch-ruleset update

Add ReSharper InspectCode to the required-status-checks list on main. Without this the job runs but doesn't gate merge.

4. Fan-out

After repo-template is proven (one successful PR landing through it), fan out the same workflow + .DotSettings to every downstream Wolfgang.* repo via the bulk-repo-pr flow.

Acceptance criteria

  • inspectcode job runs on every pull_request to main
  • Job runs in parallel with Stage 1 / 2 / 3 (no serial dependency)
  • SARIF uploads to GitHub Code Scanning (visible in PR "Files changed" tab as inline annotations and in Security tab)
  • error-severity findings fail the job
  • warning-severity findings surface but don't fail (tune up to error later when noise floor is acceptable)
  • .DotSettings committed with the canonical noise-floor profile
  • Branch ruleset on main lists "ReSharper InspectCode" as required
  • Wall-clock impact of pipeline is ≤ slowest existing stage (InspectCode typically 3–5 min vs Stage 2 Windows at 8–12 min)

Notes

  • InspectCode needs dotnet build to succeed first; keep build+inspect in the same job to avoid serializing them.
  • The Detect .NET Projects protected-files guard will fire on the PR that adds the workflow (since it edits pr.yaml). Use the standard maintainer-bypass flow to land it.
  • For private commercial repos: confirm JetBrains licensing terms allow CI use in your context. OSS/MIT public usage is unambiguously fine.

Related

  • repo-template will land the canonical version first; downstream repos pick it up via template-sync.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions