写点什么

代码评审 -findBugs

  • 2024-04-25
    广东
  • 本文字数:4031 字

    阅读完需:约 13 分钟

背景:


我们在开发过程中,因为每一个人的水平都不一样,所以写出来的代码也是千人千面,风格各异,水平参差不齐。所以在带团队过程中,怎么提高大家伙的水平成为了一个我日常思考的问题。

首先我认为大家都喜欢阅读清晰、明了的代码,这样修改别人代码时,也知道在什么位置进行扩展,维护性比较高。这种经验上或者技巧的东西除了每周分享或者组织 code review 提供一个交流学习的机会,让成员接受到组内大佬的熏陶。日常开发怎么也能保证自己的代码质量呢?


更重要的是,提高代码质量同样为项目提供了质量保障,减少了测试的成本。


需求:

我的期望是利用静态代码检查工具,在代码提交的时候做一次代码检查,如果检查结果不通过的话,就提示并拒绝当前提交。这样间接提高大家对自己的代码质量的认识以及要求,后续如果把结果进行统计报送,后续 review 时还可以当作案例讨论,有更多有意思的场景。


调研一下常用的静态代码检查工具:

  1. checkstyle: 检查代码风格,统一换行,最大行字符,import 的顺序,代码缩进等等

  2. archunit: 检查代码分层关系,比如在 dao 层代码不能直接访问 service、controller 层代码

  3. findbugs: 检查潜在的缺陷,比如 NPE、try catch 资源释放、数值精度问题


相关技术:

git hook,maven


具体实现:

讲解一下结合 git hook、findbugs 的插件在代码提交前做检查

git hook

以下是 kimiAi 生成




Git Hooks 是 Git 版本控制系统的一个特性,允许用户在特定的 Git 事件发生时自动执行自定义脚本。这些钩子可以用于自动化常规任务,提高工作流程的效率,加强代码质量控制,以及实施项目特定的策略。以下是 Git Hooks 的一些基本知识点:


  1. 定义:Git Hooks 是在 Git 仓库中的特定事件发生时自动触发的脚本,脚本内容可以由 shell、py 进行编写。

  2. 分类

  3. 本地钩子(Client Hooks):在本地仓库上触发,如 pre-commitpost-commitpre-push 等。

  4. 服务端钩子(Server Hooks):在服务器端触发,如 pre-receivepost-receive 等。

  5. 用途:Git Hooks 可用于多种用途,包括但不限于:

  6. 自动运行代码检查和测试。

  7. 格式化代码。

  8. 验证提交信息的格式。

  9. 阻止不符合特定条件的提交或推送。

  10. 创建和使用

  11. 在 Git 仓库的 .git/hooks 目录下创建一个以期望的钩子名称命名的文件。

  12. 将该文件的权限设置为可执行。

  13. 编写脚本内容以实现所需的功能。

  14. 常用钩子

  15. pre-commit:在提交操作发生前运行,常用于代码风格检查、简单测试等。

  16. post-commit:在提交操作完成后运行,可以用于通知或日志记录。

  17. pre-push:在推送操作发生前运行,适合用在执行集成测试或检查兼容性。

  18. post-receive:在服务器端接收到推送后运行,可用于自动部署或其他服务器端任务。

  19. Husky:是一个流行的 npm 包,可以简化 Git Hooks 的安装和配置过程。

  20. 参数和环境变量:Git Hooks 可以接收参数和使用环境变量,这些参数和变量提供了关于触发钩子的 Git 事件的上下文


ok,我们就使用pre-commit钩子满足我们的需求


maven find bugs 配置


以下是 kimiAi 生成


Maven FindBugs 插件是一个用于在 Maven 项目中集成 FindBugs 工具的插件,FindBugs 是一个静态代码分析工具,用于在 Java 代码中发现潜在的错误。以下是在 IntelliJ IDEA 中使用 Maven FindBugs 插件的说明和常用配置项的说明:


在 IntelliJ IDEA 中使用 Maven FindBugs 插件

  1. 确保 Maven 插件已安装:在 IntelliJ IDEA 中,确保已经安装了 Maven 插件。如果没有安装,可以通过 File -> Settings -> Plugins 进行安装。

  2. 导入 Maven 项目:通过 File -> Import Project 导入你的 Maven 项目。

  3. 运行 FindBugs 扫描

    在项目工具栏中,点击右侧的 Maven 面板,选择 Plugins -> findbugs -> check

    或者,使用终端命令,在项目根目录下运行 mvn findbugs:check

  4. 查看结果:扫描完成后,FindBugs 会在 IntelliJ IDEA 的底部窗口中显示结果。

  5. 使用 FindBugs GUI:如果你想通过图形界面查看结果,可以使用命令 mvn findbugs:gui 打开 FindBugs 的图形界面。


常用配置项说明

以下是一些 Maven FindBugs 插件的常用配置项:

  1. effort:设置分析工作的等级,可以为 MinDefaultMaxLow 最严格,High 只扫描严重错误。建议使用 Medium

  2. threshold:设置 Bug 的严重性等级,可以是 LowMediumHigh。只有高于这个等级的 Bug 才会被报告。

  3. failOnError:如果设置为 true,当发现 Bug 时,构建会失败。

  4. includeTests:如果设置为 true,FindBugs 也会分析测试代码。

  5. excludeFilterFile:指定一个 XML 文件,用于忽略特定的 Bug 类型或代码区域。

  6. onlyAnalyze:指定要分析的特定包或类。

  7. pluginsList:指定要使用的 FindBugs 插件。

  8. jvmArgs:为 FindBugs 分析过程指定 JVM 参数。

  9. debug:如果设置为 true,FindBugs 将运行在调试模式下。


