Jenkins 入门小结
Jenkins 入门小结
https://testerhome.com/topics/5526
何为持续集成?
持续集成是一种软件开发实践,即团队开发成员经常集成他们的工作,通常每个成员每天至少集成一次,也就意味着每天可能会发生多次集成。每次集成都通过自动化的构建(包括编译,发布,自动化测试)来验证,从而尽快地发现集成错误。许多团队发现这个过程可以大大减少集成的问题,让团队能够更快的开发内聚的软件。
持续集成的价值:
减少风险
一天中进行多次的集成,并做了相应的测试,这样有利于检查缺陷,了解软件的健康状况,减少假定。
减少重复过程
减少重复的过程可以节省时间、费用和工作量。说起来简单,做起来难。这些浪费时间的重复劳动可能在我们的项目活动的任何一个环节发生,包括代码编译、数据库集成、测试、审查、部署及反馈。通过自动化的持续集成可以将这些重复的动作都变成自动化的,无需太多人工干预,让人们的时间更多的投入到动脑筋的、更高价值的事情上。
任何时间、任何地点生成可部署的软件
持续集成可以让您在任何时间发布可以部署的软件。从外界来看,这是持续集成最明显的好处,我们可以对改进软件品质和减少风险说起来滔滔不绝,但对于客户来说,可以部署的软件产品是最实际的资产。利用持续集成,您可以经常对源代码进行一些小改动,并将这些改动和其他的代码进行集成。如果出现问题,项目成员马上就会被通知到,问题会第一时间被修复。不采用持续集成的情况下,这些问题有可能到交付前的集成测试的时候才发现,有可能会导致延迟发布产品,而在急于修复这些缺陷的时候又有可能引入新的缺陷,最终可能导致项目失败。
增强项目的可见性
持续集成让我们能够注意到趋势并进行有效的决策。如果没有真实或最新的数据提供支持,项目就会遇到麻烦,每个人都会提出他最好的猜测。通常,项目成员通过手工收集这些信息,增加了负担,也很耗时。持续集成可以带来两点积极效果:
(1)有效决策:持续集成系统为项目构建状态和品质指标提供了及时的信息,有些持续集成系统可以报告功能完成度和缺陷率。
(2)注意到趋势:由于经常集成,我们可以看到一些趋势,如构建成功或失败、总体品质以及其它的项目信息。
建立团队对开发产品的信心
持续集成可以建立开发团队对开发产品的信心,因为他们清楚的知道每一次构建的结果,他们知道他们对软件的改动造成了哪些影响,结果怎么样。
一:Jenkins介绍和安装
Jenkins是基于Java开发的一种持续集成工具,用于监控持续重复的工作,功能包括:
持续的软件版本发布/测试项目。
监控外部调用执行的工作。
跟其他持续集成相比,它的主要优点有:开源,即免费。支持多种平台(windows、linux、os x都支持)。
安装、配置简单。Web可视化管理界面,并且有丰富的tips帮助信息。
为什么要选择Jenkins?
Jenins是现在非常流行的持续集成CI服务器,这与它的前身Hudson也有着很大的关系,Jenkins易于安装,不需要数据库的支持,直接通过Web界面进行配置,而且集成了RSS/Email的通知机制,支持分布式构建,具有丰富的插件,这些都是Jenkins相比其他持续集成服务器的优势所在。
对于版本控制软件的选择要看项目需要了,可能是SVN也可能是Git,一般来说Jenkins都有提供插件支持。
1.1 CentOS下配置Jenkins
1.1.1安装jdk
新建目录 mkdir /usr/local/java
将xvf jdk-8u77-linux-x64.gz压缩包移动到/usr/local/java目录下
解压 tar xvf jdk-8u77-linux-x64.gz
修改系统变量文件:
Vi /etc/profile
export JAVA_HOME=/usr/local/java/jdk1.8.0_77
export JRE_HOME=/usr/local/java/jdk1.8.0_77/jre
export CLASSPATH=.$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib:$CLASSPATH
export PATH=$JAVA_HOME/bin:$PATH
重新编译文件 使系统变量即时生效
source /etc/profile
检查jdk是否安装成功
Java -version
1.1.2安装Jenkins
下载源码包
wget wget http://pkg.jenkins-ci.org/redhat/jenkins-1.656-1.1.noarch.rpm
安装jenkins
rpm -ivh jenkins-1.656-1.1.noarch.rpm
启动Jenkins: service jenkins start
可能会报错:Starting Jenkins bash: /usr/bin/java: 没有那个文件或目录
将/usr/local/java/jdk1.8.0_77/bin/java添加到/etc/init.d/jenkins文件中对应的位置
再次执行service jenkins start启动jenkins服务
1.2Windows下配置Jenkins
安装过程太过简单 这里不做更多的说明,方式两种:
1:将jenkins.war放到tomcat安装目录下的webapp下,启动tomcat即可。
2:使用java –jar命令启动如下
//设置jenkins的工作目录
set JENKINS_HOME=E:\ToolsForTesting\Jenkins
cd /d %JENKINS_HOME%
//指定jenkins端口并启动jenkins服务
java -jar jenkins.war --httpPort=8080
二:Jenkins插件介绍
2.1 Jenkins集成Svn
2.1.1 Svn服务端部署
Step1:CentOS上安装Svn服务端:
yum install svn
Step2:创建版本库目录
mkdir -p /home/svn/svnfile
创建版本库
svnadmin create /home/svn/svnfile
生成以下目录
Step3:配置权限
进入conf目录下,在passwd文件中配置用户名/密码;
在authz文件中设置用户权限;
在svnserve.conf文件中配置svn服务。
Step4:启动SVN服务
svnserve -d -r /home/svn/
2.1.2 Svn常用命令
从服务器上签出:svn co url (ps: co为checkout缩写)
向服务器提交更新两种情况:
1)添加新文件并提交到服务器
Step1:svn add file Step2:svn commit –m “comments”
2)更改已存在的文件后提交到服务器
一步到位:svn ci –m “comments” file_name (ps:ci为commit的缩写)
对文件/目录加锁&解锁
svn lock file_name(or path)
svn unlocl file_name(or path)
更新工作区
svn up(ps:up为update的简写)
回退到指定版本
1) 先svn up,保证更新到最新的版本。
2) svn log,查看历史版本,找出要恢复的版本。
3) 回滚到指定版本号svn merge –r 最新版本好:指定的回退版本号。
删除文件或分支
svn del/rm URL(or file) (ps:del为delete缩写;rm为remove缩写)
比较差异
Svn diff –r 版本号1:版本号B
将两个版本间的差异合并到当前文件
svn merge –r 版本号A:版本号2 path
切换到分支
svn switch (tag/分支)URL
建立tags
svn copy trunk_URL tags_URL –m “comments”
删除tags
svn rm tags_URL
创建分支
svn cp trunk_URL branch_URL –m “comments”
同步主干和分支
svn merge trunk_URL branch_URL
2.1.3 Jenkins上设置svn
Step 1:Jenkins上设置svn
Jenkins上”系统管理””系统设置”中选择svn服务器端的版本
Step2:源代码管理设置
点击Add图标可在页面浮出层中设置svn的用户名密码。
Check-out Strategy签出策略中设置为Use ‘svn update’ as much as possible。
Step3:构建出发器
选中Poll SCM,填写H/10 * * * *
设置触发器为每10分钟比对Svn服务器,有新的提交则触发当前job的构建。
2.2 Jenkins集成git
2.2.1 git的通信协议
Git 可以使用四种主要的协议来传输数据:本地传输,SSH 协议,Git 协议和 HTTP 协议。
(Ps:HTTP 协议外,其他所有协议都要求在服务器端安装并运行 Git)
本地协议
如果你使用一个共享的文件系统,就可以在一个本地文件系统中克隆仓库,推送和获取。克隆的时候只需要将远程仓库的路径作为 URL 使用,比如:
$ git clone /opt/git/project.git
$ git clone file:///opt/git/project.git
本地协议的缺点:
与基本的网络连接访问相比,难以控制从不同位置来的访问权限。如果你想从家里的笔记本电脑上推送,就要先挂载远程硬盘,这和基于网络连接的访问相比更加困难和缓慢。
另一个很重要的问题是该方法不一定就是最快的,尤其是对于共享挂载的文件系统。本地仓库只有在你对数据访问速度快的时候才快。在同一个服务器上,如果二者同时允许 Git 访问本地硬盘,通过 NFS 访问仓库通常会比 SSH 慢。
SSH 协议
SSH 也是唯一一个同时支持读写操作的网络协议;SSH 同时也是一个验证授权的网络协议。
通过 SSH 克隆一个 Git 仓库,你可以像下面这样给出 ssh:// 的 URL:
$ git clone ssh://user@server/project.git
不指明某个协议Git 会默认使用 SSH :
$ git clone user@server:project.git
如果不指明用户,Git 会默认使用当前登录的用户名连接服务器。
SSH协议的缺点:
SSH 的限制在于不能通过它实现仓库的匿名访问。也必须在能通过 SSH 访问主机的前提下才能访问仓库,这使得 SSH 不利于开源的项目。
Git 协议
是一个包含在 Git 软件包中的特殊守护进程;
它会监听一个提供类似于 SSH 服务的特定端口(9418),而无需任何授权。打算支持 Git 协议的仓库,需要先创建 git-daemon-export-ok文件 —它是协议进程提供仓库服务的必要条件。
Git协议的缺点:
Git 协议消极的一面是缺少授权机制。用 Git 协议作为访问项目的唯一方法通常是不可取的。一般的做法是,同时提供 SSH 接口,让几个开发者拥有推送(写)权限,其他人通过 git:// 拥有只读权限。 Git 协议可能也是最难架设的协议。它要求有单独的守护进程,需要定制 — 我们将在本章的 “Gitosis” 一节详细介绍它的架设 — 需要设定 xinetd 或类似的程序,而这些工作就没那么轻松了。该协议还要求防火墙开放 9418 端口,而企业级防火墙一般不允许对这个非标准端口的访问。大型企业级防火墙通常会*这个少见的端口。
HTTP/S 协议
HTTP 或 HTTPS 协议的优美之处在于架设的简便性。基本上,只需要把 Git 的裸仓库文件放在 HTTP 的根目录下,配置一个特定的 post-update 挂钩(hook)就可以搞定。
下面的操作可以允许通过 HTTP 对仓库进行读取:
$ cd /var/www/htdocs/
$ git clone --bare /path/to/git_project gitproject.git
$ cd gitproject.git
$ mv hooks/post-update.sample hooks/post-update
$ chmod a+x hooks/post-update
这样就可以了。Git 附带的 post-update 挂钩会默认运行合适的命令(git update-server-info)来确保通过 HTTP 的获取和克隆正常工作。
HTTP/S协议的缺点:
克隆或者下载仓库内容可能会花费更多时间,而且 HTTP 传输的体积和网络开销比其他任何一个协议都大。因为它没有按需供应的能力 — 传输过程中没有服务端的动态计算 — 因而 HTTP 协议经常会被称为傻瓜(dumb)协议。
2.2.2 脑补git命令
以下示例选择git oschina为git服务器,在git oschina上新建一个private的项目。
下载git for windows并安装,完成安装后打开Git Bash。
在D盘新建文件夹作为仓库
初始化仓库
git init(ps:git init –bare也可)
二者区别是:
git init使用普通库初始化
git init –bare使用裸库初始化
//仓库初始化完成后 d/testgit文件夹下会有一个.git的文件夹,它是版本库。
配置邮件和用户名
git config –-global user.email “邮箱地址”
git config –-global user.anme “用户名可随意”
创建SSH Key
ssh-keygen -t rsa -C "你的邮箱地址"
一路回车即可,在当前用户主目录里的.ssh下会生成两个文件id_rsa(私钥)和id_rsa.pub(公钥)
登录git oschina,在个人资料----SSH公钥栏中添加生成的公钥
克隆远程仓库
git clone 仓库URL
如: git clone https://git.oschina.net/Share-Cherish/showgitcommand.git
git clone和git remote add的区别是:
git clone无需初始化仓库,它会拉取远程仓库到本地。
git remote add操作必须在仓库中执行。
简要来说git clone等同于如下操作
mkdir "exampleProject"
cd "exampleProject"
git init
git remote add origin git@github.com:exampleUser/exampleProject.git
git pull origin master
创建分支
git branch 分支名(ps:git branch会列出所有分支)
如:git branch develop
切换分支
git checkout 分支名
如:git checkout master
git checkout –b 分支名(创建并切换到分支) 它等同于git branch 分支后再执行git checkout分支。
添加新文件
1) 新建文件 vi first_newfile.txt 在里面输入内容add the first line
2) 将文件添加到缓冲区git add first_newfile.txt
3) 将修改的内容提交到仓库 git commit –m “备注信息”
查看修改日志
git log
若想以精简方式显示log信息可以使用git log–pretty=oneline
版本回退
git reset –hard HEAD^回退到上一个版本; -head HEAD^^回退到上上一个版本;
回退到4个版本之前git reset –hard HEAD~4
撤销修改
1) 修改了文件内容 没有执行git add和git commit操作
git checkout --需要撤销修改内容的文件名
2) 修改了文件内容 已执行git add操作 想撤销修改需要两步
先执行git reset HEAD 文件名 再执行git checkout –文件名
从版本库中删除文件
先执行git rm 文件名 再执行git commit
合并分支
git merge 分支名(把指定分支合并到当前分支上)
如:git checkout master; git merge develop(把develop分支合并到master上)
git merge默认会使用Fast forward模式,该模式下,删除分支后,会丢掉分支信息。
git merge –no-ff –m “comments” 分支名:
禁用Fast forward模式合并分支并添加一个新的备注。
删除分支
git branch –d 分支名
如:git branch –d develop
推送本地修改到远程仓库
git push 远程仓库名 本地分支名
如:git push origin develop
拉取远程分支到本地当前仓库
git pull
若git pull操作时提示“no tracking information”,则说明本地分支和远程分支的链接关系未创建,用命令git branch --set-upstream 本地分支名 origin/远程仓库分支名来创建本地分支和远程分支的链接。
2.2.3 Jekins上的git设置
在系统管理----插件管理中选择git插件进行安装
在job的源码管理栏配置远程仓库URL
配置触发器
点击立即构建 测试Job是否可以构建成功
2.3 Jenkins集成Ant
2.3.1 Ant安装
1)CentOS上安装Ant
下载Ant :wget http://apache.opencas.org//ant/binaries/apache-ant-1.9.7-bin.tar.gz
解压Ant包:tar -xvzf apache-ant-1.9.7-bin.tar.gz
编辑/etc/profile文件 vi /etc/profile 添加内容export ANT_HOME=Ant包解压的目录
创建链接 cd /bin 执行ln -s -f /root/Ant/apache-ant-1.9.7/bin/ant
2)windows上安装Ant
下载Ant包, 将解压后的目录作为环境变量ANT_HOME的值添加到系统变量即可。
2.3.2 Ant常用配置项详解
<project>
1) name属性:项目名称
2) deault属性:必填项 表示默认的运行目标
3) basedir属性:项目的基准目标
4) description属性:项目的描述
示例如下:
<project name="ant_firsttest" default="dist" basedir=".">
<description>ant firsttest!</description>
<target>
1) name属性:必填项 表示声明
2) depends属性:依赖的目标
3) unless属性:属性未设置时才知晓
4) description属性:项目描述
示例如下:
<target name="compile" depends="init" description="compile the source " >
<do something/>
</target>
<mkdir>
<mkdir dir="目录名"/> 创建目录
<jar>
1) destfile 表示 jar 文件名
2) basedir 表示被归档的文件名
3) include 表示被归档的文件模式
4) exclueds 表示被排除的文件模式
示例如下:
<jar destfile="${build}/${db}/hii-${db}.jar" basedir="${build}/${db}/hii"/>
<javac>
1) srcdir 表示源文件的目录
2) destdir 表示 class 文件的输出目录
3) include 表示被编译的文件的模式
4)excludes 表示被排除的文件的模式
5)classpath 表示使用的类路径
6)debug 表示包含的调试信息
7)optimize 表示是否使用优化
8)verbose 表示提供详细的输出信息
9)fileonerror 表示当碰到错误就自动停止
示例如下:
<javac destdir="${build}/${db}/xdcpba" encoding="UTF-8" includeAntRuntime="false" debug="on">
<classpath refid="project.classpath"/>
<src path="${java}"/>
<src path="${src-main}/${db}/java"/>
<include name="com/huntto/hii/*"/>
<include name="com/huntto/hii/model/*"/>
<include name="com/huntto/hii/model/basic/**"/>
<include name="com/huntto/hii/dao/*"/>
<include name="com/huntto/hii/dao/basic/**"/>
<include name="com/huntto/hii/dao/hibernate/basic/**"/>
<include name="com/huntto/hii/util/**"/>
<include name="com/huntto/hii/xdcpba/**"/>
</javac>
<delete>
1)file 表示要删除的文件
2)dir 表示要删除的目录
3)includEmptyDirs 表示是否要删除空目录,默认值是删除
4)failonerror 表示指定当碰到错误是否停止,默认值是自动停止
5)verbose 是否列出所删除的文件,默认是不列出
使用示例:
<target name="clean-mysql-xdcpba" description="clean up xdcpba for mysql">
<delete file="${build}/${db}/hii-xdcpba-${db}.jar"/>
<delete dir="${build}/${db}/xdcpba"/>
<delete dir="${dist}/${db}/xdcpba"/>
</target>
<copy>
file 表示源文件
tofile 表示目标文件
todir 表示目标目录
overwrite 表示指定是否覆盖目标文件,默认值是不覆盖
includeEmptyDirs 表示指定是否拷贝空目录,默认是拷贝
failonerror 表示指定如目标没有发现是否自动台停止,默认是停止
使用示例:
<copy todir="${build}/${db}/xg">
<fileset dir="${java}" includes="**/*.xml" />
<fileset dir="${src-main}/${db}/java" includes="**/*.xml" />
</copy>
Ant实例详解:
<?xml version="1.0" encoding="UTF-8"?>
<project name="ant_web_hello" basedir="." default="deploy">
<!-- java源文件目录 -->
<property name="src.dir" location="/src" />
<!-- 构建目录 -->
<property name="build.dir" location="build" />
<!-- class文件的存放目录 -->
<property name="build.classes" location="${build.dir}/classes" />
<!--war包的存放目录-->
<property name="build.war" location="${build.dir}/war" />
<!-- tomcat_home路径 -->
<property name="tomcat.home" location="E:\ToolsForTesting\apache-tomcat" />
<!-- <property name="tomcat.lib" location="${tomcat.home}/lib" /> -->
<!-- web应用名 -->
<property name="web.name" value="anthello" />
<!-- web根目录-->
<property name="web.root" value="/WebContent" />
<property name="web.WEB-INF" location="${web.root}/WEB-INF" />
<property name="web.lib" location="${web.WEB-INF}/lib" />
<!--Svn远程目录-->
<property name="svn-url" value="svn://192.168.10.217/JavaWebDemo" />
<!-- 编译时的classpath -->
<path id="compile.path">
<fileset dir="${web.lib}" includes="*.lib">
</fileset>
<fileset dir="${tomcat.home}/lib">
<include name="**/*.jar" />
</fileset>
</path>
<target name="svn_co">
<echo message="hello ant!"></echo>
<!-- 直接调用svn exec要确保安装了svn客户端-->
<exec executable="svn" >
<!-- 设置svn 的命令行参数 -->
<arg line="co ${svn-url}"/>
</exec>
</target>
<target name="init" depends="svn_co" description="初始化项目构建">
<mkdir dir="${build.dir}" />
<mkdir dir="${build.classes}" />
<mkdir dir="${build.war}" />
<echo>start init task</echo>
</target>
<target name="compile" depends="init" description="编译任务">
<javac destdir="${build.classes}" srcdir="${src.dir}" includeantruntime="false" fork="true">
<compilerarg line="-encoding UTF-8 " />
<classpath refid="compile.path" />
</javac>
<echo message="complate compile task"></echo>
</target>
<target name="war" depends="compile" description="打war包">
<war destfile="${build.war}/${web.name}.war">
<fileset dir="${web.root}" includes="**/*.*" />
<lib dir="${web.lib}" />
<webinf dir="${web.WEB-INF}" />
<classes dir="${build.classes}" />
</war>
<echo>complate tar package of war</echo>
</target>
<target name="deploy" depends="war" description="发布">
<copy todir="${tomcat.home}/webapps">
<fileset dir="${build.war}" includes="*.war" />
</copy>
<echo>deploy to tomcat</echo>
</target>
<target name="clean" description="清理发布环境">
<deldir dir="" />
<deldir dir="" />
</target>
</project>
2.3.3 Jenkins上的Ant配置使用
配置ANT_HOME
新建*风格的Job,源码管理配置为svn地址:
构建触发器(每10分钟扫描svn):
配置构建组件(这里我用的是环境变量Ant_Home,target填写build.xml里的deploy):
任务构建完成:
2.4 Jenkins集成Maven
2.4.1 Maven安装和命令使用
Maven 是什么?
Maven 是一个项目管理和整合工具。Maven 为开发者提供了一套完整的构建生命周期框架。开发团队几乎不用花多少时间就能够自动完成工程的基础构建配置,因为 Maven 使用了一个标准的目录结构和一个默认的构建生命周期。
在有多个开发团队环境的情况下,Maven 能够在很短的时间内使得每项工作都按照标准进行。因为大部分的工程配置操作都非常简单并且可复用,在创建报告、检查、构建和测试自动配置时,Maven 可以让开发者的工作变得更简单。
Maven 能够帮助开发者完成以下工作:
• 构建
• 文档生成
• 报告
• 依赖
• SCMs
• 发布
• 分发
• 邮件列表
总的来说,Maven 简化了工程的构建过程,并对其标准化。它无缝衔接了编译、发布、文档生成、团队合作和其他任务。Maven 提高了重用性,负责了大部分构建相关的任务。
CentOS上安装Maven:
下载maven包:
wget http://mirrors.hust.edu.cn/apache/maven/maven-3/3.3.9/binaries/apache-maven-3.3.9-bin.tar.gz
解压:
Tar –zxvf apache-maven-3.3.9-bin.tar.gz
建立软链接:
Ln –s apache-maven-3.3.9 maven
配置环境变量:
vi /etc/profile
export M2_HOME=/usr/local/apache-maven
export PATH=$PATH:$M2_HOME/bin
使环境变量生效:
source /etc/profile
验证安装结果:
2.4.2 Maven常用命令介绍
mvn help:system 自动在本用户下创建 ~/.m2/repository
mvn clean compile 清理编译
mvn clean test 清理测试
mvn clean package 清理打包
mvn clean install 清理将打包好的jar存入 本地仓库 注意是本地仓库
mvn archetype:generate 使用Archetype生成项目骨架
mvn clean deploy 根据pom中的配置信息将项目发布到远程仓库中
Maven项目的目录结构:
src/main/java :正式内容包路径
src/mian/resources :正式的配置文件路径
src/test/java :测试包路径
src/test/resources :测试的配置文件路径
src/main/webapp : war 资源目录
mvn dependency:list 显示所有已经解析的所有依赖
mvn dependency:tree 以目录树的形式展现依赖, 最高层为一层依赖 其次二层依赖 三层依赖....
mvn dependency:analyze 第一部分显示 已经使用但是未显示依赖的的 第二部分显示项目未使用的但是依赖的
构件: jar 插件 war 所有依赖的jar
构建:编译 测试 打包 发布
构建生命周期:
生命周期就是接口:表明要干什么事情
插件就是具体的实现:表明怎么干这件事情
一个典型的 Maven 构建生命周期是由以下几个阶段的序列组成的:
阶段 处理 描述
prepare-resources 资源拷贝 本阶段可以自定义需要拷贝的资源
compile 编译 本阶段完成源代码编译
package 打包 本阶段根据 pom.xml 中描述的打包配置创建 JAR / WAR 包
install 安装 本阶段在本地 / 远程仓库中安装工程包
当需要在某个特定阶段之前或之后执行目标时,可以使用 pre 和 post 来定义这个目标。
Pom.xml实例:
<project
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.temp</groupId>
<artifactId>Demo</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>Demo Maven Webapp</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.htmlparser</groupId>
<artifactId>htmlparser</artifactId>
<version>1.6</version>
</dependency>
<!-- spring需要的jar包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.2.4.RELEASE</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>3.2.4.RELEASE</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>3.2.4.RELEASE</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>3.2.4.RELEASE</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>3.2.4.RELEASE</version>
<type>jar</type>
</dependency>
<!-- 连接MySQL数据库需要的jar包 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.34</version>
</dependency>
<!-- jstl需要的jar包 -->
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- log4j需要的jar包 -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<!-- mybatis需要的jar -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.3.0</version>
</dependency>
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.2.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.5.3</version>
</dependency>
<!-- PDFBOX -->
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox-tools</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.1</version>
</dependency>
</dependencies>
<build>
<finalName>zfyz</finalName>
</build>
</project>
2.4.3 Jenkins上配置使用Maven
系统管理中配置Maven:
新建Maven构建项目:
设置源码管理的svnurl
配置构建项:
立即构建验证效果:
2.5 Jenkin集成Java静态检查工具
2.5.1 PMD安装和使用
PMD介绍:
PMD是一种开源分析Java代码错误的工具。与其他分析工具不同的是,PMD通过静态分析获知代码错误。也就是说,在不运行Java程序的情况下报告错误。PMD附带了许多可以直接使用的规则,利用这些规则可以找出Java源程序的许多问题,例如:
® 潜在的bug:空的try/catch/finally/switch语句
® 未使用的代码:未使用的局部变量、参数、私有方法等
® 可选的代码:String/StringBuffer的滥用
® 复杂的表达式:不必须的if语句、可以使用while循环完成的for循环
® 重复的代码:拷贝/粘贴代码意味着拷贝/粘贴bugs
® 循环体创建新对象:尽量不要再for或while循环体内实例化一个新对象
@ 资源关闭:Connect,Result,Statement等使用之后确保关闭掉
此外,用户还可以自己定义规则,检查Java代码是否符合某些特定的编码规范。例如,你可以编写一个规则,要求PMD找出所有创建Thread和Socket对象的操作。
PMD安装:
在https://github.com/mrniko/redisson/wikipmd的wiki信息可查看
在https://pmd.github.io/ 下载pmd。
使用Ant执行PMD的task:
Java项目的目录结构:
其中的PMD文件夹中存放的是pmd依赖的jar包和自定义的检查规则。
Pmd的task如下编写:
<?xml version="1.0" encoding="UTF-8"?>
<project name="pmd" default="pmd" basedir=".">
<property name="sourcedir" location="src" />
<property name="pmddir" location="pmd" />
<!-- 定义pmd的classpath,均为下载的pmd包解压后lib目录下的jar包-->
<path id="pmd.classpath">
<fileset dir="${pmddir}">
<include name="**/*.jar">
</include>
</fileset>
</path>
<target name="pmd">
<taskdef name="pmd" classname="net.sourceforge.pmd.ant.PMDTask" classpathref="pmd.classpath" />
<!-- 定义PMD检测规则所在的文件,规则集在pmdrule.xml文件中定义-->
<pmd rulesetfiles="${pmddir}/pmd-java-rule.xml" encoding="UTF-8">
<!-- 输出html格式的报告-->
<formatter type="html" tofile="pmd-report.html" />
<!-- 静态代码检测工程下src目录下的所有java文件-->
<fileset dir="${sourcedir}">
<include name="**/*.java" />
</fileset>
</pmd>
</target>
</project>
我们执行ant –f pmd-task.xml:
构建pmd的task成功后 在指定的目录下会生产报告pmd-report.html
接下来我们将pmd集成到Jenkins中:
首先安装插件PMD Plug-in,Maven Integration plugin,Static Analysis Collector Plug-in,Static Analysis Utilities。
新建Job命名为jenkins+pmd;配置远程源码仓库url地址:
构建出发器:每10分钟检查源码仓库是否有更新:
配置构建任务:
配置构建后的操作:
立即构建后我们即可查收邮件并查看pmd的检查结果:
邮件内容:
查看PMD Warnings:
2.5.2 CheckStyle的安装和使用
Checkstyle介绍:
CheckStyle是什么?
CheckStyle是SourceForge下的一个项目,提供了一个帮助JAVA开发人员遵守某些编码规范的工具。它能够自动化代码规范检查过程,从而使得开发人员从这项重要,但是枯燥的任务中解脱出来[1]。
2.2. CheckStyle检验的主要内容
CheckStyle默认提供一下主要检查内容:
•Javadoc注释
•命名约定
•标题
•Import语句
•体积大小
•空白
•修饰符
•块
•代码问题
•类设计
•混合检查(包活一些有用的比如非必须的System.out和printstackTrace)
从上面可以看出,CheckStyle提供了大部分功能都是对于代码规范的检查,而没有提供象PMD和Jalopy那么多的增强代码质量和修改代码的功能。但是,对于团队开发,尤其是强调代码规范的公司来说,它的功能已经足够强大。
安装checkstyle:
首先请务必到github上去读官方文档: https://github.com/checkstyle/checkstyle
将checkstyle的jar包放置在ant安装目录下的lib下即可。
创建ant任务(ps:大百度搜索结果都是特么扯淡 请直接去官网看怎么写的):
<?xml version="1.0" encoding="UTF-8"?>
<project name="fuck" default="checkstyle">
<property name="checkstyle.jar" location="E:\ToolsForTesting\ant\checkstyle"/>
<property name="checkrule.dir" location="E:\ToolsForTesting\ant\checkstyle"/>
<target name="checkstyle">
<taskdef name="checkstyle" classname="com.puppycrawl.tools.checkstyle.ant.CheckstyleAntTask" classpath="${checkstyle.jar}\checkstyle-6.18-all.jar"/>
<checkstyle config="${checkrule.dir}\sun_checks.xml" failOnViolation="false" failureProperty="checkstyle.failure">
<fileset dir="./src" includes="**/*.java"/>
<formatter type="xml" toFile="./checkstyle_report.xml"/>
</checkstyle>
</target>
</project>
Jenkins上集成checkstyle插件:
我这里直接上截图哦
最重要的两步之一:构建(配置ant_home,targets和build file)
构建后将checkstyle的结果发布出来:
因为在ant的任务配置中我是直接把checkstyle的结果生成在项目的根目录下,所以我下面的checkstyle results直接写了文件名。
任务配置完成后 我们直接点立即构建可查看效果(我这里试了几次,所以前几次构建是失败的):
我们可点击checkstyle warnings查看checkstyle的检查结果:
2.5.3 Findbugs安装和使用
FindBugs 是什么?
FindBugs 是一个静态分析工具,它检查类或者 JAR 文件,将字节码与一组缺陷模式进行对比以发现可能的问题。有了静态分析工具,就可以在不实际运行程序的情况对软件进行分析。不是通过分析类文件的形式或结构来确定程序的意图,而是通常使用 Visitor 模式(请参阅 参考资料)。图 1 显示了分析一个匿名项目的结果(为防止可怕的犯罪,这里不给出它的名字):
在FindBugs的GUI中,需要先选择待扫描的.class文件(FindBugs其实就是对编译后的class进行扫描,藉以发现一些隐藏的bug。)。如果你拥有这些.class档对应的源文件,可把这些.java文件再选上,这样便可以从稍后得出的报告中快捷的定位到出问题的代码上面。此外,还可以选上工程所使用的library,这样似乎可以帮助FindBugs做一些高阶的检查,藉以发现一些更深层的bug。
选定了以上各项后,便可以开始检测了。检测的过程可能会花好几分钟,具体视工程的规模而定。检测完毕可生成一份详细的报告,藉由这份报告,可以发现许多代码中间潜在的bug。比较典型的,如引用了空指针(null pointer dereference), 特定的资源(db connection)未关闭,等等。如果用人工检查的方式,这些bug可能很难才会被发现,或许永远也无法发现,直到运行时发作…当除掉了这些典型的(classic) bug后,可以确信的是,我们的系统稳定度将会上一个新的台阶。
以目前遇到的状况来看,FindBugs可以有两种使用时机。
开发阶段
当Developer完成了某一部分功能模块开发的时候(这通常是指代码撰写完成,并已debug通过之后),可藉由FindBugs对该模块涉及的java文件进行一次扫描,以发现一些不易察觉的bug或是效能问题。交付新版的时候,开发团队可以跑一下FindBugs,除掉一些隐藏的Bug。FindBugs得出的报告可以作为该版本的一个参考文档一并交付给测试团队留档待查。
在开发阶段使用FindBugs,一方面开发人员可以对新版的品质更有信心,另一方面,测试人员藉此可以把更多的精力放在业务逻辑的确认上面,而不是花大量精力去进一些要在特殊状况下才可能出现的BUG(典型的如Null Pointer Dereference)。从而可以提高测试的效率。
维护阶段
这里指的是系统已经上线,却发现因为代码中的某一个bug导致系统崩溃。在除掉这个已暴露的bug之后,为了快速的找出类似的但还未暴露的 bug,可以使用FindBugs对该版的代码进行扫描。当然,在维护阶段使用FindBugs往往是无奈之举,且时间紧迫。此外,如果本来在新版交付的时候就使用过FindBugs的话,往往意味着这种bug是FindBugs还无法检测出的。这也是FindBugs局限的地方。
FindBugs出到目前的版本,功能已经相当强大,不过也有待完善的地方。从实际使用来看,有一些隐藏的bug并不能靠FindBugs直接发现。那么,可不可以撰写一个新的 Detector,来发现这种将一个未初始化的reference传来传去而形成的潜在的bug呢?理论上来讲,应该是可以的。这个 Detector目前还未实现。哪位如果有兴趣的话,可以参考FindBugs, Part 2: Writing custom detectors(扩展阅读)这篇文章,帮忙实现这个Detector。实现一个新的Detector,便可以检测出一种新型的bug,这样不知又可以帮开发人员省去多少人工检查的时间,功德无量啊。
FindBugs也不能发现非java的Bug。对于非java撰写的代码,如javascript,SQL等等,要找出其中可能的bug,FindBugs是无能为力的。当然,javascript中的bug似乎还不至于使系统崩溃,而SQL中的bug往往又跟业务逻辑相关,只要测试仔细一些应该是可以发现的。
FindBugs不过是一个工具。作为开发人员,当然首先要在编程的时候努力避免引入bug,而不要依赖于某个工具来为自己把关。不过由于代码的复杂性,一些隐藏的bug确实很难靠咱们的肉眼发现。这时,应用一些好的工具或许就可以帮你发现这样的bug。这便是FingBug存在的价值。
为什么应该将 FindBugs 集成到编译过程中?
经常问到的第一个问题是为什么要将 FindBugs 加入到编译过程中?虽然有大量理由,最明显的回答是要保证尽可能早地在进行编译时发现问题。当团队扩大,并且不可避免地在项目中加入更多新开发人员时,FindBugs 可以作为一个安全网,检测出已经识别的缺陷模式。我想重申在一篇 FindBugs 论文中表述的一些观点。如果让一定数量的开发人员共同工作,那么在代码中就会出现缺陷。像 FindBugs 这样的工具当然不会找出所有的缺陷,但是它们会帮助找出其中的部分。现在找出部分比客户在以后找到它们要好——特别是当将 FindBugs 结合到编译过程中的成本是如此低时。
一旦确定了加入哪些过滤器和类,运行 FindBugs 就没什么成本了,而带来的好处就是它会检测出新缺陷。如果编写特定于应用程序的检测器,则这个好处可能更大。
生成有意义的结果
重要的是要认识到这种成本/效益分析只有在不生成大量误检时才有效。换句话说,如果在每次编译时,不能简单地确定是否引入了新的缺陷,那么这个工具的价值就会被抵消。分析越自动化越好。如果修复缺陷意味着必须吃力地分析检测出的大量不相干的缺陷,那么您就不会经常使用它,或者至少不会很好地使用它。
确定不关心哪些问题并从编译中排除它们。也可以挑出 确实关注的一小部分检测器并只运行它们。另一种选择是从个别的类中排除一组检测器,但是其他的类不排除。FindBugs 提供了使用过滤器的极大灵活性,这可帮助生成对团队有意义的结果。
确定用 FindBugs 的结果做什么
可能看来很显然,但是团队中有多少加入了类似 FindBugs 这样的工具而没有真正利用它。深入探讨这个问题——用结果做什么?明确回答这个问题是困难的,因为这与团队的组织方式、如何处理代码所有权问题等有很大关系。不过,下面是一些指导:
可以考虑将 FindBugs 结果加入到源代码管理(SCM)系统中。一般的经验做法是不将编译工件(artifact)放到 SCM 系统中。不过,在这种特定情况下,打破这个规则可能是正确的,因为它使您可以监视代码质量随时间的变化。
可以选择将 XML 结果转换为可以发送到团队的网站上的 HTML 报告。转换可以用 XSL 样式表或者脚本实现。有关例子请查看 FindBugs 网站或者邮件列表(请参阅 参考资料)。
像 FindBugs 这样的工具通常会成为用于敲打团队或者个人的政治武器。尽量抵制这种做法或者不让它发生——记住,它只是一个工具,它可以帮助改进团队成员代码的质量。
Findbugs安装:
下载findbugs https://sourceforge.net/projects/findbugs/
配置findbugs的ant-task:
<?xml version="1.0" encoding="UTF-8"?>
<project name="crm_findbugs" default="findbugs">
<!--set findbugs\'s home-->
<property name ="findbugs.home" location="E:\ToolsForTesting\ant\findbugs"/>
<!--set findbugs check rule file-->
<property name="findbugs_include_filter" location="${findbugs.home}\findbugs-filter.xml"/>
<path id="findbugs.lib">
<fileset dir ="${findbugs.home}/lib">
<include name ="findbugs-ant.jar"/>
</fileset>
</path>
<!--set reference of task findbugs-->
<taskdef name="findbugs" classpathref ="findbugs.lib" classname="edu.umd.cs.findbugs.anttask.FindBugsTask"></taskdef>
<!--define task findbugs-->
<target name ="findbugs">
<findbugs home ="${findbugs.home}" includeFilter="${findbugs_include_filter}" jvmargs="-Xmx1024m" output ="xml" outputFile ="findbugs-report.xml">
<class location =".\build\classes\com\sxxy"/>
<auxClasspath path="${findbugs.home}/lib/findbugs-ant.jar"/>
<sourcePath path =".\src"/>
</findbugs>
</target>
</project>
自定义检查规则:
<?xml version="1.0" encoding="UTF-8"?>
<FindBugsFilter>
<!--set filter rule of java class or jar files-->
<!--all class files use HE rule to be checked-->
<Match>
<BugCode name ="HE"/>
</Match>
<Match>
<BugCode name ="GC"/>
</Match>
<Match>
<BugCode name ="DM"/>
</Match>
<Match>
<BugCode name ="HRS"/>
</Match>
<Match>
<BugCode name ="SQL"/>
</Match>
<Match>
<BugCode name ="XSS"/>
</Match>
</FindBugsFilter>
在Jenkins上集成findbugs:
和pmd以及checkstyle一样创建一个*风格的job
源代码使用svn管理
我这里直接上图:
构建成功后点击 FindBugs Warnings查看结果:
2.7 Jenkins上的邮件扩展
安装邮件扩展插件
在”系统设置”----“Extended E-mail Notification”中配置扩展邮件项
(ps:注意这里的邮箱地址要和Jenkins Location—系统管理员邮件地址一致)
我这里是使用163邮箱作示例,需要登录到163邮箱进行一些设置
在”设置”---“POP3/SMTP/IMAP”中开启POP3/SMTP服务和IMAP/SMTP服务
在”客户端授权密码”中设置客户端的授权密码(此处的授权密码即为Jenkins中的邮箱密码)
在Job中设置构建后的发送邮件步骤:
立即构建查看邮件内容:
OK 大功告成!(PS:各位同学可根据自己需要来设计邮件内容模板)
2.8 Jenkins集成RobotFrameWork test results
首先在”系统管理”---“管理插件”中搜索Robot 然后选择Robot Framework plugin插件进行安装
在Job总配置RobotFramework插件
立即构建该job来验证我们的设置
我也可以看到测试的完成情况,也可以点击Robot Results来查看详情
三:后记:
历时数周终成此稿,不忍窃为己有,遂飨众亲; 不负晚上加餐后长的那二两肥膘~~~~~~~~~