Skip to content

Commit f7bf2d4

Browse files
authored
将 PR Checkstyle 报告同步至 Pull Request 审查评论 (#6692)
1 parent a10c501 commit f7bf2d4

4 files changed

Lines changed: 189 additions & 3 deletions

File tree

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
const fs = require("fs");
2+
3+
module.exports = async ({ github, context, core }) => {
4+
const prNumberPath = process.env.PULL_REQUEST_NUMBER_PATH;
5+
if (!prNumberPath || !fs.existsSync(prNumberPath) || !fs.statSync(prNumberPath).isFile()) {
6+
core.setFailed("Pull request number file not found.");
7+
return;
8+
}
9+
10+
const reportsPath = process.env.REPORTS_PATH;
11+
if (!reportsPath || !fs.existsSync(reportsPath) || !fs.statSync(reportsPath).isFile()) {
12+
core.setFailed("Reports file not found.");
13+
return;
14+
}
15+
16+
const PULL_REQUEST_NUMBER = parseInt(fs.readFileSync(prNumberPath, "utf8").trim(), 10);
17+
if (isNaN(PULL_REQUEST_NUMBER)) {
18+
core.setFailed("Failed to parse the pull request number.");
19+
return;
20+
}
21+
22+
const { owner, repo } = context.repo;
23+
24+
let pr;
25+
try {
26+
const response = await github.rest.pulls.get({
27+
owner,
28+
repo,
29+
pull_number: PULL_REQUEST_NUMBER,
30+
});
31+
pr = response.data;
32+
} catch (error) {
33+
core.setFailed(`Failed to fetch PR #${PULL_REQUEST_NUMBER}: ${error.message}`);
34+
return;
35+
}
36+
37+
core.info(`Current PR state: ${pr.state}`);
38+
if (pr.state !== "open") {
39+
core.setFailed("The pull request is not open. Skipping comment creation.");
40+
return;
41+
}
42+
43+
const run = context.payload.workflow_run;
44+
if (!run) {
45+
core.setFailed("context.payload.workflow_run is undefined. Ensure this script runs on the 'workflow_run' event.");
46+
return;
47+
}
48+
49+
if (pr.head.sha !== run.head_sha) {
50+
core.setFailed("PR head SHA does not match the workflow run head SHA. Skipping.");
51+
return;
52+
}
53+
54+
if (pr.head.ref !== run.head_branch) {
55+
core.setFailed("PR head branch does not match the workflow run head branch. Skipping.");
56+
return;
57+
}
58+
59+
if (pr.head.repo.full_name !== run.head_repository.full_name) {
60+
core.setFailed("PR head repository fullname does not match the workflow run head repository fullname. Skipping.");
61+
return;
62+
}
63+
64+
const comments = [];
65+
const maxCommentCount = 10;
66+
const reports = fs.readFileSync(reportsPath, "utf8").trim().split("\n").filter(Boolean);
67+
for (const report of reports) {
68+
if (comments.length >= maxCommentCount) break;
69+
try {
70+
const data = JSON.parse(report);
71+
if (typeof data !== "object" || Array.isArray(data)) continue;
72+
73+
const { location, message, severity, code } = data;
74+
if (typeof location !== "object" || Array.isArray(location)) continue;
75+
if (typeof message !== "string") continue;
76+
const severities = ["UNKNOWN_SEVERITY", "ERROR", "WARNING", "INFO", 0, 1, 2, 3];
77+
if (!severities.includes(severity)) continue;
78+
const severityText = typeof severity === "string" ? severity : severities[severity];
79+
if (typeof code !== "object" || Array.isArray(code)) continue;
80+
81+
const path = location.path;
82+
const line = location.range?.start?.line;
83+
const codeText = code.value ? `[${code.value}] ` : "";
84+
85+
if (path && line) {
86+
comments.push({
87+
path,
88+
line,
89+
side: "RIGHT",
90+
body: `**[${severityText}]** ${codeText}\n\n${message}`
91+
});
92+
}
93+
} catch (error) {
94+
core.warning(`Failed to parse report: ${error.message}`);
95+
}
96+
}
97+
98+
if (comments.length === 0) {
99+
core.info("No diagnostics found to report as comments.");
100+
return;
101+
}
102+
103+
core.info(`Successfully prepared ${comments.length} comment${comments.length > 1 ? "s" : ""} to post.`);
104+
105+
try {
106+
await github.rest.pulls.createReview({
107+
owner,
108+
repo,
109+
pull_number: PULL_REQUEST_NUMBER,
110+
commit_id: run.head_sha,
111+
body: "🤖 Static analysis found the following issues (max count 10):",
112+
event: "COMMENT",
113+
comments: comments
114+
});
115+
core.info("Review comments successfully posted to the pull request.");
116+
} catch (error) {
117+
core.setFailed(`Failed to post review comments to GitHub: ${error.message}`);
118+
return;
119+
}
120+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
name: Check Codes Comment
2+
3+
on:
4+
workflow_run:
5+
workflows: ["Check Codes"]
6+
types:
7+
- completed
8+
9+
permissions:
10+
actions: read
11+
contents: read
12+
pull-requests: write
13+
14+
jobs:
15+
comment:
16+
runs-on: ubuntu-latest
17+
if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'failure'
18+
steps:
19+
- name: Checkout Script
20+
uses: actions/checkout@v7
21+
with:
22+
sparse-checkout: |
23+
.github/scripts/check-codes-comment.js
24+
sparse-checkout-cone-mode: false
25+
- name: Download Artifact
26+
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
27+
with:
28+
name: checkstyle-artifact
29+
path: ${{ runner.temp }}/checkstyle-artifact
30+
run-id: ${{ github.event.workflow_run.id }}
31+
github-token: ${{ secrets.GITHUB_TOKEN }}
32+
- name: Generate Review Comment
33+
uses: actions/github-script@v9
34+
env:
35+
REPORTS_PATH: ${{ runner.temp }}/checkstyle-artifact/ALL_REPORTS.jsonl
36+
PULL_REQUEST_NUMBER_PATH: ${{ runner.temp }}/checkstyle-artifact/PULL_REQUEST_NUMBER
37+
with:
38+
script: |
39+
const script = require("./.github/scripts/check-codes-comment.js");
40+
await script({ github, context, core });

.github/workflows/check-codes.yml

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ jobs:
1515
runs-on: ubuntu-latest
1616
steps:
1717
- uses: actions/checkout@v6
18-
- name: Set up JDK 17
18+
- name: Setup JDK 17
1919
uses: actions/setup-java@v5
2020
with:
2121
distribution: 'zulu'
@@ -27,3 +27,29 @@ jobs:
2727
cache-cleanup: never
2828
- name: Check Codes
2929
run: ./gradlew checkstyle checkTranslations --no-daemon --parallel --stacktrace
30+
- if: failure() && github.event_name == 'pull_request'
31+
name: Setup reviewdog
32+
uses: reviewdog/action-setup@d8edfce3dd5e1ec6978745e801f9c50b5ef80252 # v1.4.0
33+
with:
34+
reviewdog_version: v0.21.0
35+
- if: failure() && github.event_name == 'pull_request'
36+
name: Generate Artifact
37+
run: |
38+
echo "${{ github.event.number }}" > PULL_REQUEST_NUMBER
39+
> ALL_REPORTS.jsonl
40+
find . -path "*/build/reports/checkstyle/*.xml" | while read -r xml_file; do
41+
if [ -s "$xml_file" ]; then
42+
echo "Processing $xml_file..."
43+
reviewdog -f=checkstyle -name="checkstyle" -reporter=rdjsonl < "$xml_file" >> ALL_REPORTS.jsonl
44+
else
45+
echo "Skipping empty or missing report: $xml_file"
46+
fi
47+
done
48+
- if: failure() && github.event_name == 'pull_request'
49+
name: Upload Artifact
50+
uses: actions/upload-artifact@v7
51+
with:
52+
name: checkstyle-artifact
53+
path: |
54+
ALL_REPORTS.jsonl
55+
PULL_REQUEST_NUMBER

.github/workflows/pr-size-label.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ jobs:
2121
uses: actions/checkout@v7
2222
with:
2323
sparse-checkout: |
24-
.github/scripts
25-
sparse-checkout-cone-mode: true
24+
.github/scripts/pr-size-label.js
25+
sparse-checkout-cone-mode: false
2626
- name: Label PR by filtered changed lines
2727
uses: actions/github-script@v9
2828
with:

0 commit comments

Comments
 (0)