Gitlab集成P3C代码规约检测

20 Jan 2022 » ci, operation

前言

公司需要对java代码进行静态代码检测,需要满足阿里规约, 但对一些已有的仓库不进行检测,考虑使用Gitlab的server hook的pre-receive实现,在代码提交时对java文件进行代码检测。 本文Gitlab服务器使用的是CentOS,其他Linux环境自行对照。

阿里规约准备

编译最新p3c-pmd模块

编写规则集xml文件

根据需要设定规则,下载实例

<?xml version="1.0"?>
<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="alibaba-pmd"
         xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
         xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 http://pmd.sourceforge.net/ruleset_2_0_0.xsd">
    <description>p3c rule set</description>
    <rule ref="rulesets/java/ali-concurrent.xml"/>
    <rule ref="rulesets/java/ali-comment.xml"/>
    <rule ref="rulesets/java/ali-constant.xml"/>
    <rule ref="rulesets/java/ali-exception.xml"/>
    <rule ref="rulesets/java/ali-flowcontrol.xml"/>
    <rule ref="rulesets/java/ali-naming.xml">
        <!-- 去掉抽象类命名规范-->
        <exclude name="AbstractClassShouldStartWithAbstractNamingRule"/>
        <!-- 去掉测试用例命名规范 -->
        <exclude name="TestClassShouldEndWithTestNamingRule"/>
    </rule>
    <rule ref="rulesets/java/ali-other.xml"/>
    <rule ref="rulesets/java/ali-orm.xml"/>
    <rule ref="rulesets/java/ali-oop.xml"/>
    <rule ref="rulesets/java/ali-set.xml"/>
</ruleset>

Gitlab Server Hook配置

1. 修改/etc/gitlab/gitlab.rb配置

# gitlab_rails['custom_hooks_dir']已过期配置
gitaly['custom_hooks_dir'] = "/opt/gitlab/embedded/service/gitlab-shell/hooks"

2. 重新配置Gitlab服务

gitlab-ctl reconfigure

3. 添加custom_hooks_dir目录

cd /opt/gitlab/embedded/service/gitlab-shell
mkdir hooks
cd hooks
# 移动ali-p3c.xml到hooks目录
mv ali-p3c.xml .
# 移动pmd包到hooks目录
mv p3c-pmd-2.1.1-jar-with-dependencies.jar .
# 创建前置钩子文件夹 文件夹只能名为pre-receive.d、post-receive.d、update.d
# 分别对应前置、后置、处理中钩子
mkdir pre-receive.d

4. 在pre-receive.d目录下创建代码检测钩子脚本p3c-pre-inspect.sh

#!/bin/sh
# 检测标识文件
hit_file=".pre-check"
# 临时目录
temp_dir="temp-${GL_ID}"
# pmd路径
pmd_dir=/opt/gitlab/embedded/service/gitlab-shell/hooks
# 初始commit id
zero_commit="0000000000000000000000000000000000000000"
# 拒绝数量
reject=0

while read oldrev newrev refname; do
    # 分支或者tag被删除
    if [ "$newrev" = "$zero_commit" ]; then
      continue
    fi

    git cat-file -e ${refname}:${hit_file}
    # 当前分支不存在静态检测文件
    if [ $? -ne 0 ]; then
        # 当次提交不存在静态检测文件 跳过检测
        git cat-file ${newrev}:${hit_file}
        if [ $? -ne 0 ]; then
            break
        fi
    fi

    files=`git diff --name-only ${oldrev} ${newrev}  | grep -e ".java$"`
    if [ -n "$files" ]; then
      # 缓存java文件
      for file in ${files}; do
        mkdir -p "${temp_dir}/`dirname ${file}`" >/dev/null
        git show $newrev:$file > ${temp_dir}/${file}
      done;

      # 检测缓存目录的文件
      java -Dfile.encoding=utf8 -cp ${pmd_dir}/p3c-pmd-2.1.1-jar-with-dependencies.jar net.sourceforge.pmd.PMD -d ${temp_dir} -R ${pmd_dir}/ali-p3c.xml -f text -shortnames -no-cache
      # 失败记录数
      reject=$?

      if [ $reject = 0 ] ;then
        echo "代码通过静态检测!"
      fi

      # 删除临时目录
      rm -rf $temp_dir
    fi
done

exit $reject

修改脚本权限为可执行

chmod 777 p3c-pre-inspect.sh

5. 自动创建检测标识文件钩子

/opt/gitlab/embedded/service/gitlab-rails/file_hooks目录下创建add_pre_check_on_project_create.rb钩子文件,根据需要设定规则, 每当项目创建时,会自动提交一个新的.pre-check文件到仓库,当前使用的是web api提交标识文件到仓库, 不知道是否存在钩子之类的后置操作,目前暂时没有想到其他更好的解决方案,如果你有,请你联系我

#!/opt/gitlab/embedded/bin/ruby

require 'net/http'
require 'uri'
require 'json'

ARGS = JSON.parse($stdin.read)
# 仅当项目创建时才添加.pre-check文件
if ARGS['event_name'] == 'project_create'
    # 设置对应gitlab服务端口
    uri = URI.parse("http://localhost/api/v4/projects/#{ARGS['project_id']}/repository/files/#{URI::encode('.pre-check')}")
    
    header = {
        'Content-Type': 'application/json',
        # 设置管理员用户的令牌
        'PRIVATE-TOKEN': 'glpat-xd1xKRCj99s9NTyZNR1N'
    }
    
    data = {
        branch: 'master',
        content: '',
        commit_message: 'init pre check commit'
    }
    
    # Create the HTTP objects
    http = Net::HTTP.new(uri.host, uri.port)
    request = Net::HTTP::Post.new(uri.request_uri, header)
    request.body = data.to_json
    
    # Send the request
    response = http.request(request)
end

修改文件权限为可执行

chmod 777 add_pre_check_on_project_create.rb

6. 安装JRE环境

# 查询合适的jdk版本
yum search java | grep jdk
yum install -y java-1.8.0-openjdk.x86_64
# 安装验证
java -version

验证钩子

图片