http://wenku.baidu.com/view/d2849ff04693daef5ef73d34.html
下面,开端
一.目标:
比来要跟踪一个项目标代码质量,保障项目质量。小我老是认为,质量保障这个器材要用数据措辞的。代码走查是一个方面,但要能应用对象完成项目组标准化的代码走查,发明项目组错误,也不失为一种不错的补充手段。连络之前本身用过、听过的几种开源对象,整合到一路,实现一个合适今朝项目标简单对象。
二.弃取:
起首是对象的选择,经过多个对象的应用连络今朝项目构成员的程度宁状况,决意从几个方面进行搜检:
常规bug
编码规范
反复代码
不想搜检太多,以前没有开展过这方面的工作,辅导是否支撑,项目成员回响是否杰出都很难说,若是大师都喜好再完美更多的搜检也不晚。
其实还差一个依附的检测,但如今项目应用的是ssh的架构,现有依附搜检的对象中,对spring的支撑都不是很好,遂放弃。
对于对象的选择,紧着本身熟悉的就选择了checkstyle、findbugs和pmd的cpd对象。
三.期望成果:
应用ant脚本,一步完成所有工作,针对项目直接产生搜检呈报。
四.步调:
1.筹办对象
ant、checkstyle、findbugs、pmd下载。还要下载cvs和eclipse,因为脚本中须要应用cvs更新代码,eclipse会让ant脚本的编辑和景象设备加倍简单。
2.脚本规划
规划脚本,全部脚本分为几个项目组,如下:
<?xml version="1.0" encoding="utf-8"?> <project name="myProject" default="start" > <!-- 变量定义 --> <!-- 景象初始化 --> <!-- checkout --> <!-- javac --> <!-- jar --> <!-- checkstyle --> <!-- findbugs --> <!-- pmd cpd --> <!-- run --> <target name="start"> </target> </project> |
全部脚本规划描述了脚本履行的过程,每个注释都将添加具体的内容。体系履行start任务,这个任务经由过程依附调用其他任务,任务间经由过程依附定义过程。
l 起首“变量定义”中定义变量,便于将来多个项目复用。
l “景象初始化”中初始化景象,所有景象清理和景象建树都在这里完成。
l “checkout”完成cvs的更新工作。
l 因为findbugs须要搜检二进制代码,“javac”完成代码编译工作。
l 同样为findbugs须要,“jar”将代码打包。
l “checkstyle”完成代码拼写搜检。
l “findbugs”完成bug搜检
l “pmd cpd”应用pmd的cpd功能搜检反复代码。
3.checkout
变量定义和景象初始化项目组,在须要时随时添加,起首是checkout过程,将代码检出cvs库。
3.1脚本编写
checkout项目组脚本如下:
<target name="checkoutlib" depends="mkDir"> <cvs cvsroot="¥{cvsroot}" package="WorkingArea/Code/lib" /> </target> <target name="checkoutsrc" depends="checkoutlib"> <cvs cvsroot="¥{cvsroot}" package="WorkingArea/Code/project" /> </target> |
checkoutlib检出公共库,checkoutsrc检出代码,同时在变量定义项目组定义cvsroot变量,如下:
<property name="cvsroot" value=":pserver:wangjianxuan:password@scm1.domain.com:/repository/project" /> |
此中文字项目组与我们常用的cvs写法雷同,可以参考eclipse中的cvs视图的项目组。
重视:上方脚本中依附的mkDir任务是初始化项目组的,为了建树相干的目次,后面有具体描述。
3.2履行
eclipse中履行ant就是有这点好,缺乏什么不消去批改景象变量,eclipse内部就解决了。履行前有几个处所须要确认:
脚本上点右键-》Run As-》Ant Build…
重视,必然是带有省略号的菜单,这个菜单才干设备景象,打开界面如下图:
这里Targets可以选择要履行的任务,履行时会连依附的任务一路履行。ClassPath定义依附的类库,JRE用来定义JRE的版本,Environment标签很首要,可以定义一些景象变量中不决义的变量,这里我因为一向没有找到cvs路径,但号令行中可以或许找到cvs,所以把Path景象变量复制订义到这里了,如下图:
脚本履行后,会将代码检出到工程目次下的“WorkingArea/Code/project”地位。
重视:景象变量和类路径等内容的设置在更改ant脚本名称后会丧失,须要从头设置。
3.3题目处理惩罚
ant调用cvs网上文章较少,题目的处理惩罚就更少了,也许是太简单了吧,但我还是碰着了一些题目。
起首,若是path路径中没有增长cvs路径,或者你没有安装cvs(windows体系须要安装cvsnt),找不到cvs路径,将报错。所以包管号令行中随便率性路径下调用“cvs”号令可以成功,若是还报错,可以将“path”景象变量增长到eclipse中。
别的,遵守ant的cvs任务申明,cvs暗码应当应用cvspass任务生成cvspass文件,在cvs任务中应用cvspass标签调用这个文件。然则,我在eclipse中这么做不会产生文件,同时cvs checkout会呈报接见被拒绝(很熟悉打听,没暗码)。处理惩罚办法就是将暗码加在cvsroot属性中,在用户名后,“@”符号前增长“:暗码”即可。
4. javac
javac任务将方才检出的代码进行编译,编译后的代码放到bin目次下。
4.1脚本
javac项目组的脚本如下:
<target name="javac" depends="checkoutsrc"> <javac srcdir="¥{srcdir}" destdir="¥{builddir}" source="1.6"> <compilerarg value="-Xlint:unchecked" /> </javac> </target> |
此中,depends指定方才检出脚本,使脚本履行时先履行检出才会履行编译。source指定编译时应用的jdk版本,这里指定了1.6版本。因为代码编译须要,指定了一个编译参数“-Xlint:unchecked”,按照实际景象,可指定任何参数,可多次应用,与号令行编译对应。
在变量定义项目组定义了两个变量:“srcdir”指定源代码路径;“builddir”指定编译后代码路径。脚本如下:
<property name="projdir" value="D:/work/quality_workspace/AntScript" /> <property name="srcdir" value="¥{projdir}/WorkingArea/Code/cginfo/src/main" /> <property name="builddir" value="¥{projdir}/WorkingArea/Code/cginfo/bin" /> |
srcdir和builddir变量共同以当前项目目次为根蒂根基,所以,又定义了一个变量“projdir”声明项目目次。
4.2履行
简单履行javac脚本可能会呈现题目,须要使classpath包含类路径。同样,脚本上右键-》Run As-》Ant Build…打开窗口中选择Classpath页签,如下:
这里要重视,
1. 只有选择“User Entries”节点时,添加jar包的按钮才有效。
2. 不知道是不是我应用的题目,Add Folders添加目次后,并不克不及把目次下所有jar包都添加到类路径来,只能将所有jar包摊在这里。
编译后就是打包了,见下节。
5.jar
与javac同样,因为findbugs的须要,将javac编译后的代码打包
5.1脚本
<target name="jar" depends="javac"> <jar destfile="¥{packagedir}/app.jar" basedir="¥{builddir}" /> </target> |
脚本destfile指定了编译后的jar包路径和文件名,basedir指定原代码的路径。
这里在变量定义项目组定义了变量packagedir用于指定jar包的路径,脚本如下:
<property name="package" value="WorkingArea/Code/commonMakeManage"/> |
履行后会在destfile地位找到打好的jar包。
6.checkstyle
终于进入正题了,筹办工作完成,可以开端搜检了,起首是checkstyle搜检并且生成呈报。
6.1脚本
搜检脚本如下:
<target name="checkstyle" depends="jar"> <taskdef resource="checkstyletask.properties" /> <checkstyle config="lib/check_rules.xml"> <formatter type="xml" tofile="¥{checkstyledir}/checkstyle_report.xml" /> <fileset dir="¥{srcdir}" includes="**/*.java" /> </checkstyle> <style in="¥{checkstyledir}/checkstyle_report.xml" out="¥{checkstyledir}/checkstyle_report.html" style="lib/checkstyle-frames.xsl" /> </target> |
脚本有点长,逐个申明注解:
起首,taskdef定义了checkstyle的ant task,以及声了然属性文件,这就须要ant的类路径中有checkstyle的jar包,这里我用的是checkstyle-5.4-all.jar。
下面,checkstyle定义了搜检的各方面,“config”定义了搜检规矩,规矩可以自定义编写,随后申明。
formatter子元素定义了输出&#26684;式以及输出文件的地位,这里定义了xml&#26684;式,同时定义了“checkstyledir”变量,代表checkstyle呈报目次。后面申明具体变量定义。
fileset子元素定义了源代码地位,dir指定了源代码目次,includes指定文件类型,也可以应用excludes打消一些文件,详见checkstyle文档。
履行后生成xml呈报文件,应用style标签连络checkstyle中自带的xsl文件将xml生成html,便于查看,checkstyle自带了很多xsl文件,多测验测验一下,看看哪个合适。
重视:这里应用的是框架样式,生成的html,生成后有时会在“¥{checkstyledir}”的同级目次生成files目次,目次中包含项目组搜检成果。
6.2变量定义
脚本如下:
<property name="checkstyledir" value="¥{projdir}/checkstyle" /> |
6.3景象初始化脚本
因为每次搜检代码前要将之前的搜检成果删除,包管成果是最新的。同时要包管文件目次存在,不然写呈报时报错。所以有如下脚本:
<target name="delDir"> < dir="¥{builddir}" /> < dir="¥{checkstyledir}" /> < dir="¥{findbugsdir}" /> < dir="¥{cpddir}" /> </target> <target name="mkDir" depends="delDir"> <mkdir dir="¥{builddir}" /> <mkdir dir="¥{checkstyledir}" /> <mkdir dir="¥{findbugsdir}" /> <mkdir dir="¥{cpddir}" /> </target> |
这里将所有须要删除和建树的脚本都写出来了,包含编译的目次builddir;代码搜检成果目次checkstyledir;bug搜检成果目次findbugsdir以及代码反复搜检目次cpddir。
6.3履行
脚本履行后会在checkstyledir目次下建树checkstyle_report.xml和checkstyle_report.html文件
6.4自定义规矩
checkstyle规矩可以自定义,具体规矩可以参考checkstyle文档,这里我只须要搜检很少的规矩,从checkstyle规矩中删除不须要的规矩,保存一项目组须要的即可。规矩如下:
<?xml version="1.0"?> <!DOCTYPE module PUBLIC "-//Puppy Crawl//DTD Check Configuration 1.3//EN" "http://www.puppycrawl.com/dtds/configuration_1_3.dtd"> <!-- Checkstyle configuration that checks the sun coding conventions : - the Java Language Specification at http://java.sun.com/docs/books/jls/second_edition/html/index.html - the Sun Code Conventions at http://java.sun.com/docs/codeconv/ - the Javadoc guidelines at http://java.sun.com/j2se/javadoc/writingdoccomments/index.html - the JDK Api documentation http://java.sun.com/j2se/docs/api/index.html - some best practices Checkstyle is very configurable. Be sure to read the documentation at http://checkstyle.sf.net (or in your downloaded distribution). Most Checks are configurable, be sure to consult the documentation. To completely disable a check, just comment it out or it the file. Finally, it is worth reading the documentation. --> <module name="Checker"> <!-- If you set the basedir property below, then all reported file names will be relative to the specified directory. See http://checkstyle.sourceforge.net/5.x/config.html#Checker <property name="basedir" value="¥{basedir}"/> --> <!-- Checks that property files contain the same keys. --> <!-- See http://checkstyle.sf.net/config_misc.html#Translation --> <module name="Translation"/>
<module name="TreeWalker"> <!-- Checks for Javadoc comments. --> <!-- See http://checkstyle.sf.net/config_javadoc.html --> <module name="JavadocMethod"/> <module name="JavadocType"/> <module name="JavadocVariable"/> <!-- Checks for Naming Conventions. --> <!-- See http://checkstyle.sf.net/config_naming.html --> <module name="ConstantName"/> <module name="LocalFinalVariableName"/> <module name="LocalVariableName"/> <module name="MemberName"/> <module name="MethodName"/> <module name="PackageName"/> <module name="ParameterName"/> <module name="StaticVariableName"/> <module name="TypeName"/> <!-- Checks for Headers --> <!-- See http://checkstyle.sf.net/config_header.html --> <!-- <module name="Header"> --> <!-- The follow property value demonstrates the ability --> <!-- to have access to ANT properties. In this case it uses --> <!-- the ¥{basedir} property to allow Checkstyle to be run --> <!-- any directory within a project. See property --> <!-- expansion, --> <!-- http://checkstyle.sf.net/config.html#properties --> <!-- <property --> <!-- name="headerFile" --> <!-- value="¥{basedir}/java.header"/> --> <!-- </module> --> <!-- Following interprets the header file as regular expressions. --> <!-- <module name="RegexpHeader"/> --> <!-- Checks for imports --> <!-- See http://checkstyle.sf.net/config_import.html --> <module name="AvoidStarImport"/> <module name="IllegalImport"/> <!-- defaults to sun.* packages --> <module name="RedundantImport"/> <module name="UnusedImports"/> <!-- Checks for common coding problems --> <!-- See http://checkstyle.sf.net/config_coding.html --> <module name="SimplifyBooleanExpression"/> <module name="SimplifyBooleanReturn"/> </module> </module> |
7.findbugs
应用findbugs搜检常见bug
7.1脚本
脚本如下:
<target name="findbugs" depends="checkstyle"> <taskdef name="findbugs" classname="edu.umd.cs.findbugs.anttask.FindBugsTask" /> <findbugs home="¥{findbugs.home}" output="html" outputFile="¥{findbugsdir}/findbugs_report.html"> <sourcePath path="¥{srcdir}" /> <class location="¥{projdir}/WorkingArea/Code/cginfo/app.jar" /> </findbugs> </target> |
同样,taskdef定义了findbugs的ant task,须要classpath中增长findbugs的jar包。一个findbugs-ant.jar根蒂根基就够了。
findbugs标签,home指定findbug安装目次。
output定义输出样式,一般输出html情势,xml情势也可,但xml情势再用样式转html老是显示不了bug,没细心查题目产生在哪里。
outputFile指定呈报的路径和文件名。
sourcePath指定源代码目次
class指定jar包的目次和文件名。
7.2履行
履行后查看呈报即可。但findbugs生成的呈报与findbugs eclipse插件搜检的成果有些进出,没有查看具体题目产生在哪里。
8.cpd
cpd是pmd的一个组件,用来搜检反复代码。
8.1脚本
脚本如下:
<target name="pmdcpd" depends="findbugs"> <taskdef name="cpd" classname="net.sourceforge.pmd.cpd.CPDTask" /> <cpd minimumTokenCount="100" encoding="UTF-8" format="xml" outputFile="¥{cpddir}/cpd.xml"> <fileset dir="¥{srcdir}"> <include name="**/*.java" /> </fileset> </cpd> </target> |
taskdef定义了cpd的ant任务,这与pmd任务是分隔的。classpath中须要增长pmd解压目次的lib目次下的所有jar包。
cpd标签的minimumTokenCount指定了最小反复行数,当反复函数大于这个量时产生呈报。
encoding指定文件编码。
format指定输出文件&#26684;式。
outputFile指定输出文件路径和文件名称。
include指定搜检的文件。可以应用exclude指定剔除的文件。
8.2履行
履行后查看输出文件,固然是xml&#26684;式,但应用IE打开很轻易查看,因为只能应用xslt连络xml情势生成html,且初步实验,生成html文件有点题目,就放弃了。
9.完全脚本
完全脚本如下:
<?xml version="1.0" encoding="utf-8"?> <project name="myProject" default="start"> <!-- 变量定义 --> <property name="cvsroot" value=":pserver:wangjianxuan:password@scm1.domain.com:/repository/opermanage" /> <property name="projdir" value="D:/work/quality_workspace/AntScript" /> <property name="srcdir" value="¥{projdir}/WorkingArea/Code/cginfo/src/main" /> <property name="builddir" value="¥{projdir}/WorkingArea/Code/cginfo/bin" /> <property name="checkstyledir" value="¥{projdir}/checkstyle" /> <property name="findbugsdir" value="¥{projdir}/findbugs" /> <property name="findbugs.home" value="D:/work/quality_workspace/findbugs-1.3.9" /> <property name="cpddir" value="¥{projdir}/cpd" /> <!-- init --> <target name="delDir"> < dir="¥{builddir}" /> < dir="¥{checkstyledir}" /> < dir="¥{findbugsdir}" /> < dir="¥{cpddir}" /> </target> <target name="mkDir" depends="delDir"> <mkdir dir="¥{builddir}" /> <mkdir dir="¥{checkstyledir}" /> <mkdir dir="¥{findbugsdir}" /> <mkdir dir="¥{cpddir}" /> </target> <!-- checkout --> <target name="checkoutlib" depends="mkDir"> <cvs cvsroot="¥{cvsroot}" package="WorkingArea/Code/lib" /> </target> <target name="checkoutsrc" depends="checkoutlib"> <cvs cvsroot="¥{cvsroot}" package="WorkingArea/Code/cginfo" /> </target> <!-- javac --> <target name="javac" depends="checkoutsrc"> <javac srcdir="¥{srcdir}" destdir="¥{builddir}" source="1.6"> <compilerarg value="-Xlint:unchecked" /> </javac> </target> <!-- jar --> <target name="jar" depends="javac"> <jar destfile="¥{projdir}/WorkingArea/Code/cginfo/app.jar" basedir="¥{builddir}" /> </target> <!-- checkstyle --> <target name="checkstyle" depends="jar"> <taskdef resource="checkstyletask.properties" /> <checkstyle config="lib/check_rules.xml" failureProperty="checkstyle.failure" failOnViolation="false"> <formatter type="xml" tofile="checkstyle/checkstyle_report.xml" /> <fileset dir="¥{srcdir}" includes="**/*.java" /> </checkstyle> <style in="checkstyle/checkstyle_report.xml" out="checkstyle/checkstyle_report.html" style="lib/checkstyle-frames.xsl" /> </target> <!-- findbugs --> <target name="findbugs" depends="checkstyle"> <taskdef name="findbugs" classname="edu.umd.cs.findbugs.anttask.FindBugsTask" /> <findbugs home="¥{findbugs.home}" output="html" outputFile="¥{findbugsdir}/findbugs_report.html"> <sourcePath path="¥{srcdir}" /> <class location="¥{projdir}/WorkingArea/Code/cginfo/app.jar" /> </findbugs> </target> <!-- pmd cpd --> <target name="pmdcpd" depends="findbugs"> <taskdef name="cpd" classname="net.sourceforge.pmd.cpd.CPDTask" /> <cpd minimumTokenCount="100" encoding="UTF-8" format="xml" outputFile="¥{cpddir}/cpd.xml"> <fileset dir="¥{srcdir}"> <include name="**/*.java" /> </fileset> </cpd> </target> <!-- run --> <target name="start" depends="pmdcpd"> </target> </project> |