Jenkins自动构建部署项目

╰半夏微凉° 2022-02-03 04:49 658阅读 0赞

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找不到。
在这里插入图片描述
一个可用的部署脚本为:

  1. task deploy(dependsOn: distTar) {
  2. println("configDir------->" + System.getProperty("configDir"))
  3. def role = ""
  4. if (System.getProperty("configDir") == null || System.getProperty("configDir").isEmpty()) {
  5. role = "debug"
  6. }
  7. println "buildDir------>$buildDir"
  8. doLast {
  9. ssh.run {
  10. session(remotes.travle) {
  11. println "role" + role
  12. // if (role.equals("debug")) {
  13. executeScript '''#!/bin/sh
  14. cd /u01/SINO/SSP-Travel-Dev
  15. bin/SSP-Travel stop
  16. pwd
  17. mv -f /u01/SINO/SSP-Travel-Dev/log /u01/SINO/log-dev
  18. rm -rf /u01/SINO/SSP-Travel-Dev
  19. '''
  20. put from: "$buildDir/distributions/SSP-Travel-${version}.tar", into: '/u01/SINO/'
  21. execute "tar -xvf /u01/SINO/SSP-Travel-${version}.tar -C /u01/SINO/"
  22. execute "mv /u01/SINO/SSP-Travel-${version} /u01/SINO/SSP-Travel-Dev"
  23. execute "mv -f /u01/SINO/log-dev /u01/SINO/SSP-Travel-Dev/log"
  24. execute "rm -rf /u01/SINO/SSP-Travel-${version}.tar"
  25. executeScript '''#!/bin/sh
  26. cd /u01/SINO/SSP-Travel-Dev
  27. bin/SSP-Travel stop
  28. bin/SSP-Travel debug 5006
  29. '''
  30. }
  31. }
  32. }
  33. }
  34. ssh.settings {
  35. knownHosts = allowAnyHosts
  36. }
  37. remotes {
  38. travle {
  39. role('debug')
  40. host = '1.1.1.1'
  41. user = 'root'
  42. password = 'xxxxxxx'
  43. }
  44. }

