svn结合checkStyle和svnchecker校验java8代码

目录

1、使用的软件版本

2、校验流程

3、搭建校验服务

3.1构建checkStyle服务

3.1.1.下载checkStyle和编译checkStyle源码

3.1.2、部署checkStyle

3.2、构建svnchecker-0.3服务

3.2.1、下载svnchecker-0.3源码

3.2.2、部署svnchecker

3.3、构建svn代码校验

3.3.1、配置svncheckerconfig.ini

3.3.2、修改pre_commit钩子

4、附录



1、使用的软件版本

  • jdk:1.8或以上
  • checkStyle:9.3
  • svnchecker:0.3
  • python:2.7.5
  • maven:3.3.6
  • 操作系统:笔者选的是centos7

2、校验流程

svn客户端提交代码后,svn服务端通过pre-commit钩子在提交前做校验。pre-commit调用svnchecker,svncheker调用checkStyle。所有的代码校验规则都是在checkStyle模块完成。

3、搭建校验服务

3.1构建checkStyle服务

3.1.1.下载checkStyle和编译checkStyle源码

url: Releases · checkstyle/checkstyle · GitHub

版本选择:选择10以下的。10以上的版本需要jdk11.10以下的版本可以使用jdk8运行。

下载选择:可以选择checkstyle-版本号-all.jar,比较简单。建议选择下载源码Source code(zip),原因需要解决中文乱码;也可以自己修改代码。

由源码构建checkstyle-版本号-all.jar:下载源码zip文件后,解压。cmd进入加压后的目录(pom.xml的同级目录)。执行命令 mvn -P assembly package。

执行完的效果:

问题和解决方法:

问题1、checkStyle中文乱码问题:

解决方法:修改DefaultLogger.java的addError(AuditEvent aEvt)。支持Unicode编码。修改后的代码下

@Override
public void addError(AuditEvent aEvt) {
    SeverityLevel severityLevel = aEvt.getSeverityLevel();
    if (!SeverityLevel.IGNORE.equals(severityLevel)) {
        String fileName = aEvt.getFileName();
        String message = aEvt.getMessage();
        int bufLen = fileName.length() + message.length() + 12;
        StringBuffer sb = new StringBuffer(bufLen);
        sb.append(fileName);
        sb.append(':').append(aEvt.getLine());
        if (aEvt.getColumn() > 0) {
            sb.append(':').append(aEvt.getColumn());
        }

        if (SeverityLevel.WARNING.equals(severityLevel)) {
            sb.append(": warning");
        }

        sb.append(": ").append(message);
        this.errorWriter.println(this.utf8ToUnicode(sb.toString()));
    }
}
private String utf8ToUnicode(String str) {
    char[] utfBytes = str.toCharArray();
    String unicodeBytes = "";

    for(int i = 0; i < utfBytes.length; ++i) {
        String hexB = Integer.toHexString(utfBytes[i]);
        if (hexB.length() <= 2) {
            hexB = "00" + hexB;
        }

        unicodeBytes = unicodeBytes + "\\u" + hexB;
    }

    return unicodeBytes;
}

问题2、执行执行命令 mvn -P assembly package命令报错。pom.xml中的reporting模块下的插件引入不了。

解决方法:将插件对应的依赖代码移到dependences下,注意不是复制是迁移。依赖引入后,重新把依赖引入的代码写到reporting下。

3.1.2、部署checkStyle

1、设置alibaba_checks.xml。笔者配置内容请参考第4章

alibaba_checks.xml是checkStyle代码风格校验文件。根据《阿里巴巴Java开发手册(公开版).pdf》编写规则。配置内容教程:checkstyle – Checks

2、将打包好的checkstyle-版本号-all.jar连同配置文件alibaba_checks.xml一起放在linux服务器的/opt/checkStyle目录下。给checkstyle-版本号-all.jar赋予可执行权限。

3.2、构建svnchecker-0.3服务

3.2.1、下载svnchecker-0.3源码

