我们的目的是想在代码commit之前去做这个检查,把不符合规范的代码标记出来,直到修改完成之后才允许提交。脚本涉及到几个重要的文件:1.pre-commit, 这个是git的一个hook文件,可以帮助我们在commit前去做一些事情,比如,调用我们第二步定义的checkstyle。2.checkstyle.gradle,这里面主要包含gradle的一个task,通过依赖checkstyle插件,然后定义我们自己的checkstyle task 去获取commit前的一些待提交文件,再运用我们定义的规则去做检查。3.checkstyle.xml文件,这个就是定义规则的文件,参考了google编码规范和华为编码规范。4.suppressions.xml,这个是过滤选项,也即是可以排除某些指定文件不受代码规范的检查,比如协议文件。
由于现在AndroidStudio已经支持了checkstyle插件,所以我们只要在.gradle文件里面引用就可以了。(我们这里采用的是checkstyle 6.5)
1.通常,我们会包装自己的checkstyle脚本,将其命名为checkstyle.gradle。代码如下:
apply plugin: 'checkstyle' dependencies { //也可依赖于生成的jar包,以后再说 //compile fileTree(dir: 'libs', include: ['*.jar']) //checkstyle files('../custom-checkstyle/custom-checkstyle.jar') //checkstyle task 依赖 custom-checkstyle module, custom-checkstyle moudle有自定义的Check checkstyle project(':custom-checkstyle') // for using compiled version //checkstyle 'com.puppycrawl.tools:checkstyle:6.5' } def reportsDir = "${ project.buildDir}/reports" checkstyle { //工具版本 toolVersion '6.5' //配置文件路径 configFile file("${ project.rootDir}/checkstyle.xml") //filter路径 configProperties.checkstyleSuppressionsPath = file("${ project.rootDir}/suppressions.xml").absolutePath } task checkstyle(type: Checkstyle, group: 'verification') { try { //try一下,即使发生异常也不影响正常编译 def isCheck = true //是否打开代码规范检查的开关 def isCommit = project.hasProperty('checkCommit') //是否是提交前检查 if (isCheck) { if (isCommit) { //检测代码路径 //source project.rootDir //--- 检查项目中所有的文件, 比较慢, 下面分模块检查, 主要是src下面的java文件 source 'xxx/src' source 'lib-xxx/src' source 'src' //submodules的检查 //排除项 exclude '**/gen/**' exclude '**/test/**' exclude '**/res/**' exclude '**/androidTest/**' exclude '**/R.java' exclude '**/BuildConfig.java' //判断是否是git pre-commit hook触发的checkstyle //如果是,只检测要提交的java文件,否则检测路径下的所有java文件 if (project.hasProperty('checkCommit') && project.property("checkCommit")) { def ft = filterCommitter(getChangeFiles()) def includeList = new ArrayList<String>() for (int i = 0; i < ft.size(); i++) { String spliter = ft.getAt(i) String[] spliterlist = spliter.split("/") String fileName = spliterlist[spliterlist.length - 1] includeList.add("**/" + fileName) } if (includeList.size() == 0) { exclude '**/*.java' } else { println("includeList==" + includeList) include includeList } } else { include '**/*.java' } classpath = files() reports { // 支持html和xml两种报告形式,可以任选其一(html更具有可读性) xml.enabled = false html.enabled = true xml { destination file("$reportsDir/checkstyle/checkstyle.xml") } html { destination file("$reportsDir/checkstyle/checkstyle.html") } } } else { //如果不是提交触发的,也就是对项目进行构建,那么需要对pre-commit文件进行copy def forceCopy = false //如有需要,可以强制去更新客户端的pre-commit文件 try { copyPreCommitFile(forceCopy) //copySubmodulesPreCommitFile(forceCopy) } catch (Exception e) { println(e) } } } }catch (Exception e){ println("checkstyle catch an exception.") e.printStackTrace() } } //src是一个文件路径,target是一个目录路径 def copyFile(boolean forceUpdate, String src, String target){ def fileName = "pre-commit" def targetFile = file(target + "/" + fileName) if(targetFile.exists() && targetFile.isFile() && !forceUpdate){ //目标文件存在且没有强制更新,不需要copy操作 println(targetFile.absolutePath + " exist.") }else { //targetFile.delete() def srcFile = file(src) if (srcFile.isFile()) { copy { from srcFile into target } } } //targetFile = file(target + "/" + fileName) if(targetFile.isFile()) { if (!targetFile.canExecute()) { targetFile.setExecutable(true) } if (!targetFile.canWrite()) { targetFile.setWritable(true) } } } //把根目录下的pre-commit文件复制到.git-->hooks目录 def copyPreCommitFile(boolean forceUpdate){ def src = "${ project.rootDir}/pre-commit" def target = "${ project.rootDir}/.git/hooks" copyFile(forceUpdate, src, target) println("copyPreCommitFile") } //把submodules目录下的pre-commit文件复制到.git-->modules-->submodules-->XXXmoudles-->hooks 目录 def copySubmodulesPreCommitFile(boolean forceUpdate){ def src = "${ project.rootDir}/submodules/pre-commit" def submodulesDir = "${ project.rootDir}/.git/modules/submodules" File file = new File(submodulesDir) File[] fileList = file.listFiles() if(fileList != null && fileList.length > 0) { def size = fileList.length for (int i = 0; i < size; i++) { if (fileList[i].isDirectory()) { //target = "${project.rootDir}/.git/modules/submodules/XXX/hooks" def target = submodulesDir + "/" + fileList[i].getName() + "/hooks" copyFile(forceUpdate, src, target) } } } println("copySubmodulesPreCommitFile") } //过滤java文件 def filterCommitter(String gitstatusinfo) { ArrayList<String> filterList = new ArrayList<String>() String[] lines = gitstatusinfo.split("\\n") for (String line : lines) { if (!line.startsWith("D ") && line.contains(".java") ) { String[] spliters = line.trim().split(" ") for (String str : spliters) { if (str.contains(".java")) { filte