在以安全與質量爲主要驅動力的項目中,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插件