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.
| Scope | Reports |
|---|---|
full | Every finding in the project (the CLI default) |
files | Findings in files the change touched |
lines | Findings on the lines the change touched |
changed | Findings 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:
| Level | Fails the run when |
|---|---|
none | Never — advisory only |
warning | Any error or warning is reported |
error | Any 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
| Format | Use |
|---|---|
console | Human-readable report (default) |
json | The full result object, for tooling |
sarif | SARIF 2.1.0, for code scanning |
gitlab | GitLab Code Quality report |
markdown | A comment body for any pull or merge request |
github | Workflow 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.