从百度网盘下载已经修改好的版本。修改的内容:支持中文提示和多文件提交

链接:百度网盘 请输入提取码

提取码:pasf

3.2.2、部署svnchecker

将下载解压后的源码部署到linux服务器的/opt/svnChecker目录下。给目录下的所有文件赋予可执行权限。

3.3、构建svn代码校验

3.3.1、配置svncheckerconfig.ini

在svn仓库目录下,进入hooks目录。创建svncheckerconfig.ini文件。配置内容主要是被svnchecker-0.3/checks/Checkstyle.py调用。使用时,记得把注释去掉,不然会报错。配置内容如下:

注意/opt/checkstyle-8.3改成checkStyle的部署目录

3.3.2、修改pre_commit钩子

在svn仓库目录下,进入hooks目录。将pre-commit.tmpl重命名为pre-commit。赋予可执行权限。

在pre-commit脚本的结尾加入如下内容:

/opt/svnchecker-0.3/Main.py PreCommit $1 $2 || exit 1

LOGMSG=`$SVNLOOK log -t "$TXN" "$REPOS" | grep "[a-zA-Z0-9]" | wc -c`

if [ "$LOGMSG" -lt 5 ];

then

echo -e "注释不能少于5个字" 1>&2

exit 1

fi

# All checks passed, so allow the commit.

exit 0

4、附录

笔者使用的alibaba_check.xml

<?xml version="1.0"?>
<!DOCTYPE module PUBLIC
    "-//Puppy Crawl//DTD Check Configuration 1.3//EN"
    "http://www.puppycrawl.com/dtds/configuration_1_3.dtd">
 
