pr-checkmate 1.20.7 → 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 +6 -1
- package/dist/scripts/circular-deps.js +5 -2
- package/dist/scripts/copy-configs.js +1 -1
- package/dist/scripts/dependency-check.js +35 -23
- package/dist/scripts/index.js +7 -1
- package/dist/scripts/license-check.js +3 -2
- package/dist/scripts/lint.js +3 -3
- package/dist/scripts/markdown-lint.js +62 -0
- package/dist/scripts/npm-audit.js +1 -1
- package/dist/scripts/outdated-deps.js +2 -2
- package/dist/scripts/pr-size-check.js +3 -3
- package/dist/scripts/pr-title-lint.js +3 -3
- package/dist/scripts/prettier-autoformat.js +4 -4
- package/dist/scripts/security.js +3 -3
- package/dist/scripts/spellcheck.js +3 -3
- 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
|
@@ -32,6 +32,11 @@ const DEFAULT_CONFIG = {
|
|
|
32
32
|
ignorePaths: [],
|
|
33
33
|
ignoreRegExpList: [],
|
|
34
34
|
},
|
|
35
|
+
// Markdownlint customization
|
|
36
|
+
markdownlint: {
|
|
37
|
+
rules: {},
|
|
38
|
+
ignores: [],
|
|
39
|
+
},
|
|
35
40
|
documentation: config_1.documentation,
|
|
36
41
|
};
|
|
37
42
|
async function init() {
|
|
@@ -72,7 +77,7 @@ async function init() {
|
|
|
72
77
|
}
|
|
73
78
|
fs_1.default.copyFileSync(workflowSource, workflowDest);
|
|
74
79
|
utils_1.logger.info('[init]: ✅ Created .github/workflows/pr-checkmate.yml');
|
|
75
|
-
utils_1.logger.info('[init]:
|
|
80
|
+
utils_1.logger.info('[init]: GitHub Actions workflow is ready for your PRs!');
|
|
76
81
|
}
|
|
77
82
|
else {
|
|
78
83
|
utils_1.logger.warn('[init]: ⚠️ Workflow template not found, skipping workflow setup');
|
|
@@ -9,7 +9,7 @@ const utils_1 = require("../utils");
|
|
|
9
9
|
const config_1 = require("../config");
|
|
10
10
|
const node_path_1 = __importDefault(require("node:path"));
|
|
11
11
|
async function runCircularDeps() {
|
|
12
|
-
utils_1.logger.info('[runCircularDeps]:
|
|
12
|
+
utils_1.logger.info('[runCircularDeps]: Checking for circular dependencies...');
|
|
13
13
|
const sourcePath = (0, config_1.getSourcePath)();
|
|
14
14
|
const pattern = node_path_1.default.join(process.cwd(), sourcePath, '**/*.{ts,tsx,js,jsx}');
|
|
15
15
|
try {
|
|
@@ -17,7 +17,10 @@ async function runCircularDeps() {
|
|
|
17
17
|
reject: false,
|
|
18
18
|
});
|
|
19
19
|
const output = (result.stdout + result.stderr).trim();
|
|
20
|
-
|
|
20
|
+
// dpdm success message also contains "circular" — match only its error patterns:
|
|
21
|
+
// "Circular Dependencies:" header or numbered entry "[1] src/a.ts -> src/b.ts"
|
|
22
|
+
const hasCircular = /circular dependencies:/i.test(output) || /^\s*\[\d+\]/m.test(output);
|
|
23
|
+
if (hasCircular) {
|
|
21
24
|
utils_1.logger.error('[runCircularDeps]: ❌ Circular dependencies detected:');
|
|
22
25
|
utils_1.logger.error(output);
|
|
23
26
|
throw new Error('Circular dependencies found');
|
|
@@ -18,7 +18,7 @@ const configFiles = [
|
|
|
18
18
|
];
|
|
19
19
|
function copyConfigs() {
|
|
20
20
|
const root = node_path_1.default.resolve(__dirname, '../..');
|
|
21
|
-
utils_1.logger.log('[copyConfigs]:
|
|
21
|
+
utils_1.logger.log('[copyConfigs]: Copying config files to package root...\n');
|
|
22
22
|
configFiles.forEach(({ source, dest }) => {
|
|
23
23
|
const srcPath = node_path_1.default.join(root, source);
|
|
24
24
|
const destPath = node_path_1.default.join(root, dest);
|
|
@@ -9,37 +9,49 @@ const utils_1 = require("../utils");
|
|
|
9
9
|
const node_path_1 = __importDefault(require("node:path"));
|
|
10
10
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
11
11
|
async function runDependencyCheck() {
|
|
12
|
-
utils_1.logger.info('[runDependencyCheck]:
|
|
12
|
+
utils_1.logger.info('[runDependencyCheck]: Checking dependencies...');
|
|
13
13
|
const projectRoot = process.cwd();
|
|
14
14
|
if (!node_fs_1.default.existsSync(node_path_1.default.join(projectRoot, 'package.json'))) {
|
|
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) {
|
|
@@ -10,7 +10,7 @@ const node_path_1 = __importDefault(require("node:path"));
|
|
|
10
10
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
11
11
|
const FORBIDDEN_LICENSES = ['GPL-2.0', 'GPL-3.0', 'AGPL-3.0', 'LGPL-2.0', 'LGPL-2.1', 'LGPL-3.0'];
|
|
12
12
|
async function runLicenseCheck() {
|
|
13
|
-
utils_1.logger.info('[runLicenseCheck]:
|
|
13
|
+
utils_1.logger.info('[runLicenseCheck]: Checking dependency licenses...');
|
|
14
14
|
if (!node_fs_1.default.existsSync(node_path_1.default.join(process.cwd(), 'package.json'))) {
|
|
15
15
|
utils_1.logger.warn('[runLicenseCheck]: ⚠️ No package.json found, skipping');
|
|
16
16
|
return;
|
|
@@ -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
|
}
|
package/dist/scripts/lint.js
CHANGED
|
@@ -38,16 +38,16 @@ async function runLint() {
|
|
|
38
38
|
]);
|
|
39
39
|
let args;
|
|
40
40
|
if (hasLocal) {
|
|
41
|
-
utils_1.logger.info(`[runLint]:
|
|
41
|
+
utils_1.logger.info(`[runLint]: Using local ESLint config (checking: ${sourcePath})`);
|
|
42
42
|
args = ['eslint', ...targets, '--ext', '.ts,.tsx,.js,.jsx', '--fix'];
|
|
43
43
|
}
|
|
44
44
|
else {
|
|
45
|
-
utils_1.logger.info(`[runLint]:
|
|
45
|
+
utils_1.logger.info(`[runLint]: Using pr-checkmate ESLint config (checking: ${sourcePath})`);
|
|
46
46
|
// Detect ESLint version and choose appropriate config
|
|
47
47
|
const eslintVersion = await getESLintMajorVersion();
|
|
48
48
|
const configFile = eslintVersion >= 9 ? 'eslint.config.mjs' : '.eslintrc.js';
|
|
49
49
|
const configPath = (0, config_1.getPackageConfigPath)(configFile);
|
|
50
|
-
utils_1.logger.info(`[runLint]:
|
|
50
|
+
utils_1.logger.info(`[runLint]: Detected ESLint v${eslintVersion}, using ${configFile}`);
|
|
51
51
|
args = ['eslint', ...targets, '--ext', '.ts,.tsx,.js,.jsx', '--fix', '--config', configPath];
|
|
52
52
|
}
|
|
53
53
|
config_1.IGNORE_PATTERNS.forEach(p => args.push('--ignore-pattern', p));
|
|
@@ -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
|
+
}
|
|
@@ -12,7 +12,7 @@ const execa_1 = require("execa");
|
|
|
12
12
|
* Run npm audit on the current project
|
|
13
13
|
*/
|
|
14
14
|
async function runNpmAudit() {
|
|
15
|
-
utils_1.logger.info('
|
|
15
|
+
utils_1.logger.info('Running npm audit...');
|
|
16
16
|
const projectRoot = process.cwd();
|
|
17
17
|
const packageJsonPath = node_path_1.default.join(projectRoot, 'package.json');
|
|
18
18
|
if (!node_fs_1.default.existsSync(packageJsonPath)) {
|
|
@@ -9,7 +9,7 @@ const utils_1 = require("../utils");
|
|
|
9
9
|
const node_path_1 = __importDefault(require("node:path"));
|
|
10
10
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
11
11
|
async function runOutdatedDeps() {
|
|
12
|
-
utils_1.logger.info('[runOutdatedDeps]:
|
|
12
|
+
utils_1.logger.info('[runOutdatedDeps]: Checking for outdated dependencies...');
|
|
13
13
|
if (!node_fs_1.default.existsSync(node_path_1.default.join(process.cwd(), 'package.json'))) {
|
|
14
14
|
utils_1.logger.warn('[runOutdatedDeps]: ⚠️ No package.json found, skipping');
|
|
15
15
|
return;
|
|
@@ -46,7 +46,7 @@ async function runOutdatedDeps() {
|
|
|
46
46
|
});
|
|
47
47
|
}
|
|
48
48
|
if (minorBehind > 0) {
|
|
49
|
-
utils_1.logger.info(`[runOutdatedDeps]:
|
|
49
|
+
utils_1.logger.info(`[runOutdatedDeps]: ${minorBehind} package(s) have minor/patch updates available`);
|
|
50
50
|
}
|
|
51
51
|
// informational only — never throws
|
|
52
52
|
}
|
|
@@ -24,10 +24,10 @@ function readBaseSha() {
|
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
async function runPrSizeCheck() {
|
|
27
|
-
utils_1.logger.info('[runPrSizeCheck]:
|
|
27
|
+
utils_1.logger.info('[runPrSizeCheck]: Checking PR size...');
|
|
28
28
|
const baseSha = readBaseSha();
|
|
29
29
|
if (!baseSha) {
|
|
30
|
-
utils_1.logger.info('[runPrSizeCheck]:
|
|
30
|
+
utils_1.logger.info('[runPrSizeCheck]: Not in GitHub PR context, skipping');
|
|
31
31
|
return;
|
|
32
32
|
}
|
|
33
33
|
try {
|
|
@@ -38,7 +38,7 @@ async function runPrSizeCheck() {
|
|
|
38
38
|
const deletions = stdout.match(/(\d+) deletion/);
|
|
39
39
|
const fileCount = filesMatch ? parseInt(filesMatch[1]) : 0;
|
|
40
40
|
const lines = (insertions ? parseInt(insertions[1]) : 0) + (deletions ? parseInt(deletions[1]) : 0);
|
|
41
|
-
utils_1.logger.info(`[runPrSizeCheck]:
|
|
41
|
+
utils_1.logger.info(`[runPrSizeCheck]: ${fileCount} files changed, ${lines} lines`);
|
|
42
42
|
if (fileCount > WARN_FILES) {
|
|
43
43
|
utils_1.logger.warn(`[runPrSizeCheck]: ⚠️ Large PR: ${fileCount} files changed (recommended < ${WARN_FILES})`);
|
|
44
44
|
}
|
|
@@ -8,10 +8,10 @@ const utils_1 = require("../utils");
|
|
|
8
8
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
9
9
|
const CONVENTIONAL_PREFIX = /^(feat|fix|docs|style|refactor|test|chore|perf|ci|build|revert)(\(.+\))?!?: .+/;
|
|
10
10
|
async function runPrTitleLint() {
|
|
11
|
-
utils_1.logger.info('[runPrTitleLint]:
|
|
11
|
+
utils_1.logger.info('[runPrTitleLint]: Checking PR title...');
|
|
12
12
|
const eventPath = process.env.GITHUB_EVENT_PATH;
|
|
13
13
|
if (!eventPath || !node_fs_1.default.existsSync(eventPath)) {
|
|
14
|
-
utils_1.logger.info('[runPrTitleLint]:
|
|
14
|
+
utils_1.logger.info('[runPrTitleLint]: Not in GitHub CI, skipping');
|
|
15
15
|
return;
|
|
16
16
|
}
|
|
17
17
|
let event;
|
|
@@ -24,7 +24,7 @@ async function runPrTitleLint() {
|
|
|
24
24
|
}
|
|
25
25
|
const pr = event.pull_request;
|
|
26
26
|
if (!pr?.title) {
|
|
27
|
-
utils_1.logger.info('[runPrTitleLint]:
|
|
27
|
+
utils_1.logger.info('[runPrTitleLint]: No PR title found, skipping');
|
|
28
28
|
return;
|
|
29
29
|
}
|
|
30
30
|
const title = pr.title;
|
|
@@ -42,7 +42,7 @@ function createTempPrettierConfig() {
|
|
|
42
42
|
// Log customizations
|
|
43
43
|
const customRulesCount = Object.keys(userConfig).length;
|
|
44
44
|
if (customRulesCount > 0) {
|
|
45
|
-
utils_1.logger.info(`[createTempPrettierConfig]:
|
|
45
|
+
utils_1.logger.info(`[createTempPrettierConfig]: Applied ${customRulesCount}
|
|
46
46
|
custom Prettier rules from pr-checkmate.json`);
|
|
47
47
|
utils_1.logger.debug(`[createTempPrettierConfig]: Custom rules: ${JSON.stringify(userConfig)}`);
|
|
48
48
|
}
|
|
@@ -60,7 +60,7 @@ function createTempIgnoreFile() {
|
|
|
60
60
|
return file;
|
|
61
61
|
}
|
|
62
62
|
async function runPrettier() {
|
|
63
|
-
utils_1.logger.info('[runPrettier]:
|
|
63
|
+
utils_1.logger.info('[runPrettier]: Running Prettier...');
|
|
64
64
|
const root = process.cwd();
|
|
65
65
|
const sourcePath = (0, config_1.getSourcePath)();
|
|
66
66
|
const changedFiles = await (0, delta_1.getChangedFiles)(['.ts', '.tsx', '.js', '.jsx', '.json', '.md']);
|
|
@@ -88,11 +88,11 @@ async function runPrettier() {
|
|
|
88
88
|
let args;
|
|
89
89
|
let tempConfig = null;
|
|
90
90
|
if (hasLocal) {
|
|
91
|
-
utils_1.logger.info(`[runPrettier]:
|
|
91
|
+
utils_1.logger.info(`[runPrettier]: Using local Prettier config (checking: ${sourcePath})`);
|
|
92
92
|
args = ['prettier', '--write', ...targets, '--ignore-path', ignorePath];
|
|
93
93
|
}
|
|
94
94
|
else {
|
|
95
|
-
utils_1.logger.info(`[runPrettier]:
|
|
95
|
+
utils_1.logger.info(`[runPrettier]: Using pr-checkmate Prettier config (checking: ${sourcePath})`);
|
|
96
96
|
// Create temporary config with merged settings
|
|
97
97
|
tempConfig = createTempPrettierConfig();
|
|
98
98
|
args = ['prettier', '--write', ...targets, '--config', tempConfig, '--ignore-path', ignorePath];
|
package/dist/scripts/security.js
CHANGED
|
@@ -32,7 +32,7 @@ async function getBaseSha() {
|
|
|
32
32
|
const event = JSON.parse(node_fs_1.default.readFileSync(eventPath, 'utf-8'));
|
|
33
33
|
const baseSha = event?.pull_request?.base?.sha;
|
|
34
34
|
if (baseSha) {
|
|
35
|
-
utils_1.logger.info(`[getBaseSha]:
|
|
35
|
+
utils_1.logger.info(`[getBaseSha]: Using PR base SHA: ${baseSha}`);
|
|
36
36
|
return baseSha;
|
|
37
37
|
}
|
|
38
38
|
}
|
|
@@ -55,10 +55,10 @@ async function getBaseSha() {
|
|
|
55
55
|
function getGitleaksCommand() {
|
|
56
56
|
const localPath = node_path_1.default.join(process.cwd(), 'node_modules', '.bin', 'gitleaks-secret-scanner');
|
|
57
57
|
if (node_fs_1.default.existsSync(localPath)) {
|
|
58
|
-
utils_1.logger.info('[getGitleaksCommand]:
|
|
58
|
+
utils_1.logger.info('[getGitleaksCommand]: Using local gitleaks-secret-scanner');
|
|
59
59
|
return localPath;
|
|
60
60
|
}
|
|
61
|
-
utils_1.logger.info('[getGitleaksCommand]:
|
|
61
|
+
utils_1.logger.info('[getGitleaksCommand]: Using npx gitleaks-secret-scanner');
|
|
62
62
|
return 'npx';
|
|
63
63
|
}
|
|
64
64
|
/**
|
|
@@ -45,7 +45,7 @@ function createTempCspellConfig() {
|
|
|
45
45
|
const customWordsCount = (userConfig.words || []).length;
|
|
46
46
|
const customIgnoresCount = (userConfig.ignorePaths || []).length;
|
|
47
47
|
if (customWordsCount > 0) {
|
|
48
|
-
utils_1.logger.info(`[createTempCspellConfig]:
|
|
48
|
+
utils_1.logger.info(`[createTempCspellConfig]: Added ${customWordsCount} custom words from pr-checkmate.json`);
|
|
49
49
|
}
|
|
50
50
|
if (customIgnoresCount > 0) {
|
|
51
51
|
utils_1.logger.info(`[createTempCspellConfig]: 🚫 Added ${customIgnoresCount}
|
|
@@ -65,7 +65,7 @@ function buildSpellcheckPatterns(projectRoot, sourcePath) {
|
|
|
65
65
|
return [base, ...excludes];
|
|
66
66
|
}
|
|
67
67
|
async function runSpellcheck() {
|
|
68
|
-
utils_1.logger.info('[runSpellcheck]:
|
|
68
|
+
utils_1.logger.info('[runSpellcheck]: Running Spellcheck...');
|
|
69
69
|
const projectRoot = process.cwd();
|
|
70
70
|
const sourcePath = (0, config_1.getSourcePath)();
|
|
71
71
|
const changedFiles = await (0, delta_1.getChangedFiles)([
|
|
@@ -86,7 +86,7 @@ async function runSpellcheck() {
|
|
|
86
86
|
args = ['cspell', ...patterns, '--no-progress'];
|
|
87
87
|
}
|
|
88
88
|
else {
|
|
89
|
-
utils_1.logger.info(`[runSpellcheck]:
|
|
89
|
+
utils_1.logger.info(`[runSpellcheck]: Using pr-checkmate cspell config (checking: ${sourcePath})`);
|
|
90
90
|
// Create temporary config with merged settings
|
|
91
91
|
tempConfigPath = createTempCspellConfig();
|
|
92
92
|
args = ['cspell', ...patterns, '--config', tempConfigPath, '--no-progress'];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pr-checkmate",
|
|
3
|
-
"version": "1.
|
|
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
|