pr-checkmate 1.22.7 → 1.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +101 -333
- package/cspell.json +9 -1
- package/dist/cli.js +32 -2
- package/dist/config/constants.d.ts +25 -1
- package/dist/config/constants.js +157 -38
- package/dist/config/index.d.ts +15 -2
- package/dist/config/index.js +28 -7
- package/dist/config/loader.js +5 -1
- package/dist/core/checks/dependencies/banned-imports.d.ts +2 -0
- package/dist/core/checks/dependencies/banned-imports.js +71 -0
- package/dist/core/checks/{circular-deps.d.ts → dependencies/circular-deps.d.ts} +1 -1
- package/dist/core/checks/{circular-deps.js → dependencies/circular-deps.js} +9 -10
- package/dist/core/checks/{dependency-check.d.ts → dependencies/dependency-check.d.ts} +1 -1
- package/dist/core/checks/{dependency-check.js → dependencies/dependency-check.js} +3 -3
- package/dist/core/checks/{license-check.d.ts → dependencies/license-check.d.ts} +1 -1
- package/dist/core/checks/{license-check.js → dependencies/license-check.js} +3 -3
- package/dist/core/checks/{npm-audit.d.ts → dependencies/npm-audit.d.ts} +1 -1
- package/dist/core/checks/{npm-audit.js → dependencies/npm-audit.js} +3 -3
- package/dist/core/checks/{outdated-deps.d.ts → dependencies/outdated-deps.d.ts} +1 -1
- package/dist/core/checks/{outdated-deps.js → dependencies/outdated-deps.js} +3 -3
- package/dist/core/checks/dependencies/vuln-scan.d.ts +9 -0
- package/dist/core/checks/dependencies/vuln-scan.js +41 -0
- package/dist/core/checks/findings.d.ts +37 -1
- package/dist/core/checks/findings.js +80 -3
- package/dist/core/checks/git/custom-rules.d.ts +2 -0
- package/dist/core/checks/git/custom-rules.js +102 -0
- package/dist/core/checks/{diff-smell.d.ts → git/diff-smell.d.ts} +1 -1
- package/dist/core/checks/{diff-smell.js → git/diff-smell.js} +3 -3
- package/dist/core/checks/git/large-files.d.ts +2 -0
- package/dist/core/checks/git/large-files.js +83 -0
- package/dist/core/checks/git/leftover-debug.d.ts +2 -0
- package/dist/core/checks/git/leftover-debug.js +77 -0
- package/dist/core/checks/git/lockfile-drift.d.ts +2 -0
- package/dist/core/checks/git/lockfile-drift.js +114 -0
- package/dist/core/checks/git/merge-conflict.d.ts +2 -0
- package/dist/core/checks/git/merge-conflict.js +109 -0
- package/dist/core/checks/git/missing-tests.d.ts +2 -0
- package/dist/core/checks/git/missing-tests.js +92 -0
- package/dist/core/checks/git/todo-fixme.d.ts +7 -0
- package/dist/core/checks/git/todo-fixme.js +74 -0
- package/dist/core/checks/{cpp-format.d.ts → languages/cpp-format.d.ts} +1 -1
- package/dist/core/checks/{cpp-format.js → languages/cpp-format.js} +3 -3
- package/dist/core/checks/languages/csharp-format.d.ts +13 -0
- package/dist/core/checks/languages/csharp-format.js +52 -0
- package/dist/core/checks/languages/go-format.d.ts +8 -0
- package/dist/core/checks/languages/go-format.js +48 -0
- package/dist/core/checks/languages/go-lint.d.ts +8 -0
- package/dist/core/checks/languages/go-lint.js +48 -0
- package/dist/core/checks/{kotlin-lint.d.ts → languages/kotlin-lint.d.ts} +1 -1
- package/dist/core/checks/{kotlin-lint.js → languages/kotlin-lint.js} +13 -17
- package/dist/core/checks/{lint.d.ts → languages/lint.d.ts} +1 -1
- package/dist/core/checks/{lint.js → languages/lint.js} +25 -14
- package/dist/core/checks/languages/php-format.d.ts +9 -0
- package/dist/core/checks/languages/php-format.js +49 -0
- package/dist/core/checks/{prettier.d.ts → languages/prettier.d.ts} +1 -1
- package/dist/core/checks/{prettier.js → languages/prettier.js} +10 -10
- package/dist/core/checks/{python-format.d.ts → languages/python-format.d.ts} +1 -1
- package/dist/core/checks/{python-format.js → languages/python-format.js} +3 -3
- package/dist/core/checks/{python-lint.d.ts → languages/python-lint.d.ts} +1 -1
- package/dist/core/checks/{python-lint.js → languages/python-lint.js} +3 -3
- package/dist/core/checks/languages/python-typecheck.d.ts +9 -0
- package/dist/core/checks/languages/python-typecheck.js +66 -0
- package/dist/core/checks/languages/ruby-lint.d.ts +8 -0
- package/dist/core/checks/languages/ruby-lint.js +50 -0
- package/dist/core/checks/languages/rust-format.d.ts +9 -0
- package/dist/core/checks/languages/rust-format.js +45 -0
- package/dist/core/checks/languages/rust-lint.d.ts +8 -0
- package/dist/core/checks/languages/rust-lint.js +50 -0
- package/dist/core/checks/{swift-lint.d.ts → languages/swift-lint.d.ts} +1 -1
- package/dist/core/checks/{swift-lint.js → languages/swift-lint.js} +13 -17
- package/dist/core/checks/{typecheck.d.ts → languages/typecheck.d.ts} +1 -1
- package/dist/core/checks/{typecheck.js → languages/typecheck.js} +3 -3
- package/dist/core/checks/{commitlint.d.ts → pr/commitlint.d.ts} +1 -1
- package/dist/core/checks/{commitlint.js → pr/commitlint.js} +4 -4
- package/dist/core/checks/{pr-body.d.ts → pr/pr-body.d.ts} +1 -1
- package/dist/core/checks/{pr-body.js → pr/pr-body.js} +2 -2
- package/dist/core/checks/{pr-size-check.d.ts → pr/pr-size-check.d.ts} +1 -1
- package/dist/core/checks/{pr-size-check.js → pr/pr-size-check.js} +13 -11
- package/dist/core/checks/{pr-title-lint.d.ts → pr/pr-title-lint.d.ts} +1 -1
- package/dist/core/checks/{pr-title-lint.js → pr/pr-title-lint.js} +2 -2
- package/dist/core/checks/quality/case-collision.d.ts +8 -0
- package/dist/core/checks/quality/case-collision.js +40 -0
- package/dist/core/checks/quality/config-validation.d.ts +8 -0
- package/dist/core/checks/quality/config-validation.js +63 -0
- package/dist/core/checks/quality/coverage.d.ts +2 -0
- package/dist/core/checks/quality/coverage.js +63 -0
- package/dist/core/checks/{dead-code.d.ts → quality/dead-code.d.ts} +1 -1
- package/dist/core/checks/{dead-code.js → quality/dead-code.js} +4 -4
- package/dist/core/checks/{duplicate-check.d.ts → quality/duplicate-check.d.ts} +1 -1
- package/dist/core/checks/{duplicate-check.js → quality/duplicate-check.js} +11 -15
- package/dist/core/checks/quality/license-header.d.ts +7 -0
- package/dist/core/checks/quality/license-header.js +74 -0
- package/dist/core/checks/{markdown-lint.d.ts → quality/markdown-lint.d.ts} +1 -1
- package/dist/core/checks/{markdown-lint.js → quality/markdown-lint.js} +8 -21
- package/dist/core/checks/{spellcheck.d.ts → quality/spellcheck.d.ts} +1 -1
- package/dist/core/checks/{spellcheck.js → quality/spellcheck.js} +11 -19
- package/dist/core/checks/{diff-security.d.ts → security/diff-security.d.ts} +1 -1
- package/dist/core/checks/security/diff-security.js +262 -0
- package/dist/core/checks/security/dockerfile-security.d.ts +2 -0
- package/dist/core/checks/security/dockerfile-security.js +92 -0
- package/dist/core/checks/security/migration-safety.d.ts +2 -0
- package/dist/core/checks/security/migration-safety.js +110 -0
- package/dist/core/checks/{security.d.ts → security/security.d.ts} +1 -1
- package/dist/core/checks/{security.js → security/security.js} +4 -4
- package/dist/core/checks/{sensitive-file-guard.d.ts → security/sensitive-file-guard.d.ts} +1 -1
- package/dist/core/checks/{sensitive-file-guard.js → security/sensitive-file-guard.js} +4 -4
- package/dist/core/checks/security/workflow-security.d.ts +2 -0
- package/dist/core/checks/security/workflow-security.js +75 -0
- package/dist/core/context.js +54 -10
- package/dist/core/registry.js +73 -28
- package/dist/core/reporters.d.ts +4 -3
- package/dist/core/reporters.js +104 -4
- package/dist/core/run-checks.js +21 -3
- package/dist/core/targets.d.ts +17 -1
- package/dist/core/targets.js +74 -4
- package/dist/core/types.d.ts +13 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +3 -1
- package/dist/init.js +86 -8
- package/dist/interfaces/index.d.ts +101 -1
- package/dist/scripts/copy-configs.js +6 -1
- package/dist/utils/detect-language.d.ts +1 -1
- package/dist/utils/detect-language.js +32 -3
- package/dist/utils/glob.d.ts +10 -0
- package/dist/utils/glob.js +25 -0
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/index.js +1 -1
- package/eslint-default-rules.json +62 -0
- package/eslint.config.mjs +6 -66
- package/package.json +3 -1
- package/pr-checkmate.schema.json +166 -0
- package/src/config/cspell.json +9 -1
- package/src/config/eslint-default-rules.json +62 -0
- package/src/config/pr-checkmate.schema.json +166 -0
- package/dist/core/checks/diff-security.js +0 -145
- package/dist/utils/delta.d.ts +0 -5
- package/dist/utils/delta.js +0 -53
- package/src/config/eslint.config.mjs +0 -180
- /package/dist/core/checks/{ruff-shared.d.ts → languages/ruff-shared.d.ts} +0 -0
- /package/dist/core/checks/{ruff-shared.js → languages/ruff-shared.js} +0 -0
package/README.md
CHANGED
|
@@ -9,66 +9,73 @@
|
|
|
9
9
|