归档打包部署完成的包:
在这里插入图片描述
构建成果文件在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

  1. <STYLE>
  2. BODY, TABLE, TD, TH, P {
  3. font-family: Calibri, Verdana, Helvetica, sans serif;
  4. font-size: 12px;
  5. color: black;
  6. }
  7. .console {
  8. font-family: Courier New;
  9. }
  10. .filesChanged {
  11. width: 10%;
  12. padding-left: 10px;
  13. }
  14. .section {
  15. width: 100%;
  16. border: thin black dotted;
  17. }
  18. .td-title-main {
  19. color: white;
  20. font-size: 200%;
  21. padding-left: 5px;
  22. font-weight: bold;
  23. }
  24. .td-title {
  25. color: white;
  26. font-size: 120%;
  27. font-weight: bold;
  28. padding-left: 5px;
  29. text-transform: uppercase;
  30. }
  31. .td-title-tests {
  32. font-weight: bold;
  33. font-size: 120%;
  34. }
  35. .td-header-maven-module {
  36. font-weight: bold;
  37. font-size: 120%;
  38. }
  39. .td-maven-artifact {
  40. padding-left: 5px;
  41. }
  42. .tr-title {
  43. background-color: <%= (build.result == null || build.result.toString() == 'SUCCESS') ? '#27AE60' : build.result.toString() == 'FAILURE' ? '#E74C3C' : '#f4e242' %>;
  44. }
  45. .test {
  46. padding-left: 20px;
  47. }
  48. .test-fixed {
  49. color: #27AE60;
  50. }
  51. .test-failed {
  52. color: #E74C3C;
  53. }
  54. </STYLE>
  55. <BODY>
  56. <!-- BUILD RESULT -->
  57. <table class="section">
  58. <tr class="tr-title">
  59. <td class="td-title-main" colspan=2>
  60. BUILD ${ build.result ?: 'COMPLETED'}
  61. </td>
  62. </tr>
  63. <tr>
  64. <td>URL:</td>
  65. <td><A href="${rooturl}${build.url}">${ rooturl}${ build.url}</A></td>
  66. </tr>
  67. <tr>
  68. <td>Project:</td>
  69. <td>${ project.name}</td>
  70. </tr>
  71. <tr>
  72. <td>Date:</td>
  73. <td>${ it.timestampString}</td>
  74. </tr>
  75. <tr>
  76. <td>Duration:</td>
  77. <td>${ build.durationString}</td>
  78. </tr>
  79. <tr>
  80. <td>Cause:</td>
  81. <td><% build.causes.each() { cause -> %> ${ cause.shortDescription} <% } %></td>
  82. </tr>
  83. </table>
  84. <br/>
  85. <!-- CHANGE SET -->
  86. <%
  87. def changeSets = build.changeSets
  88. if(changeSets != null) {
  89. def hadChanges = false %>
  90. <table class="section">
  91. <tr class="tr-title">
  92. <td class="td-title" colspan="2">CHANGES</td>
  93. </tr>
  94. <% changeSets.each() {
  95. cs_list -> cs_list.each() {
  96. cs -> hadChanges = true %>
  97. <tr>
  98. <td>
  99. Revision
  100. <%= cs.metaClass.hasProperty('commitId') ? cs.commitId : cs.metaClass.hasProperty('revision') ? cs.revision : cs.metaClass.hasProperty('changeNumber') ? cs.changeNumber : "" %>
  101. by <B><%= cs.author %></B>
  102. </td>
  103. <td>${ cs.msgAnnotated}</td>
  104. </tr>
  105. <% cs.affectedFiles.each() {
  106. p -> %>
  107. <tr>
  108. <td class="filesChanged">${ p.editType.name}</td>
  109. <td>${ p.path}</td>
  110. </tr>
  111. <% }
  112. }
  113. }
  114. if ( !hadChanges ) { %>
  115. <tr>
  116. <td colspan="2">No Changes</td>
  117. </tr>
  118. <% } %>
  119. </table>
  120. <br/>
  121. <% } %>
  122. <!-- ARTIFACTS -->
  123. <%
  124. def artifacts = build.artifacts
  125. if ( artifacts != null && artifacts.size() > 0 ) { %>
  126. <table class="section">
  127. <tr class="tr-title">
  128. <td class="td-title">BUILD ARTIFACTS</td>
  129. </tr>
  130. <% artifacts.each() {
  131. f -> %>
  132. <tr>
  133. <td>
  134. <a href="${rooturl}${build.url}artifact/${f}">${ f}</a>
  135. </td>
  136. </tr>
  137. <% } %>
  138. </table>
  139. <br/>
  140. <% } %>
  141. <!-- MAVEN ARTIFACTS -->
  142. <%
  143. try {
  144. def mbuilds = build.moduleBuilds
  145. if ( mbuilds != null ) { %>
  146. <table class="section">
  147. <tr class="tr-title">
  148. <td class="td-title">BUILD ARTIFACTS</td>
  149. </tr>
  150. <%
  151. try {
  152. mbuilds.each() {
  153. m -> %>
  154. <tr>
  155. <td class="td-header-maven-module">${ m.key.displayName}</td>
  156. </tr>
  157. <%
  158. m.value.each() {
  159. mvnbld -> def artifactz = mvnbld.artifacts
  160. if ( artifactz != null && artifactz.size() > 0) { %>
  161. <tr>
  162. <td class="td-maven-artifact">
  163. <% artifactz.each() {
  164. f -> %>
  165. <a href="${rooturl}${mvnbld.url}artifact/${f}">${ f}</a><br/>
  166. <% } %>
  167. </td>
  168. </tr>
  169. <% }
  170. }
  171. }
  172. } catch(e) {
  173. // we don't do anything
  174. } %>
  175. </table>
  176. <br/>
  177. <% }
  178. } catch(e) {
  179. // we don't do anything
  180. } %>
  181. <!-- JUnit TEMPLATE -->
  182. <%
  183. def junitResultList = it.JUnitTestResult
  184. try {
  185. def cucumberTestResultAction = it.getAction("org.jenkinsci.plugins.cucumber.jsontestsupport.CucumberTestResultAction")
  186. junitResultList.add( cucumberTestResultAction.getResult() )
  187. } catch(e) {
  188. //cucumberTestResultAction not exist in this build
  189. }
  190. if ( junitResultList.size() > 0 ) { %>
  191. <table class="section">
  192. <tr class="tr-title">
  193. <td class="td-title" colspan="5">${ junitResultList.first().displayName}</td>
  194. </tr>
  195. <tr>
  196. <td class="td-title-tests">Name</td>
  197. <td class="td-title-tests">Failed</td>
  198. <td class="td-title-tests">Passed</td>
  199. <td class="td-title-tests">Skipped</td>
  200. <td class="td-title-tests">Total</td>
  201. </tr>
  202. <% junitResultList.each {
  203. junitResult -> junitResult.getChildren().each {
  204. packageResult -> %>
  205. <tr>
  206. <td>${ packageResult.getName()}</td>
  207. <td>${ packageResult.getFailCount()}</td>
  208. <td>${ packageResult.getPassCount()}</td>
  209. <td>${ packageResult.getSkipCount()}</td>
  210. <td>${ packageResult.getPassCount() + packageResult.getFailCount() + packageResult.getSkipCount()}</td>
  211. </tr>
  212. <% packageResult.getPassedTests().findAll({ it.getStatus().toString() == "FIXED";}).each{
  213. test -> %>
  214. <tr>
  215. <td class="test test-fixed" colspan="5">
  216. ${ test.getFullName()} ${ test.getStatus()}
  217. </td>
  218. </tr>
  219. <% } %>
  220. <% packageResult.getFailedTests().sort({ a,b -> a.getAge() <=> b.getAge()}).each{
  221. failed_test -> %>
  222. <tr>
  223. <td class="test test-failed" colspan="5">
  224. ${ failed_test.getFullName()} (Age: ${ failed_test.getAge()})
  225. </td>
  226. </tr>
  227. <% }
  228. }
  229. } %>
  230. </table>
  231. <br/>
  232. <% } %>
  233. <!-- CONSOLE OUTPUT -->
  234. <%
  235. if ( build.result == hudson.model.Result.FAILURE ) { %>
  236. <table class="section" cellpadding="0" cellspacing="0">
  237. <tr class="tr-title">
  238. <td class="td-title">CONSOLE OUTPUT</td>
  239. </tr>
  240. <% build.getLog(100).each() {
  241. line -> %>
  242. <tr>
  243. <td class="console">${ org.apache.commons.lang.StringEscapeUtils.escapeHtml(line)}</td>
  244. </tr>
  245. <% } %>
  246. </table>
  247. <br/>
  248. <% } %>
  249. </BODY>

