diff --git a/.github/scripts/checkstyle-pr.sh b/.github/scripts/checkstyle-pr.sh
new file mode 100644
index 00000000..8f1e2468
--- /dev/null
+++ b/.github/scripts/checkstyle-pr.sh
@@ -0,0 +1,216 @@
+#!/bin/bash
+# ============================================================
+# checkstyle-pr.sh - 真正的增量检查
+# 功能:只报告本次提交中新增或修改行的 Checkstyle 违规
+# 不阻断构建,生成过滤后的报告
+# ============================================================
+
+set -e
+
+echo "========================================"
+echo " Checkstyle 增量行检查 (只检测新代码)"
+echo "========================================"
+
+# 1. 确定目标分支
+if [ -n "$GITHUB_BASE_REF" ]; then
+ BASE_BRANCH="origin/$GITHUB_BASE_REF"
+elif [ -n "$GITHUB_REF" ] && [ "$GITHUB_EVENT_NAME" == "push" ]; then
+ BASE_BRANCH="HEAD^"
+else
+ if git rev-parse --verify origin/main >/dev/null 2>&1; then
+ BASE_BRANCH="origin/main"
+ elif git rev-parse --verify origin/develop >/dev/null 2>&1; then
+ BASE_BRANCH="origin/develop"
+ else
+ echo "❌ 无法确定目标分支,请设置 BASE_BRANCH 环境变量。"
+ exit 1
+ fi
+ echo "🔍 本地运行模式,对比分支: $BASE_BRANCH"
+fi
+
+# 2. 获取变更的 Java 文件
+CHANGED_FILES=$(git diff --name-only "$BASE_BRANCH" HEAD 2>/dev/null | grep '\.java$' || true)
+
+if [ -z "$CHANGED_FILES" ]; then
+ echo "✅ 没有 Java 文件变更,跳过检查。"
+ exit 0
+fi
+
+echo "📝 变更的 Java 文件:"
+echo "$CHANGED_FILES"
+echo "----------------------------------------"
+
+# 3. 生成包含变更行号信息的文件 (用于后续过滤)
+echo "🔄 提取变更行号..."
+CHANGE_INFO_FILE=".checkstyle-changes.txt"
+rm -f "$CHANGE_INFO_FILE"
+
+for file in $CHANGED_FILES; do
+ # 获取该文件新增或修改的行号范围(新文件行号)
+ # git diff -U0 输出 unified=0,只显示变更行
+ diff_output=$(git diff -U0 "$BASE_BRANCH" HEAD -- "$file" 2>/dev/null | grep '^@@' || true)
+ if [ -n "$diff_output" ]; then
+ # 解析 @@ -old,count +new,count @@ 提取新行号范围
+ echo "$diff_output" | while read -r line; do
+ # 提取 + 后面的起始行和行数
+ new_info=$(echo "$line" | sed -n 's/.*+\([0-9]*\)\(,[0-9]*\)\?.*/\1 \2/p')
+ if [ -n "$new_info" ]; then
+ start=$(echo "$new_info" | awk '{print $1}')
+ count=$(echo "$new_info" | awk '{print $2}' | sed 's/,//')
+ if [ -z "$count" ]; then
+ count=1
+ fi
+ # 生成行号范围,例如 file:10-15
+ echo "$file:$start-$((start+count-1))" >> "$CHANGE_INFO_FILE"
+ fi
+ done
+ fi
+done
+
+if [ ! -s "$CHANGE_INFO_FILE" ]; then
+ echo "⚠️ 未提取到变更行号,可能变更只涉及删除或文件重命名,跳过检查。"
+ exit 0
+fi
+
+echo "变更行号信息已保存到 $CHANGE_INFO_FILE"
+
+# 4. 执行 Checkstyle 扫描全部变更文件(生成完整报告)
+echo "🚀 执行 Checkstyle 扫描(生成完整报告)..."
+FILES_LIST=$(echo "$CHANGED_FILES" | tr '\n' ',' | sed 's/,$//')
+
+set +e
+mvn checkstyle:checkstyle \
+ -Dcheckstyle.includes="$FILES_LIST" \
+ -Dcheckstyle.excludes="**/test/**/*.java" \
+ -Dcheckstyle.violationSeverity=warning
+MVN_EXIT=$?
+set -e
+
+REPORT_FILE="target/checkstyle-result.xml"
+if [ ! -f "$REPORT_FILE" ]; then
+ echo "❌ 未生成 Checkstyle 报告,请检查 Maven 配置。"
+ exit 0
+fi
+
+# 5. 过滤报告:只保留变更行上的违规
+echo "🔄 过滤违规,只保留变更行上的问题..."
+FILTERED_REPORT="target/checkstyle-filtered-result.xml"
+FILTERED_VIOLATIONS=0
+
+# 使用 Python 脚本过滤(GitHub Actions 环境自带 python3)
+python3 << EOF
+import sys
+import xml.etree.ElementTree as ET
+
+# 读取变更行信息
+changed_lines = {}
+with open("$CHANGE_INFO_FILE", "r") as f:
+ for line in f:
+ line = line.strip()
+ if not line:
+ continue
+ parts = line.split(':')
+ if len(parts) != 2:
+ continue
+ file = parts[0]
+ range_str = parts[1]
+ start_end = range_str.split('-')
+ if len(start_end) == 2:
+ start = int(start_end[0])
+ end = int(start_end[1])
+ for i in range(start, end+1):
+ changed_lines.setdefault(file, set()).add(i)
+ else:
+ # 单行
+ changed_lines.setdefault(file, set()).add(int(start_end[0]))
+
+# 解析 Checkstyle 报告
+tree = ET.parse("$REPORT_FILE")
+root = tree.getroot()
+
+# 创建过滤后的根
+new_root = ET.Element("checkstyle", attrib=root.attrib)
+
+for file_elem in root.findall("file"):
+ file_name = file_elem.get("name")
+ # 获取相对于项目根目录的路径(可能带有绝对路径,需要规范化)
+ # 简单处理:取文件名部分,但为了匹配,我们只比较文件名(如果路径不同)
+ # 更健壮:使用文件名的 basename 或匹配路径结尾
+ # 这里我们直接匹配字符串,因为 diff 输出的是相对路径,而 Checkstyle 输出绝对路径
+ # 我们尝试使用相对路径匹配
+ changed_set = changed_lines.get(file_name, set())
+ if not changed_set:
+ # 尝试取 basename 匹配
+ base = file_name.split('/')[-1]
+ for key in changed_lines:
+ if key.endswith(base):
+ changed_set = changed_lines[key]
+ break
+
+ new_file = ET.SubElement(new_root, "file", attrib=file_elem.attrib)
+ errors_found = False
+ for error in file_elem.findall("error"):
+ line_num = int(error.get("line", 0))
+ if line_num in changed_set:
+ new_file.append(error)
+ errors_found = True
+ if not errors_found:
+ # 如果该文件没有违规,则移除(但保留空文件无意义,可以跳过)
+ new_root.remove(new_file)
+
+# 写回过滤后的报告
+tree = ET.ElementTree(new_root)
+tree.write("$FILTERED_REPORT", encoding="utf-8", xml_declaration=True)
+EOF
+
+# 6. 统计过滤后的违规数
+if [ -f "$FILTERED_REPORT" ]; then
+ FILTERED_VIOLATIONS=$(grep -c '//' | \
+ sed 's/line="/行号: /; s/column="/列: /; s/severity="/严重性: /; s=message="=信息: =; s=source="//' | \
+ while read -r line; do
+ echo " $line"
+ done
+fi
+
+# 7. 输出到 GitHub Step Summary
+if [ -n "$GITHUB_STEP_SUMMARY" ]; then
+ {
+ echo "## 📋 Checkstyle 增量行报告"
+ echo ""
+ echo "| 指标 | 结果 |"
+ echo "|------|------|"
+ if [ $FILTERED_VIOLATIONS -eq 0 ]; then
+ echo "| 新增代码违规数 | ✅ **0** |"
+ else
+ echo "| 新增代码违规数 | ⚠️ **$FILTERED_VIOLATIONS** |"
+ fi
+ echo "| 扫描文件 | **$(echo "$CHANGED_FILES" | wc -l)** 个变更 Java 文件 |"
+ echo "| 检查范围 | 仅新增或修改的行 |"
+ echo ""
+ echo "📄 [下载完整报告(所有文件)](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})"
+ echo "📄 [下载过滤后报告(仅新增行)](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})"
+ } >> "$GITHUB_STEP_SUMMARY"
+ echo "✅ Step Summary 已更新"
+fi
+
+# 8. 替换原始报告为过滤后的报告(以便 Artifact 上传只包含过滤结果)
+# 但为了保留完整报告,我们不上传过滤后的,而是上传原始和过滤两份。
+# 在 YAML 中,我们会上传整个 target/ 下的相关文件,所以无所谓。
+
+# 9. 清理临时文件
+rm -f "$CHANGE_INFO_FILE"
+
+# 10. 始终以成功状态退出
+exit 0
\ No newline at end of file
diff --git a/.github/workflows/checkstyle.yml b/.github/workflows/checkstyle.yml
index 74529b84..176c5e7b 100644
--- a/.github/workflows/checkstyle.yml
+++ b/.github/workflows/checkstyle.yml
@@ -3,35 +3,48 @@ name: Checkstyle Code Quality
on:
push:
branches:
- - develop # 或者你想要检查的分支
+ - develop
pull_request:
branches:
- - develop # 你可以在 PR 时检查代码
+ - develop
jobs:
- check:
+ checkstyle:
runs-on: ubuntu-24.04
steps:
- # 检出代码
- name: Checkout code
uses: actions/checkout@v4
+ with:
+ fetch-depth: 0 # 必须拉取完整历史,才能比较分支差异
- # 设置 JDK(如果是 Java 项目)
- - name: Set up JDK 17.*
+ - name: Set up JDK 17
uses: actions/setup-java@v4
with:
- java-version: '17.*'
+ java-version: '17'
distribution: 'temurin'
- # 安装依赖并运行 Checkstyle(如果是 Maven 项目)
- - name: Install dependencies and run Checkstyle
- run: |
- mvn clean package
+ # 缓存 Maven 依赖,加速构建
+ - name: Cache Maven dependencies
+ uses: actions/cache@v4
+ with:
+ path: ~/.m2/repository
+ key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
+ restore-keys: |
+ ${{ runner.os }}-maven-
+
+ # 直接运行 Checkstyle 检查(不执行完整的 package)
+ - name: Run Checkstyle
+ run: bash .github/scripts/checkstyle-pr.sh
+ env:
+ GITHUB_BASE_REF: ${{ github.base_ref }}
- # 查看 Checkstyle 检查报告
+ # 如果检查失败,仍然上传报告供查看
- name: Upload Checkstyle report
+ if: always() # 即使失败也上传报告
uses: actions/upload-artifact@v4
with:
name: checkstyle-report
- path: target/checkstyle-result.xml # 这个路径应该是 Maven 生成的检查报告路径
+ path: |
+ */target/checkstyle-result.xml
+ */target/site/checkstyle.html
diff --git a/checkstyle/huawei-checkstyle.xml b/checkstyle/huawei-checkstyle.xml
new file mode 100644
index 00000000..a2a60652
--- /dev/null
+++ b/checkstyle/huawei-checkstyle.xml
@@ -0,0 +1,225 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index c651a73c..a4bdd76f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -235,6 +235,30 @@
17
+
+
+ org.apache.maven.plugins
+ maven-checkstyle-plugin
+ 3.3.1
+
+
+ ./checkstyle/huawei-checkstyle.xml
+
+ false
+ warning
+
+ xml
+
+
+
+ checkstyle-check
+ validate
+
+ check
+
+
+
+