|
|
10
10
|
[](https://pr-checkmate-docs.pages.dev)
|
|
11
11
|
|
|
12
|
-
>
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
## Why PR CheckMate
|
|
17
|
-
|
|
18
|
-
Most teams wire up linters and formatters separately
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
-
|
|
23
|
-
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
12
|
+
> PR CheckMate is a universal PR quality checker: one `npm install`, 48 checks across
|
|
13
|
+
> 11 languages, running in CI on every pull request. The bundled languages need no
|
|
14
|
+
> per-language toolchain setup.
|
|
15
|
+
|
|
16
|
+
## Why PR CheckMate
|
|
17
|
+
|
|
18
|
+
Most teams wire up linters and formatters separately in every repo. PR CheckMate ships
|
|
19
|
+
them pre-bundled. You add one step to a GitHub Actions workflow and the checks run on
|
|
20
|
+
every PR.
|
|
21
|
+
|
|
22
|
+
- One package, any stack. Language is auto-detected from the repo.
|
|
23
|
+
- Bundled tooling. ESLint, Prettier, Ruff, clang-format, and gitleaks run inside the
|
|
24
|
+
package (WASM/JS), so clients install nothing for those languages.
|
|
25
|
+
- Delta mode. In a PR only the changed files are checked; a full-project scan is the
|
|
26
|
+
fallback outside PR context.
|
|
27
|
+
- Parallel phases. Checks run concurrently within each phase: blocking, then
|
|
28
|
+
informational, then format.
|
|
29
|
+
- Reports in the PR. Results post as a single comment that updates in place, and
|
|
30
|
+
formatter fixes are committed back to the branch.
|
|
31
|
+
- Tunable. Any check can be re-scoped, downgraded, or disabled in `pr-checkmate.json`.
|
|
27
32
|
|
|
28
33
|
## Language Support
|
|
29
34
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
| **TypeScript** | `tsconfig.json` | ESLint + SonarJS | Prettier | `tsc --noEmit` | Fully bundled |
|
|
33
|
-
| **JavaScript** | `package.json` | ESLint | Prettier | — | Fully bundled |
|
|
34
|
-
| **Python** | `pyproject.toml`, `requirements.txt` | Ruff (WASM) | Ruff (WASM) | — | Fully bundled, no Python install needed |
|
|
35
|
-
| **C++** | `CMakeLists.txt` | — | clang-format (WASM) | — | Fully bundled, no clang install needed |
|
|
36
|
-
| **Swift** | `Package.swift` | SwiftLint | — | — | Requires `swiftlint` on runner |
|
|
37
|
-
| **Android/Kotlin** | `build.gradle`, `AndroidManifest.xml` | ktlint | — | — | Requires `ktlint` on runner |
|
|
35
|
+
Bundled languages need nothing on the runner. Runner-dependency languages need their
|
|
36
|
+
tool installed; the check skips gracefully when the tool is absent.
|
|
38
37
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
38
|
+
| Language | Checks | Toolchain |
|
|
39
|
+
|---|---|---|
|
|
40
|
+
| TypeScript / JavaScript | ESLint, Prettier, `tsc --noEmit` | Bundled |
|
|
41
|
+
| Python | Ruff (lint + format), mypy/pyright (types) | Ruff bundled; types need mypy or pyright on the runner |
|
|
42
|
+
| C++ | clang-format | Bundled |
|
|
43
|
+
| Swift | SwiftLint | `swiftlint` on the runner |
|
|
44
|
+
| Kotlin / Java | ktlint | `ktlint` on the runner |
|
|
45
|
+
| Go | `go vet`, `gofmt` | Go toolchain on the runner |
|
|
46
|
+
| Rust | `cargo clippy`, `cargo fmt` | Rust toolchain on the runner |
|
|
47
|
+
| C# | `dotnet format` | .NET SDK on the runner |
|
|
48
|
+
| Ruby | RuboCop | `rubocop` on the runner |
|
|
49
|
+
| PHP | PHP-CS-Fixer | `php-cs-fixer` on the runner |
|
|
50
|
+
|
|
51
|
+
Secret scanning (gitleaks) and the universal git-diff checks are bundled and run for
|
|
52
|
+
every language.
|
|
42
53
|
|
|
43
54
|
## Quickstart
|
|
44
55
|
|
|
45
|
-
|
|
56
|
+
Install:
|
|
46
57
|
|
|
47
58
|
```bash
|
|
48
59
|
npm install --save-dev pr-checkmate
|
|
49
60
|
```
|
|
50
61
|
|
|
51
|
-
|
|
62
|
+
Scaffold `pr-checkmate.json` and `.github/workflows/pr-checkmate.yml` for the detected
|
|
63
|
+
languages:
|
|
52
64
|
|
|
53
65
|
```bash
|
|
54
66
|
npx pr-checkmate init
|
|
55
67
|
```
|
|
56
68
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
### 3. Run
|
|
69
|
+
Run all checks:
|
|
60
70
|
|
|
61
71
|
```bash
|
|
62
72
|
npx pr-checkmate all
|
|
63
73
|
```
|
|
64
74
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
## GitHub Actions — Examples by Language
|
|
75
|
+
## GitHub Actions
|
|
68
76
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
### TypeScript / JavaScript
|
|
77
|
+
Every workflow follows the same shape: checkout, set up Node, install, run. The
|
|
78
|
+
TypeScript setup is the baseline:
|
|
72
79
|
|
|
73
80
|
```yaml
|
|
74
81
|
name: PR CheckMate
|
|
@@ -92,324 +99,85 @@ jobs:
|
|
|
92
99
|
- run: npx pr-checkmate all
|
|
93
100
|
```
|
|
94
101
|
|
|
95
|
-
|
|
102
|
+
For a runner-dependency language, add its toolchain setup step before the run: Go with
|
|
103
|
+
`actions/setup-go`, Rust with `dtolnay/rust-toolchain`, C# with `actions/setup-dotnet`,
|
|
104
|
+
Ruby with `ruby/setup-ruby` (plus `gem install rubocop`), PHP with
|
|
105
|
+
`shivammathur/setup-php` (tools: `php-cs-fixer`), Kotlin by fetching the `ktlint`
|
|
106
|
+
binary. Swift's `swiftlint` is pre-installed on `macos-latest`. Anything missing is
|
|
107
|
+
skipped, not failed.
|
|
96
108
|
|
|
97
|
-
|
|
109
|
+
## Checks
|
|
98
110
|
|
|
99
|
-
|
|
100
|
-
name: PR CheckMate
|
|
101
|
-
on:
|
|
102
|
-
pull_request:
|
|
103
|
-
branches: [main]
|
|
111
|
+
48 checks, grouped by category and run in parallel within each phase:
|
|
104
112
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
- uses: actions/setup-node@v4
|
|
116
|
-
with: { node-version: 24 }
|
|
117
|
-
# No pip install needed — Ruff runs via bundled WASM
|
|
118
|
-
- run: npm install pr-checkmate
|
|
119
|
-
- run: npx pr-checkmate all
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
> Ruff (lint + format) runs via WASM — no Python or pip required on the runner.
|
|
123
|
-
|
|
124
|
-
---
|
|
125
|
-
|
|
126
|
-
### C++
|
|
127
|
-
|
|
128
|
-
```yaml
|
|
129
|
-
name: PR CheckMate
|
|
130
|
-
on:
|
|
131
|
-
pull_request:
|
|
132
|
-
branches: [main]
|
|
133
|
-
|
|
134
|
-
permissions:
|
|
135
|
-
contents: write
|
|
136
|
-
pull-requests: write
|
|
137
|
-
|
|
138
|
-
jobs:
|
|
139
|
-
quality:
|
|
140
|
-
runs-on: ubuntu-latest
|
|
141
|
-
steps:
|
|
142
|
-
- uses: actions/checkout@v4
|
|
143
|
-
with: { fetch-depth: 0 }
|
|
144
|
-
- uses: actions/setup-node@v4
|
|
145
|
-
with: { node-version: 24 }
|
|
146
|
-
# No clang install needed — clang-format runs via bundled WASM
|
|
147
|
-
- run: npm install pr-checkmate
|
|
148
|
-
- run: npx pr-checkmate all
|
|
149
|
-
```
|
|
150
|
-
|
|
151
|
-
> clang-format runs via WASM — no system clang or LLVM install required.
|
|
152
|
-
|
|
153
|
-
---
|
|
154
|
-
|
|
155
|
-
### Swift
|
|
156
|
-
|
|
157
|
-
```yaml
|
|
158
|
-
name: PR CheckMate
|
|
159
|
-
on:
|
|
160
|
-
pull_request:
|
|
161
|
-
branches: [main]
|
|
162
|
-
|
|
163
|
-
permissions:
|
|
164
|
-
contents: read
|
|
165
|
-
pull-requests: write
|
|
166
|
-
|
|
167
|
-
jobs:
|
|
168
|
-
quality:
|
|
169
|
-
runs-on: macos-latest # SwiftLint is pre-installed on macOS runners
|
|
170
|
-
steps:
|
|
171
|
-
- uses: actions/checkout@v4
|
|
172
|
-
with: { fetch-depth: 0 }
|
|
173
|
-
- uses: actions/setup-node@v4
|
|
174
|
-
with: { node-version: 24 }
|
|
175
|
-
- run: npm install pr-checkmate
|
|
176
|
-
- run: npx pr-checkmate all
|
|
177
|
-
```
|
|
178
|
-
|
|
179
|
-
> `swiftlint` is pre-installed on GitHub's `macos-latest` runner. If not available, the check is skipped automatically.
|
|
180
|
-
|
|
181
|
-
---
|
|
182
|
-
|
|
183
|
-
### Android / Kotlin
|
|
184
|
-
|
|
185
|
-
```yaml
|
|
186
|
-
name: PR CheckMate
|
|
187
|
-
on:
|
|
188
|
-
pull_request:
|
|
189
|
-
branches: [main]
|
|
190
|
-
|
|
191
|
-
permissions:
|
|
192
|
-
contents: read
|
|
193
|
-
pull-requests: write
|
|
194
|
-
|
|
195
|
-
jobs:
|
|
196
|
-
quality:
|
|
197
|
-
runs-on: ubuntu-latest
|
|
198
|
-
steps:
|
|
199
|
-
- uses: actions/checkout@v4
|
|
200
|
-
with: { fetch-depth: 0 }
|
|
201
|
-
- uses: actions/setup-node@v4
|
|
202
|
-
with: { node-version: 24 }
|
|
203
|
-
- name: Install ktlint
|
|
204
|
-
run: |
|
|
205
|
-
curl -sSLO https://github.com/pinterest/ktlint/releases/latest/download/ktlint
|
|
206
|
-
chmod +x ktlint
|
|
207
|
-
sudo mv ktlint /usr/local/bin/
|
|
208
|
-
- run: npm install pr-checkmate
|
|
209
|
-
- run: npx pr-checkmate all
|
|
210
|
-
```
|
|
211
|
-
|
|
212
|
-
> `ktlint` is not pre-installed on Ubuntu runners — the snippet above fetches the latest release binary. If ktlint is unavailable, the check is skipped automatically.
|
|
213
|
-
|
|
214
|
-
---
|
|
215
|
-
|
|
216
|
-
## All Checks
|
|
217
|
-
|
|
218
|
-
| Check | Phase | Description |
|
|
219
|
-
|---|---|---|
|
|
220
|
-
| ESLint + SonarJS + JSDoc | blocking | Lint with complexity, import order, and doc coverage rules |
|
|
221
|
-
| TypeScript | blocking | `tsc --noEmit` type check |
|
|
222
|
-
| Dependency Check | blocking | Unused / missing deps via depcheck; silence CLI-only false positives with `dependency.ignore` |
|
|
223
|
-
| NPM Audit | blocking | Vulnerability scan (`moderate`+) |
|
|
224
|
-
| Circular Deps | blocking | Circular dependency detection |
|
|
225
|
-
| License Check | blocking | Blocks GPL / AGPL / LGPL packages |
|
|
226
|
-
| Ruff Lint | informational | Python linting via WASM |
|
|
227
|
-
| SwiftLint | informational | Swift linting |
|
|
228
|
-
| ktlint | informational | Kotlin linting |
|
|
229
|
-
| Dead Code | informational | Unused exports (`ts-unused-exports`); test and mock files are excluded from the report by default — override with `deadCode.ignoreFiles` (regex) |
|
|
230
|
-
| Duplicate Code | informational | `jscpd` — 5 lines / 50 tokens threshold; test files ignored by default (set `duplicate.ignore`); only source-code formats are scanned, so YAML/JSON/Markdown are skipped unless you override `duplicate.formats` |
|
|
231
|
-
| Diff Smell | informational | `console.*`, `debugger`, `TODO/FIXME` in added lines |
|
|
232
|
-
| Diff Security | informational | XSS, `eval`, SQLi, weak crypto in added lines |
|
|
233
|
-
| Sensitive Files | informational | `.env`, private keys, CI configs touched in PR |
|
|
234
|
-
| PR Size | informational | Warns if PR > 50 files or 1 000 lines |
|
|
235
|
-
| PR Title | informational | Conventional Commits format |
|
|
236
|
-
| PR Body | informational | Min 20 chars + ticket reference |
|
|
237
|
-
| Commitlint | informational | Commit message convention |
|
|
238
|
-
| Outdated Deps | informational | Major-behind packages |
|
|
239
|
-
| Markdown Lint | informational | `.md` / `.mdx` via markdownlint |
|
|
240
|
-
| Spellcheck | informational | EN, ES, FR, RU, UK, HE dictionaries |
|
|
241
|
-
| Prettier | format | Auto-format; commits fixes back to branch |
|
|
242
|
-
| C++ Format | format | clang-format via WASM |
|
|
243
|
-
| Python Format | format | Ruff formatter via WASM |
|
|
244
|
-
|
|
245
|
-
---
|
|
113
|
+
- Universal git-diff (18) — language-agnostic and bundled: merge-conflict markers,
|
|
114
|
+
secret scan, diff security (JS/TS/Python/Go/Kotlin), GitHub Actions and Dockerfile
|
|
115
|
+
security, case-collision, custom rules, banned imports, license headers, leftover
|
|
116
|
+
debug lines, lockfile drift, large/binary files, TODO/FIXME, missing tests, coverage
|
|
117
|
+
presence, DB migration safety, and sensitive-file guard.
|
|
118
|
+
- Dependencies (6) — unused/missing, circular, outdated, license compliance, npm audit,
|
|
119
|
+
and a cross-language vuln scan (osv-scanner, opt-in).
|
|
120
|
+
- Quality (4) — duplicate code, dead code, multi-language spellcheck, markdown lint.
|
|
121
|
+
- PR hygiene (4) — size, title, body, and commit-message convention.
|
|
122
|
+
- Per-language (16) — lint, format, and type-check for the languages listed above.
|
|
246
123
|
|
|
247
124
|
## Configuration
|
|
248
125
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
126
|
+
Everything lives in `pr-checkmate.json`. Run `npx pr-checkmate init` to scaffold the
|
|
127
|
+
full file for your detected languages.
|
|
128
|
+
|
|
129
|
+
- Severity map. The one universal control. Key any check by its display name (as it
|
|
130
|
+
appears in the report) and set `"error"` to fail the run, `"warn"` for advisory, or
|
|
131
|
+
`"off"` to disable it. This works for every check, old or new.
|
|
132
|
+
- Per-check options. For example `prSize.maxFiles`/`maxLines`, `largeFiles.maxSizeKb`
|
|
133
|
+
and `allow`, `prBody.minLength`, `duplicate.minLines`, `missingTests.ignore`, or
|
|
134
|
+
`<check>.ignore` to mute a single finding. Any check also takes `enabled: false`.
|
|
135
|
+
- `customRules`. Your own regex rules run against the diff; a rule with
|
|
136
|
+
`severity: "error"` blocks the run. Fields: `name`, `pattern`, `message?`,
|
|
137
|
+
`severity?`, `include?`, `exclude?`.
|
|
138
|
+
- `bannedImports` forbids specific dependencies or imports. `licenseHeader` requires a
|
|
139
|
+
header on newly added source files (opt-in).
|
|
140
|
+
- Inline suppression. Append `// pr-checkmate-ignore` to any line to skip it.
|
|
141
|
+
|
|
142
|
+
```jsonc
|
|
252
143
|
{
|
|
253
|
-
|
|
254
|
-
"
|
|
255
|
-
"
|
|
256
|
-
"
|
|
144
|
+
// Promote, downgrade, or disable ANY check by its display name.
|
|
145
|
+
"severity": {
|
|
146
|
+
"PR Size": "error", // oversized PRs now fail the run
|
|
147
|
+
"Spellcheck": "off" // turn a check off entirely
|
|
257
148
|
},
|
|
258
|
-
"
|
|
259
|
-
"
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
"enabled": true,
|
|
264
|
-
"minLines": 10,
|
|
265
|
-
"formats": ["javascript", "typescript", "jsx", "tsx", "python", "kotlin", "swift", "c", "cpp"],
|
|
266
|
-
"ignore": ["**/__tests__/**", "**/*.test.*", "**/*.spec.*", "**/test/**", "**/tests/**"]
|
|
267
|
-
},
|
|
268
|
-
"deadCode": {
|
|
269
|
-
"enabled": true,
|
|
270
|
-
"ignoreFiles": ["src/index\\.ts", "handler"]
|
|
271
|
-
},
|
|
272
|
-
"dependency": {
|
|
273
|
-
"enabled": true,
|
|
274
|
-
"ignore": ["@types/*", "some-cli-tool"]
|
|
275
|
-
},
|
|
276
|
-
"commitlint": {
|
|
277
|
-
"enabled": true,
|
|
278
|
-
"types": ["feat", "fix", "docs", "chore", "ci", "refactor", "test"]
|
|
279
|
-
},
|
|
280
|
-
"licenseCheck": {
|
|
281
|
-
"allowPackages": [],
|
|
282
|
-
"allowLicenses": ["LGPL-3.0"]
|
|
283
|
-
},
|
|
284
|
-
"prBody": { "enabled": true, "minLength": 20, "requireTicket": true }
|
|
149
|
+
"prSize": { "maxFiles": 40, "maxLines": 800 },
|
|
150
|
+
"customRules": [
|
|
151
|
+
{ "name": "no-fixme", "pattern": "FIXME", "severity": "error" }
|
|
152
|
+
]
|
|
153
|
+
// Skip a single line by appending `// pr-checkmate-ignore` to it.
|
|
285
154
|
}
|
|
286
155
|
```
|
|
287
156
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
- Setting it replaces the default test-file list rather than merging with it. If you add your own patterns, include any test globs you still want excluded.
|
|
291
|
-
- `node_modules/**`, `dist/**`, and `.git/**` are always excluded, regardless of config.
|
|
292
|
-
- `duplicate.formats` defaults to source-code formats only, so data files like YAML, JSON, and Markdown are not scanned. Setting it replaces the default list, so add `"yaml"` if you want duplication flagged in those files too.
|
|
293
|
-
|
|
294
|
-
A note on `dependency.ignore`:
|
|
295
|
-
|
|
296
|
-
- List dependency names or globs (such as `"@types/*"`) to exclude from the unused/missing check. The values are passed straight to depcheck's `--ignores`.
|
|
297
|
-
- Use it for packages that only run as CLI binaries or are referenced from config files. depcheck sees no `import` for them and would otherwise flag them as unused.
|
|
298
|
-
- When set, `dependency.ignore` takes precedence over any `.depcheckrc` file. Leave it empty or unset and your existing `.depcheckrc` still applies.
|
|
299
|
-
|
|
300
|
-
A note on `deadCode.ignoreFiles`:
|
|
301
|
-
|
|
302
|
-
- The values are regex sources, not globs, and each one is matched against the file path. So `\.test\.` matches any file with `.test.` in its name.
|
|
303
|
-
- It defaults to test and mock files: `/__tests__/`, `/__mocks__/`, `/__mock__/`, `/tests?/`, `\.test\.`, `\.spec\.`. Their exports are consumed only by the test runner, so they showed up as false-positive "unused" before.
|
|
304
|
-
- Setting it replaces the default list rather than merging with it. Reach for it to exempt entry points or barrels like `src/index.ts` or a lambda `handler` whose exports are the public surface.
|
|
305
|
-
- It applies to the report only and never drops files from analysis, so a match here cannot cascade into missed dead code elsewhere.
|
|
306
|
-
|
|
307
|
-
---
|
|
308
|
-
|
|
309
|
-
## Delta Mode
|
|
310
|
-
|
|
311
|
-
In GitHub Actions PR context, language checks automatically switch to **delta mode** — only files changed in the PR are checked. Outside PR context (local, push workflows) the checks fall back to a full project scan.
|
|
157
|
+
## PR Summary Comment
|
|
312
158
|
|
|
313
|
-
|
|
159
|
+
After `npx pr-checkmate all`, a summary table is posted to the PR and updated in place
|
|
160
|
+
on later pushes, so there are no duplicate comments. Format fixes (Prettier, Ruff,
|
|
161
|
+
clang-format, and the rest) are committed straight back to the branch. Posting needs
|
|
162
|
+
the `pull-requests: write` permission, which the generated workflow already includes.
|
|
314
163
|
|
|
315
164
|
## Programmatic API
|
|
316
165
|
|
|
317
|
-
Besides the CLI, PR CheckMate ships a typed
|
|
318
|
-
|
|
319
|
-
|
|
166
|
+
Besides the CLI, PR CheckMate ships a typed API for embedding the same gates in your own
|
|
167
|
+
tooling. Import `runChecks`, `defineCheck`, and the outcome helpers, then run the
|
|
168
|
+
registry or your own checks. The full reference is at the
|
|
169
|
+
[API docs site](https://pr-checkmate-docs.pages.dev).
|
|
320
170
|
|
|
321
171
|
```ts
|
|
322
172
|
import { runChecks } from 'pr-checkmate';
|
|
323
|
-
import type { CheckReport } from 'pr-checkmate';
|
|
324
|
-
|
|
325
|
-
const report: CheckReport = await runChecks({
|
|
326
|
-
cwd: process.cwd(),
|
|
327
|
-
reporter: 'stdout', // 'none' | 'stdout' | 'github' | (report) => void
|
|
328
|
-
});
|
|
329
173
|
|
|
174
|
+
const report = await runChecks({ cwd: process.cwd(), reporter: 'github' });
|
|
330
175
|
if (!report.ok) process.exit(1);
|
|
331
176
|
```
|
|
332
177
|
|
|
333
|
-
`runChecks` never throws on violations and never calls `process.exit
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
```ts
|
|
338
|
-
import { runChecks, defineCheck, pass, fail } from 'pr-checkmate';
|
|
339
|
-
|
|
340
|
-
const noFixmes = defineCheck({
|
|
341
|
-
name: 'no-fixmes',
|
|
342
|
-
phase: 'lint',
|
|
343
|
-
applies: () => true,
|
|
344
|
-
run: async (ctx) => {
|
|
345
|
-
// inspect ctx (config, changed files, language, sha range) and return an outcome
|
|
346
|
-
return pass();
|
|
347
|
-
},
|
|
348
|
-
});
|
|
349
|
-
|
|
350
|
-
await runChecks({ checks: [noFixmes] }); // appended to the built-in registry by default
|
|
351
|
-
```
|
|
352
|
-
|
|
353
|
-
### Key exports
|
|
354
|
-
|
|
355
|
-
| Export | Purpose |
|
|
356
|
-
|---|---|
|
|
357
|
-
| `runChecks` | Run the check pipeline; returns a structured `CheckReport` |
|
|
358
|
-
| `buildContext` | Build the `CheckContext` (language, config, sha range) checks receive |
|
|
359
|
-
| `REGISTRY` | The array of built-in checks |
|
|
360
|
-
| `defineCheck` | Identity helper for authoring a `Check` with full type inference |
|
|
361
|
-
| `pass` / `warn` / `fail` / `skip` | Outcome constructors for check bodies |
|
|
362
|
-
| `getSourcePath` / `getPackageConfigPath` / `hasLocalConfig` | Config-path helpers |
|
|
363
|
-
| Types | `Check`, `CheckContext`, `CheckReport`, `CheckResult`, `CheckOutcome`, `CheckStatus`, `RunOptions`, `Language`, `Phase`, `ReporterKind`, `ReporterFn`, `PRCheckMateConfig` |
|
|
364
|
-
|
|
365
|
-
Regenerate the docs locally with `npm run docs` (output in `docs/api`).
|
|
366
|
-
|
|
367
|
-
---
|
|
368
|
-
|
|
369
|
-
## PR Summary Comment
|
|
370
|
-
|
|
371
|
-
After `npx pr-checkmate all`, a summary table is posted to the PR. On repeated pushes the comment is updated in place — no duplicate comments.
|
|
372
|
-
|
|
373
|
-
```text
|
|
374
|
-
## PR CheckMate Summary
|
|
375
|
-
|
|
376
|
-
11 passed · 3 warnings · 0 failed · 0 skipped
|
|
377
|
-
|
|
378
|
-
| Check | Result |
|
|
379
|
-
|----------------|-----------------------------------------|
|
|
380
|
-
| ESLint | ✅ pass |
|
|
381
|
-
| TypeScript | ✅ pass |
|
|
382
|
-
| Ruff Lint | ⚠️ warn — 3 issues in 2 files |
|
|
383
|
-
| Diff Smell | ⚠️ warn — 2x console.*(), 1x TODO |
|
|
384
|
-
| PR Body | ⚠️ warn — no ticket reference |
|
|
385
|
-
| ... | ... |
|
|
386
|
-
```
|
|
387
|
-
|
|
388
|
-
Requires `pull-requests: write` permission — the generated workflow includes this automatically.
|
|
389
|
-
|
|
390
|
-
---
|
|
391
|
-
|
|
392
|
-
## Tech Stack
|
|
393
|
-
|
|
394
|
-
| Tool | Role |
|
|
395
|
-
|---|---|
|
|
396
|
-
| ESLint + @typescript-eslint | TypeScript / JS linting |
|
|
397
|
-
| eslint-plugin-sonarjs | Complexity analysis |
|
|
398
|
-
| eslint-plugin-import | Import ordering |
|
|
399
|
-
| eslint-plugin-jsdoc | Documentation coverage |
|
|
400
|
-
| Prettier | Code formatting |
|
|
401
|
-
| @astral-sh/ruff-wasm-nodejs | Python lint + format (WASM) |
|
|
402
|
-
| @wasm-fmt/clang-format | C++ formatting (WASM) |
|
|
403
|
-
| SwiftLint | Swift linting (system binary) |
|
|
404
|
-
| ktlint | Kotlin linting (system binary) |
|
|
405
|
-
| cspell | Multilingual spellcheck |
|
|
406
|
-
| gitleaks | Secret scanning |
|
|
407
|
-
| depcheck | Dependency analysis |
|
|
408
|
-
| ts-unused-exports | Dead code detection |
|
|
409
|
-
| jscpd | Duplicate code detection |
|
|
410
|
-
| license-checker | License compliance |
|
|
411
|
-
|
|
412
|
-
---
|
|
178
|
+
`runChecks` never throws on violations and never calls `process.exit`; the caller
|
|
179
|
+
decides. `report.ok` is `true` when nothing failed, and warnings and skips do not
|
|
180
|
+
affect it.
|
|
413
181
|
|
|
414
182
|
## License
|
|
415
183
|
|
package/cspell.json
CHANGED
|
@@ -693,7 +693,15 @@
|
|
|
693
693
|
"litert",
|
|
694
694
|
"SHTPB",
|
|
695
695
|
"FUTX",
|
|
696
|
-
"subdirs"
|
|
696
|
+
"subdirs",
|
|
697
|
+
"clippy",
|
|
698
|
+
"mypy",
|
|
699
|
+
"pyright",
|
|
700
|
+
"jacoco",
|
|
701
|
+
"depcheckrc",
|
|
702
|
+
"gofmt",
|
|
703
|
+
"dotnet",
|
|
704
|
+
"rubocop"
|
|
697
705
|
],
|
|
698
706
|
"ignorePaths": [
|
|
699
707
|
"**/node_modules/**",
|
package/dist/cli.js
CHANGED
|
@@ -22,6 +22,21 @@ const COMMAND_TO_CHECK = {
|
|
|
22
22
|
typecheck: 'TypeScript',
|
|
23
23
|
'diff-smell': 'Diff Smells',
|
|
24
24
|
'diff-security': 'Diff Security',
|
|
25
|
+
'workflow-security': 'Workflow Security',
|
|
26
|
+
'custom-rules': 'Custom Rules',
|
|
27
|
+
'banned-imports': 'Banned Imports',
|
|
28
|
+
'license-header': 'License Header',
|
|
29
|
+
'config-validation': 'Config Validation',
|
|
30
|
+
'dockerfile-security': 'Dockerfile Security',
|
|
31
|
+
'case-collision': 'Case Collision',
|
|
32
|
+
'vuln-scan': 'Vuln Scan',
|
|
33
|
+
'leftover-debug': 'Leftover Debug',
|
|
34
|
+
'lockfile-drift': 'Lockfile Drift',
|
|
35
|
+
'large-files': 'Large Files',
|
|
36
|
+
'todo-fixme': 'TODO/FIXME',
|
|
37
|
+
'missing-tests': 'Missing Tests',
|
|
38
|
+
coverage: 'Coverage',
|
|
39
|
+
'migration-safety': 'Migration Safety',
|
|
25
40
|
'sensitive-files': 'Sensitive Files',
|
|
26
41
|
'pr-body': 'PR Body',
|
|
27
42
|
duplicate: 'Duplicate Code',
|
|
@@ -29,6 +44,14 @@ const COMMAND_TO_CHECK = {
|
|
|
29
44
|
'cpp-format': 'C++ Format',
|
|
30
45
|
'python-lint': 'Ruff Lint',
|
|
31
46
|
'python-format': 'Ruff Format',
|
|
47
|
+
'python-typecheck': 'Python Types',
|
|
48
|
+
'go-lint': 'Go Vet',
|
|
49
|
+
'go-format': 'Go Format',
|
|
50
|
+
'rust-lint': 'Clippy',
|
|
51
|
+
'rust-format': 'Rustfmt',
|
|
52
|
+
'csharp-format': 'C# Format',
|
|
53
|
+
'ruby-lint': 'RuboCop',
|
|
54
|
+
'php-format': 'PHP CS Fixer',
|
|
32
55
|
};
|
|
33
56
|
const cmd = process.argv[2];
|
|
34
57
|
void (async () => {
|
|
@@ -37,9 +60,16 @@ void (async () => {
|
|
|
37
60
|
await (0, init_1.init)();
|
|
38
61
|
process.exit(0);
|
|
39
62
|
}
|
|
40
|
-
// Full run:
|
|
63
|
+
// Full run: auto-detect the CI platform (GitHub/GitLab/Bitbucket), post the
|
|
64
|
+
// summary to its PR/MR, and allow formatters to write.
|
|
41
65
|
if (!cmd || cmd === 'all') {
|
|
42
|
-
const report = await (0, core_1.runChecks)({ reporter: '
|
|
66
|
+
const report = await (0, core_1.runChecks)({ reporter: 'auto', write: true });
|
|
67
|
+
process.exit(report.ok ? 0 : 1);
|
|
68
|
+
}
|
|
69
|
+
// Local pre-commit: check the staged changes (index vs HEAD), print to
|
|
70
|
+
// stdout, never modify files. Exits non-zero on failure to block the commit.
|
|
71
|
+
if (cmd === 'precommit') {
|
|
72
|
+
const report = await (0, core_1.runChecks)({ staged: true, reporter: 'stdout', write: false });
|
|
43
73
|
process.exit(report.ok ? 0 : 1);
|
|
44
74
|
}
|
|
45
75
|
const checkName = COMMAND_TO_CHECK[cmd];
|
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Build output, dependency, tooling, and report directories that are never
|
|
3
|
+
* product code. Every check excludes them by directory-name segment match (see
|
|
4
|
+
* `targets.ts`): a match on any segment of a path drops the file. Untracked
|
|
5
|
+
* build dirs are already excluded because checks read git-tracked files only —
|
|
6
|
+
* this list additionally covers dirs that repos commonly *commit* (`.github`,
|
|
7
|
+
* `.vscode`, `.idea`, `.claude`) and any checked-in build artifacts.
|
|
8
|
+
*
|
|
9
|
+
* Covers the common ecosystems: Node/JS/web, Python, Java/Kotlin/Gradle/Android,
|
|
10
|
+
* Swift/iOS/Xcode, and C/C++/CMake. Add more here.
|
|
11
|
+
*/
|
|
12
|
+
export declare const IGNORED_DIRS: string[];
|
|
13
|
+
/**
|
|
14
|
+
* Glob form of the ignore list, for tools that take glob ignores directly
|
|
15
|
+
* (ESLint `--ignore-pattern`, cspell `--exclude`, the generated
|
|
16
|
+
* `.prettierignore`). Combines {@link IGNORED_DIRS} with a few tool-specific
|
|
17
|
+
* nested report globs that are not plain directory names.
|
|
3
18
|
*/
|
|
4
19
|
export declare const IGNORE_PATTERNS: string[];
|
|
5
20
|
/**
|
|
@@ -66,3 +81,12 @@ export declare const documentation: {
|
|
|
66
81
|
cspell: string;
|
|
67
82
|
};
|
|
68
83
|
export declare const CONFIG_FILE: string;
|
|
84
|
+
/**
|
|
85
|
+
* Every top-level key PR CheckMate recognises in pr-checkmate.json — the union
|
|
86
|
+
* of the `PRCheckMateConfig` interface fields and the keys the `init` generator
|
|
87
|
+
* writes (which use `eslint`/`cspell`/`markdownlint` rather than the interface's
|
|
88
|
+
* `lint`/`spellcheck`). The Config Validation check warns on any key not in this
|
|
89
|
+
* set (typos), ignoring `//`-prefixed comment keys and `$schema`. Keep in sync
|
|
90
|
+
* when adding a new configurable check.
|
|
91
|
+
*/
|
|
92
|
+
export declare const KNOWN_CONFIG_KEYS: Set<string>;
|