测试的配置如下

    <build>        <plugins>            <plugin>                <groupId>org.apache.maven.plugins</groupId>                <artifactId>maven-compiler-plugin</artifactId>                <version>3.6.1</version>                <configuration>                    <source>1.8</source>                    <target>1.8</target>                </configuration>            </plugin>            <plugin>                <groupId>org.codehaus.mojo</groupId>                <artifactId>findbugs-maven-plugin</artifactId>                <version>3.0.4</version>                <configuration>                    <effort>min</effort>                </configuration>                <executions>                    <execution>                        <goals>                            <goal>check</goal>                        </goals>                    </execution>                </executions>            </plugin>        </plugins>    </build>
复制代码




关于 findbugs 更多使用参考官网:

FindBugs™ Manual (sourceforge.net)

FindBugs Maven Plugin – Usage (gleclaire.github.io)


脚本编写

找到当前项目,创建文件,并给执行权限。将一下脚本内容复制到 pre-commit 即可

touch .git/hooks/pre-commit

chmod 755 pre-commit

#!/bin/bashstaged_files=$(git diff --cached --name-only)module_name=()class_name=()index=0filter_file="staged_files_filter.xml"

staged_files_length=${#staged_files[@]}echo "提交文件的数量为: $staged_files_length"
if [ "$staged_files_length" -lt 1 ]; then echo "警告:文件数量为Null, 请检查提交的文件列表!" exit 0;fi
# 定义函数,传入参数为待处理的字符串convert_to_package() { local input_string=$1 local package_string=$(echo "$input_string" | sed 's/^\///; s/\//./g; s/\.java$//') echo "全限定类名: $package_string" class_name[index]=$package_string}
# 定义函数,传入参数为待处理的字符串split_string() { echo "当前文件: $1" # 使用 sed 来匹配并提取前面的字符串和后面的字符串 local prefix=$(echo "$1" | sed 's/\/src\/main\/java.*//') local suffix=$(echo "$1" | sed 's/.*\/src\/main\/java//')
# 输出结果 echo "前面的字符串: $prefix" echo "后面的字符串: $suffix"
# 将模块名称存储在数组中 module_name[index]=$prefix # 获取全类名 convert_to_package "$suffix"}
for file in ${staged_files[@]}; do split_string "$file" index=$((index + 1)) echo "loop str: $file, index: $index"done

echo "所有的模块名称:"for element in "${module_name[@]}"; do echo "$element"done
# 去重并计算数组长度unique_module_name=($(echo "${module_name[@]}" | tr ' ' '\n' | awk '!seen[$0]++'))unique_module_length=${#unique_module_name[@]}
# 直接访问数组中的元素echo "去重模块数组中的结果:"for element in "${unique_module_name[@]}"; do echo "$element"done
# 去重并计算数组长度unique_class_name=($(echo "${class_name[@]}" | tr ' ' '\n' | awk '!seen[$0]++'))unique_class_length=${#unique_class_name[@]}
echo "去重全类名数组中的结果:"for element in "${unique_class_name[@]}"; do echo "$element"done
if [ "$unique_module_length" -gt 1 ]; then echo "警告:模块名称不唯一,请检查提交的文件列表!" exit 1;fi

echo "<FindBugsFilter>" >$filter_filefor file in ${unique_class_name[@]}; do echo " <Match>" >>$filter_file echo " <Class name=\"$file\" />" >>$filter_file echo " </Match>" >>$filter_filedoneecho "</FindBugsFilter>" >>$filter_file
# Print the filter file contentecho "生成扫描文件: $filter_file:"cat $filter_file
echo "=====准备编译====="mvn clean compile -T 5 findbugs:findbugs -Dfindbugs.skip=false -Dfindbugs.includeFilterFile=$filter_fileecho "=====编译结束====="
# 清理临时文件rm $filter_file

echo "=====开始检测====="for module in $(find . -name 'findbugsXml.xml'); do if [ -f "$module" ]; then if grep -q "<BugInstance " "$module"; then # 复制文件到 target 目录 cp "$module" "target/findbugsXml.xml" echo "你有Bug了,在 $module. 请修复它.使用 mvn findbugs:gui 命令查看" exit 1 else echo "No potential issues found by FindBugs in $module." fi else echo "FindBugs report not found in $module." fidone
复制代码


在提交代码时便会进行使用插件进行检查提交的文件是否存在问题。

后续优化


  1. findbugs 检查的是字节码文件,所以需要编译项目,如果项目体量很大,提交代码的时间成本太高了。只编译提交的类。

  2. 提交的时候使用 AI 进行检查,但是没有想到一个好的交互。慢慢想吧

发布于: 刚刚阅读数: 4
用户头像

还未添加个人签名 2021-01-10 加入

还未添加个人简介

评论

发布
暂无评论
代码评审-findBugs_代码质量_追随月光的战士_InfoQ写作社区