diff --git a/.github/scripts/checkstyle-pr.sh b/.github/scripts/checkstyle-pr.sh new file mode 100644 index 00000000..cce8116a --- /dev/null +++ b/.github/scripts/checkstyle-pr.sh @@ -0,0 +1,162 @@ +#!/bin/bash +# ============================================================ +# checkstyle-pr.sh - 增量检查(扫描整个变更文件,不过滤行号) +# 功能:对本次提交中变更的 Java 文件执行完整的 Checkstyle 检查 +# 不阻断构建,生成完整报告 +# ============================================================ + +set -e + +echo "========================================" +echo " Checkstyle 增量检查" +echo " 扫描范围:本次变更的 Java 文件(完整文件)" +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 "----------------------------------------" + +# 按模块分组 +declare -A module_files +for file in $CHANGED_FILES; do + module="${file%%/*}" + if [ -z "$module" ] || [ "$module" == "$file" ]; then + echo "⚠️ 忽略根目录文件: $file" + continue + fi + rel="${file#$module/}" + if [ -z "${module_files[$module]}" ]; then + module_files[$module]="$rel" + else + module_files[$module]="${module_files[$module]},$rel" + fi +done + +if [ ${#module_files[@]} -eq 0 ]; then + echo "⚠️ 没有识别到任何模块,跳过检查。" + exit 0 +fi + +echo "📝 按模块分组后的相对路径:" +for module in "${!module_files[@]}"; do + echo " $module: ${module_files[$module]}" +done +echo "----------------------------------------" + +total_violations=0 + +# 对每个模块执行 Checkstyle +for module in "${!module_files[@]}"; do + file_list="${module_files[$module]}" + echo "🚀 扫描模块: $module" + echo " 文件列表: $file_list" + + if [ ! -d "$module" ] || [ ! -f "$module/pom.xml" ]; then + echo "⚠️ 模块目录 $module 不存在或没有 pom.xml,跳过。" + continue + fi + + echo " - 生成 XML 报告..." + set +e + (cd "$module" && mvn checkstyle:check -X ... 2>&1 | grep "Loading checkstyle configuration" \ + -Dcheckstyle.config.location=../checkstyle/huawei-checkstyle.xml \ + -Dcheckstyle.includes="$file_list" \ + -Dcheckstyle.violationSeverity=warning) + if [ $? -ne 0 ]; then + echo " ⚠️ 模块 $module 的 Checkstyle 检查失败(但继续)" + fi + set -e + + echo " - 生成 HTML 报告..." + set +e + (cd "$module" && mvn checkstyle:checkstyle \ + -Dcheckstyle.config.location=../checkstyle/huawei-checkstyle.xml \ + -Dcheckstyle.includes="$file_list" \ + -Dcheckstyle.outputFormat=html \ + -Dcheckstyle.violationSeverity=warning) + if [ $? -ne 0 ]; then + echo " ⚠️ 模块 $module 的 HTML 报告生成失败(但继续)" + fi + set -e + + report_file="$module/target/checkstyle-result.xml" + if [ -f "$report_file" ]; then + count=$(grep -c '/dev/null || true) + else + count=0 + fi + echo "" +done + +echo "----------------------------------------" +if [ $total_violations -eq 0 ]; then + echo "✅ 所有变更文件未发现违规!" +else + echo "⚠️ 总计发现 $total_violations 个违规。" + # 显示部分违规摘要(第一个有违规的模块) + echo "" + echo "📋 违规摘要(前 30 条):" + for module in "${!module_files[@]}"; do + report_file="$module/target/checkstyle-result.xml" + if [ -f "$report_file" ] && [ $(grep -c '//' | \ + sed 's|line="|行号: |g; s|column="|列: |g; s|severity="|严重性: |g; s|message="|信息: |g; s|source="||g' | \ + while read -r line; do + echo " $line" + done || true + break + fi + done +fi + +# Step Summary +if [ -n "$GITHUB_STEP_SUMMARY" ]; then + { + echo "## 📋 Checkstyle 汇总报告" + echo "" + echo "| 指标 | 结果 |" + echo "|------|------|" + if [ $total_violations -eq 0 ]; then + echo "| 总违规数 | ✅ **0** |" + else + echo "| 总违规数 | ⚠️ **$total_violations** |" + fi + echo "| 涉及模块 | ${!module_files[*]} |" + echo "" + echo "📥 完整报告已作为 Artifact 上传。" + } >> "$GITHUB_STEP_SUMMARY" +fi + +# 根据违规数决定退出码 +if [ $total_violations -eq 0 ]; then + echo "✅ 检查通过,构建成功。" + exit 0 +else + echo "❌ 发现 $total_violations 个违规,构建失败。" + exit 1 +fi \ No newline at end of file diff --git a/.github/scripts/pmd-pr.sh b/.github/scripts/pmd-pr.sh new file mode 100644 index 00000000..15796f4f --- /dev/null +++ b/.github/scripts/pmd-pr.sh @@ -0,0 +1,90 @@ +#!/bin/bash +# ============================================================ +# pmd-pr.sh - PMD 增量扫描脚本 +# 功能:只扫描本次提交中变更的 Java 文件 +# 生成报告到 target/pmd-report.xml(或自定义路径) +# ============================================================ + +set -e + +echo "========================================" +echo " PMD 增量扫描" +echo " 扫描范围:本次变更的 Java 文件" +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 文件变更,跳过 PMD 扫描。" + exit 0 +fi + +echo "📝 变更的 Java 文件:" +echo "$CHANGED_FILES" +echo "----------------------------------------" + +# 3. 生成文件列表(绝对路径) +FILE_LIST="changed-files.txt" +> "$FILE_LIST" +for file in $CHANGED_FILES; do + echo "$PWD/$file" >> "$FILE_LIST" +done + +echo "📄 文件列表已生成:$FILE_LIST" +echo "----------------------------------------" + +# 4. 准备 PMD(如果未安装) +PMD_VERSION="6.55.0" +PMD_HOME="./pmd" +if [ ! -d "$PMD_HOME" ]; then + echo "⬇️ 下载 PMD $PMD_VERSION ..." + curl -L "https://github.com/pmd/pmd/releases/download/pmd_releases%2F${PMD_VERSION}/pmd-bin-${PMD_VERSION}.zip" -o pmd.zip + unzip -q pmd.zip + mv pmd-bin-${PMD_VERSION} "$PMD_HOME" + rm pmd.zip +fi +PMD_CMD="$PMD_HOME/bin/run.sh" +chmod +x "$PMD_CMD" + +# 5. 执行 PMD 扫描(使用 -filelist) +echo "🚀 执行 PMD 扫描..." +REPORT_FILE="target/pmd-report.xml" +set +e +"$PMD_CMD" pmd --no-cache \ + -filelist "$FILE_LIST" \ + -f xml \ + -R category/java/quickstart.xml \ + -r "$REPORT_FILE" +EXIT_CODE=$? +set -e + +# 6. 检查是否生成报告 +if [ -f "$REPORT_FILE" ]; then + echo "✅ PMD 报告已生成:$REPORT_FILE" +else + echo "⚠️ PMD 未生成报告,可能无违规或出错。" +fi + +# 7. 清理临时文件 +rm -f "$FILE_LIST" + +# 8. 始终以成功状态退出(违规由 YAML 汇总步骤决定) +exit 0 \ No newline at end of file diff --git a/.github/scripts/spotbugs-incremental.sh b/.github/scripts/spotbugs-incremental.sh new file mode 100644 index 00000000..65f76802 --- /dev/null +++ b/.github/scripts/spotbugs-incremental.sh @@ -0,0 +1,74 @@ +#!/bin/bash +# ============================================================ +# spotbugs-incremental.sh - 增量 SpotBugs 扫描 +# 功能:只分析本次变更的 Java 文件对应的类 +# ============================================================ + +set -e + +echo "========================================" +echo " SpotBugs 增量扫描" +echo "========================================" + +# 确定目标分支 +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 + +# 获取变更的 Java 文件 +CHANGED_JAVA=$(git diff --name-only "$BASE_BRANCH" HEAD 2>/dev/null | grep '\.java$' || true) + +if [ -z "$CHANGED_JAVA" ]; then + echo "✅ 没有 Java 文件变更,跳过 SpotBugs 扫描。" + exit 0 +fi + +echo "📝 变更的 Java 文件:" +echo "$CHANGED_JAVA" + +# 提取类名列表 +class_list="" +for file in $CHANGED_JAVA; do + # 文件可能已被删除,跳过 + if [ ! -f "$file" ]; then + continue + fi + # 提取包名(假设文件中有 package 声明) + pkg=$(grep '^package' "$file" | sed -E 's/package\s+([^;]+);.*/\1/' | head -1) + if [ -z "$pkg" ]; then + echo "⚠️ 跳过 $file(未找到 package 声明)" + continue + fi + # 提取类名(不含 .java 后缀) + classname=$(basename "$file" .java) + fqdn="$pkg.$classname" + if [ -z "$class_list" ]; then + class_list="$fqdn" + else + class_list="$class_list,$fqdn" + fi +done + +if [ -z "$class_list" ]; then + echo "⚠️ 未能提取到任何有效的类名,跳过 SpotBugs。" + exit 0 +fi + +echo "📋 待分析的类:$class_list" +echo "----------------------------------------" + +# 执行 SpotBugs 增量分析 +echo "🚀 执行 SpotBugs 增量扫描..." +mvn spotbugs:check -Dspotbugs.onlyAnalyze="$class_list" \ No newline at end of file diff --git a/.github/workflows/checkstyle.yml b/.github/workflows/checkstyle.yml index 74529b84..8c0a161d 100644 --- a/.github/workflows/checkstyle.yml +++ b/.github/workflows/checkstyle.yml @@ -1,37 +1,87 @@ -name: Checkstyle Code Quality - -on: - push: - branches: - - develop # 或者你想要检查的分支 - pull_request: - branches: - - develop # 你可以在 PR 时检查代码 - -jobs: - check: - runs-on: ubuntu-24.04 - - steps: - # 检出代码 - - name: Checkout code - uses: actions/checkout@v4 - - # 设置 JDK(如果是 Java 项目) - - name: Set up JDK 17.* - uses: actions/setup-java@v4 - with: - java-version: '17.*' - distribution: 'temurin' - - # 安装依赖并运行 Checkstyle(如果是 Maven 项目) - - name: Install dependencies and run Checkstyle - run: | - mvn clean package - - # 查看 Checkstyle 检查报告 - - name: Upload Checkstyle report - uses: actions/upload-artifact@v4 - with: - name: checkstyle-report - path: target/checkstyle-result.xml # 这个路径应该是 Maven 生成的检查报告路径 +name: Checkstyle Code Quality + +on: + push: + branches: + - develop + pull_request: + branches: + - develop + +jobs: + checkstyle: + runs-on: ubuntu-24.04 + env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + + steps: + - name: Checkout code + uses: actions/checkout@v6 + with: + fetch-depth: 0 # 必须拉取完整历史,才能比较分支差异 + + - name: Set up JDK 17 + uses: actions/setup-java@v5 + with: + java-version: '17' + distribution: 'temurin' + + # 缓存 Maven 依赖,加速构建 + - name: Cache Maven dependencies + uses: actions/cache@v5 + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-maven- + # 新增:安装所有模块到本地仓库,解决依赖解析 + - name: Install project (for dependency resolution) + run: mvn install -DskipTests -Dmaven.test.skip=true -Dcheckstyle.skip=true -Dpmd.skip=true -Dspotbugs.skip=true -Dcpd.skip=true + + # 直接运行 Checkstyle 检查(不执行完整的 package) + - name: Run Checkstyle + run: bash .github/scripts/checkstyle-pr.sh + env: + GITHUB_BASE_REF: ${{ github.base_ref }} + + # ==================== PMD 增量扫描 ==================== + - name: Run PMD (incremental) + id: pmd + run: bash .github/scripts/pmd-pr.sh + env: + GITHUB_BASE_REF: ${{ github.base_ref }} + # ==================== 调试:列出所有报告 ==================== + - name: Debug - list all reports + if: always() + run: | + echo "当前工作目录: $(pwd)" + echo "=== 查找所有检查报告 ===" + find . -type f \( -name "checkstyle-result.xml" -o -name "pmd-report.xml" -o -name "cpd.xml" -o -name "spotbugsXml.xml" \) + + - name: Debug - list all checkstyle reports + run: | + echo "当前工作目录: $(pwd)" + echo "=== 列出所有 target 目录 ===" + find . -type d -name "target" -exec echo "目录: {}" \; -exec ls -la {}/ \; + echo "=== 查找 checkstyle 文件 ===" + find . -name "checkstyle*.xml" -o -name "checkstyle*.html" | while read f; do echo "找到: $f"; done + + - name: Debug - Check HTML existence + run: | + echo "Searching for checkstyle.html:" + find . -name "checkstyle.html" -type f + echo "Also check reports directory:" + ls -la base/target/reports/ || echo "base/target/reports not found" + + # 如果检查失败,仍然上传报告供查看 + - name: Upload Checkstyle report + if: always() # 即使失败也上传报告 + uses: actions/upload-artifact@v7 + with: + name: checkstyle-report + path: | + **/target/checkstyle-result.xml + **/target/checkstyle-checker.xml + **/target/reports/ + if-no-files-found: warn + diff --git a/.github/workflows/pmd.yml b/.github/workflows/pmd.yml new file mode 100644 index 00000000..3ac2e69e --- /dev/null +++ b/.github/workflows/pmd.yml @@ -0,0 +1,131 @@ +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. + +name: pmd + +on: + push: + branches: [ "develop" ] + pull_request: + branches: [ "develop" ] + schedule: + - cron: '41 12 * * 3' + +permissions: + contents: read + +jobs: + pmd-code-scan: + permissions: + contents: read # for actions/checkout to fetch code + security-events: write # for github/codeql-action/upload-sarif to upload SARIF results + actions: read # only required for a private repository by github/codeql-action/upload-sarif to get the Action run status + runs-on: ubuntu-latest + env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + steps: + - uses: actions/checkout@v5 + with: + fetch-depth: 0 # 必须拉取完整历史,才能比较分支差异 + - name: Set up JDK 17 + uses: actions/setup-java@v5 + with: + java-version: '17' + distribution: 'temurin' + - name: Run PMD on changed Java files only + id: pmd + run: | + # 1. 确定目标分支(从环境变量获取) + if [ -n "$GITHUB_BASE_REF" ]; then + BASE_BRANCH="$GITHUB_BASE_REF" + else + # 如果是 push 事件,回退到 main 或 develop + BASE_BRANCH="develop" # 或 main,根据项目调整 + fi + + # 2. 确保目标分支的远程引用存在 + git fetch origin "$BASE_BRANCH" --depth=1 || true + + # 3. 获取变更的 Java 文件(比较当前 HEAD 与目标分支) + CHANGED_FILES=$(git diff --name-only "origin/$BASE_BRANCH" HEAD | grep '\.java$' || true) + + echo "📝 变更的 Java 文件列表:" + if [ -n "$CHANGED_FILES" ]; then + echo "$CHANGED_FILES" + else + echo "(无)" + fi + echo "----------------------------------------" + + if [ -z "$CHANGED_FILES" ]; then + echo "No Java files changed, skipping PMD." + echo "violations=0" >> $GITHUB_OUTPUT + exit 0 + fi + + # 4. 生成文件列表(绝对路径) + > changed-files.txt + for file in $CHANGED_FILES; do + echo "$PWD/$file" >> changed-files.txt + done + + # 5. 下载 PMD + PMD_VERSION="6.55.0" + curl -L "https://github.com/pmd/pmd/releases/download/pmd_releases%2F${PMD_VERSION}/pmd-bin-${PMD_VERSION}.zip" -o pmd.zip + unzip -q pmd.zip + mv pmd-bin-${PMD_VERSION} pmd + PMD_CMD="$PWD/pmd/bin/run.sh" + chmod +x "$PMD_CMD" + + # 6. 扫描变更的 Java 文件 + "$PMD_CMD" pmd --no-cache \ + --file-list changed-files.txt \ + -f sarif \ + -R rulesets/java/quickstart.xml \ + -r pmd-report.sarif || true + + # 7. 统计违规数 + if [ -f pmd-report.sarif ]; then + violations=$(jq '.runs[0].results | length' pmd-report.sarif) + else + violations=0 + fi + echo "violations=$violations" >> $GITHUB_OUTPUT + + # 清理 + rm -f changed-files.txt + + + - name: Install sarif-tools and convert to HTML + run: | + pip install sarif-tools + sarif html pmd-report.sarif --output pmd-report.html + + - name: Upload SARIF file + uses: github/codeql-action/upload-sarif@v4 + with: + sarif_file: pmd-report.sarif + + - name: Upload SARIF file as artifact + uses: actions/upload-artifact@v7 + with: + name: pmd-sarif-report # 给工件起一个有意义的名字 + path: pmd-report.sarif + + - name: Upload HTML report + uses: actions/upload-artifact@v7 + with: + name: pmd-html-report + path: pmd-report.html + + - name: Check PMD violations + run: | + if [[ ${{ steps.pmd.outputs.violations }} -eq 0 ]]; then + echo "✅ PMD 未发现代码问题,构建通过。" + exit 0 + else + echo "❌ PMD 发现 ${{ steps.pmd.outputs.violations }} 个代码问题,构建失败。" + exit 1 + fi \ No newline at end of file diff --git a/app/src/main/java/com/tinyengine/it/test/SampleViolations.java b/app/src/main/java/com/tinyengine/it/test/SampleViolations.java new file mode 100644 index 00000000..d967edbd --- /dev/null +++ b/app/src/main/java/com/tinyengine/it/test/SampleViolations.java @@ -0,0 +1,95 @@ +package com.tinyengine.it.test; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +public class SampleViolations { + // 1. 未使用的私有字段 (UnusedPrivateField) + private String unusedField = "I am not used"; + + // 2. 常量命名不符合规范 (ConstantNamingConventions) → 应全大写 + public static final String myConstant = "should be UPPER_CASE"; + + // 3. 字段命名不符合规范 (FieldNamingConventions) → 应 camelCase,这里合规,略过 + + // 4. 不应使用 'l' 作为变量名 (AvoidFieldNameMatchingMethodName) 但更常见的是短变量名 + + public void demoMethod() { + // 5. 未使用的局部变量 (UnusedLocalVariable) + int unusedLocal = 42; + + // 6. 短变量名 (ShortVariable) + int a = 10; + + // 7. 使用 System.out.println (SystemPrintln) + System.out.println("This is a direct system print"); + + // 8. 魔法数字 (MagicNumber) + int magic = (int) (3.14 * 2); // 3.14 和 2 都是魔法数字 + + // 9. 在循环中创建对象 (AvoidInstantiatingObjectsInLoops) + List list = new ArrayList<>(); + for (int i = 0; i < 10; i++) { + String s = new String("loop object"); // 无必要 + list.add(s); + } + + // 10. 空的 catch 块 (EmptyCatchBlock) + try { + Files.readAllLines(Paths.get("nonexistent.txt")); + } catch (IOException e) { + // empty + } + + // 11. 未关闭的资源 (CloseResource) + try { + Connection conn = DriverManager.getConnection("jdbc:hsqldb:mem:test", "sa", ""); + // 使用 conn 后未关闭 + } catch (SQLException e) { + e.printStackTrace(); + } + + // 12. 使用 'return' 语句过多 (MultipleReturns) 或过于复杂 + if (magic > 0) { + return; + } else { + // 多个 return 点 + } + + // 13. 未使用的参数 (UnusedFormalParameter) + unusedMethod("hello", 123); + } + + private void unusedMethod(String param1, int param2) { + // 这里只使用了 param1,param2 未使用 + System.out.println(param1); + } + + // 14. 方法过长 (TooLongMethod) 但这里仅作演示,可通过增加行数制造,但不必 + // 15. 参数过多 (TooManyParameters) + public void tooManyParams(int p1, int p2, int p3, int p4, int p5, int p6, int p7, int p8, int p9, int p10) { + // 10个参数,可能触发参数过多规则 + } + + // 16. 不应使用 'Thread.sleep' 在循环中?不强制 + + // 17. 使用 'ConcurrentHashMap' 代替 'Hashtable'?不强制 + + // 18. 使用 'BigDecimal' 构造函数时避免 double (BigDecimalConstructor) + public void bigDecimalIssue() { + java.math.BigDecimal bd = new java.math.BigDecimal(0.1); // 可能触发 + } + + // 19. 使用 'StringBuffer' 而不是 'StringBuilder'? (StringBufferUsage) + public void stringBufferUsage() { + StringBuffer sb = new StringBuffer(); // 可能建议使用 StringBuilder + sb.append("test"); + } + +} diff --git a/base/src/main/java/com/tinyengine/it/common/utils/CheckstyleValidation.java b/base/src/main/java/com/tinyengine/it/common/utils/CheckstyleValidation.java new file mode 100644 index 00000000..c273d28d --- /dev/null +++ b/base/src/main/java/com/tinyengine/it/common/utils/CheckstyleValidation.java @@ -0,0 +1,31 @@ +package com.tinyengine.it.common.utils; + +public class CheckstyleValidation { + // This class intentionally violates Checkstyle rules for testing GitHub Action + + public static final int CONSTANT = 42; // Valid constant name + + private int bad_variable_name; // Violates naming convention + + public CheckstyleValidation() { + // Empty constructor (violates EmptyBlock rule) + } + + public void badMethod() { + if (true) { + System.out.println("This is a bad method"); // Violates line length if too long + } else { + return; // SimplifyBooleanReturn violation + } + } + + public void multipleVariables() { + int a = 1, b = 2; // Violates MultipleVariableDeclarations rule + } + + public void longMethod() { // Violates MethodLength if too long + for (int i = 0; i < 100; i++) { + System.out.println("Line " + i); + } + } +} diff --git a/base/src/main/java/com/tinyengine/it/common/utils/testCheckstyle.java b/base/src/main/java/com/tinyengine/it/common/utils/testCheckstyle.java new file mode 100644 index 00000000..0649b1f4 --- /dev/null +++ b/base/src/main/java/com/tinyengine/it/common/utils/testCheckstyle.java @@ -0,0 +1,117 @@ +package com.tinyengine.it.common.utils; +import java.lang.reflect.Field; + +/** + * 类名错误:应使用 UpperCamelCase(首字母大写) + * 这里故意写成了小写开头的 testCheckstyle + */ +public class testCheckstyle { + + // 常量命名错误:应全部大写并用下划线分隔 + public static final String myConstant = "Hello"; + + // 成员变量命名错误:不应以下划线开头 + private String _name; + + // 成员变量命名错误:不应使用单个字符 + private int a; + + /** + * 构造方法:可以接受参数,但未提供 Javadoc + */ + public testCheckstyle(String name) { + this._name = name; + } + + public void test() { + long value = 1l; // 错误:使用了小写 l + System.out.println(value); + } + public void longMethod() { + // 填充到超过 300 行,例如添加 301 个空行或打印语句 + for (int i = 0; i < 301; i++) { + System.out.println("line " + i); + } + } + + public void test1() { + if (true) { + if (true) { + if (true) { + if (true) { // 第4层嵌套,超过最大值3 + System.out.println("deep"); + } + } + } + } + } + + public void test2() { + String s = "hello"; + if (s == "hello") { // 错误:应使用 equals() + System.out.println("equal"); + } + } + + /** + * 方法名错误:不应包含大写字母,应使用 lowerCamelCase + */ + public void SayHello() { + // 行长度超限(超过120字符),故意写长 + System.out.println("This line is intentionally made extremely long to exceed the maximum line length limit which is usually set to 120 characters in Huawei coding standard. It definitely exceeds 120 chars."); + + // 缩进可能使用Tab(如果你的编辑器未转换,此处会触发) + // 未使用的局部变量 + String unused = "I am not used anywhere"; + } + + /** + * 公共方法缺少 Javadoc 注释 + */ + public void doSomething() { + // 方法体为空或简单,但缺少注释 + + } + + /** + * 方法名包含下划线,违反 lowerCamelCase + */ + public void do_this() { + // 空方法体 + } + + /** + * 参数和返回值缺少 Javadoc 说明(如果有要求) + */ + public int add(int a, int b) { + return a + b; + } + + /** + * 重载方法,但缺少 Javadoc + */ + public int add(int a, int b, int c) { + return a + b + c; + } + + // 缺少访问修饰符的方法(默认包级别,可能不符合规范) + void packagePrivateMethod() { + System.out.println("This method has no access modifier."); + } + + // 静态方法命名错误 + public static void StaticMethod() { + // 方法名首字母大写,违反 lowerCamelCase + } + + // 常量应放在静态代码块或声明时赋值,但此处未遵循顺序 + public static final String ANOTHER_CONST; + static { + ANOTHER_CONST = "Init"; + } + + void test3(){ + String json = "{\"key\":\"value\",\"number\":123}"; + byte[] jsonBytes = json.getBytes(); + } +} diff --git a/base/src/test/java/com/tinyengine/it/common/utils/JsonUtilsTest.java b/base/src/test/java/com/tinyengine/it/common/utils/JsonUtilsTest.java index 80562311..37cdcc38 100644 --- a/base/src/test/java/com/tinyengine/it/common/utils/JsonUtilsTest.java +++ b/base/src/test/java/com/tinyengine/it/common/utils/JsonUtilsTest.java @@ -270,7 +270,7 @@ void testEncodePrettily_ComplexObject() { void testDecode_ByteArray() { // Arrange String json = "{\"key\":\"value\",\"number\":123}"; - byte[] jsonBytes = json.getBytes(StandardCharsets.UTF_8); + byte[] jsonBytes = json.getBytes(); // Act Map result = JsonUtils.decode(jsonBytes, Map.class); diff --git a/checkstyle/huawei-checkstyle.xml b/checkstyle/huawei-checkstyle.xml new file mode 100644 index 00000000..ae341aac --- /dev/null +++ b/checkstyle/huawei-checkstyle.xml @@ -0,0 +1,253 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index c651a73c..a13d7c73 100644 --- a/pom.xml +++ b/pom.xml @@ -235,6 +235,104 @@ 17 + + + org.apache.maven.plugins + maven-checkstyle-plugin + 3.6.0 + + + + ${session.executionRootDirectory}/checkstyle/huawei-checkstyle.xml + + true + warning + + xml + + ${project.basedir}/src/main/java + ${project.basedir}/src/test/java + + + + + + checkstyle-check + validate + + check + + + + + + + + org.apache.maven.plugins + maven-pmd-plugin + 3.21.0 + + + category/java/bestpractices.xml + category/java/codestyle.xml + category/java/design.xml + category/java/errorprone.xml + category/java/performance.xml + category/java/security.xml + + true + false + 100 + + + + pmd-check + verify + + check + + + true + + + + + cpd-check + verify + + cpd-check + + + true + + + + + + + com.github.spotbugs + spotbugs-maven-plugin + 4.7.3.1 + + + spotbugs-check + verify + + check + + + + + Max + Low + true + true + true + ${project.build.directory}/spotbugs-reports + + + + diff --git a/sonar-project.properties b/sonar-project.properties new file mode 100644 index 00000000..dfb04fd9 --- /dev/null +++ b/sonar-project.properties @@ -0,0 +1 @@ +sonar.sourceEncoding=UTF-8 \ No newline at end of file