<module name="Checker">
 
    <!-- 检查文件是否以一个空行结束 -->
    <module name="NewlineAtEndOfFile"/>
 
    <!-- 文件长度不超过1500行 -->
    <module name="FileLength">
        <property name="max" value="1500"/>
     </module>
 
    <!-- 每个java文件一个语法树 -->
    <module name="TreeWalker">
        <!-- import检查-->
        <!-- 避免使用* -->
        <module name="AvoidStarImport">
            <property name="excludes" value="java.io,java.net,java.lang.Math"/>
            <!-- 实例;import java.util.*;.-->
            <property name="allowClassImports" value="false"/>
            <!-- 实例 ;import static org.junit.Assert.*;-->
            <property name="allowStaticMemberImports" value="true"/>
            <message key="import.avoidStar" value="引用包时不能使用*号"/>
        </module>
        <!-- 检查是否从非法的包中导入了类 -->
        <module name="IllegalImport">
            <message key="import.illegal" value="非法导入: {0}"/>
        </module>
        <!-- 检查是否导入了多余的包 -->
        <module name="RedundantImport">
            <message key="import.control.disallowed" value="不允许的导入: {0} 。"/>
            <message key="import.duplicate" value="第{0,number,integer}行重复导入:{1} 。"/>
            <message key="import.illegal" value="非法导入: {0} 。"/>
        </module>
        <!-- 没用的import检查,比如:1.没有被用到2.重复的3.import java.lang的4.import 与该类在同一个package的 -->   
        <module name="UnusedImports">
            <message key="import.unused" value="无用导入 - {0} 。"/>
        </module>
 
 
        <!-- 注释检查 -->
        <!-- 检查方法和构造函数的javadoc -->
        <module name="JavadocType">
            <property name="allowUnknownTags" value="true"/>
            <message key="javadoc.missing" value="类注释:缺少Javadoc注释。"/>
        </module>
        <module name="JavadocMethod">
            <property name="tokens" value="METHOD_DEF" />
            <message key="javadoc.missing" value="方法注释:缺少Javadoc注释。"/>
        </module>
 
        <!-- 命名检查 -->
        <!-- 局部的final变量,包括catch中的参数的检查 -->
        <module name="LocalFinalVariableName" >  
            <property name="severity" value="error"/>
            <message key="name.invalidPattern" value="变量名 ''{0}''没有通过小驼峰命名法命名,具体名称应使用意义完整的英文描述"/>
        </module>
        <!-- 局部的非final型的变量,包括catch中的参数的检查 -->
        <module name="LocalVariableName">       
            <property name="format" value="(^[a-z][a-zA-Z0-9]*$)"/>  
            <message key="name.invalidPattern" value="变量名 ''{0}''没有通过小驼峰命名法命名,具体名称应使用意义完整的英文描述"/>  
        </module>
        <!-- 包名的检查(只允许小写字母),默认^[a-z]+(\.[a-zA-Z_][a-zA-Z_0-9_]*)*$ -->
        <module name="PackageName">
            <property name="format" value="^[a-z]+(\.[a-z][a-z0-9]*)*$" />
            <message key="name.invalidPattern" value="包名 ''{0}'' 要符合 ''{1}''格式."/>
        </module>
        <!-- 仅仅是static型的变量(不包括static final型)的检查 -->
        <module name="StaticVariableName">
            <message key="name.invalidPattern" value="变量名 ''{0}''没有通过小驼峰命名法命名,具体名称应使用意义完整的英文描述"/>
        </module>
        <!-- 接口、枚举、注解类的命名,匹配规则默认:(^[A-Z][a-zA-Z0-9]*$),必须以大写字母开始 -->
        <module name="TypeName">
            <property name="tokens" value="INTERFACE_DEF , ENUM_DEF , ANNOTATION_DEF"/>
            <message key="name.invalidPattern" value="接口类,枚举类,注解类 ''{0}''没有通过大驼峰命名法命名,具体名称应使用意义完整的英文描述"/> 
        </module>
        <!-- 类命名,支持DO\VO\DAO\DTO.匹配规则默认:(^[A-Z][a-zA-Z0-9]*$),必须以大写字母开始 -->
        <module name="TypeName">
            <property name="format" value="(^(([A-Z][a-z]+)+)(VO)?(DO)?(DAO)?(DTO)?$)"/>    
            <property name="tokens" value="CLASS_DEF"/>
            <message key="name.invalidPattern" value="普通类名 ''{0}''没有通过大驼峰命名法命名,具体名称应使用意义完整的英文描述"/> 
        </module>
        <!-- 非static型变量的检查 -->
        <!-- 变量命名 -->
        <module name="MemberName">  
            <message key="name.invalidPattern" value="变量名 ''{0}''没有通过小驼峰命名法命名,具体名称应使用意义完整的英文描述"/>  
        </module>
        <!-- 方法名的检查 -->
        <module name="MethodName">  
            <property name="severity" value="error"/>  
            <property name="format" value="(^[a-z][a-zA-Z0-9]*$)"/>  
            <message key="name.invalidPattern" value="方法名 ''{0}''没有通过小驼峰命名法命名,具体名称应使用意义完整的英文描述"/>       
        </module> 
        <!-- 方法的参数名 -->
        <!--参数名-->
        <module name="ParameterName">
            <property name="severity" value="error"/>           
            <message key="name.invalidPattern" value="参数名 ''{0}''没有通过小驼峰命名法命名,具体名称应使用意义完整的英文描述"/>
        </module>
        <!-- 常量名的检查(只允许大写),默认^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$ -->
        <!-- 常量命名-->
        <module name="ConstantName">
            <property name="severity" value="error"/>
            <message key="name.invalidPattern" value="常量 ''{0}'' 命名不符合规范,常量名必须全部大写且以下划线相连"/>
        </module>
 
        <!-- 定义检查 -->
        <!-- 检查数组类型定义的样式 -->
        <!-- 数组变量命名 -->
        <module name="ArrayTypeStyle">
            <property name="severity" value="error"/>
            <message key="array.type.style" value="数组定义没有采取int[] index这种方式"/>
        </module>
        <!-- 检查long型定义是否有大写的“L” -->
        <module name="UpperEll">
            <message key="upperEll" value="请使用大写''L''"/>
        </module>
 
        
        <!-- 方法不超过50行 -->
        <module name="MethodLength">
            <property name="tokens" value="METHOD_DEF" />
            <property name="max" value="50" />
            <message key="maxLen.method" value="方法 {2} {0,number,integer} 行(最多: {1,number,integer} 行)。"/>
        </module>
        <!-- 方法的参数个数不超过5个。 并且不对构造方法进行检查-->
        <module name="ParameterNumber">
            <property name="max" value="5" />
            <property name="ignoreOverriddenMethods" value="true"/>
            <property name="tokens" value="METHOD_DEF" />
            <message key="maxParam" value="参数共: {1,number,integer}个,最多:{0,number,integer}个。"/>
        </module>
 
        <!-- 空格检查-->
        <!-- 方法名后跟左圆括号"(" -->
        <module name="MethodParamPad" >
            <message key="line.previous" value="''{0}'' 应在前一行。"/>
            <message key="ws.notPreceded" value="''{0}'' 前应有空格。"/>
            <message key="ws.preceded" value="''{0}'' 前不应有空格。"/>
        </module>
        <!-- 在类型转换时,不允许左圆括号右边有空格,也不允许与右圆括号左边有空格 -->
        <module name="TypecastParenPad">
            <property name="severity" value="error"/>
            <property name="tokens" value="RPAREN,TYPECAST"/>
            <message key="ws.followed" value="''{0}''后面多一个空格"/>
            <message key="ws.preceded" value="''{0}''前面多一个空格"/>
        </module> 
        <!-- 检查在某个特定关键字之后应保留空格 -->
        <module name="NoWhitespaceAfter">
            <message key="ws.followed" value="''{0}'' 后不应有空格。"/>
        </module>
        <!-- 检查在某个特定关键字之前应保留空格 -->
        <module name="NoWhitespaceBefore">
            <message key="ws.preceded" value="''{0}''前面多一个空格"/>
        </module>
        
        <!--操作符换行策略检查-->
        <module name="OperatorWrap">
            <property name="severity" value="error"/>
            <message key="line.after" value="''{0}'没有放在新行之首"/>
            <message key="line.new" value="{0} 没有放在新行之首"/>
        </module>
        <!-- 圆括号空白 -->
        <module name="ParenPad">
            <message key="ws.followed" value="''{0}'' 后不应有空格。"/>
            <message key="ws.notFollowed" value="''{0}'' 后应有空格。"/>
            <message key="ws.notPreceded" value="''{0}'' 前应有空格。"/>
            <message key="ws.preceded" value="''{0}''前面多一个空格"/>
        </module>
        <!-- 检查分隔符是否在空白之后 -->
        <module name="WhitespaceAfter">
            <property name="severity" value="error"/>
            <property name="tokens" value="COMMA,SEMI"/>
            <message key="ws.notFollowed" value="''{0}''后面多一个空格"/>
        </module>
        <!-- 检查分隔符周围是否有空白 -->
        <module name="WhitespaceAround">
            <property name="severity" value="error"/>
            <property name="tokens" value="RCURLY,LITERAL_ASSERT,LITERAL_ASSERT,LITERAL_CATCH,LITERAL_DO,LITERAL_ELSE,LITERAL_FINALLY,LITERAL_FOR,LITERAL_IF,LITERAL_RETURN,LITERAL_SYNCHRONIZED,LITERAL_TRY,LITERAL_WHILE"/>
            <property name="allowEmptyConstructors" value="true"/>
            <property name="allowEmptyMethods" value="true"/>
            <message key="ws.notPreceded" value="''{0}'' 关键字前少一个空格"/>
            <message key="ws.notFollowed" value="''{0}'' 关键字后少一个空格"/>
        </module>
 
        <!-- 修饰符检查 -->
        <!-- 检查修饰符的顺序是否遵照java语言规范,默认public、protected、private、abstract、static、final、transient、volatile、synchronized、native、strictfp -->
        <module name="ModifierOrder">
            <message key="line.previous" value="''{0}'' 应在前一行。"/>
            <message key="ws.notPreceded" value="''{0}'' 关键字前少一个空格"/>
            <message key="ws.preceded" value="''{0}''前面多一个空格"/>
        </module>
        <!-- 检查接口和annotation中是否有多余修饰符,如接口方法不必使用public -->
        <!-- 多余的关键字,包含不适用this作为关键字 --> 
        <module name="RedundantModifier">  
            <message key="redundantModifier" value="''{0}'' 多余的修饰符"/>  
        </module>
 
        <!-- 代码块检查 -->
        <!-- 检查是否有嵌套代码块 -->
        <module name="AvoidNestedBlocks">
            <message key="block.nested" value="避免内嵌块。"/>
        </module>
        <!-- 检查是否有空代码块 -->
        <module name="EmptyBlock">
            <message key="block.empty" value="空 {0} 块。"/>
            <message key="block.noStatement" value="块中应至少有一条代码语句。"/>
        </module>
        <!-- 检查左大括号位置 -->
        <module name="LeftCurly">
            <property name="severity" value="error"/>
            <message key="line.previous" value="左侧大括号没有放在前一行代码的行尾"/>            
        </module>
        <!-- 检查代码块是否缺失{} -->
        <!-- 检查代码块是否缺失大括号 -->
        <module name="NeedBraces">  
            <message key="needBraces" value="''{0}'' 结构没有用大括号 '''{}'''s"/>  
        </module>
        <!-- 检查右大括号位置 -->
        <module name="RightCurly">    
            <property name="option" value="alone"/> 
            <property name="severity" value="error"/>     
            <message key="line.alone" value="''{0}''应该独占一行"/>
        </module> 
 
        <!-- 代码检查 -->
        <!-- 检查空的代码段 -->
        <module name="EmptyStatement">
            <message key="empty.statement" value="避免空行。"/>
        </module>
        <!-- 检查在重写了equals方法后是否重写了hashCode方法 -->
        <module name="EqualsHashCode">
            <message key="equals.noEquals" value="重写''hashCode()''方法后,必须重写''equals()''方法。"/>
            <message key="equals.noHashCode" value="重写''equals()''方法后,必须重写''hashCode()''方法。"/>
        </module>
        <!-- 检查局部变量或参数是否隐藏了类中的变量 -->
        <module name="HiddenField">
            <property name="tokens" value="VARIABLE_DEF"/>
            <message key="hidden.field" value="''{0}'' 隐藏属性。"/>
        </module>
        <!-- 检查是否使用工厂方法实例化 -->
        <module name="IllegalInstantiation">
            <message key="instantiation.avoid" value="应避免 {0} 的实例化。"/>
        </module>
        <!-- 检查子表达式中是否有赋值操作 -->
        <module name="InnerAssignment">
            <message key="assignment.inner.avoid" value="应避免在子表达式中赋值。"/>
        </module>
        <!-- 检查是否有"魔术"数字 -->
        <module name="MagicNumber">
           <property name="ignoreNumbers" value="0, 1"/>
           <property name="ignoreAnnotation" value="true"/>
           <message key="magic.number" value="''{0}'' 是一个魔法数(即常数)"/>  

       </module>
        <!-- 检查switch语句是否有default -->
        <module name="MissingSwitchDefault" >
            <property name="severity" value="error"/>
            <message key="missing.switch.default" value="switch 语句后边没有 default 语句"/>
        </module>
        <!-- 检查是否有过度复杂的布尔表达式 -->
        <module name="SimplifyBooleanExpression">
            <property name="severity" value="error"/>
            <message key="simplify.expression" value="存在布尔冗余"/>
        </module>
        <!-- 检查是否有过于复杂的布尔返回代码段 -->
        <module name="SimplifyBooleanReturn">
            <message key="simplify.boolReturn" value="不必要的条件逻辑。"/>
        </module>
 
        <!-- 类设计检查 -->
        <!-- 检查类是否为扩展设计l -->
        <!-- 检查只有private构造函数的类是否声明为final -->
        <module name="FinalClass">
            <message key="final.class" value="只有私有构造器的类必须声明为final"/>
        </module>
        <!-- 检查工具类是否有putblic的构造器 -->
        <module name="HideUtilityClassConstructor">
            <message key="hide.utility.class" value="工具类应隐藏 public 构造器。"/>
        </module>
        <!-- 检查接口是否仅定义类型 -->
        <module name="InterfaceIsType">
            <message key="interface.type" value="接口应描述一种类型,从而必须拥有方法。"/>
        </module>
        <!-- 检查类成员的可见度 检查类成员的可见性。只有static final 成员是public的 
        除非在本检查的protectedAllowed和packagedAllowed属性中进行了设置-->
        <module name="VisibilityModifier">
            <property name="packageAllowed" value="true"/>
            <property name="protectedAllowed" value="true"/>
            <message key="variable.notPrivate" value="变量 ''{0}'' 应定义为 private 的,并配置访问方法。"/>
        </module>
 
        <!-- 语法 -->
        <!-- String的比较不能用!= 和 == -->
        <module name="StringLiteralEquality">
            <message key="string.literal.equality" value="字符串应使用equals()方法进行比较,而非''{0}''。"/>
        </module>
        <!-- 限制for循环最多嵌套2层 -->
        <module name="NestedForDepth">
            <property name="max" value="3"/>
            <message key="nested.for.depth" value="至多{1,number,integer}层 for,目前{0,number,integer}层。"/>
        </module>
        <!-- if最多嵌套3层 -->
        <module name="NestedIfDepth">
            <property name="max" value="3"/>
            <message key="nested.if.depth" value="至多{1,number,integer}层 if,目前{0,number,integer}层。"/>
        </module>
        <!-- 检查未被注释的main方法,排除以App结尾命名的类 -->
        <module name="UncommentedMain">
            <property name="excludedClasses" value=".*App$"/>
            <message key="uncommented.main" value="未注释的Main方法。"/>
        </module>
        <!-- 禁止使用System.out.println -->
        <module name="Regexp">
            <property name="format" value="System\.out\.println"/>
            <property name="illegalPattern" value="true"/>
            <message key="duplicate.regexp" value="重复表达式: ''{0}''。"/>
            <message key="illegal.regexp" value="当前行匹配非法表达式: ''{0}''。"/>
            <message key="required.regexp" value="文件缺少表达式: ''{0}'' 。"/>
        </module>
        <!-- return个数 3个-->
        <module name="ReturnCount">
            <property name="max" value="3"/>
            <message key="return.count" value="Return 次数 {0,number,integer} 次(最大允许非空虚方法/ 拉姆达: {1,number,integer} 次)。"/>
            <message key="return.countVoid" value="Return 次数 {0,number,integer} 次(最大允許為void方法/構造函數/ 拉姆达: {1,number,integer} 次)。"/>
        </module>
        <!--try catch 异常处理数量 3-->
        <module name="NestedTryDepth ">
            <property name="max" value="3"/>
            <message key="nested.try.depth" value="至多{1,number,integer}层 try,目前{0,number,integer}层。"/>
        </module>
        <!-- clone方法必须调用了super.clone() -->
        <module name="SuperClone">
            <message key="missing.super.call" value="方法 ''{0}'' 应调用 ''super.{0}''。"/>
        </module>
        <!-- finalize 必须调用了super.finalize() -->
        <module name="SuperFinalize">
            <message key="missing.super.call" value="方法 ''{0}'' 应调用 ''super.{0}''。"/>
        </module>
 
 
    </module>


    <!-- 单行字符数 -->
    <module name="LineLength">  
        <property name="max" value="120"/>  
        <message key="maxLineLen" value="行字符数超过120个"/>  
    </module>
</module>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阳光程序员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值