@sun-asterisk/sunlint 1.3.19 → 1.3.21
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/core/cli-program.js +8 -1
- package/core/file-targeting-service.js +66 -15
- package/core/git-utils.js +121 -11
- package/core/github-annotate-service.js +1017 -67
- package/core/output-service.js +292 -29
- package/docs/GITHUB_ACTIONS_INTEGRATION.md +421 -0
- package/package.json +2 -2
|
@@ -0,0 +1,421 @@
|
|
|
1
|
+
# GitHub Actions Integration
|
|
2
|
+
|
|
3
|
+
Hướng dẫn tích hợp SunLint với GitHub Actions để tự động review Pull Requests.
|
|
4
|
+
|
|
5
|
+
## Tính năng mới: Auto GitHub Annotation
|
|
6
|
+
|
|
7
|
+
SunLint giờ đây có thể tự động tạo review comments trên Pull Requests mà **không cần chỉ định `--output` và `--format=json`**.
|
|
8
|
+
|
|
9
|
+
### 3 Annotation Modes
|
|
10
|
+
|
|
11
|
+
`--github-annotate` hỗ trợ 3 modes:
|
|
12
|
+
|
|
13
|
+
#### 1. **`annotate`** - Inline Comments Only
|
|
14
|
+
Tạo review comments trực tiếp trên code (inline comments)
|
|
15
|
+
```bash
|
|
16
|
+
sunlint --all --input=src --github-annotate=annotate
|
|
17
|
+
```
|
|
18
|
+
- ✅ Comment trên từng dòng code có lỗi
|
|
19
|
+
- ✅ Duplicate detection
|
|
20
|
+
- ✅ Batch processing (30 comments/review)
|
|
21
|
+
|
|
22
|
+
#### 2. **`summary`** - Summary Comment Only
|
|
23
|
+
Tạo 1 comment tổng hợp (như GitHub Actions summary)
|
|
24
|
+
```bash
|
|
25
|
+
sunlint --all --input=src --github-annotate=summary
|
|
26
|
+
```
|
|
27
|
+
- ✅ Thống kê tổng quan (errors, warnings, files)
|
|
28
|
+
- ✅ Top 10 files có nhiều lỗi nhất
|
|
29
|
+
- ✅ Auto update comment cũ (không spam)
|
|
30
|
+
|
|
31
|
+
#### 3. **`all`** - Both (Default)
|
|
32
|
+
Tạo cả inline comments và summary comment
|
|
33
|
+
```bash
|
|
34
|
+
sunlint --all --input=src --github-annotate # default
|
|
35
|
+
sunlint --all --input=src --github-annotate=all # explicit
|
|
36
|
+
```
|
|
37
|
+
- ✅ Full experience: inline + summary
|
|
38
|
+
- ✅ Resilient: nếu 1 task fail, task kia vẫn chạy
|
|
39
|
+
|
|
40
|
+
### Cách hoạt động
|
|
41
|
+
|
|
42
|
+
Khi sử dụng flag `--github-annotate`:
|
|
43
|
+
|
|
44
|
+
1. ✅ **Tự động phát hiện PR event** - Chỉ chạy khi event là `pull_request`
|
|
45
|
+
2. ✅ **Tự động tạo JSON report** - Không cần `--output` và `--format=json`
|
|
46
|
+
3. ✅ **Tự động cleanup** - Xóa temp file sau khi annotate
|
|
47
|
+
4. ✅ **Intelligent error handling** - Báo lỗi chi tiết và gợi ý fix
|
|
48
|
+
5. ✅ **Duplicate detection** - Tránh spam comments trùng lặp
|
|
49
|
+
6. ✅ **3 flexible modes** - Chọn mode phù hợp với workflow
|
|
50
|
+
|
|
51
|
+
## Quick Start
|
|
52
|
+
|
|
53
|
+
### Workflow đơn giản nhất
|
|
54
|
+
|
|
55
|
+
```yaml
|
|
56
|
+
name: SunLint PR Review
|
|
57
|
+
on:
|
|
58
|
+
pull_request:
|
|
59
|
+
branches: [main, develop]
|
|
60
|
+
|
|
61
|
+
jobs:
|
|
62
|
+
sunlint:
|
|
63
|
+
runs-on: ubuntu-latest
|
|
64
|
+
permissions:
|
|
65
|
+
pull-requests: write
|
|
66
|
+
contents: read
|
|
67
|
+
|
|
68
|
+
steps:
|
|
69
|
+
- uses: actions/checkout@v4
|
|
70
|
+
|
|
71
|
+
- name: Setup Node.js
|
|
72
|
+
uses: actions/setup-node@v4
|
|
73
|
+
with:
|
|
74
|
+
node-version: '18'
|
|
75
|
+
|
|
76
|
+
- name: Install SunLint
|
|
77
|
+
run: npm install -g sunlint
|
|
78
|
+
|
|
79
|
+
- name: Run SunLint with Auto Annotation
|
|
80
|
+
run: sunlint --all --input=src --github-annotate
|
|
81
|
+
env:
|
|
82
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
**Đó là tất cả!** SunLint sẽ tự động:
|
|
86
|
+
- Phân tích code
|
|
87
|
+
- Tạo JSON report (tạm thời)
|
|
88
|
+
- Comment lên PR
|
|
89
|
+
- Xóa file tạm
|
|
90
|
+
|
|
91
|
+
## Advanced Usage
|
|
92
|
+
|
|
93
|
+
### 1. Analyze only changed files
|
|
94
|
+
|
|
95
|
+
```yaml
|
|
96
|
+
- name: Run SunLint on Changed Files
|
|
97
|
+
run: sunlint --all --changed-files --github-annotate
|
|
98
|
+
env:
|
|
99
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### 2. Save report file + annotate
|
|
103
|
+
|
|
104
|
+
```yaml
|
|
105
|
+
- name: Run SunLint
|
|
106
|
+
run: sunlint --all --input=src --output=sunlint-report.json --github-annotate
|
|
107
|
+
env:
|
|
108
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
109
|
+
|
|
110
|
+
- name: Upload Report
|
|
111
|
+
uses: actions/upload-artifact@v4
|
|
112
|
+
if: always()
|
|
113
|
+
with:
|
|
114
|
+
name: sunlint-report
|
|
115
|
+
path: sunlint-report.json
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### 3. Run specific rules
|
|
119
|
+
|
|
120
|
+
```yaml
|
|
121
|
+
- name: Run Security Rules Only
|
|
122
|
+
run: sunlint --security --input=src --github-annotate
|
|
123
|
+
env:
|
|
124
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### 4. Multiple languages
|
|
128
|
+
|
|
129
|
+
```yaml
|
|
130
|
+
- name: Run SunLint on TypeScript and Kotlin
|
|
131
|
+
run: sunlint --all --languages=typescript,kotlin --input=. --github-annotate
|
|
132
|
+
env:
|
|
133
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### 5. Với verbose logging
|
|
137
|
+
|
|
138
|
+
```yaml
|
|
139
|
+
- name: Run SunLint (Verbose)
|
|
140
|
+
run: sunlint --all --input=src --github-annotate --verbose
|
|
141
|
+
env:
|
|
142
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## Complete Example Workflow
|
|
146
|
+
|
|
147
|
+
```yaml
|
|
148
|
+
name: Code Quality Check
|
|
149
|
+
on:
|
|
150
|
+
pull_request:
|
|
151
|
+
branches: [main, develop, 'release/**']
|
|
152
|
+
paths:
|
|
153
|
+
- '**.ts'
|
|
154
|
+
- '**.tsx'
|
|
155
|
+
- '**.js'
|
|
156
|
+
- '**.jsx'
|
|
157
|
+
- '**.kt'
|
|
158
|
+
- '**.dart'
|
|
159
|
+
|
|
160
|
+
jobs:
|
|
161
|
+
sunlint:
|
|
162
|
+
name: SunLint Analysis
|
|
163
|
+
runs-on: ubuntu-latest
|
|
164
|
+
|
|
165
|
+
permissions:
|
|
166
|
+
contents: read
|
|
167
|
+
pull-requests: write
|
|
168
|
+
|
|
169
|
+
steps:
|
|
170
|
+
- name: Checkout code
|
|
171
|
+
uses: actions/checkout@v4
|
|
172
|
+
with:
|
|
173
|
+
fetch-depth: 0 # For git diff
|
|
174
|
+
|
|
175
|
+
- name: Setup Node.js
|
|
176
|
+
uses: actions/setup-node@v4
|
|
177
|
+
with:
|
|
178
|
+
node-version: '18'
|
|
179
|
+
cache: 'npm'
|
|
180
|
+
|
|
181
|
+
- name: Install dependencies
|
|
182
|
+
run: npm ci
|
|
183
|
+
|
|
184
|
+
- name: Install SunLint
|
|
185
|
+
run: npm install -g sunlint
|
|
186
|
+
|
|
187
|
+
- name: Run SunLint on Changed Files
|
|
188
|
+
id: sunlint
|
|
189
|
+
continue-on-error: true # Don't fail the workflow
|
|
190
|
+
run: |
|
|
191
|
+
sunlint --all \
|
|
192
|
+
--changed-files \
|
|
193
|
+
--diff-base=origin/${{ github.base_ref }} \
|
|
194
|
+
--github-annotate \
|
|
195
|
+
--output=sunlint-report.json \
|
|
196
|
+
--verbose
|
|
197
|
+
env:
|
|
198
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
199
|
+
|
|
200
|
+
- name: Upload Report
|
|
201
|
+
uses: actions/upload-artifact@v4
|
|
202
|
+
if: always()
|
|
203
|
+
with:
|
|
204
|
+
name: sunlint-report-${{ github.event.pull_request.number }}
|
|
205
|
+
path: sunlint-report.json
|
|
206
|
+
retention-days: 30
|
|
207
|
+
|
|
208
|
+
- name: Comment Summary
|
|
209
|
+
if: always()
|
|
210
|
+
uses: actions/github-script@v7
|
|
211
|
+
with:
|
|
212
|
+
script: |
|
|
213
|
+
const fs = require('fs');
|
|
214
|
+
if (!fs.existsSync('sunlint-report.json')) return;
|
|
215
|
+
|
|
216
|
+
const report = JSON.parse(fs.readFileSync('sunlint-report.json', 'utf8'));
|
|
217
|
+
let violations = 0;
|
|
218
|
+
let errors = 0;
|
|
219
|
+
let warnings = 0;
|
|
220
|
+
|
|
221
|
+
for (const file of report) {
|
|
222
|
+
violations += file.messages.length;
|
|
223
|
+
errors += file.errorCount;
|
|
224
|
+
warnings += file.warningCount;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
const body = `## SunLint Report
|
|
228
|
+
|
|
229
|
+
📊 **Summary:**
|
|
230
|
+
- Total violations: ${violations}
|
|
231
|
+
- Errors: ${errors}
|
|
232
|
+
- Warnings: ${warnings}
|
|
233
|
+
|
|
234
|
+
${violations === 0 ? '✅ No issues found!' : '⚠️ Please check the PR comments for details.'}
|
|
235
|
+
`;
|
|
236
|
+
|
|
237
|
+
github.rest.issues.createComment({
|
|
238
|
+
issue_number: context.issue.number,
|
|
239
|
+
owner: context.repo.owner,
|
|
240
|
+
repo: context.repo.repo,
|
|
241
|
+
body: body
|
|
242
|
+
});
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
## Environment Variables
|
|
246
|
+
|
|
247
|
+
SunLint tự động đọc các biến môi trường từ GitHub Actions:
|
|
248
|
+
|
|
249
|
+
| Variable | Description | Required |
|
|
250
|
+
|----------|-------------|----------|
|
|
251
|
+
| `GITHUB_TOKEN` | GitHub token for API access | ✅ Yes |
|
|
252
|
+
| `GITHUB_REPOSITORY` | Repository (owner/repo) | Auto |
|
|
253
|
+
| `GITHUB_EVENT_NAME` | Event type (pull_request) | Auto |
|
|
254
|
+
| `GITHUB_EVENT_PATH` | Path to event payload | Auto |
|
|
255
|
+
| `RUNNER_TEMP` | Temp directory | Auto |
|
|
256
|
+
|
|
257
|
+
## Permissions Required
|
|
258
|
+
|
|
259
|
+
```yaml
|
|
260
|
+
permissions:
|
|
261
|
+
contents: read # To checkout code
|
|
262
|
+
pull-requests: write # To create review comments
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
## Troubleshooting
|
|
266
|
+
|
|
267
|
+
### 1. "GitHub annotation only works on pull_request events"
|
|
268
|
+
|
|
269
|
+
**Nguyên nhân:** Workflow chạy trên `push` event thay vì `pull_request`
|
|
270
|
+
|
|
271
|
+
**Giải pháp:**
|
|
272
|
+
```yaml
|
|
273
|
+
on:
|
|
274
|
+
pull_request: # Thay vì push
|
|
275
|
+
branches: [main]
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
### 2. "Missing GITHUB_TOKEN"
|
|
279
|
+
|
|
280
|
+
**Nguyên nhân:** Thiếu GITHUB_TOKEN trong env
|
|
281
|
+
|
|
282
|
+
**Giải pháp:**
|
|
283
|
+
```yaml
|
|
284
|
+
env:
|
|
285
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
### 3. "Permission denied"
|
|
289
|
+
|
|
290
|
+
**Nguyên nhân:** Token không có quyền `pull-requests: write`
|
|
291
|
+
|
|
292
|
+
**Giải pháp:**
|
|
293
|
+
```yaml
|
|
294
|
+
permissions:
|
|
295
|
+
pull-requests: write
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
### 4. Annotations không hiển thị
|
|
299
|
+
|
|
300
|
+
**Nguyên nhân:** File paths không đúng format
|
|
301
|
+
|
|
302
|
+
**Giải pháp:** Đảm bảo paths là relative từ repo root:
|
|
303
|
+
```yaml
|
|
304
|
+
- uses: actions/checkout@v4 # Checkout đúng branch
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
### 5. Fork PRs không annotate được
|
|
308
|
+
|
|
309
|
+
**Nguyên nhân:** `pull_request` event từ fork có quyền hạn chế
|
|
310
|
+
|
|
311
|
+
**Giải pháp:** Dùng `pull_request_target` (cẩn thận về security!)
|
|
312
|
+
```yaml
|
|
313
|
+
on:
|
|
314
|
+
pull_request_target: # Cho fork PRs
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
## Best Practices
|
|
318
|
+
|
|
319
|
+
### 1. Fail on errors, warn on warnings
|
|
320
|
+
|
|
321
|
+
```yaml
|
|
322
|
+
- name: Run SunLint
|
|
323
|
+
run: sunlint --all --input=src --github-annotate
|
|
324
|
+
continue-on-error: false # Fail if errors found
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
### 2. Cache SunLint installation
|
|
328
|
+
|
|
329
|
+
```yaml
|
|
330
|
+
- name: Cache SunLint
|
|
331
|
+
uses: actions/cache@v3
|
|
332
|
+
with:
|
|
333
|
+
path: ~/.npm
|
|
334
|
+
key: ${{ runner.os }}-sunlint-${{ hashFiles('**/package-lock.json') }}
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
### 3. Run only on specific files
|
|
338
|
+
|
|
339
|
+
```yaml
|
|
340
|
+
on:
|
|
341
|
+
pull_request:
|
|
342
|
+
paths:
|
|
343
|
+
- 'src/**'
|
|
344
|
+
- '!src/**/*.test.ts'
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
### 4. Matrix strategy for multiple projects
|
|
348
|
+
|
|
349
|
+
```yaml
|
|
350
|
+
jobs:
|
|
351
|
+
sunlint:
|
|
352
|
+
strategy:
|
|
353
|
+
matrix:
|
|
354
|
+
project: [frontend, backend, mobile]
|
|
355
|
+
steps:
|
|
356
|
+
- run: sunlint --all --input=${{ matrix.project }} --github-annotate
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
### 5. Skip on draft PRs
|
|
360
|
+
|
|
361
|
+
```yaml
|
|
362
|
+
jobs:
|
|
363
|
+
sunlint:
|
|
364
|
+
if: github.event.pull_request.draft == false
|
|
365
|
+
steps:
|
|
366
|
+
- run: sunlint --all --github-annotate
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
## Migration Guide
|
|
370
|
+
|
|
371
|
+
### From old style (with --output)
|
|
372
|
+
|
|
373
|
+
**Before:**
|
|
374
|
+
```yaml
|
|
375
|
+
- name: Run SunLint
|
|
376
|
+
run: sunlint --all --input=src --output=report.json --format=json
|
|
377
|
+
|
|
378
|
+
- name: Annotate PR
|
|
379
|
+
run: node annotate-script.js
|
|
380
|
+
env:
|
|
381
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
**After:**
|
|
385
|
+
```yaml
|
|
386
|
+
- name: Run SunLint with Auto Annotation
|
|
387
|
+
run: sunlint --all --input=src --github-annotate
|
|
388
|
+
env:
|
|
389
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
## FAQ
|
|
393
|
+
|
|
394
|
+
**Q: Có thể dùng cho push events không?**
|
|
395
|
+
A: Không. `--github-annotate` chỉ hoạt động cho `pull_request` events. Dùng `--output` để save report cho push events.
|
|
396
|
+
|
|
397
|
+
**Q: Có bị rate limit không?**
|
|
398
|
+
A: SunLint có retry mechanism và batch processing để tránh rate limit. Maximum 30 comments/review, tự động chia batches nếu nhiều hơn.
|
|
399
|
+
|
|
400
|
+
**Q: Có thể customize comment format không?**
|
|
401
|
+
A: Hiện tại format là `[rule-id] message`. Customize format đang được phát triển.
|
|
402
|
+
|
|
403
|
+
**Q: Có delete được comments cũ không?**
|
|
404
|
+
A: SunLint có duplicate detection để tránh spam. Comments cũ được giữ lại cho lịch sử.
|
|
405
|
+
|
|
406
|
+
**Q: Performance với large PRs?**
|
|
407
|
+
A: SunLint optimize cho large PRs với:
|
|
408
|
+
- Batch processing
|
|
409
|
+
- Only comment on changed files
|
|
410
|
+
- Async operations
|
|
411
|
+
- Retry mechanism
|
|
412
|
+
|
|
413
|
+
## Examples Repository
|
|
414
|
+
|
|
415
|
+
Xem thêm examples tại: [examples/github-actions/](../examples/github-actions/)
|
|
416
|
+
|
|
417
|
+
## Support
|
|
418
|
+
|
|
419
|
+
- Issues: [GitHub Issues](https://github.com/sun-asterisk/engineer-excellence/issues)
|
|
420
|
+
- Docs: [Documentation](../README.md)
|
|
421
|
+
- Community: [Discussions](https://github.com/sun-asterisk/engineer-excellence/discussions)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sun-asterisk/sunlint",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.21",
|
|
4
4
|
"description": "☀️ SunLint - Multi-language static analysis tool for code quality and security | Sun* Engineering Standards",
|
|
5
5
|
"main": "cli.js",
|
|
6
6
|
"bin": {
|
|
@@ -139,4 +139,4 @@
|
|
|
139
139
|
"url": "https://github.com/sun-asterisk/engineer-excellence/issues"
|
|
140
140
|
},
|
|
141
141
|
"homepage": "https://github.com/sun-asterisk/engineer-excellence/tree/main/coding-quality/extensions/sunlint#readme"
|
|
142
|
-
}
|
|
142
|
+
}
|