jenkins 郵件配置
jenkins預設的郵件通知
我先講解下,預設的。
jenkins預設就有一個郵件通知,只是太簡單的,不能個性化或者說定製化。
設定系統管理員郵件地址
郵件通知
①SMTP
伺服器:如果你使用的是公司郵箱,那麼就詢問你自己公司裡的運維人員吧;他們一般都知道,至少我就是問公司裡的運維人員;要是你打算使用QQ郵箱
,那麼你需要設定下,網上有教程;網易郵箱預設開啟。
說明:SMTP
是一種協議
②使用者預設郵件字尾:根據自己情況去設定
③勾選使用SMTP認證
,使用者名稱:根據自己情況設定,密碼也是。
④SMTP
埠:預設25
配置好了後,可以勾選 測試,在Test e-mail recipient
成功後,我們可以到job
中進行配置:
配置好了後,接下來測試,我下面是故意寫錯echo
,使其構建失敗,驗證郵件。
傳送郵件的結果:
可以看出這個郵件內容純文字,連個超連結都沒有,內容也不夠豐富!
接下來我們使用增強版的郵件通知
系統配置
在安裝好外掛後,你的系統設定
裡面會有這麼一個設定:
接上面圖片:
上面點選高階
按鈕後:
①SMTP server
:和之前同理
②Default user E-mail suffix
:根據自己情況填寫
③勾選Use SMTP Authentication
④
SMTP port
:預設25 ⑤
Default Content Type
:郵件文件型別 ⑥
Default Recipients
:預設接收人列表,已逗號進行分割
其他我都使用預設或者說沒有填寫,點選儲存。
注意:
上面配置中,凡是以Default
開頭的名稱,都可以在job
的配置中當做變數使用。比如:預設的收件人地址:在單獨的job
中可以這樣使用$DEFAULT_RECIPIENTS
。
單個job的單獨配置
在增加構建後操作步驟
,新增增強版郵件通知(看紅色圈住的部分):
之後你會得到:
稍微講解下:
①Disable Extended Email Publisher
②
Project Recipient List
:收件人地址;多個收件人郵件地址用逗號進行分割;想使用全域性預設配置的話,可以使用$DEFAULT_RECIPIENTS
。 ③
Project Reply-To List
:允許回覆人的地址;想使用系統設定中的預設值的話,可以使用$DEFAULT_REPLYTO
; ④
Content Type
:郵件文件的型別,可以設定HTML
等格式; ⑤
Default Subject
:預設主題,也就是郵件標題;同理可以使用$DEFAULT_SUBJECT
⑥
Default Content
:預設郵件內容;這裡是關鍵;我這裡使用的是模板${SCRIPT, template="groovy-html.template"}
;後面會講;當然不想使用模板的話,可以通過使用jenkins
自身提供的變數來自己定義; ⑦
Attach Build Log
:傳送的郵件是否包含日誌; 下面幾個預設就好,最後一個
Triggers
非常關鍵; 假設最後一個不改的話,郵件是接收不到的,這個是官方留下的一個大坑,一定要自己再新增一個
Recipient List
。
點選儲存,點選構建後,收到的郵件格式如下:
遇到的問題
問題一
An attempt to send an e-mail to empty list of recipients, ignored.
- 1
這個問題,我一直卡著很久,差不多1天吧!始終不知道為什麼收不到郵件
直到Google
到這個地方:
https://stackoverflow.com/a/37167955/6952713
問題二
Exception raised during template rendering: No signature of method: hudson.model.FreeStyleBuild.getExactRuns() is applicable for argument types: () values: [] Possible solutions: getActions(), getActions(java.lang.Class) groovy.lang.MissingMethodException: No signature of method: hudson.model.FreeStyleBuild.getExactRuns() is applicable for argument types: () values: [] Possible solutions: getActions(), getActions(java.lang.Class) at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:58) at org.codehaus.groovy.runtime.callsite.PojoMetaClassSite.call(PojoMetaClassSite.java:49) at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:117) at SimpleTemplateScript3.run(SimpleTemplateScript3.groovy:106) at groovy.text.SimpleTemplateEngine$SimpleTemplate$1.writeTo(SimpleTemplateEngine.java:168) at groovy.text.SimpleTemplateEngine$SimpleTemplate$1.toString(SimpleTemplateEngine.java:180) at hudson.plugins.emailext.plugins.content.ScriptContent.renderTemplate(ScriptContent.java:127) at hudson.plugins.emailext.plugins.content.ScriptContent.evaluate(ScriptContent.java:68) at hudson.plugins.emailext.plugins.content.AbstractEvalContent.evaluate(AbstractEvalContent.java:64) at org.jenkinsci.plugins.tokenmacro.DataBoundTokenMacro.evaluate(DataBoundTokenMacro.java:199) at
這個錯誤是我在使用郵件模板時,報的錯!
我的步驟如下:
我在參考官方 :https://wiki.jenkins.io/display/JENKINS/Email-ext+plugin
中的Script content這一章節內容時,下載了兩個Template Examples
jenkins-matrix-email-html.template
jenkins-generic-matrix-email-html.template
按照官方教程在jenkins home
(/home/jenkins/dataspace
)目錄中建立了email-templates
資料夾,並把那兩個模板上傳上去了,之後在job
配置中的Default Content
中寫入:
${SCRIPT, template="jenkins-matrix-email-html.template"}
然後構建時,就報錯!
這一塊也困擾我很久!直到Google
到了這麼一段話(網上資料真心少);
http://jenkins-ci.361315.n4.nabble.com/Email-Template-Testing-Exception-td4807117.html
內容如下:
Looks like you are trying to test a matrix template with a non matrix job.
意思是說:
看起來像你在一個非
matrix job
中測試一個matrix
模板
之後又去查詢什麼是matrix job
;
這是一篇關於matrix
的官方教程
Building a matrix project
看到裡面內容卻是構建一個Multi-Configuration Projects
;這時就有點迷糊了!接著檢視Matrix Project Plugin
這個外掛;裡面的講解有這麼一句話:
Multi-configuration (matrix) project type.
基本可以肯定matrix job
就是Multi-configuration project
(構建一個多配置專案)。也就是說我要使用jenkins-matrix-email-html.template
這個模板就必須建立與之對應的job
;
經過測試後,果然可以,配置都是類似的:郵件結果如下:
那麼matrix job
這個用的場景多嗎?
這是官方給出的經驗:
Experience with Hudson - Building matrix project
其講解到:
比如 你的專案想在jdk 1.4 、1.5、1.6中進行測試,你就可以通過建立這種型別的
job
;
使用自定義模板
通過上面遇到的問題,我們有時會想自己來定義模板!
使用自己的模板有兩種方法:
方法一 不使用模板
在Default Content
這一欄中,自己通過Token
來寫:
(這裡的token
不要翻譯成令牌,因為不知道翻譯成啥,就保留原文token
吧)
- <html>
- <head>
- <meta charset="UTF-8">
- <title>${ENV, var="JOB_NAME"}-第${BUILD_NUMBER}次構建日誌</title>
- </head>
- <body leftmargin="8" marginwidth="0" topmargin="8" marginheight="4"
- offset="0">
- <table width="95%" cellpadding="0" cellspacing="0"
- style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif">
- <tr>
- <td>
- <h2>
- <font>來自Mr.Jenkins的郵件通知</font>
- </h2>
- </td>
- </tr>
- <tr>
- <td>
- <br />
- <b><font color="#0B610B">構建資訊</font></b>
- <hr size="2" width="100%" align="center" />
- </td>
- </tr>
- <tr>
- <td>
- <ul>
- <li>專案名稱 : ${PROJECT_NAME}</li>
- <li>觸發原因 :${CAUSE}</li>
- <li>構建日誌 : <a href="${BUILD_URL}console">${BUILD_URL}console</a></li>
- <li>單元測試報告 :<a href="${BUILD_URL}testReport/">${BUILD_URL}testReport/</a></li>
- <li>工作目錄 : <a href="${PROJECT_URL}ws">${PROJECT_URL}ws</a></li>
- </ul>
- </td>
- </tr>
- <tr>
- <td><b><font color="#0B610B">構建日誌:</font></b>
- <hr size="2" width="100%" align="center" /></td>
- </tr>
- <tr>
- <td><textarea cols="80" rows="30" readonly="readonly"
- style="font-family: Courier New">${BUILD_LOG}</textarea>
- </td>
- </tr>
- </table>
- </body>
- </html>
這段程式碼是從網上找來的,我好奇的是這個寫法:
- ${ENV, var="JOB_NAME"}
- # 這個寫法其實和${JOB_NAME}、$JOB_NAME是等價的
可以理解成:
${ENV(var:JOB_NAME)}
因為引數就一個所以可以簡寫為:
${JOB_NAME}或者$JOB_NAME
方法二 使用模板
之前使用模板出錯是因為使用了matrix
專案的模板。
如果使用groovy
模板也是可以的
這是官方給的groovy
的模板:
在資料夾email-templates
,建立一個檔案,比如我:
- //我的路徑: /home/jenkins/dataspace/email-templates
- [root
- // 再把官方給的模板複製貼上進去,程式碼如下:
- <STYLE>
- BODY, TABLE, TD, TH, P {
- font-family:Verdana,Helvetica,sans serif;
- font-size:11px;
- color:black;
- }
- h1 { color:black; }
- h2 { color:black; }
- h3 { color:black; }
- TD.bg1 { color:white; background-color:#0000C0; font-size:120% }
- TD.bg2 { color:white; background-color:#4040FF; font-size:110% }
- TD.bg3 { color:white; background-color:#8080FF; }
- TD.test_passed { color:blue; }
- TD.test_failed { color:red; }
- TD.console { font-family:Courier New; }
- </STYLE>
- <BODY>
- <TABLE>
- <TR><TD align="right"><IMG SRC="${rooturl}static/e59dfe28/images/32x32/<%= (build.result == null || build.result.toString() == 'SUCCESS') ? "blue.gif" : build.result.toString() == 'FAILURE' ? 'red.gif' : 'yellow.gif' %>" />
- </TD><TD valign="center"><B style="font-size: 200%;">BUILD ${build.result ?: 'SUCCESSFUL'}</B></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 width="100%">
- <TR><TD class="bg1" colspan="2"><B>CHANGES</B></TD></TR>
- <% changeSets.each() { cs_list ->
- cs_list. each() { cs ->
- hadChanges = true %>
- <TR>
- <TD colspan="2" class="bg2"> Revision <B><%= cs.metaClass.hasProperty('commitId') ? cs.commitId : cs.metaClass.hasProperty('revision') ? cs.revision :
- cs.metaClass.hasProperty( 'changeNumber') ? cs.changeNumber : "" %></B> by
- <B><%= cs.author %>: </B>
- <B>(${cs.msgAnnotated})</B>
- </TD>
- </TR>
- <% cs.affectedFiles.each() { p -> %>
- <TR>
- <TD width="10%"> ${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 width="100%">
- <TR><TD class="bg1"><B>BUILD ARTIFACTS</B></TD></TR>
- <TR>
- <TD>
- <% artifacts.each() { f -> %>
- <li>
- <a href="${rooturl}${build.url}artifact/${f}">${f}</a>
- </li>
- <% } %>
- </TD>
- </TR>
- </TABLE>
- <BR/>
- <% } %>
- <!-- MAVEN ARTIFACTS -->
- <%
- try {
- def mbuilds = build.moduleBuilds
- if(mbuilds != null) { %>
- <TABLE width="100%">
- <TR><TD class="bg1"><B>BUILD ARTIFACTS</B></TD></TR>
- <%
- try {
- mbuilds. each() { m -> %>
- <TR><TD class="bg2"><B>${m.key.displayName}</B></TD></TR>
- <% m.value.each() { mvnbld ->
- def artifactz = mvnbld.artifacts
- if(artifactz != null && artifactz.size() > 0) { %>
- <TR>
- <TD>
- <% artifactz.each() { f -> %>
- <li>
- <a href="${rooturl}${mvnbld.url}artifact/${f}">${f}</a>
- </li>
- <% } %>
- </TD>
- </TR>
- <% }
- }
- }
- } catch(e) {
- // we don 't do anything
- } %>
- </TABLE>
- <BR/>
- <% }