模板需要在Jenkins的主目录下建立email-templates目录,把模板放入其中,如下所示:
在这里插入图片描述
可以测试下邮件效果:
在这里插入图片描述
邮件的最终效果如下:
在这里插入图片描述

4.邮件添加附件和附件正文

进行如下配置即可添加附件:
在这里插入图片描述
效果如下:
在这里插入图片描述
实现把附件的内容添加到邮件正文,需要使用groovy的邮件模板,采用groovy编程语言的优势进行文件的读取和显示:
在这里插入图片描述
在这里插入图片描述
结果如下:
在这里插入图片描述

5.认证,使用域账户登录

在这里插入图片描述

6.参考文献

  • jenkins 邮件配置之良心之作
  • Jenkins进阶系列之——01使用email-ext替换Jenkins的默认邮件通知
  • Jenkins自动构建部署项目到远程服务器上

发表评论

表情:
评论列表 (有 0 条评论,658人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Jenkins自动部署项目

    目录 1.安装插件 2.配置 -------------------- 本文只讲解通过插件来自动部署项目,Jenkins的安装可以看博主的另一篇文章,绝对保姆级,简洁

    相关 jenkins+svn自动构建项目

    1.场景还原      随着微服务架构的日益盛行,自动化打包构建及部署,势在必行!今天,笔者就jenkins+svn自动化构建及部署做个相关的分享; 2.实现方案