Docker+Jenkins持续集成环境(3)集成PMD、FindBugs、Checkstyle静态代码检查工具并邮件发送检查结果
为了规范代码,我们一般会集成静态代码检测工具,比如PMD、FindBugs、Checkstyle,那么Jenkins如何集成这些检查工具,并把检查结果放到构建邮件里呢?
今天做了调研和实现,过程如下
首先看,最终效果:
1.pom.xml
build。plugins 增加:
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<finalName>${project.artifactId}-${project.version}</finalName>
<appendAssemblyId>false</appendAssemblyId>
<descriptors>
<descriptor>src/assembly/assembly-descriptor.xml</descriptor>
</descriptors>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>findbugs-maven-plugin</artifactId>
<version>3.0.5</version>
<configuration>
<threshold>High</threshold>
<effort>Default</effort>
<findbugsXmlOutput>true</findbugsXmlOutput>
<findbugsXmlWithMessages>true</findbugsXmlWithMessages>
<xmlOutput>true</xmlOutput>
<formats><format>html</format></formats>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-pmd-plugin</artifactId>
<version>3.8</version>
</plugin>
reporting 增加:
<reporting>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>3.0.0</version>
<reportSets>
<reportSet>
<reports>
<report>checkstyle</report>
</reports>
</reportSet>
</reportSets>
</plugin>
<!--pmd-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-pmd-plugin</artifactId>
<configuration>
<linkXref>true</linkXref>
<sourceEncoding>utf-8</sourceEncoding>
<minimumTokens>100</minimumTokens>
<targetJdk>1.8</targetJdk>
<excludes>
<exclude>**/*Bean.java</exclude>
<exclude>**/generated/*.java</exclude>
</excludes>
<excludeRoots>
<excludeRoot>target/generated-sources/stubs</excludeRoot>
</excludeRoots>
</configuration>
<version>3.8</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jxr-plugin</artifactId>
<version>2.5</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-report-plugin</artifactId>
<version>2.14.1</version>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>cobertura-maven-plugin</artifactId>
</plugin>
</plugins>
</reporting>
2 jenkins设置
2.1 安装相关插件
直接搜索安装:
- Checkstyle Plug-in
- PMD Plug-in
- FindBugs Plug-in
- Static Analysis Collector Plug-in
邮件插件安装:
- Email Extension Plugin
- Email Extension Template Plugin
2.2 项目配置
maven构建Goals设置为:
pmd:pmd checkstyle:checkstyle findbugs:findbugs package -DskipTests
在构建设置里,勾上
- Publish Checkstyle analysis results
- Publish FindBugs analysis results
- Publish PMD analysis results
构建后操作,添加Publish combined static analysis results,默认设置即可。
2.3 邮件配置
首先在系统设置里,配置Extended E-mail Notification部分
设置:
- Default Subject : 自动构建通知:$PROJECT_NAME - Build # $BUILD_NUMBER - $BUILD_STATUS!
- Default Content: ${JELLY_SCRIPT, template="analysis.jelly"}
剩下的自己配置下SMTP和收件人。
这里邮件内容使用analysis.jelly,使用jelly script,系统没有这个模板,我们需要配置一下:
打开系统管理-Managed files,增加一个Extended Email Publisher Jelly Template
模板文件如下,该模板修改自官方的模板,做了一定的本地化和样式调整:
<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define">
<html>
<head>
<title>${project.name}</title>
<style>
body table, td, th, p, h1, h2 {
margin:0;
font:normal normal
100% Georgia, Serif;
}
h1, h2 {
border-bottom:dotted 1px #999999;
padding:5px;
margin-bottom:10px;
color: #000000;
font: normal bold 130%
Georgia,Serif;
background-color:#f0f0f0;
}
tr.gray {
background-color:#f0f0f0;
}
h2 {
padding:5px;
margin-top:5px;
margin-bottom:5px;
font: italic bold 110% Georgia,Serif;
}
.bg2 {
color:black;
background-color:#E0E0E0;
font-size:110%
}
th {
font-weight: bold;
}
tr, td, th {
padding:2px;
}
td.test_passed {
color:blue;
}
td.test_failed {
color:red;
}
td.center {
text-align: center;
}
td.test_skipped {
color:grey;
}
.console {
font: normal normal 90% Courier New,
monotype;
padding:0px;
margin:0px;
}
div.content, div.header {
background: #ffffff;
border: dotted
1px #666;
margin: 2px;
content:
2px;
padding: 2px;
}
table.border, th.border, td.border {
border:
1px solid black;
border-collapse:collapse;
}
.round_border{margin-bottom:5px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;margin-top:0;font-size:14px;padding:6px;border:1px solid #ccc}
.status{background-color:<j:choose><j:when test="${build.result=='SUCCESS'}">green</j:when><j:otherwise>red</j:otherwise></j:choose>;font-size:28px;font-weight:bold;color:white;height:52px;margin-bottom:18px;text-align:center;vertical-align:middle;border-collapse:collapse;background-repeat:no-repeat}
.status .info{color:white!important;text-shadow:0 -1px 0 rgba(0,0,0,0.3);font-size:32px;line-height:36px;padding:8px 0}
</style>
</head>
<body>
<div class="status">
<p class="info">${project.name}构建<j:choose><j:when test="${build.result=='SUCCESS'}">成功</j:when><j:otherwise>失败</j:otherwise></j:choose></p>
</div>
<div class="header round_border">
<j:set var="spc" value=" " />
<h1>基本信息</h1>
<table>
<tr>
<td>构建地址</td>
<td>
<a href="${rooturl}${build.url}">${rooturl}${build.url}</a>
</td>
</tr>
<tr>
<td>项目:</td>
<td>${project.name}</td>
</tr>
<tr>
<td>构建时间:</td>
<td>${it.timestampString}</td>
</tr>
<tr>
<td>构建耗时:</td>
<td>${build.durationString}</td>
</tr>
<tr>
<td>构建原因:</td>
<td>
<j:forEach var="cause" items="${build.causes}">${cause.shortDescription}
</j:forEach>
</td>
</tr>
<tr>
<td>构建描述:</td>
<td>${build.description}</td>
</tr>
<tr>
<td>构建服务器:</td>
<td>
<j:choose>
<j:when test="${build.builtOnStr!=''}">${build.builtOnStr}</j:when>
<j:otherwise>master</j:otherwise>
</j:choose>
</td>
</tr>
</table>
</div>
<!-- HEALTH TEMPLATE -->
<div class="content round_border">
<j:set var="healthIconSize" value="16x16" />
<j:set var="healthReports" value="${project.buildHealthReports}" />
<j:if test="${healthReports!=null}">
<h1>构建健康报告</h1>
<table>
<tr>
<th>W</th>
<th>Description</th>
<th>Score</th>
</tr>
<j:forEach var="healthReport" items="${healthReports}">
<tr>
<td>
<img
src="${rooturl}${healthReport.getIconUrl(healthIconSize)}" />
</td>
<td>${healthReport.description}</td>
<td>${healthReport.score}</td>
</tr>
</j:forEach>
</table>
<br />
</j:if>
</div>
<!-- CHANGE SET -->
<div class="content round_border">
<j:set var="changeSet" value="${build.changeSet}" />
<j:if test="${changeSet!=null}">
<j:set var="hadChanges" value="false" />
<a href="${rooturl}${build.url}/changes">
<h1>代码变更记录</h1>
</a>
<j:forEach var="cs" items="${changeSet.logs}"
varStatus="loop">
<j:set var="hadChanges" value="true" />
<h2>${cs.msgAnnotated}</h2>
<p>
by <em>${cs.author}</em>
</p>
<table>
<j:forEach var="p" items="${cs.affectedFiles}">
<tr>
<td width="10%">${spc}${p.editType.name}</td>
<td>
<tt>${p.path}</tt>
</td>
</tr>
</j:forEach>
</table>
</j:forEach>
<j:if test="${!hadChanges}">
<p>无变更</p>
</j:if>
<br />
</j:if>
</div>
<!-- ARTIFACTS -->
<j:set var="artifacts" value="${build.artifacts}" />
<j:if test="${artifacts!=null and artifacts.size()>0}">
<div class="content round_border">
<h1>构建产物</h1>
<ul>
<j:forEach var="f" items="${artifacts}">
<li>
<a href="${rooturl}${build.url}artifact/${f}">${f}</a>
</li>
</j:forEach>
</ul>
</div>
</j:if>
<!-- MAVEN ARTIFACTS -->
<j:set var="mbuilds" value="${build.moduleBuilds}" />
<j:if test="${mbuilds!=null}">
<div class="content round_border">
<h1>MAVEN 构建产物</h1>
<j:forEach var="m" items="${mbuilds}">
<h2>${m.key.displayName}</h2>
<j:forEach var="mvnbld" items="${m.value}">
<j:set var="artifacts" value="${mvnbld.artifacts}" />
<j:if test="${artifacts!=null and artifacts.size()>0}">
<ul>
<j:forEach var="f" items="${artifacts}">
<li>
<a href="${rooturl}${mvnbld.url}artifact/${f}">${f}</a>
</li>
</j:forEach>
</ul>
</j:if>
</j:forEach>
</j:forEach>
<br />
</div>
</j:if>
<!-- JUnit TEMPLATE -->
<j:set var="junitResultList" value="${it.JUnitTestResult}" />
<j:if test="${junitResultList.isEmpty()!=true}">
<div class="content round_border">
<a href="${rooturl}${build.url}/testReport">
<h1>JUnit Tests</h1>
</a>
<table class="border">
<tr>
<th class="border">Package</th>
<th class="border">Failed</th>
<th class="border">Passed</th>
<th class="border">Skipped</th>
<th class="border">Total</th>
</tr>
<j:forEach var="junitResult" items="${it.JUnitTestResult}">
<j:forEach var="packageResult" items="${junitResult.getChildren()}">
<tr>
<td class="border">
<tt>${packageResult.getName()}</tt>
</td>
<td class="border test_failed">${packageResult.getFailCount()}</td>
<td class="border test_passed">${packageResult.getPassCount()}</td>
<td class="border test_skipped">${packageResult.getSkipCount()}</td>
<td class="border">
<b>${packageResult.getPassCount()+packageResult.getFailCount()+packageResult.getSkipCount()}
</b>
</td>
</tr>
<j:forEach var="failed_test"
items="${packageResult.getFailedTests()}">
<tr>
<td class="test_failed" colspan="5">
<tt>${failed_test.getFullName()}</tt>
</td>
</tr>
</j:forEach>
</j:forEach>
</j:forEach>
</table>
<br />
</div>
</j:if>
<!-- Static Analysis -->
<j:set var="actions" value="${it.staticAnalysisActions}" />
<j:if test="${!actions.isEmpty()}">
<div class="content round_border">
<h1>代码静态检查结果</h1>
<table>
<tr>
<th>名称</th>
<th>检查结果</th>
<th>总数</th>
<th>High</th>
<th>Normal</th>
<th>Low</th>
</tr>
<j:forEach var="action" items="${actions}">
<tr>
<td>
<a href="${rooturl}${build.url}/${action.urlName}">${action.displayName}</a>
</td>
<td class="center">
<j:choose>
<j:when test="${action.result.pluginResult=='SUCCESS'}">
<img src="${rooturl}static/e59dfe28/images/16x16/blue.gif" />
</j:when>
<j:when test="${action.result.pluginResult=='FAILURE'}">
<img src="${rooturl}static/e59dfe28/images/16x16/red.gif" />
</j:when>
<j:otherwise>
<img src="${rooturl}static/e59dfe28/images/16x16/yellow.gif" />
</j:otherwise>
</j:choose>
</td>
<td class="center">${action.result.numberOfAnnotations} </td>
<td class="center">${action.result.getNumberOfAnnotations('HIGH')} </td>
<td class="center">${action.result.getNumberOfAnnotations('NORMAL')} </td>
<td class="center">${action.result.getNumberOfAnnotations('LOW')} </td>
</tr>
</j:forEach>
</table>
</div>
</j:if>
<div class="content round_border">
<!-- CONSOLE OUTPUT -->
<a href="${rooturl}${build.url}/console">
<h1>Console 输出结果(后50行)</h1>
</a>
<table class="console">
<j:forEach var="line" items="${build.getLog(50)}">
<tr>
<td>
<tt>${line}</tt>
</td>
</tr>
</j:forEach>
</table>
<br />
</div>
</body>
</html>
</j:jelly>
保存。
然后配置系统管理——Editable Email Notification Templates,增加一个默认模板,名称为默认,直接保存。
回到项目配置, 在构建环境里,
勾上Provide Configuration files
选择File为刚新增的jelly文件,target填写/var/jenkins_home/email-templates
Variable填写analysis.jelly
然后,在构建后操作里增加Editable Email Notification Templates,选择默认模板。
这样就完成了配置。
作者:Jadepeng
出处:jqpeng的技术记事本--http://www.cnblogs.com/xiaoqi
您的支持是对博主最大的鼓励,感谢您的认真阅读。
本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
Docker+Jenkins持续集成环境(3)集成PMD、FindBugs、Checkstyle静态代码检查工具并邮件发送检查结果的更多相关文章
- Docker+Jenkins持续集成环境(4):使用etcd+confd实现容器服务注册与发现
前面我们已经通过jenkins+docker搭建了基本的持续集成环境,实现了服务的自动构建和部署,但是,我们遇到一个问题,jenkins构建出来的镜像部署后,需要通过ip:port去访问,有什么更好的 ...
- Docker+Jenkins持续集成环境(5): android构建与apk发布
项目组除了常规的java项目,还有不少android项目,如何使用jenkins来实现自动构建呢?本文会介绍安卓项目通过jenkins构建的方法,并设计开发一个类似蒲公英的app托管平台. andro ...
- Docker+Jenkins持续集成
Docker+Jenkins持续集成 使用etcd+confd实现容器服务注册与发现 前面我们已经通过jenkins+docker搭建了基本的持续集成环境,实现了服务的自动构建和部署,但是,我们遇 ...
- Jenkins+PMD构建自动化静态代码检测
前言:软件缺陷是不可避免的,要尽量减少错误并提高软件质量,主要有两在类技术,即缺陷预防和缺陷检测 缺陷预防包括编写更好的设计规范.实施代码审核制度.运行代码静态分析工具.运行单元测试等 PMD是一种开 ...
- Eclipse插件(导出UML图,打开文件资源管理器插件,静态代码分析工具PMD,在eclipse上安装插件)
目录 能够导出UML图的Eclipse插件 打开文件资源管理器插件 Java静态代码分析工具PMD 如何在eclipse上安装插件 JProfiler性能分析工具 从更新站点安装EclEmma 能够导 ...
- 静态代码扫描工具PMD定制xml的规则(一)操作篇
0.前言 PMD作为开源的静态代码扫描工具有很强的扩展能力,可使用java或xpath定制rule.第一篇从操作上讲解如何定制一个用于扫描xml是否规范的规则.首先我们知道xml格式的文件在java工 ...
- Docker+Jenkins持续集成环境(2)使用docker+jenkins构建nodejs前端项目
前文使用Docker搭建Jenkins+Docker持续集成环境我们已经搭建了基于docker+jenkins的持续集成环境,并构建了基于maven的项目.这一节,我们继续扩展功能,增加对Nodejs ...
- Docker+Jenkins持续集成环境(1)使用Docker搭建Jenkins+Docker持续集成环境
本文介绍如何通过Jenkins的docker镜像从零开始构建一个基于docker镜像的持续集成环境,包含自动化构建.发布到仓库\并部署上线. 0. 前置条件 服务器安装docker,并启动docker ...
- Docker + Jenkins 持续部署 ASP.NET Core 项目
Docker 是个好东西,特别是用它来部署 ASP.NET Core Web 项目的时候,但是仅仅的让程序运行起来远远不能满足我的需求,如果能够像 DaoCloud 提供的持续集成服务那样,检测 gi ...
随机推荐
- Saltstack的安装和配置
1.安装salt 因为系统自带的yum源不支持saltstack安装包的支持,所以需要安装第三方yum源(epel) # yum -y install epel-release salt分为主服务器( ...
- c#全宇宙最牛的编程软件
c#走的道路!PC,PD,电脑一体,一个账户就可以三合一,可以跨平台的编程,在未来的道路如果微软能一直走下去,那么c#将成为宇宙最牛B的编程软件.
- Paho -物联网 MQTT C Cient的实现和详解
概述 在文章Paho - MQTT C Cient的实现中,我介绍了如何使用Paho开源项目创建MQTTClient_pulish客户端.但只是简单的介绍了使用方法,而且客户端的结果与之前介绍的并 ...
- K:java中正则表达式的使用说明及其举例
从Java1.4起,java核心API就引入了java.util.regex程序包来处理正则表达式,并使用该包下的相关类进行字符串的匹配.搜索.提取.分析结构化内容等工作.需要注意的是,正则表达式本身 ...
- 跟我一起学JQuery插件开发教程
在逛codeproject网站的时候,突然看到一篇文章:How to write plugin in Jquery. 如果对E文好的同学 ,可以看上面的连接.现在我把上面网站的及结合自己的想法写这篇文 ...
- Robot Framework学习笔记(五)------Collections 库
Collections 库同样为 Robot Framework 标准类库,它所提供的关键字主要用于列表.索引.字典的处理. 1.添加类 在使用之前需要在测试套件(项目)中添加 2.创建字典 字典也是 ...
- amaze UI 笔记 - JS
导航添加依据 http://amazeui.org/javascript 下面内容属学习笔记,如有理解偏差和错误请留言相告,感谢!* =(官网这块写的很详细) 一 .UI增强 1.警告框 显示可关闭的 ...
- 自己封装的一个js方法用于获取显示的星期和日期时间
自己封装的一个js方法用于获取显示的星期和日期时间 /** * 获取用于显示的星期和日期时间 * @param date * @returns {string} */ function getWeek ...
- MicroPython教程之TPYBoard v102 CAN总线通信
0x00前言 CAN是控制器局域网络(ControllerAreaNetwork,CAN)的简称,是ISO国际标准化的串行通信协议.CAN总线结构简单,只需2根线与外部相连,并且内部集成了错误探测和管 ...
- angular4.0中form表单双向数据绑定正确姿势
issue:用[(ngModel)]="property"指令双向数据绑定,报错. reason1:使用ngModel绑定数据需要注入FormsModule模块,在app.modu ...