pr-checkmate 1.21.0 → 1.21.1
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/.markdownlint.json +10 -0
- package/README.md +217 -70
- package/dist/config/pr-checkmate-workflow.yml +21 -0
- package/dist/index.js +7 -1
- package/dist/init.js +5 -0
- package/dist/scripts/dependency-check.js +34 -22
- package/dist/scripts/index.js +7 -1
- package/dist/scripts/license-check.js +2 -1
- package/dist/scripts/markdown-lint.js +62 -0
- package/package.json +3 -1
- package/src/config/pr-checkmate-workflow.yml +21 -0
package/README.md
CHANGED
|
@@ -2,64 +2,67 @@
|
|
|
2
2
|

|
|
3
3
|

|
|
4
4
|
|
|
5
|
-
|
|
6
5
|
# ♟️ PR CheckMate
|
|
6
|
+
>
|
|
7
7
|
> **PR CheckMate** is an npm package for automating Pull Request checks.
|
|
8
|
-
> It helps teams maintain code quality by automatically validating linting, formatting, dependencies, and spelling before merging to `main`.
|
|
8
|
+
> It helps teams maintain code quality by automatically validating linting, formatting, dependencies, security, and spelling before merging to `main`.
|
|
9
9
|
|
|
10
10
|
## 🔍 Why PR CheckMate?
|
|
11
|
+
|
|
11
12
|
* ✅ Automatic checks on every PR without extra setup.
|
|
12
13
|
* ✅ No need to install ESLint, Prettier, or cspell in your project — all included.
|
|
13
14
|
* ✅ Enforces a unified code style across repositories.
|
|
14
|
-
* ✅
|
|
15
|
-
* ✅
|
|
16
|
-
* ✅
|
|
17
|
-
* ✅
|
|
15
|
+
* ✅ Detects unused and missing dependencies via `depcheck`.
|
|
16
|
+
* ✅ Finds circular dependencies before they reach production.
|
|
17
|
+
* ✅ Blocks GPL/AGPL/LGPL licensed packages from slipping in.
|
|
18
|
+
* ✅ Validates PR title against Conventional Commits.
|
|
19
|
+
* ✅ Warns about oversized PRs and major-behind packages.
|
|
20
|
+
* ✅ Spellcheck for code, docs, and JSON with multilingual support (EN, RU, UK, HE, FR).
|
|
21
|
+
* ✅ Package vulnerability check via `npm audit`.
|
|
22
|
+
* ✅ Secret scanning via `gitleaks`.
|
|
23
|
+
* ✅ **Delta mode** — in GitHub PR context only changed files are checked, not the entire project.
|
|
24
|
+
* ✅ **Parallel execution** — all independent checks run concurrently, cutting CI time ~4×.
|
|
18
25
|
|
|
19
26
|
<br>
|
|
20
27
|
> ⚠️ **Note:** Currently, PR CheckMate only supports **Node.js projects**.
|
|
21
28
|
|
|
22
|
-
|
|
23
|
-
- [PR CheckMate](https://www.npmjs.com/package/pr-checkmate) – Zero-config CLI that automates ESLint, Prettier, spellcheck, dependency checks, and npm audit for pull requests.
|
|
29
|
+
* [PR CheckMate](https://www.npmjs.com/package/pr-checkmate) – Zero-config CLI that automates ESLint, Prettier, spellcheck, dependency checks, and npm audit for pull requests.
|
|
24
30
|
|
|
25
31
|
## 🚀 Zero-Config by Default
|
|
32
|
+
|
|
26
33
|
You don't need to install or configure:
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
34
|
+
|
|
35
|
+
* ESLint
|
|
36
|
+
* Prettier
|
|
37
|
+
* cspell (with multilingual dictionaries)
|
|
38
|
+
* Security scanning tools
|
|
31
39
|
|
|
32
40
|
> Everything works out of the box.
|
|
33
41
|
<br>
|
|
34
42
|
|
|
35
43
|
### 🧩 Fully Customizable
|
|
44
|
+
|
|
36
45
|
Users can override:
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
46
|
+
|
|
47
|
+
* ESLint rules and ignore patterns
|
|
48
|
+
* Prettier rules
|
|
49
|
+
* CSpell dictionary and ignore lists
|
|
50
|
+
* Which checks run (skip flags)
|
|
51
|
+
* Source code path
|
|
42
52
|
|
|
43
53
|
User configuration is stored in:
|
|
54
|
+
|
|
44
55
|
```
|
|
45
56
|
<project-root>/pr-checkmate.json
|
|
46
57
|
```
|
|
58
|
+
|
|
47
59
|
<br>
|
|
48
60
|
|
|
49
61
|
### ⚙️ Example: pr-checkmate.json
|
|
62
|
+
|
|
50
63
|
```json
|
|
51
64
|
{
|
|
52
65
|
"sourcePath": "src",
|
|
53
|
-
"commands": {
|
|
54
|
-
"npx pr-checkmate init": "Update pr-checkmate.json",
|
|
55
|
-
"npx pr-checkmate all": "Run all checks",
|
|
56
|
-
"npx pr-checkmate lint": "Lint code using ESLint",
|
|
57
|
-
"npx pr-checkmate prettier": "Format code using Prettier",
|
|
58
|
-
"npx pr-checkmate deps": "Check project dependencies",
|
|
59
|
-
"npx pr-checkmate npm-audit": "Run package vulnerabilities check",
|
|
60
|
-
"npx pr-checkmate security": "Security scan",
|
|
61
|
-
"npx pr-checkmate spellcheck": "Run spellcheck via cspell"
|
|
62
|
-
},
|
|
63
66
|
"eslint": {
|
|
64
67
|
"rules": {},
|
|
65
68
|
"ignorePatterns": []
|
|
@@ -79,11 +82,12 @@ User configuration is stored in:
|
|
|
79
82
|
"cspell": "https://cspell.org/configuration/"
|
|
80
83
|
}
|
|
81
84
|
}
|
|
82
|
-
|
|
83
85
|
```
|
|
86
|
+
|
|
84
87
|
<br>
|
|
85
88
|
|
|
86
89
|
## 🛠 How It Works
|
|
90
|
+
|
|
87
91
|
### 1. Install
|
|
88
92
|
|
|
89
93
|
```bash
|
|
@@ -91,28 +95,47 @@ npm install --save-dev pr-checkmate
|
|
|
91
95
|
```
|
|
92
96
|
|
|
93
97
|
### 2. Initialize
|
|
98
|
+
|
|
94
99
|
```bash
|
|
95
100
|
npx pr-checkmate init
|
|
96
101
|
```
|
|
102
|
+
|
|
97
103
|
> This creates:
|
|
98
|
-
>
|
|
99
|
-
>
|
|
104
|
+
>
|
|
105
|
+
> * `pr-checkmate.json` — configuration file for source path and custom rules
|
|
106
|
+
> * `.github/workflows/pr-checkmate.yml` — GitHub Actions workflow with per-job checks and auto-commit support
|
|
100
107
|
|
|
101
108
|
### 3. Run Checks
|
|
109
|
+
|
|
102
110
|
```bash
|
|
103
111
|
npx pr-checkmate <job>
|
|
104
112
|
```
|
|
105
113
|
|
|
106
114
|
#### ⚡ Jobs
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
| `
|
|
111
|
-
| `
|
|
112
|
-
| `
|
|
113
|
-
| `
|
|
114
|
-
| `
|
|
115
|
-
| `
|
|
115
|
+
|
|
116
|
+
| Job | Description |
|
|
117
|
+
|----------------|-------------|
|
|
118
|
+
| `all` | Run all checks in parallel (lint, deps, audit, security, circular, license, then spellcheck, pr-size, pr-title, outdated, markdown, then prettier) |
|
|
119
|
+
| `lint` | Lint code using ESLint |
|
|
120
|
+
| `prettier` | Format code using Prettier |
|
|
121
|
+
| `deps` | Check unused / missing dependencies via depcheck |
|
|
122
|
+
| `security` | Scan for secrets using gitleaks |
|
|
123
|
+
| `spellcheck` | Spellcheck via cspell (EN, RU, UK, HE, FR) |
|
|
124
|
+
| `audit` | Run `npm audit --audit-level=moderate` |
|
|
125
|
+
| `circular` | Detect circular dependencies via dpdm |
|
|
126
|
+
| `license` | Block GPL / AGPL / LGPL licensed packages |
|
|
127
|
+
| `pr-size` | Warn if PR exceeds 50 files or 1 000 changed lines |
|
|
128
|
+
| `pr-title` | Validate PR title against Conventional Commits format |
|
|
129
|
+
| `outdated` | Report packages that are major versions behind |
|
|
130
|
+
| `markdown` | Lint `.md`/`.mdx` files via markdownlint (warning-only, delta mode) |
|
|
131
|
+
|
|
132
|
+
<br>
|
|
133
|
+
|
|
134
|
+
### ⚡ Delta Mode
|
|
135
|
+
|
|
136
|
+
In a GitHub Actions PR context, `lint`, `prettier`, `spellcheck`, and `markdown` automatically switch to **delta mode** — only the files changed in the PR are checked instead of the entire project. This is transparent and requires no configuration.
|
|
137
|
+
|
|
138
|
+
Outside of a PR context (local runs, push workflows) the checks fall back to the full project scan.
|
|
116
139
|
|
|
117
140
|
<br>
|
|
118
141
|
|
|
@@ -133,28 +156,149 @@ permissions:
|
|
|
133
156
|
pull-requests: write
|
|
134
157
|
|
|
135
158
|
jobs:
|
|
136
|
-
|
|
137
|
-
name:
|
|
159
|
+
lint:
|
|
160
|
+
name: ESLint
|
|
161
|
+
runs-on: ubuntu-latest
|
|
162
|
+
steps:
|
|
163
|
+
- uses: actions/checkout@v4
|
|
164
|
+
with: { ref: "${{ github.head_ref }}", fetch-depth: 0 }
|
|
165
|
+
- uses: actions/setup-node@v4
|
|
166
|
+
with: { node-version: 20 }
|
|
167
|
+
- run: npm ci
|
|
168
|
+
- run: npx pr-checkmate lint
|
|
169
|
+
continue-on-error: true
|
|
170
|
+
|
|
171
|
+
deps:
|
|
172
|
+
name: Dependency Check
|
|
173
|
+
runs-on: ubuntu-latest
|
|
174
|
+
steps:
|
|
175
|
+
- uses: actions/checkout@v4
|
|
176
|
+
with: { ref: "${{ github.head_ref }}", fetch-depth: 0 }
|
|
177
|
+
- uses: actions/setup-node@v4
|
|
178
|
+
with: { node-version: 20 }
|
|
179
|
+
- run: npm ci
|
|
180
|
+
- run: npx pr-checkmate deps
|
|
181
|
+
continue-on-error: true
|
|
182
|
+
|
|
183
|
+
circular-deps:
|
|
184
|
+
name: Circular Dependencies
|
|
185
|
+
runs-on: ubuntu-latest
|
|
186
|
+
steps:
|
|
187
|
+
- uses: actions/checkout@v4
|
|
188
|
+
with: { ref: "${{ github.head_ref }}", fetch-depth: 0 }
|
|
189
|
+
- uses: actions/setup-node@v4
|
|
190
|
+
with: { node-version: 20 }
|
|
191
|
+
- run: npm ci
|
|
192
|
+
- run: npx pr-checkmate circular
|
|
193
|
+
continue-on-error: true
|
|
194
|
+
|
|
195
|
+
license-check:
|
|
196
|
+
name: License Check
|
|
138
197
|
runs-on: ubuntu-latest
|
|
139
198
|
steps:
|
|
140
|
-
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
- name: Setup Node.js
|
|
147
|
-
uses: actions/setup-node@v4
|
|
148
|
-
with:
|
|
149
|
-
node-version: 20
|
|
150
|
-
|
|
151
|
-
- name: Install dependencies
|
|
152
|
-
run: npm ci
|
|
153
|
-
|
|
154
|
-
- name: Run PR Checkmate All Checks
|
|
155
|
-
run: npx pr-checkmate all
|
|
199
|
+
- uses: actions/checkout@v4
|
|
200
|
+
with: { ref: "${{ github.head_ref }}", fetch-depth: 0 }
|
|
201
|
+
- uses: actions/setup-node@v4
|
|
202
|
+
with: { node-version: 20 }
|
|
203
|
+
- run: npm ci
|
|
204
|
+
- run: npx pr-checkmate license
|
|
156
205
|
continue-on-error: true
|
|
157
206
|
|
|
207
|
+
pr-size:
|
|
208
|
+
name: PR Size
|
|
209
|
+
runs-on: ubuntu-latest
|
|
210
|
+
steps:
|
|
211
|
+
- uses: actions/checkout@v4
|
|
212
|
+
with: { ref: "${{ github.head_ref }}", fetch-depth: 0 }
|
|
213
|
+
- uses: actions/setup-node@v4
|
|
214
|
+
with: { node-version: 20 }
|
|
215
|
+
- run: npm ci
|
|
216
|
+
- run: npx pr-checkmate pr-size
|
|
217
|
+
continue-on-error: true
|
|
218
|
+
|
|
219
|
+
pr-title:
|
|
220
|
+
name: PR Title Lint
|
|
221
|
+
runs-on: ubuntu-latest
|
|
222
|
+
steps:
|
|
223
|
+
- uses: actions/checkout@v4
|
|
224
|
+
with: { ref: "${{ github.head_ref }}", fetch-depth: 0 }
|
|
225
|
+
- uses: actions/setup-node@v4
|
|
226
|
+
with: { node-version: 20 }
|
|
227
|
+
- run: npm ci
|
|
228
|
+
- run: npx pr-checkmate pr-title
|
|
229
|
+
continue-on-error: true
|
|
230
|
+
|
|
231
|
+
outdated-deps:
|
|
232
|
+
name: Outdated Dependencies
|
|
233
|
+
runs-on: ubuntu-latest
|
|
234
|
+
steps:
|
|
235
|
+
- uses: actions/checkout@v4
|
|
236
|
+
with: { ref: "${{ github.head_ref }}", fetch-depth: 0 }
|
|
237
|
+
- uses: actions/setup-node@v4
|
|
238
|
+
with: { node-version: 20 }
|
|
239
|
+
- run: npm ci
|
|
240
|
+
- run: npx pr-checkmate outdated
|
|
241
|
+
continue-on-error: true
|
|
242
|
+
|
|
243
|
+
markdown-lint:
|
|
244
|
+
name: Markdown Lint
|
|
245
|
+
runs-on: ubuntu-latest
|
|
246
|
+
steps:
|
|
247
|
+
- uses: actions/checkout@v4
|
|
248
|
+
with: { ref: "${{ github.head_ref }}", fetch-depth: 0 }
|
|
249
|
+
- uses: actions/setup-node@v4
|
|
250
|
+
with: { node-version: 20 }
|
|
251
|
+
- run: npm ci
|
|
252
|
+
- run: npx pr-checkmate markdown
|
|
253
|
+
continue-on-error: true
|
|
254
|
+
|
|
255
|
+
spellcheck:
|
|
256
|
+
name: Spellcheck
|
|
257
|
+
runs-on: ubuntu-latest
|
|
258
|
+
steps:
|
|
259
|
+
- uses: actions/checkout@v4
|
|
260
|
+
with: { ref: "${{ github.head_ref }}", fetch-depth: 0 }
|
|
261
|
+
- uses: actions/setup-node@v4
|
|
262
|
+
with: { node-version: 20 }
|
|
263
|
+
- run: npm ci
|
|
264
|
+
- run: npx pr-checkmate spellcheck
|
|
265
|
+
continue-on-error: true
|
|
266
|
+
|
|
267
|
+
security:
|
|
268
|
+
name: Security Scan
|
|
269
|
+
runs-on: ubuntu-latest
|
|
270
|
+
steps:
|
|
271
|
+
- uses: actions/checkout@v4
|
|
272
|
+
with: { ref: "${{ github.head_ref }}", fetch-depth: 0 }
|
|
273
|
+
- uses: actions/setup-node@v4
|
|
274
|
+
with: { node-version: 20 }
|
|
275
|
+
- run: npm ci
|
|
276
|
+
- run: npx pr-checkmate security
|
|
277
|
+
continue-on-error: true
|
|
278
|
+
|
|
279
|
+
npm-audit:
|
|
280
|
+
name: NPM Audit
|
|
281
|
+
runs-on: ubuntu-latest
|
|
282
|
+
steps:
|
|
283
|
+
- uses: actions/checkout@v4
|
|
284
|
+
with: { ref: "${{ github.head_ref }}", fetch-depth: 0 }
|
|
285
|
+
- uses: actions/setup-node@v4
|
|
286
|
+
with: { node-version: 20 }
|
|
287
|
+
- run: npm ci
|
|
288
|
+
- run: npx pr-checkmate audit
|
|
289
|
+
continue-on-error: true
|
|
290
|
+
|
|
291
|
+
prettier:
|
|
292
|
+
name: Prettier
|
|
293
|
+
runs-on: ubuntu-latest
|
|
294
|
+
steps:
|
|
295
|
+
- uses: actions/checkout@v4
|
|
296
|
+
with: { ref: "${{ github.head_ref }}", fetch-depth: 0 }
|
|
297
|
+
- uses: actions/setup-node@v4
|
|
298
|
+
with: { node-version: 20 }
|
|
299
|
+
- run: npm ci
|
|
300
|
+
- run: npx pr-checkmate prettier
|
|
301
|
+
continue-on-error: true
|
|
158
302
|
- name: Auto-commit formatting changes
|
|
159
303
|
run: |
|
|
160
304
|
git config user.name "github-actions[bot]"
|
|
@@ -163,9 +307,6 @@ jobs:
|
|
|
163
307
|
if ! git diff --cached --quiet; then
|
|
164
308
|
git commit -m "style: auto-format code with Prettier"
|
|
165
309
|
git push origin HEAD:${{ github.head_ref }}
|
|
166
|
-
echo "Formatting changes committed and pushed"
|
|
167
|
-
else
|
|
168
|
-
echo "No formatting changes needed"
|
|
169
310
|
fi
|
|
170
311
|
env:
|
|
171
312
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
@@ -186,14 +327,15 @@ For the auto-commit feature to work, ensure your repository has the correct perm
|
|
|
186
327
|
## 🌍 Multilingual Spellcheck Support
|
|
187
328
|
|
|
188
329
|
PR CheckMate includes built-in dictionaries for:
|
|
189
|
-
- 🇬🇧 English (en)
|
|
190
|
-
- 🇪🇸 Spanish (es)
|
|
191
|
-
- 🇫🇷 French (fr)
|
|
192
|
-
- 🇷🇺 Russian (ru)
|
|
193
|
-
- 🇺🇦 Ukrainian (uk)
|
|
194
|
-
- 🇮🇱 Hebrew (he)
|
|
195
330
|
|
|
196
|
-
|
|
331
|
+
* 🇬🇧 English (en)
|
|
332
|
+
* 🇪🇸 Spanish (es)
|
|
333
|
+
* 🇫🇷 French (fr)
|
|
334
|
+
* 🇷🇺 Russian (ru)
|
|
335
|
+
* 🇺🇦 Ukrainian (uk)
|
|
336
|
+
* 🇮🇱 Hebrew (he)
|
|
337
|
+
|
|
338
|
+
No additional configuration needed — just use `npx pr-checkmate spellcheck` and it will check spelling in all supported languages.
|
|
197
339
|
|
|
198
340
|
<br>
|
|
199
341
|
|
|
@@ -205,9 +347,11 @@ No additional configuration needed - just use `npx pr-checkmate spellcheck` and
|
|
|
205
347
|
* ✅ Automatic formatting and commits when needed
|
|
206
348
|
* ✅ Multilingual spellcheck support out of the box
|
|
207
349
|
* ✅ Minimal setup — just `init` and `npx pr-checkmate all`
|
|
208
|
-
|
|
350
|
+
* ✅ Delta mode keeps CI fast — only changed files are scanned
|
|
351
|
+
* ✅ License guard prevents copyleft packages from entering your project
|
|
209
352
|
|
|
210
353
|
## 🧰 Tech Stack
|
|
354
|
+
|
|
211
355
|
* **Node.js 20** — executes CLI scripts
|
|
212
356
|
* **TypeScript** — fully typed code
|
|
213
357
|
* **ESLint + @typescript-eslint** — code linting
|
|
@@ -215,7 +359,10 @@ No additional configuration needed - just use `npx pr-checkmate spellcheck` and
|
|
|
215
359
|
* **cspell** — spellchecking with multilingual dictionaries
|
|
216
360
|
* **execa** — running CLI commands from Node.js
|
|
217
361
|
* **gitleaks** — secret scanning
|
|
362
|
+
* **depcheck** — unused and missing dependency analysis
|
|
363
|
+
* **dpdm** — circular dependency detection
|
|
364
|
+
* **license-checker** — license compliance validation
|
|
218
365
|
|
|
366
|
+
## 📜 License
|
|
219
367
|
|
|
220
|
-
|
|
221
|
-
LicenseRef Proprietary © 2025
|
|
368
|
+
LicenseRef Proprietary © 2025
|
|
@@ -242,3 +242,24 @@ jobs:
|
|
|
242
242
|
- name: Check Outdated Dependencies
|
|
243
243
|
run: npx pr-checkmate outdated
|
|
244
244
|
continue-on-error: true
|
|
245
|
+
|
|
246
|
+
markdown-lint:
|
|
247
|
+
name: Markdown Lint
|
|
248
|
+
runs-on: ubuntu-latest
|
|
249
|
+
steps:
|
|
250
|
+
- name: Checkout code
|
|
251
|
+
uses: actions/checkout@v4
|
|
252
|
+
with:
|
|
253
|
+
fetch-depth: 0
|
|
254
|
+
|
|
255
|
+
- name: Setup Node.js
|
|
256
|
+
uses: actions/setup-node@v4
|
|
257
|
+
with:
|
|
258
|
+
node-version: 20
|
|
259
|
+
|
|
260
|
+
- name: Install dependencies
|
|
261
|
+
run: npm ci
|
|
262
|
+
|
|
263
|
+
- name: Run Markdown Lint
|
|
264
|
+
run: npx pr-checkmate markdown
|
|
265
|
+
continue-on-error: true
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.runOutdatedDeps = exports.runPrTitleLint = exports.runPrSizeCheck = exports.runLicenseCheck = exports.runCircularDeps = exports.runNpmAudit = exports.runSecurityScan = exports.runSpellcheck = exports.runPrettier = exports.runDependencyCheck = exports.runLint = exports.hasLocalConfig = exports.getPackageConfigPath = exports.getSourcePath = void 0;
|
|
3
|
+
exports.runMarkdownLint = exports.runOutdatedDeps = exports.runPrTitleLint = exports.runPrSizeCheck = exports.runLicenseCheck = exports.runCircularDeps = exports.runNpmAudit = exports.runSecurityScan = exports.runSpellcheck = exports.runPrettier = exports.runDependencyCheck = exports.runLint = exports.hasLocalConfig = exports.getPackageConfigPath = exports.getSourcePath = void 0;
|
|
4
4
|
exports.runAllChecks = runAllChecks;
|
|
5
5
|
exports.runChecks = runChecks;
|
|
6
6
|
/**
|
|
@@ -19,6 +19,7 @@ const license_check_1 = require("./scripts/license-check");
|
|
|
19
19
|
const pr_size_check_1 = require("./scripts/pr-size-check");
|
|
20
20
|
const pr_title_lint_1 = require("./scripts/pr-title-lint");
|
|
21
21
|
const outdated_deps_1 = require("./scripts/outdated-deps");
|
|
22
|
+
const markdown_lint_1 = require("./scripts/markdown-lint");
|
|
22
23
|
const utils_1 = require("./utils");
|
|
23
24
|
var config_1 = require("./config");
|
|
24
25
|
Object.defineProperty(exports, "getSourcePath", { enumerable: true, get: function () { return config_1.getSourcePath; } });
|
|
@@ -46,6 +47,8 @@ var pr_title_lint_2 = require("./scripts/pr-title-lint");
|
|
|
46
47
|
Object.defineProperty(exports, "runPrTitleLint", { enumerable: true, get: function () { return pr_title_lint_2.runPrTitleLint; } });
|
|
47
48
|
var outdated_deps_2 = require("./scripts/outdated-deps");
|
|
48
49
|
Object.defineProperty(exports, "runOutdatedDeps", { enumerable: true, get: function () { return outdated_deps_2.runOutdatedDeps; } });
|
|
50
|
+
var markdown_lint_2 = require("./scripts/markdown-lint");
|
|
51
|
+
Object.defineProperty(exports, "runMarkdownLint", { enumerable: true, get: function () { return markdown_lint_2.runMarkdownLint; } });
|
|
49
52
|
/**
|
|
50
53
|
* Run all checks with parallel execution where possible.
|
|
51
54
|
* Blocking: lint, deps, npm-audit, security, circular-deps, license.
|
|
@@ -67,6 +70,7 @@ async function runAllChecks() {
|
|
|
67
70
|
(0, pr_size_check_1.runPrSizeCheck)(),
|
|
68
71
|
(0, pr_title_lint_1.runPrTitleLint)(),
|
|
69
72
|
(0, outdated_deps_1.runOutdatedDeps)(),
|
|
73
|
+
(0, markdown_lint_1.runMarkdownLint)(),
|
|
70
74
|
(0, spellcheck_1.runSpellcheck)().catch(() => utils_1.logger.warn('⚠️ Spellcheck found issues, continuing...')),
|
|
71
75
|
]);
|
|
72
76
|
// Phase 3: prettier last — writes files
|
|
@@ -94,6 +98,8 @@ async function runChecks(config = {}) {
|
|
|
94
98
|
await (0, pr_title_lint_1.runPrTitleLint)();
|
|
95
99
|
if (!config.skipOutdated)
|
|
96
100
|
await (0, outdated_deps_1.runOutdatedDeps)();
|
|
101
|
+
if (!config.skipMarkdown)
|
|
102
|
+
await (0, markdown_lint_1.runMarkdownLint)();
|
|
97
103
|
if (!config.skipSpell)
|
|
98
104
|
await (0, spellcheck_1.runSpellcheck)();
|
|
99
105
|
if (!config.skipFormat)
|
package/dist/init.js
CHANGED
|
@@ -15,31 +15,43 @@ async function runDependencyCheck() {
|
|
|
15
15
|
utils_1.logger.warn('[runDependencyCheck]: ⚠️ No package.json found, skipping');
|
|
16
16
|
return;
|
|
17
17
|
}
|
|
18
|
+
// execa v9 always throws on non-zero exit; depcheck exits 255 when it finds issues
|
|
19
|
+
// but the JSON result is still in error.stdout — extract it either way
|
|
20
|
+
let stdout;
|
|
18
21
|
try {
|
|
19
|
-
|
|
20
|
-
const result = JSON.parse(stdout);
|
|
21
|
-
const unused = result.dependencies ?? [];
|
|
22
|
-
const missing = Object.keys(result.missing ?? {});
|
|
23
|
-
if (unused.length === 0 && missing.length === 0) {
|
|
24
|
-
utils_1.logger.info('[runDependencyCheck]: ✅ Dependencies are clean');
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
if (unused.length > 0) {
|
|
28
|
-
utils_1.logger.warn(`[runDependencyCheck]: ⚠️ ${unused.length} unused dependency(ies):`);
|
|
29
|
-
unused.forEach(dep => utils_1.logger.warn(` ${dep}`));
|
|
30
|
-
}
|
|
31
|
-
if (missing.length > 0) {
|
|
32
|
-
utils_1.logger.error(`[runDependencyCheck]: ❌ ${missing.length} missing dependency(ies):`);
|
|
33
|
-
missing.forEach(dep => utils_1.logger.error(` ${dep} (used in: ${result.missing[dep]?.join(', ')})`));
|
|
34
|
-
throw new Error(`Missing dependencies: ${missing.join(', ')}`);
|
|
35
|
-
}
|
|
36
|
-
// Unused deps are warnings — don't block the build
|
|
22
|
+
({ stdout } = await (0, execa_1.execa)('npx', ['depcheck', '--json'], { cwd: projectRoot }));
|
|
37
23
|
}
|
|
38
24
|
catch (err) {
|
|
39
|
-
|
|
40
|
-
|
|
25
|
+
if (err instanceof execa_1.ExecaError && err.stdout) {
|
|
26
|
+
stdout = err.stdout;
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
utils_1.logger.error(`[runDependencyCheck]: ❌ Dependency check failed\n${err}`);
|
|
41
30
|
throw err;
|
|
42
|
-
|
|
43
|
-
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
let result;
|
|
34
|
+
try {
|
|
35
|
+
result = JSON.parse(stdout);
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
utils_1.logger.error('[runDependencyCheck]: ❌ Failed to parse depcheck output');
|
|
39
|
+
throw new Error('depcheck produced invalid JSON');
|
|
40
|
+
}
|
|
41
|
+
const unused = result.dependencies ?? [];
|
|
42
|
+
const missing = Object.keys(result.missing ?? {});
|
|
43
|
+
if (unused.length === 0 && missing.length === 0) {
|
|
44
|
+
utils_1.logger.info('[runDependencyCheck]: ✅ Dependencies are clean');
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
if (unused.length > 0) {
|
|
48
|
+
utils_1.logger.warn(`[runDependencyCheck]: ⚠️ ${unused.length} unused dependency(ies):`);
|
|
49
|
+
unused.forEach(dep => utils_1.logger.warn(` ${dep}`));
|
|
50
|
+
}
|
|
51
|
+
if (missing.length > 0) {
|
|
52
|
+
utils_1.logger.error(`[runDependencyCheck]: ❌ ${missing.length} missing dependency(ies):`);
|
|
53
|
+
missing.forEach(dep => utils_1.logger.error(` ${dep} (used in: ${result.missing[dep]?.join(', ')})`));
|
|
54
|
+
throw new Error(`Missing dependencies: ${missing.join(', ')}`);
|
|
44
55
|
}
|
|
56
|
+
// Unused deps are warnings — don't block the build
|
|
45
57
|
}
|
package/dist/scripts/index.js
CHANGED
|
@@ -25,6 +25,7 @@ const license_check_1 = require("./license-check");
|
|
|
25
25
|
const pr_size_check_1 = require("./pr-size-check");
|
|
26
26
|
const pr_title_lint_1 = require("./pr-title-lint");
|
|
27
27
|
const outdated_deps_1 = require("./outdated-deps");
|
|
28
|
+
const markdown_lint_1 = require("./markdown-lint");
|
|
28
29
|
const utils_1 = require("../utils");
|
|
29
30
|
const lint_1 = require("./lint");
|
|
30
31
|
__exportStar(require("./dependency-check"), exports);
|
|
@@ -37,6 +38,7 @@ __exportStar(require("./license-check"), exports);
|
|
|
37
38
|
__exportStar(require("./pr-size-check"), exports);
|
|
38
39
|
__exportStar(require("./pr-title-lint"), exports);
|
|
39
40
|
__exportStar(require("./outdated-deps"), exports);
|
|
41
|
+
__exportStar(require("./markdown-lint"), exports);
|
|
40
42
|
async function runJob(jobName) {
|
|
41
43
|
utils_1.logger.info(`[runJob]: 🚀 Running job: ${jobName}`);
|
|
42
44
|
try {
|
|
@@ -56,6 +58,7 @@ async function runJob(jobName) {
|
|
|
56
58
|
(0, pr_size_check_1.runPrSizeCheck)(),
|
|
57
59
|
(0, pr_title_lint_1.runPrTitleLint)(),
|
|
58
60
|
(0, outdated_deps_1.runOutdatedDeps)(),
|
|
61
|
+
(0, markdown_lint_1.runMarkdownLint)(),
|
|
59
62
|
(0, spellcheck_1.runSpellcheck)().catch(() => utils_1.logger.warn('⚠️ Spellcheck found issues, continuing...')),
|
|
60
63
|
]);
|
|
61
64
|
// Phase 3: prettier last — writes files
|
|
@@ -100,8 +103,11 @@ async function runJob(jobName) {
|
|
|
100
103
|
case 'outdated':
|
|
101
104
|
await (0, outdated_deps_1.runOutdatedDeps)();
|
|
102
105
|
break;
|
|
106
|
+
case 'markdown':
|
|
107
|
+
await (0, markdown_lint_1.runMarkdownLint)();
|
|
108
|
+
break;
|
|
103
109
|
default:
|
|
104
|
-
utils_1.logger.warn(`[runJob]: Unknown job "${jobName}". Available: all, lint, deps, npm-audit, prettier, spellcheck, security, circular, license, pr-size, pr-title, outdated`);
|
|
110
|
+
utils_1.logger.warn(`[runJob]: Unknown job "${jobName}". Available: all, lint, deps, npm-audit, prettier, spellcheck, security, circular, license, pr-size, pr-title, outdated, markdown`);
|
|
105
111
|
}
|
|
106
112
|
}
|
|
107
113
|
catch (err) {
|
|
@@ -22,7 +22,8 @@ async function runLicenseCheck() {
|
|
|
22
22
|
const licenses = JSON.parse(stdout);
|
|
23
23
|
const violations = [];
|
|
24
24
|
for (const [pkg, info] of Object.entries(licenses)) {
|
|
25
|
-
const
|
|
25
|
+
const raw = info.licenses ?? '';
|
|
26
|
+
const license = Array.isArray(raw) ? raw.join(' OR ') : raw;
|
|
26
27
|
if (FORBIDDEN_LICENSES.some(f => license.includes(f))) {
|
|
27
28
|
violations.push(` ${pkg}: ${license}`);
|
|
28
29
|
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.runMarkdownLint = runMarkdownLint;
|
|
7
|
+
const execa_1 = require("execa");
|
|
8
|
+
const utils_1 = require("../utils");
|
|
9
|
+
const delta_1 = require("../utils/delta");
|
|
10
|
+
const config_1 = require("../config");
|
|
11
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
12
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
13
|
+
function loadUserMarkdownConfig() {
|
|
14
|
+
const configPath = node_path_1.default.join(process.cwd(), 'pr-checkmate.json');
|
|
15
|
+
if (!node_fs_1.default.existsSync(configPath)) {
|
|
16
|
+
return {};
|
|
17
|
+
}
|
|
18
|
+
try {
|
|
19
|
+
const config = JSON.parse(node_fs_1.default.readFileSync(configPath, 'utf-8'));
|
|
20
|
+
return config.markdownlint || {};
|
|
21
|
+
}
|
|
22
|
+
catch (err) {
|
|
23
|
+
utils_1.logger.warn(`[loadUserMarkdownConfig]: ⚠️ Failed to read markdownlint config from pr-checkmate.json: ${err}`);
|
|
24
|
+
return {};
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
async function runMarkdownLint() {
|
|
28
|
+
utils_1.logger.info('[runMarkdownLint]: 📝 Running Markdown lint...');
|
|
29
|
+
const root = process.cwd();
|
|
30
|
+
const changedFiles = await (0, delta_1.getChangedFiles)(['.md', '.mdx']);
|
|
31
|
+
const targets = changedFiles ?? [`${root}/**/*.md`];
|
|
32
|
+
const userConfig = loadUserMarkdownConfig();
|
|
33
|
+
// Prefer local .markdownlint.json → else fall back to bundled one
|
|
34
|
+
let configArg;
|
|
35
|
+
if ((0, config_1.hasLocalConfig)(['.markdownlint.json', '.markdownlint.jsonc', '.markdownlint.yaml', '.markdownlint.yml'])) {
|
|
36
|
+
utils_1.logger.info('[runMarkdownLint]: 📋 Using local .markdownlint config');
|
|
37
|
+
configArg = [];
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
const bundledConfig = (0, config_1.getPackageConfigPath)('.markdownlint.json');
|
|
41
|
+
utils_1.logger.info('[runMarkdownLint]: 📋 Using pr-checkmate bundled markdownlint config');
|
|
42
|
+
configArg = ['--config', bundledConfig];
|
|
43
|
+
}
|
|
44
|
+
const extraIgnores = (userConfig.ignores ?? []).flatMap(p => ['--ignore', p]);
|
|
45
|
+
const args = [
|
|
46
|
+
'markdownlint',
|
|
47
|
+
...targets,
|
|
48
|
+
...configArg,
|
|
49
|
+
'--ignore', 'node_modules',
|
|
50
|
+
'--ignore', 'dist',
|
|
51
|
+
'--ignore', 'coverage',
|
|
52
|
+
...extraIgnores,
|
|
53
|
+
];
|
|
54
|
+
const result = await (0, execa_1.execa)('npx', args, { reject: false, stdio: 'inherit' });
|
|
55
|
+
if (result.exitCode === 0) {
|
|
56
|
+
utils_1.logger.info('[runMarkdownLint]: ✅ Markdown lint passed');
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
utils_1.logger.warn('[runMarkdownLint]: ⚠️ Markdown lint found issues (see above)');
|
|
60
|
+
// warning only — never block
|
|
61
|
+
}
|
|
62
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pr-checkmate",
|
|
3
|
-
"version": "1.21.
|
|
3
|
+
"version": "1.21.1",
|
|
4
4
|
"description": "Automated PR quality checks: linting, formatting, dependency analysis, and spellcheck",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"github-actions",
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
".eslintignore",
|
|
27
27
|
"cspell.json",
|
|
28
28
|
"src/config/pr-checkmate-workflow.yml",
|
|
29
|
+
".markdownlint.json",
|
|
29
30
|
"LICENSE"
|
|
30
31
|
],
|
|
31
32
|
"scripts": {
|
|
@@ -73,6 +74,7 @@
|
|
|
73
74
|
"eslint-plugin-prettier": "^5.5.4",
|
|
74
75
|
"execa": "^9.6.0",
|
|
75
76
|
"gitleaks-secret-scanner-fixed": "^2.1.3",
|
|
77
|
+
"markdownlint-cli": "^0.45.0",
|
|
76
78
|
"inquirer": "^13.0.1",
|
|
77
79
|
"prettier": ">=3.0.0",
|
|
78
80
|
"ts-node": "^10.9.1",
|
|
@@ -242,3 +242,24 @@ jobs:
|
|
|
242
242
|
- name: Check Outdated Dependencies
|
|
243
243
|
run: npx pr-checkmate outdated
|
|
244
244
|
continue-on-error: true
|
|
245
|
+
|
|
246
|
+
markdown-lint:
|
|
247
|
+
name: Markdown Lint
|
|
248
|
+
runs-on: ubuntu-latest
|
|
249
|
+
steps:
|
|
250
|
+
- name: Checkout code
|
|
251
|
+
uses: actions/checkout@v4
|
|
252
|
+
with:
|
|
253
|
+
fetch-depth: 0
|
|
254
|
+
|
|
255
|
+
- name: Setup Node.js
|
|
256
|
+
uses: actions/setup-node@v4
|
|
257
|
+
with:
|
|
258
|
+
node-version: 20
|
|
259
|
+
|
|
260
|
+
- name: Install dependencies
|
|
261
|
+
run: npm ci
|
|
262
|
+
|
|
263
|
+
- name: Run Markdown Lint
|
|
264
|
+
run: npx pr-checkmate markdown
|
|
265
|
+
continue-on-error: true
|