Hudson:持续集成服务器工具介绍

本文详细介绍了持续集成工具Hudson的工作原理、安装配置、通用设置以及创建构建任务的过程,包括如何配置SVN、Ant、JUnit等。此外,还展示了在Android项目中的应用,如ngux构建和Espier构建,以及构建后的测试报告发布。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

资料参考

介绍

什么是持续集成(Continuous Integration)

持续集成(CI)是一种实践,旨在缓和和稳固软件的构建过程。在整个软件开发生命周期内,它主要用于保证代码质量,确保尽早遇到问题(如代码缺陷),避免问题在软件开发周期晚期变复杂时才被发现。CI的作用主要有如下几个方面:
  • 软件构建自动化。
  • 构建可持续的自动化检查。
  • 构建可持续的自动化测试。
  • 生成后后续过程的自动化。

组件

实现CI的上述功能,需要三个组件:
  • 用 Ant 或 Maven 等工具建立的自动构建过程。
  • 一个代码存储库,比如 CVS 或 Subversion。
  • 一个 CI 服务器,比如 Hudson。

hudson介绍

Hudson 是一种革命性的开放源码 CI 服务器,它从以前的 CI服务器吸取了许多经验教训。Hudson最吸引人的特性之一是它很容易配置:很难找到更容易设置的 CI 服务器,也很难找到开箱即用特性如此丰富的CI 服务器。Hudson 容易使用的第二个原因是它具有强大的插件框架 ,所以很容易添加特性。例如,一个 Hudson 插件可以随时间的推移跟踪FindBugs 和代码覆盖。它还可以报告测试结果的趋势(来自 JUnit 或 TestNG? )以及构建结果和对应的执行时间。有人调查过,Hudson是目前使用最多的CI服务器。

工作原理

  • CI系统的基本结构图

CI.png

构建过程

  • 触发构建--手动、代码更新、定制时间。
  • 更新代码--Svn、Git、CVS。
  • 构建--执行 Shell、执行 Windows 批处理、使用Ant、使用Maven。

安装

  • 安装sun-java6-jdk,设置环境变量JAVA_HOME
  • 安装tomcat6
  • 安装 ant (optional)
  • hudson官网下载hudson.war,放到tomcat/webapps下。访问http://localhost:8080/hudson,进入hudson的启动页面。注:使用sudo apt-get install tomcat6时,将hudson.war放在/var/lib/tomcat6/webapps目录下。
  • 默认在/usr/share/tomcat6/.hudson下建立hudson的主目录。注意权限问题。

通用配置

