Jenkins自动构建部署项目
1. 楔子
在实际开发中,经常需要编译、静态代码检查、自动化测试、打包、部署、启动等一连串重复机械的动作,浪费时间、而且容易出错,而Jenkins就是专门Continuous integration(CI)/ Continuous Deploy(CD)
开源工具,本文简单介绍Jenkins的使用。
在线无安装免费试用Jenkins:http://www.jenkins.org.cn/test
2.jenkins介绍
Jenkins只是一个平台,真正运作的都是插件。这就是jenkins流行的原因,因为jenkins什么插件都有
Hudson是Jenkins的前身,是基于Java开发的一种持续集成工具,用于监控程序重复的工作,Hudson后来被收购,成为商业版。后来创始人又写了一个jenkins,jenkins在功能上远远超过hudson
官网:https://jenkins.io/
插件库:https://plugins.jenkins.io/
3.创建流水线
首先创建一个新的自由风格的流水线,是功能比较强大和自由的流水线方式。
填写流水线信息和构建结果保留策略:
配置代码管理,主要是拉取哪个目录的代码、放入哪个目录。
代码仓库结构为:
拉取到的效果为:(当前目录为workspace/Travel-dev-deploy
Travel-dev-deploy为流水线项目名字)
可以配置流水线触发策略,比如定时,间隔或者cron表达式等:
执行gradle脚本完成构建、部署等。主要功能有gradle脚本完成。
一定要配置gradle脚本的目录,不然gradle的命令task找不到。
一个可用的部署脚本为:
task deploy(dependsOn: distTar) {
println("configDir------->" + System.getProperty("configDir"))
def role = ""
if (System.getProperty("configDir") == null || System.getProperty("configDir").isEmpty()) {
role = "debug"
}
println "buildDir------>$buildDir"
doLast {
ssh.run {
session(remotes.travle) {
println "role" + role
// if (role.equals("debug")) {
executeScript '''#!/bin/sh
cd /u01/SINO/SSP-Travel-Dev
bin/SSP-Travel stop
pwd
mv -f /u01/SINO/SSP-Travel-Dev/log /u01/SINO/log-dev
rm -rf /u01/SINO/SSP-Travel-Dev
'''
put from: "$buildDir/distributions/SSP-Travel-${version}.tar", into: '/u01/SINO/'
execute "tar -xvf /u01/SINO/SSP-Travel-${version}.tar -C /u01/SINO/"
execute "mv /u01/SINO/SSP-Travel-${version} /u01/SINO/SSP-Travel-Dev"
execute "mv -f /u01/SINO/log-dev /u01/SINO/SSP-Travel-Dev/log"
execute "rm -rf /u01/SINO/SSP-Travel-${version}.tar"
executeScript '''#!/bin/sh
cd /u01/SINO/SSP-Travel-Dev
bin/SSP-Travel stop
bin/SSP-Travel debug 5006
'''
}
}
}
}
ssh.settings {
knownHosts = allowAnyHosts
}
remotes {
travle {
role('debug')
host = '1.1.1.1'
user = 'root'
password = 'xxxxxxx'
}
}
归档打包部署完成的包:
构建成果文件在Jenkins上的位置如下,需要把这个文件拷贝归档。
采用匹配的方式,把所有符合规则的构建成果文件进行归档,效果如下:
配置邮件发送,构建成功或者失败给 特定的人 和 更改过代码的人发送邮件:
Default Content:默认邮件内容;这里是关键;我这里使用的是模板${SCRIPT, template="groovy-html-dev.template"};
后面会讲;当然不想使用模板的话,可以通过使用jenkins自身提供的变量来自己定义;
下面一定要注意:
邮件模板采用groovy模板,官方给出了很多的模板(matrix模板、groovy模板):
本文采用的是Gradle的变成语言groovy模板,官方实例为:
https://github.com/jenkinsci/email-ext-plugin/blob/master/src/main/resources/hudson/plugins/emailext/templates/groovy-html.template
<STYLE>
BODY, TABLE, TD, TH, P {
font-family: Calibri, Verdana, Helvetica, sans serif;
font-size: 12px;
color: black;
}
.console {
font-family: Courier New;
}
.filesChanged {
width: 10%;
padding-left: 10px;
}
.section {
width: 100%;
border: thin black dotted;
}
.td-title-main {
color: white;
font-size: 200%;
padding-left: 5px;
font-weight: bold;
}
.td-title {
color: white;
font-size: 120%;
font-weight: bold;
padding-left: 5px;
text-transform: uppercase;
}
.td-title-tests {
font-weight: bold;
font-size: 120%;
}
.td-header-maven-module {
font-weight: bold;
font-size: 120%;
}
.td-maven-artifact {
padding-left: 5px;
}
.tr-title {
background-color: <%= (build.result == null || build.result.toString() == 'SUCCESS') ? '#27AE60' : build.result.toString() == 'FAILURE' ? '#E74C3C' : '#f4e242' %>;
}
.test {
padding-left: 20px;
}
.test-fixed {
color: #27AE60;
}
.test-failed {
color: #E74C3C;
}
</STYLE>
<BODY>
<!-- BUILD RESULT -->
<table class="section">
<tr class="tr-title">
<td class="td-title-main" colspan=2>
BUILD ${ build.result ?: 'COMPLETED'}
</td>
</tr>
<tr>
<td>URL:</td>
<td><A href="${rooturl}${build.url}">${ rooturl}${ build.url}</A></td>
</tr>
<tr>
<td>Project:</td>
<td>${ project.name}</td>
</tr>
<tr>
<td>Date:</td>
<td>${ it.timestampString}</td>
</tr>
<tr>
<td>Duration:</td>
<td>${ build.durationString}</td>
</tr>
<tr>
<td>Cause:</td>
<td><% build.causes.each() { cause -> %> ${ cause.shortDescription} <% } %></td>
</tr>
</table>
<br/>
<!-- CHANGE SET -->
<%
def changeSets = build.changeSets
if(changeSets != null) {
def hadChanges = false %>
<table class="section">
<tr class="tr-title">
<td class="td-title" colspan="2">CHANGES</td>
</tr>
<% changeSets.each() {
cs_list -> cs_list.each() {
cs -> hadChanges = true %>
<tr>
<td>
Revision
<%= cs.metaClass.hasProperty('commitId') ? cs.commitId : cs.metaClass.hasProperty('revision') ? cs.revision : cs.metaClass.hasProperty('changeNumber') ? cs.changeNumber : "" %>
by <B><%= cs.author %></B>
</td>
<td>${ cs.msgAnnotated}</td>
</tr>
<% cs.affectedFiles.each() {
p -> %>
<tr>
<td class="filesChanged">${ p.editType.name}</td>
<td>${ p.path}</td>
</tr>
<% }
}
}
if ( !hadChanges ) { %>
<tr>
<td colspan="2">No Changes</td>
</tr>
<% } %>
</table>
<br/>
<% } %>
<!-- ARTIFACTS -->
<%
def artifacts = build.artifacts
if ( artifacts != null && artifacts.size() > 0 ) { %>
<table class="section">
<tr class="tr-title">
<td class="td-title">BUILD ARTIFACTS</td>
</tr>
<% artifacts.each() {
f -> %>
<tr>
<td>
<a href="${rooturl}${build.url}artifact/${f}">${ f}</a>
</td>
</tr>
<% } %>
</table>
<br/>
<% } %>
<!-- MAVEN ARTIFACTS -->
<%
try {
def mbuilds = build.moduleBuilds
if ( mbuilds != null ) { %>
<table class="section">
<tr class="tr-title">
<td class="td-title">BUILD ARTIFACTS</td>
</tr>
<%
try {
mbuilds.each() {
m -> %>
<tr>
<td class="td-header-maven-module">${ m.key.displayName}</td>
</tr>
<%
m.value.each() {
mvnbld -> def artifactz = mvnbld.artifacts
if ( artifactz != null && artifactz.size() > 0) { %>
<tr>
<td class="td-maven-artifact">
<% artifactz.each() {
f -> %>
<a href="${rooturl}${mvnbld.url}artifact/${f}">${ f}</a><br/>
<% } %>
</td>
</tr>
<% }
}
}
} catch(e) {
// we don't do anything
} %>
</table>
<br/>
<% }
} catch(e) {
// we don't do anything
} %>
<!-- JUnit TEMPLATE -->
<%
def junitResultList = it.JUnitTestResult
try {
def cucumberTestResultAction = it.getAction("org.jenkinsci.plugins.cucumber.jsontestsupport.CucumberTestResultAction")
junitResultList.add( cucumberTestResultAction.getResult() )
} catch(e) {
//cucumberTestResultAction not exist in this build
}
if ( junitResultList.size() > 0 ) { %>
<table class="section">
<tr class="tr-title">
<td class="td-title" colspan="5">${ junitResultList.first().displayName}</td>
</tr>
<tr>
<td class="td-title-tests">Name</td>
<td class="td-title-tests">Failed</td>
<td class="td-title-tests">Passed</td>
<td class="td-title-tests">Skipped</td>
<td class="td-title-tests">Total</td>
</tr>
<% junitResultList.each {
junitResult -> junitResult.getChildren().each {
packageResult -> %>
<tr>
<td>${ packageResult.getName()}</td>
<td>${ packageResult.getFailCount()}</td>
<td>${ packageResult.getPassCount()}</td>
<td>${ packageResult.getSkipCount()}</td>
<td>${ packageResult.getPassCount() + packageResult.getFailCount() + packageResult.getSkipCount()}</td>
</tr>
<% packageResult.getPassedTests().findAll({ it.getStatus().toString() == "FIXED";}).each{
test -> %>
<tr>
<td class="test test-fixed" colspan="5">
${ test.getFullName()} ${ test.getStatus()}
</td>
</tr>
<% } %>
<% packageResult.getFailedTests().sort({ a,b -> a.getAge() <=> b.getAge()}).each{
failed_test -> %>
<tr>
<td class="test test-failed" colspan="5">
${ failed_test.getFullName()} (Age: ${ failed_test.getAge()})
</td>
</tr>
<% }
}
} %>
</table>
<br/>
<% } %>
<!-- CONSOLE OUTPUT -->
<%
if ( build.result == hudson.model.Result.FAILURE ) { %>
<table class="section" cellpadding="0" cellspacing="0">
<tr class="tr-title">
<td class="td-title">CONSOLE OUTPUT</td>
</tr>
<% build.getLog(100).each() {
line -> %>
<tr>
<td class="console">${ org.apache.commons.lang.StringEscapeUtils.escapeHtml(line)}</td>
</tr>
<% } %>
</table>
<br/>
<% } %>
</BODY>
模板需要在Jenkins的主目录下建立email-templates
目录,把模板放入其中,如下所示:
可以测试下邮件效果:
邮件的最终效果如下:
4.邮件添加附件和附件正文
进行如下配置即可添加附件:
效果如下:
实现把附件的内容添加到邮件正文,需要使用groovy的邮件模板,采用groovy编程语言的优势进行文件的读取和显示:
结果如下:
5.认证,使用域账户登录
6.参考文献
- jenkins 邮件配置之良心之作
- Jenkins进阶系列之——01使用email-ext替换Jenkins的默认邮件通知
- Jenkins自动构建部署项目到远程服务器上
还没有评论,来说两句吧...