在以安全与质量为主要驱动力的项目中,CI相当重要。javascript
所以,我从个人团队开始进行“概念验证”,以代表如下技术已准备好协同工做:java
本文的范围是解释安装和设置必要工具的全部步骤,以使Java 8的CI服务器彻底正常运行。请注意,该证实已在Windows 7的开发人员机器上完成,但很容易作到。在Linux服务器中也是如此。mysql
下图高层次显示了将在帖子中描述的体系结构。sql
咱们正在建立模块化应用程序。该应用程序具备多层体系结构,其中每一个层都是模块套件,而最终的可执行文件只是一组集成套件。数据库
咱们正在使用Ant 来构建咱们的项目,可是若是您使用的是Maven,则甚至能够简化该过程,由于Jenkins中的Sonar集成能够经过使用Maven的插件来完成。编程
天然,咱们正在进行单元测试,所以,咱们使用JUnit4。它在任何地方均可以很好地集成,尤为是在NetBeans中。segmentfault
Jacoco 是生成代码覆盖率的绝佳工具,而且自0.7.1版起,它彻底支持Java 8。安全
Jenkins是咱们CI服务器的引擎,它将与上述全部技术集成在一块儿,没有任何问题。测试的版本是1.554。服务器
声纳正在对代码进行全部质量分析。4.2版与Java 8彻底兼容。网络
将Sonar与Ant一块儿使用须要一个小型库,其中包含要集成到Jenkins中的目标。若是您使用的是Maven,则能够只安装Maven插件。
<?xml version="1.0" encoding="UTF-8"?> <!-- --> <project name="sonar-jacoco-module" basedir="." xmlns:jacoco="antlib:org.jacoco.ant" xmlns:sonar="antlib:org.sonar.ant"> <description>Builds the module suite otherSuite.</description> <property name="jacoco.dir" location="${nbplatform.default.harness.dir}/jacoco-0.7.1"/> <property name="result.exec.file" location="${jacoco.dir}/jacoco.exec"/> <property name="build.test.results.dir" location="build/test/unit/results"/> <property file="nbproject/project.properties"/> <!-- Step 1: Import JaCoCo Ant tasks --> <taskdef uri="antlib:org.jacoco.ant" resource="org/jacoco/ant/antlib.xml"> <classpath path="${jacoco.dir}/jacocoant.jar"/> </taskdef> <!-- Target at the level of modules --> <target name="-do-junit" depends="test-init"> <echo message="Doing testing for jacoco"/> <macrodef name="junit-impl"> <attribute name="test.type"/> <attribute name="disable.apple.ui" default="false"/> <sequential> <jacoco:coverage destfile="${build.test.results.dir}/${code.name.base}_jacoco.exec"> <junit showoutput="true" fork="true" failureproperty="tests.failed" errorproperty="tests.failed" filtertrace="${test.filter.trace}" tempdir="${build.test.@{test.type}.results.dir}" timeout="${test.timeout}"> <batchtest todir="${build.test.@{test.type}.results.dir}"> <fileset dir="${build.test.@{test.type}.classes.dir}" includes="${test.includes}" excludes="${test.excludes}"/> </batchtest> <classpath refid="test.@{test.type}.run.cp"/> <syspropertyset refid="test.@{test.type}.properties"/> <jvmarg value="${test.bootclasspath.prepend.args}"/> <jvmarg line="${test.run.args}"/> <!--needed to have tests NOT to steal focus when running, works in latest apple jdk update only.--> <sysproperty key="apple.awt.UIElement" value="@{disable.apple.ui}"/> <formatter type="brief" usefile="false"/> <formatter type="xml"/> </junit> </jacoco:coverage> <copy file="${build.test.results.dir}/${code.name.base}_jacoco.exec" todir="${suite.dir}/build/coverage"/> <!-- Copy the result of all the unit tests of all the modules into one common folder at the level of the suite, so that sonar could find those files to generate associated reports --> <copy todir="${suite.dir}/build/test-results"> <fileset dir="${build.test.results.dir}"> <include name="**/TEST*.xml"/> </fileset> </copy> <fail if="tests.failed" unless="continue.after.failing.tests">Some tests failed; see details above. </fail> </sequential> </macrodef> <junit-impl test.type="${run.test.type}" disable.apple.ui="${disable.apple.ui}"/> </target> </project>
该文件的范围是覆盖添加jacoco覆盖范围的do-junit任务,并复制套件构建中每一个模块的单元测试结果,以便声纳将找到全部这些元素一块儿进行分析。
<?xml version="1.0" encoding="UTF-8"?> <project name="sonar-jacoco-suite" basedir="." xmlns:jacoco="antlib:org.jacoco.ant" xmlns:sonar="antlib:org.sonar.ant"> <description>Builds the module suite otherSuite.</description> <property name="jacoco.dir" location="${nbplatform.default.harness.dir}/jacoco-0.7.1"/> <property name="result.exec.file" location="build/coverage"/> <!-- Define the SonarQube global properties (the most usual way is to pass these properties via the command line) --> <property name="sonar.jdbc.url" value="jdbc:mysql://localhost:3306/sonar?useUnicode=true&characterEncoding=utf8" /> <property name="sonar.jdbc.username" value="sonar" /> <property name="sonar.jdbc.password" value="sonar" /> <!-- Define the SonarQube project properties --> <property name="sonar.projectKey" value="org.codehaus.sonar:example-java-ant" /> <property name="sonar.projectName" value="Simple Java Project analyzed with the SonarQube Ant Task" /> <property name="sonar.projectVersion" value="1.0" /> <property name="sonar.language" value="java" /> <!-- Load the project properties file for retrieving the modules of the suite --> <property file="nbproject/project.properties"/> <!-- Using Javascript functions to build the paths of the data source for sonar configuration --> <script language="javascript"> <![CDATA[ // getting the value modulesName = project.getProperty("modules"); modulesName = modulesName.replace(":",","); res = modulesName.split(","); srcModules = ""; binariesModules = ""; testModules = ""; //Build the paths for (var i=0; i<res.length; i++) { srcModules += res[i]+"/src,"; binariesModules += res[i]+"/build/classes,"; testModules += res[i]+"/test,"; } //Remove the last comma srcModules = srcModules.substring(0, srcModules.length - 1); binariesModules = binariesModules.substring(0, binariesModules.length - 1); testModules = testModules.substring(0, testModules.length - 1); // store the result in a new properties project.setProperty("srcModulesPath",srcModules); project.setProperty("binariesModulesPath",binariesModules); project.setProperty("testModulesPath",testModules); ]]> </script> <!-- Display the values --> <property name="sonar.sources" value="${srcModulesPath}"/> <property name="sonar.binaries" value="${binariesModulesPath}" /> <property name="sonar.tests" value="${testModulesPath}" /> <!-- Define where the coverage reports are located --> <!-- Tells SonarQube to reuse existing reports for unit tests execution and coverage reports --> <property name="sonar.dynamicAnalysis" value="reuseReports" /> <!-- Tells SonarQube where the unit tests execution reports are --> <property name="sonar.junit.reportsPath" value="build/test-results" /> <!-- Tells SonarQube that the code coverage tool by unit tests is JaCoCo --> <property name="sonar.java.coveragePlugin" value="jacoco" /> <!-- Tells SonarQube where the unit tests code coverage report is --> <property name="sonar.jacoco.reportPath" value="${result.exec.file}/merged.exec" /> <!-- Step 1: Import JaCoCo Ant tasks --> <taskdef uri="antlib:org.jacoco.ant" resource="org/jacoco/ant/antlib.xml"> <classpath path="${jacoco.dir}/jacocoant.jar"/> </taskdef> <target name="merge-coverage"> <jacoco:merge destfile="${result.exec.file}/merged.exec"> <fileset dir="${result.exec.file}" includes="*.exec"/> </jacoco:merge> </target> <target name="sonar"> <taskdef uri="antlib:org.sonar.ant" resource="org/sonar/ant/antlib.xml"> <!-- Update the following line, or put the "sonar-ant-task-*.jar" file in your "$HOME/.ant/lib" folder --> <classpath path="${harness.dir}/sonar-ant-task-2.1/sonar-ant-task-2.1.jar" /> </taskdef> <!-- Execute the SonarQube analysis --> <sonar:sonar /> </target> </project>
该文件的范围是在套件级别定义声纳配置和声纳任务。若是您使用声纳,则某些特殊的数据库或特殊的用户必须在此处更改配置。
定义的另外一项任务是jacoco合并,该合并实际上将获取每一个模块的全部生成的exec,并将它们合并到套件构建中的单个exec中,以容许声纳进行分析。
<description>Builds, tests, and runs the project com.infrabel.jacoco.</description> <property file="nbproject/suite.properties"/> <property file="${suite.dir}/nbproject/private/platform-private.properties"/> <property file="${user.properties.file}"/> <import file="${nbplatform.default.harness.dir}/sonar-jacoco-module.xml"/> <import file="nbproject/build-impl.xml"/>
<description>Builds the module suite otherSuite.</description> <property file="nbproject/private/platform-private.properties"/> <property file="${user.properties.file}"/> <import file="${nbplatform.default.harness.dir}/sonar-jacoco-suite.xml"/> <import file="nbproject/build-impl.xml"/>
若是您在防火墙或代理后面,而且在配置网络设置时遇到问题,能够随时今后处手动下载并安装它们。在这种状况下,请记住还要先下载每一个插件的依赖项。
按照此脚本建立数据库,并选择运行此查询以使链接正常工做:GRANT ALL PRIVILEGES ON 'sonar'.* TO 'sonar'@'localhost';
进入声纳的配置文件(sonar.properties)并启用MySQL,该文件位于安装的conf文件夹中:
sonar.jdbc.username=sonar sonar.jdbc.password=sonar sonar.jdbc.url=jdbc:mysql://localhost:3306/sonar?useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true
在声纳的配置中,若是须要与Java 8兼容,请更新Java插件