nestjs-doctorGitHub

CI & Pull Requests

Running a linter on a codebase that predates it produces a wall of findings nobody reads. nestjs-doctor solves that by reporting only what a change introduced, and leaving the existing backlog to the score.

Scope

The whole project is always analysed. Cross-file rules like architecture/no-circular-module-deps and performance/no-unused-providers would produce nonsense from a partial view, so --scope narrows only what gets reported.

ScopeReports
fullEvery finding in the project (the CLI default)
filesFindings in files the change touched
linesFindings on the lines the change touched
changedFindings the change introduced, measured against the base (the action's default)

changed checks the base revision out into a temporary git worktree, scans it with the same rules and config, and subtracts what was already there. Findings are matched on rule, file, message, and source text — never on line number — so an unrelated edit higher up in a file does not make an old finding look new. The comment also reports how many findings the change resolved.

lines reports only findings whose line falls inside a diff hunk. Schema findings describe an entity rather than a line, so they never appear at this scope; use files or changed if you want them.

# What did this branch introduce?
npx nestjs-doctor . --scope changed --base origin/main

# Pre-commit hook: only what you are about to commit
npx nestjs-doctor . --staged --blocking error

Gates

Two gates run independently, and either one failing exits 1.

--min-score gates on the project score. The score always reflects the whole codebase regardless of scope — narrowing a report cannot make a project look healthier than it is.

--blocking gates on the reported findings:

LevelFails the run when
noneNever — advisory only
warningAny error or warning is reported
errorAny error is reported

The default is error for the console report and none for --json and --score, which reproduces the behaviour that shipped before the flag existed. Pass --blocking explicitly and both paths behave identically.

Exit codes: 0 pass, 1 a gate failed, 2 bad input.

Code scanning

SARIF sends findings to a code-scanning backend, where they persist across runs as alerts rather than living only in a pull request comment.

permissions:
  contents: read
  security-events: write

steps:
  - uses: actions/checkout@v4
  - run: npx nestjs-doctor@latest . --format sarif --output nestjs-doctor.sarif
  - uses: github/codeql-action/upload-sarif@v3
    with:
      sarif_file: nestjs-doctor.sarif

Every result carries a partialFingerprints entry derived from the rule, path, message, and source text. Without it GitHub computes its own fingerprint from surrounding source, and an edit near a finding closes the old alert and opens an identical new one.

GitLab

The gitlab format emits the CodeClimate subset GitLab's Code Quality widget reads, so findings appear on the merge request diff.

nestjs-doctor:
  image: node:22
  script:
    - npx nestjs-doctor@latest . --format gitlab --output gl-code-quality-report.json
  artifacts:
    reports:
      codequality: gl-code-quality-report.json

Other output formats

FormatUse
consoleHuman-readable report (default)
jsonThe full result object, for tooling
sarifSARIF 2.1.0, for code scanning
gitlabGitLab Code Quality report
markdownA comment body for any pull or merge request
githubWorkflow annotations plus a job summary, alongside the console report

--output <path> writes the payload to a file instead of stdout, and --json-compact drops the indentation from the JSON-based formats.

github is additive rather than a replacement: it prints annotations and appends the markdown report to $GITHUB_STEP_SUMMARY while still printing the readable console report to the log. GitHub caps annotations at ten errors and ten warnings per step and silently drops the rest, so the annotations are a convenience — the job summary carries every finding.

Pre-commit hook

# .husky/pre-commit
npx nestjs-doctor . --staged --blocking error

--staged scopes to the files in the git index. The project is still analysed in full, so a change that breaks a cross-file rule is caught even when the file it is reported against is not part of the commit.

Running from inside a hook is safe: git exports GIT_DIR, GIT_INDEX_FILE, and friends to every hook, and children inherit them, so nestjs-doctor clears those before shelling out to git and resolves everything against the directory it was pointed at.