系统管理

  • 打开系统管理-系统设置,进行配置。
    • 主目录:这个目录用来保存所有的配置信息和数据。默认是当前用户目录下的.hudson。也可创建一个空目录,并将这个目录路径赋给环境变量 hudson/WEB-INF/web.xml中的HUDSON_HOME,重启hudson。
    • JDK:设置JDK的路径,默认是自动安装的,如果你的电脑安装过JDK那就将自动安装复选框勾掉,填写JAVA_HOME的路径即可。
    • Ant:设置Ant的路径ANT_HOME。
    • Android Emulator:针对Android项目,设置 SDK安装路径。
    • Xvnc-Command line:设置vncserver启动路径及参数。如:/usr/bin/vncserver :99 -geometry 800x600。
    • Xvnc-Base display number:设置桌面显示号的基数。如:99.
  • 打开系统管理-管理插件,可安装插件。hudson默认的插件保存目录为:HUDSON_HOME/plugins,所以也可以直接将插件拷贝到该目录下,重启hudson即可。
  • HUDSON_HOME目录结构
    HUDSON_HOME
              |-------config.xml (hudson基础配置) 
              |-------*.xml (其他站点范围内的配置文件)
              |-------userContent (此目录中的文件将被送达您的http://server/hudson/userContent/。)
              |-------fingerprints (存储指纹记录,关于fingerprints请查阅文件指纹识别)
              |-------plugins (存储插件集)
              |-------jobs(构建任务总目录)
                      |-------[JOBNAME] (为每个作业定义一个子目录) 
                              |-------config.xml (作业配置文件) 
                              |-------workspace (为版本控制系统而工作的目录)
                              |-------lastSuccessful (这个符号关联到最近的成功构建。)
                              |-------builds

用户配置

选中系统设置-启用安全 ,进行用户配置
  • JNLP节点代理的TCP端口选项中选择“Disable”。
  • 访问控制-安全域
    • 选择“Hudson专有用户数据库”:使用Hudson自己的用户列表验证, 而不是外部系统代理. 这适用于没有用户数据库小范围的设定. 建立的用户配置信息保存在HUDSON_HOUME/users下。
    • 允许用户注册:如果勾选上,则表示允许用户自己注册一个新账号,通过点击页面右上角的注册链接进行操作。取消这个选框表示禁止任意注册新账号。 当这个选框被取消,就必须使用系统管理员来创建账号。
  • 授权策略-安全矩阵
    • 需要先注册一个admin用户(与角色名称相同),赋予全部的权限以便检验,否则我们将无法管理hudson。
    • 默认会有一个匿名用户角色,表示未登录用户的访问权限,你可以不授权或只授予read权限。
    • 添加用户/组:输入一个名称,然后点击添加,这里实际上是先建立一个角色,因为这时用户并不存在。然后注册一个相同名字的用户。
  • 授权策略-项目矩阵授权策略
    • 这个授权模型扩展自"安全矩阵",允许把下面的ACL(访问控制列表)矩阵附加到每个项目定义中(在Job配置页面). 就是说,除了可以在这里进行全局授权外,还可以在JOB中进行配置。
    • 任务设置-启用项目安全:这里只能对当前的JOb进行授权配置,同样的,这里也是创建角色,用户需要自己注册或管理员进行创建。如果“系统设置”与“JOB设置”中存在相同的角色,则权限取并集。
  • 反设置
    • 有时候会出现这样的情况,就是虽然创建了角色,但是没有勾选上“允许用户注册”,这时就无法控制hudson了,这时可以通过如下修改,开启“允许用户注册”。
    • 在$HUDSON_HOME环境变量对应的文件夹下config.xml,修改true 元素为false。重启hudson,这时候的Hudson又回归到无认证模式,任何人都能拥有该系统的全部权限。

创建构建任务

配置JOB_WORKSPACE

  • 构建时使用的目录,也就是从代码仓库中取得的代码所要保存的路径,默认路径为:HUDSON_HOME/jobs/$jobname/workspace
  • job的配置中,所有涉及到路径的配置,都是基于JOB_WORKSPACE基础上的,配置时都是使用相对路径,也就是从这个路径开始计算。
  • 可以在job设置中修改这个路径,找到Advanced Project Options,点击“Advanced”,勾选Use custom workspace,并设置一个绝对路径,比如/usr/local/hudson/jobname/workspace,保存。

ngux构建:svn+cppcheck+gtest

注:需要安装hudson的svn插件、cppcheck插件。

  • 新建任务
  • Source Code Management:设置项目的源码获取方式Subversion地址
    svn+ssh://hjhei@192.168.1.4/home/projects/svn/ngux/trunk@HEAD
  • Build Triggers:设置构建的触发器
    • Poll SCM:指定一个定时作业表达式来定义Hudson每隔多久检查一下您源代码仓库的变化。如果发现变化,就执行一次构建。
    • Build periodically:选项支持类似crontab格式的任务周期定制。* * * * *对应分钟,小时,月份相应的日期,月份,星期

  • Build:添加指令以执行构建脚本,这里添加的是shell脚本
    • 执行cppcheck的脚本,并在ngux的目录下生成cppcheck-result.xml测试报告。
      cd ./ngux
      cppcheck --enable=all -q --xml . 2>cppcheck-result.xml

    • 编译执行gtest测试用例的脚本,在ngux/unittest/reports目录下生成每个类对应的xml测试报告。
      cd ./ngux
      make clean
      make -j3
      cd .unittest/
      ./run_gtest.sh

    • run_gtest.sh文件内容
      #!/bin/bash
      TEST_ITEMS=(textviewtest imageviewtest gridviewtest pageviewtest pagenavigateviewtest panelviewtest boxlayoutviewtest pairlayoutviewtest buttonviewtest linelayoutviewtest scrollviewtest menuviewtest itemviewtest listviewtest listviewlooptest trackbarviewtest)
      
      [ -e reports/ ] || mkdir reports
      
      for item in ${TEST_ITEMS[*]}
      do
          ./$item --gtest_output=xml:$item.xml
          if [ -f $item.xml ]; then
              mv $item.xml reports/
          else
              echo "====================build $item failed===================="
              continue
          fi
      done

  • Post-build Actions:构建完成后需要进行的处理
    • Publish JUnit test result report:如果构建脚本执行了JUnit测试,此选项将指示Hudson处理XML测试文档并为每次连续构建产生一份可持续的报告,依据正在进行的测试汇总处理结果。其结果是当前工作主页的一份报告,作业中的单元测试会随着时间的推移按由老至新进行陈列。
      ngux/unittest/reports/*.xml


    • Publish Cppcheck results:发布cppcheck测试报告,同JUnit。
      **/cppcheck-result.xml


    • E-mail Notification:当选择此选项,可以输入一个或多个电子邮件地址[多个可用空格分隔],当Hudson完成了执行作业后,将会给它们发送通知。事件触发时将产生一份 Email,包括构建失败、构建不稳定等。这儿有一个额外的选项,当由于用户的错误提交造成Hudson决定废弃此次构建,将会发送一份专门的邮件给这位 SCM提交者,以便让他检查源代码。注:如果集成了gtest,测试用例不通过,会构建失败。

Espier构建:svn+Ant+Findbugs

注:需要安装ant、Findbugs插件、Static Analysis Collector结果分析插件、Android Emulator模拟器插件、Xvnc插件。

  • 新建任务
  • Source Code Management:设置项目的源码获取方式Subversion地址
    svn+ssh://hjhei@192.168.1.4/home/projects/svn/espier/branches/nowebcore/Espier@HEAD
  • Build Triggers:设置构建的触发器
  • Build Environment:
    • 勾选Run Xvnc during build。
    • 勾选Run an Android emulator during build,并设置模拟器的属性。
    • Common emulator options:勾选显示模拟器窗口。
  • Build:添加指令以执行构建脚本,这里使用的是Ant-build.xml。
    • Invoke Ant-Targets
      clean
      all
      findbugs

    • build.xml内容
      <?xml version="1.0" encoding="UTF-8"?>
      <project name="Espier" default="all" basedir=".">
      
          <property environment="env"></property>
      	<property name="android_sdk_path" value="/opt/android-sdk-linux_x86"/>
          <property name="android_api_level" value="10"/>
          <property name="android_platform" value="${android_sdk_path}/platforms/android-${android_api_level}"/>
          <property name="android_jar" value="${android_platform}/android.jar"/>
          <property name="refjars" value="jars/common.jar:jars/framework.jar:jars/core.jar:jars/layout.jar:jars/fmsoft_guava.jar"/>
          <property name="classpath" value="${refjars}:${android_jar}"/>
          <property name="debug_keystore" value="/home/heihuijing/.android/debug.keystore"/>
          <property name="espier_package" value="com.fmsoft.espier"/>
      
          <target name="all" depends="Step7_jarsign"/>
      
          <target name="Step0_updateVersion">
              <echo message="Update Version in AndroidManifest.xml ..."/>
              <exec executable="bash">
                  <arg line="build_version.sh"/>
              </exec>
          </target>
      
          <target name="Step1_genR" depends="Step0_updateVersion">
              <echo message="Generate R.java ..."/>
              <mkdir dir="gen"/>
              <exec executable="${android_sdk_path}/platform-tools/aapt">
                  <arg line="package -f --auto-add-overlay -m -J gen -S res -A assets -M AndroidManifest.xml -I ${android_jar}"/>
              </exec>
          </target>
      
          <target name="Step2_aidl" depends="Step1_genR">
              <echo message="Preprocess aidl ..."/>
          </target>
      
          <target name="Step3_compile_java" depends="Step2_aidl">
              <echo message="Compile all java files ..."/>
              <mkdir dir="bin"/>
              <javac srcdir="gen:application:quicksearchbox" destdir="bin" classpath="${classpath}" debug="true" debuglevel="lines,vars,source"/>
          </target>
      
          <target name="Step4_dx" depends="Step3_compile_java">
              <echo message="Package all classes to classes.dex ..."/>
              <java jar="${android_sdk_path}/platform-tools/lib/dx.jar" args="--dex --output=bin/classes.dex bin" fork="true"/>
          </target>
      
          <target name="Step5_compile_res" depends="Step4_dx">
              <echo message="Compile all resource files ..."/>
              <exec executable="${android_sdk_path}/platform-tools/aapt">
                  <arg line="package -f -M AndroidManifest.xml -S res -A assets -F bin/ResClass -I ${android_jar}"/>
              </exec> 
          </target>
      
          <target name="Step6_apkbuild" depends="Step5_compile_res">
              <echo message="Build apk ..."/>
              <exec executable="${android_sdk_path}/tools/apkbuilder">
                  <arg line="bin/${ant.project.name}.apk -u -z bin/ResClass -f bin/classes.dex"/>
              </exec> 
          </target>
      
          <target name="Step7_jarsign" depends="Step6_apkbuild">
              <echo message="Sign the apk ..."/>
              <exec executable="jarsigner">
                  <arg line="-keystore ${debug_keystore}"/>
                  <arg line="-keypass android -storepass android"/>
                  <arg line="bin/${ant.project.name}.apk androiddebugkey"/>
              </exec> 
          </target>
      
      <!--clean target-->
          <target name="clean">
              <delete dir="bin"/>
              <delete dir="gen"/>
          </target>
      
      <!--findbugs target-->
      <taskdef name="findbugs" classname="edu.umd.cs.findbugs.anttask.FindBugsTask"/>
        <property name="findbugs.home" value="/home/heihuijing/tool/findbugs-1.3.9" />
      
          <path id="findbugs.path">
              <fileset dir="/home/heihuijing/findbugs-1.3.9">
                  <include name="**/*.jar" /> 
              </fileset> 
          </path>
      
        <target name="findbugs">
          <findbugs home="${findbugs.home}"
                    output="xml"
                    outputfile="findbugs.xml">
            <!--auxClasspath path="${findbugs.home}/lib/Regex.jar" /-->
            <sourcePath path="gen:application:quicksearchbox" />
            <class location="${basedir}/bin" />
          </findbugs>
        </target>
      </project>


  • Post-build Actions:构建完成后需要进行的处理
    • Publish FindBugs? analysis results :发布FindBugs测试报告,同Junit。
    • Build other projects:任务完成后,可触发其他任务构建。如:espiertest。espier任务完成后,触发espiertest构建。

EspierTest? 构建:svn+Ant+JUnit

  • 新建任务
  • Source Code Management:设置项目的源码获取方式Subversion地址
    svn+ssh://hjhei@192.168.1.4/home/projects/svn/espier/branches/nowebcore/EspierTest@HEAD       
  • Build Triggers:设置构建的触发器。如设置Build after other projects are built为espier,在espier构建完成后开始该任务的构建。
  • Build Environment:
    • 勾选Run Xvnc during build。
    • 勾选Run an Android emulator during build,并设置模拟器的属性。
    • Common emulator options:勾选显示模拟器窗口。
  • Build:添加指令以执行构建脚本,这里使用的是Ant-build.xml。
    • Invoke Ant-Targets
      uninstall
      reinstall
      run-test
      

    • build.xml内容
      <?xml version="1.0" encoding="UTF-8"?>
      <project name="EspierTest" default="Step7_jarsign" basedir=".">
      
          <property environment="env"></property>
      	<property name="android_sdk_path" value="/opt/android-sdk-linux_x86"/>
          <property name="android_api_level" value="10"/>
          <property name="android_platform" value="${android_sdk_path}/platforms/android-${android_api_level}"/>
          <property name="android_jar" value="${android_platform}/android.jar"/>
          <property name="tested_project" value="/home/heihuijing/fm/android-espier/Espier"/>
          <property name="targetPackage" value="mobi.espier.browser"/>
          <!-- <property name="refjars" value="jars/common.jar:jars/framework.jar:jars/core.jar:jars/layout.jar:jars/fmsoft_guava.jar"/> -->
          <!-- <property name="classpath" value="${refjars}:${android_jar}"/> -->
          <property name="adb" value="${android_sdk_path}/platform-tools/adb"/>
          <property name="classpath" value="${tested_project}/bin:${android_jar}"/>
          <property name="debug_keystore" value="/home/heihuijing/.android/debug.keystore"/>
          <property name="espiertest_package" value="mobi.espier.browser.test"/>
      
      
          <target name="Step1_genR" >
              <echo message="Generate R.java ..."/>
              <exec executable="${android_sdk_path}/platform-tools/aapt">
                  <arg line="package -f --auto-add-overlay -m -J gen -S res -A assets -M AndroidManifest.xml -I ${android_jar}"/>
              </exec>
          </target>
      
          <target name="Step2_aidl" depends="Step1_genR">
              <echo message="Preprocess aidl ..."/>
          </target>
      
          <target name="Step3_compile_java" depends="Step2_aidl">
              <echo message="Compile all java files ..."/>
              <javac srcdir="gen:src" destdir="bin" classpath="${classpath}" debug="true" debuglevel="lines,vars,source" encoding="UTF-8" includeantruntime="false">
                  <classpath>
                      <fileset dir="${tested_project}/jars" includes="*.jar" />
                      <!-- <fileset dir="libs" includes="*.jar" /> -->
                  </classpath>
      
              </javac>
          </target>
      
          <target name="Step4_dx" depends="Step3_compile_java">
              <echo message="Package all classes to classes.dex ..."/>
              <java jar="${android_sdk_path}/platform-tools/lib/dx.jar" fork="true">
                  <arg line="--dex --output=bin/classes.dex bin"/>
              </java>
          </target>
      
          <target name="Step5_compile_res" depends="Step4_dx">
              <echo message="Compile all resource files ..."/>
              <exec executable="${android_sdk_path}/platform-tools/aapt">
                  <arg line="package -f -M AndroidManifest.xml -S res -A assets -F bin/ResClass -I ${android_jar}"/>
              </exec> 
          </target>
      
          <target name="Step6_apkbuild" depends="Step5_compile_res">
              <echo message="Build apk ..."/>
              <exec executable="${android_sdk_path}/tools/apkbuilder">
                  <arg line="bin/${ant.project.name}.apk -u -z bin/ResClass -f bin/classes.dex"/>
              </exec> 
          </target>
      
          <target name="Step7_jarsign" depends="Step6_apkbuild">
              <echo message="Sign the apk ..."/>
              <exec executable="jarsigner">
                  <arg line="-keystore ${debug_keystore}"/>
                  <arg line="-keypass android -storepass android"/>
                  <arg line="bin/${ant.project.name}.apk androiddebugkey"/>
              </exec> 
          </target>
      
      <!--clean testproject target-->
          <target name="clean">
              <delete includeEmptyDirs="true">
                  <fileset dir="bin"/>
                  <fileset dir="gen"/>
              </delete>
          </target>
      
      <!--install-test-apk to emulator-->
          <target name="install" depends="Step7_jarsign" description="Install android-test project.">
              <exec executable="${adb}">
                  <arg line="install bin/${ant.project.name}.apk"/>
              </exec>
          </target>
      
      <!--reinstall-test-apk to emulator-->
          <target name="reinstall" depends="clean, Step7_jarsign" description="ReInstall android-test project.">
              <exec executable="${adb}">
                  <arg line="install -r bin/${ant.project.name}.apk"/>
              </exec>
          </target>
      
      <!--uninstall-test-apk from emulator-->
          <target name="uninstall" description="Uninstall android-test project">
              <exec executable="${adb}">
                  <arg line="uninstall ${espiertest_package}"/>
              </exec>
          </target>
      
      <!--run-test-->
          <target name="run-test" description="run test project">
              <property name="reports.dir" value="reports"/>
              <property name="files.dir" value="/data/data/${targetPackage}/files"/>
              <!-- <property name="test.runner" value="com.zutubi.android.junitreport.JUnitReportTestRunner"/> -->
              <property name="test.runner" value="mobi.espier.browser.test.XMLInstrumentationTestRunner"/>
      
              <echo>Cleaning up previous test reports...</echo>
              <exec executable="${adb}" failonerror="true">
                  <!-- <arg line="${adb.device.arg}" /> -->
                  <arg value="shell" />
                  <arg value="rm" />
                  <arg value="${files.dir}/*" />
              </exec>
      
              <echo>Running tests...</echo>
              <exec executable="${adb}" failonerror="true">
                  <!-- <arg line="${adb.device.arg}"/> -->
                  <arg value="shell" />
                  <arg value="am" />
                  <arg value="instrument" />
                  <arg value="-w" />
                  <arg value="-e" />
                  <arg value="outfile" />
                  <arg value="test-results.xml" />
                  <!-- <arg value="-e" /> -->
                  <!-- <arg value="multiFile" /> -->
                  <!-- <arg value="true" /> -->
                  <arg value="${espiertest_package}/${test.runner}" />
              </exec>
      
              <echo>Downloading XML test reports...</echo>
              <exec executable="${adb}" failonerror="true">
                  <!-- <arg line="${adb.device.arg}"/> -->
                  <arg value="pull" />
                  <arg value="${files.dir}" />
                  <arg value="${reports.dir}" />
              </exec>
      
          </target>
      
      </project>

  • Post-build Actions:构建完成后需要进行的处理
    • Publish JUnit test result report:发布JUnit测试报告。
      espiertest/reports/*.xml


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值