blob: c5151243a79e4feef72a466056cb16bd99eab443 [file] [log] [blame]
Jakub Josef79ecec32017-02-17 14:36:28 +01001package com.mirantis.mk
2
3/**
4 *
5 * Common functions
6 *
7 */
8
9/**
10 * Generate current timestamp
11 *
12 * @param format Defaults to yyyyMMddHHmmss
13 */
14def getDatetime(format="yyyyMMddHHmmss") {
15 def now = new Date();
16 return now.format(format, TimeZone.getTimeZone('UTC'));
17}
18
19/**
Jakub Josef79ecec32017-02-17 14:36:28 +010020 * Return workspace.
21 * Currently implemented by calling pwd so it won't return relevant result in
22 * dir context
23 */
24def getWorkspace() {
25 def workspace = sh script: 'pwd', returnStdout: true
26 workspace = workspace.trim()
27 return workspace
28}
29
30/**
31 * Get credentials from store
32 *
33 * @param id Credentials name
34 */
Jakub Josef3d9d9ab2017-03-14 15:09:03 +010035def getCredentials(id, cred_type = "username_password") {
36 def credClass;
37 if(cred_type == "username_password"){
38 credClass = com.cloudbees.plugins.credentials.common.StandardUsernamePasswordCredentials.class
39 }else if(cred_type == "key"){
40 credClass = com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey.class
41 }
Jakub Josef79ecec32017-02-17 14:36:28 +010042 def creds = com.cloudbees.plugins.credentials.CredentialsProvider.lookupCredentials(
Jakub Josef3d9d9ab2017-03-14 15:09:03 +010043 credClass,
Jakub Josef79ecec32017-02-17 14:36:28 +010044 jenkins.model.Jenkins.instance
45 )
46
47 for (Iterator<String> credsIter = creds.iterator(); credsIter.hasNext();) {
48 c = credsIter.next();
49 if ( c.id == id ) {
50 return c;
51 }
52 }
53
54 throw new Exception("Could not find credentials for ID ${id}")
55}
56
57/**
58 * Abort build, wait for some time and ensure we will terminate
59 */
60def abortBuild() {
61 currentBuild.build().doStop()
62 sleep(180)
63 // just to be sure we will terminate
64 throw new InterruptedException()
65}
66
67/**
68 * Print informational message
69 *
70 * @param msg
71 * @param color Colorful output or not
72 */
73def infoMsg(msg, color = true) {
74 printMsg(msg, "cyan")
75}
76
77/**
78 * Print error message
79 *
80 * @param msg
81 * @param color Colorful output or not
82 */
83def errorMsg(msg, color = true) {
84 printMsg(msg, "red")
85}
86
87/**
88 * Print success message
89 *
90 * @param msg
91 * @param color Colorful output or not
92 */
93def successMsg(msg, color = true) {
94 printMsg(msg, "green")
95}
96
97/**
98 * Print warning message
99 *
100 * @param msg
101 * @param color Colorful output or not
102 */
103def warningMsg(msg, color = true) {
Jakub Josef0e7bd632017-03-16 16:25:05 +0100104 printMsg(msg, "yellow")
Jakub Josef79ecec32017-02-17 14:36:28 +0100105}
106
107/**
Jakub Josef952ae0b2017-03-14 19:04:21 +0100108 * Print debug message, this message will show only if DEBUG global variable is present
109 * @param msg
110 * @param color Colorful output or not
111 */
112def debugMsg(msg, color = true){
113 def debugEnabled
114 try {
115 debugEnabled = DEBUG
116 } catch (MissingPropertyException e) {
117 debugEnabled = false
118 }
119 if(debugEnabled){
Jakub Josef74b34692017-03-15 12:10:57 +0100120 printMsg("[DEBUG] ${msg}", "red")
Jakub Josef952ae0b2017-03-14 19:04:21 +0100121 }
122}
123
124/**
Jakub Josef79ecec32017-02-17 14:36:28 +0100125 * Print message
126 *
127 * @param msg Message to be printed
128 * @param level Level of message (default INFO)
129 * @param color Color to use for output or false (default)
130 */
131def printMsg(msg, color = false) {
132 colors = [
133 'red' : '\u001B[31m',
134 'black' : '\u001B[30m',
135 'green' : '\u001B[32m',
136 'yellow': '\u001B[33m',
137 'blue' : '\u001B[34m',
138 'purple': '\u001B[35m',
139 'cyan' : '\u001B[36m',
140 'white' : '\u001B[37m',
141 'reset' : '\u001B[0m'
142 ]
143 if (color != false) {
144 wrap([$class: 'AnsiColorBuildWrapper']) {
145 print "${colors[color]}${msg}${colors.reset}"
146 }
147 } else {
148 print "[${level}] ${msg}"
149 }
150}
151
152/**
153 * Traverse directory structure and return list of files
154 *
155 * @param path Path to search
156 * @param type Type of files to search (groovy.io.FileType.FILES)
157 */
158@NonCPS
159def getFiles(path, type=groovy.io.FileType.FILES) {
160 files = []
161 new File(path).eachFile(type) {
162 files[] = it
163 }
164 return files
165}
166
167/**
168 * Helper method to convert map into form of list of [key,value] to avoid
169 * unserializable exceptions
170 *
171 * @param m Map
172 */
173@NonCPS
174def entries(m) {
175 m.collect {k, v -> [k, v]}
176}
177
178/**
179 * Opposite of build-in parallel, run map of steps in serial
180 *
181 * @param steps Map of String<name>: CPSClosure2<step>
182 */
183def serial(steps) {
184 stepsArray = entries(steps)
185 for (i=0; i < stepsArray.size; i++) {
186 s = stepsArray[i]
187 dummySteps = ["${s[0]}": s[1]]
188 parallel dummySteps
189 }
190}
191
192/**
193 * Get password credentials from store
194 *
195 * @param id Credentials name
196 */
197def getPasswordCredentials(id) {
198 def creds = com.cloudbees.plugins.credentials.CredentialsProvider.lookupCredentials(
199 com.cloudbees.plugins.credentials.common.StandardUsernamePasswordCredentials.class,
200 jenkins.model.Jenkins.instance
201 )
202
203 for (Iterator<String> credsIter = creds.iterator(); credsIter.hasNext();) {
204 c = credsIter.next();
205 if ( c.id == id ) {
206 return c;
207 }
208 }
209
210 throw new Exception("Could not find credentials for ID ${id}")
211}
212
213/**
214 * Get SSH credentials from store
215 *
216 * @param id Credentials name
217 */
218def getSshCredentials(id) {
219 def creds = com.cloudbees.plugins.credentials.CredentialsProvider.lookupCredentials(
220 com.cloudbees.plugins.credentials.common.StandardUsernameCredentials.class,
221 jenkins.model.Jenkins.instance
222 )
223
224 for (Iterator<String> credsIter = creds.iterator(); credsIter.hasNext();) {
225 c = credsIter.next();
226 if ( c.id == id ) {
227 return c;
228 }
229 }
230
231 throw new Exception("Could not find credentials for ID ${id}")
232}
Jakub Josef79ecec32017-02-17 14:36:28 +0100233
234/**
235 * Tests Jenkins instance for existence of plugin with given name
236 * @param pluginName plugin short name to test
237 * @return boolean result
238 */
239@NonCPS
240def jenkinsHasPlugin(pluginName){
241 return Jenkins.instance.pluginManager.plugins.collect{p -> p.shortName}.contains(pluginName)
242}
243
244@NonCPS
245def _needNotification(notificatedTypes, buildStatus, jobName) {
246 if(notificatedTypes && notificatedTypes.contains("onchange")){
247 if(jobName){
248 def job = Jenkins.instance.getItem(jobName)
249 def numbuilds = job.builds.size()
250 if (numbuilds > 0){
251 //actual build is first for some reasons, so last finished build is second
252 def lastBuild = job.builds[1]
253 if(lastBuild){
254 if(lastBuild.result.toString().toLowerCase().equals(buildStatus)){
255 println("Build status didn't changed since last build, not sending notifications")
256 return false;
257 }
258 }
259 }
260 }
261 }else if(!notificatedTypes.contains(buildStatus)){
262 return false;
263 }
264 return true;
265}
266
267/**
268 * Send notification to all enabled notifications services
269 * @param buildStatus message type (success, warning, error), null means SUCCESSFUL
270 * @param msgText message text
271 * @param enabledNotifications list of enabled notification types, types: slack, hipchat, email, default empty
272 * @param notificatedTypes types of notifications will be sent, default onchange - notificate if current build result not equal last result;
273 * otherwise use - ["success","unstable","failed"]
274 * @param jobName optional job name param, if empty env.JOB_NAME will be used
275 * @param buildNumber build number param, if empty env.JOB_NAME will be used
276 * @param buildUrl build url param, if empty env.JOB_NAME will be used
277 * @param mailFrom mail FROM param, if empty "jenkins" will be used, it's mandatory for sending email notifications
278 * @param mailTo mail TO param, it's mandatory for sending email notifications
279 */
280def sendNotification(buildStatus, msgText="", enabledNotifications = [], notificatedTypes=["onchange"], jobName=null, buildNumber=null, buildUrl=null, mailFrom="jenkins", mailTo=null){
281 // Default values
282 def colorName = 'blue'
283 def colorCode = '#0000FF'
284 def buildStatusParam = buildStatus != null && buildStatus != "" ? buildStatus : "SUCCESS"
285 def jobNameParam = jobName != null && jobName != "" ? jobName : env.JOB_NAME
286 def buildNumberParam = buildNumber != null && buildNumber != "" ? buildNumber : env.BUILD_NUMBER
287 def buildUrlParam = buildUrl != null && buildUrl != "" ? buildUrl : env.BUILD_URL
288 def subject = "${buildStatusParam}: Job '${jobNameParam} [${buildNumberParam}]'"
289 def summary = "${subject} (${buildUrlParam})"
290
291 if(msgText != null && msgText != ""){
292 summary+="\n${msgText}"
293 }
294 if(buildStatusParam.toLowerCase().equals("success")){
295 colorCode = "#00FF00"
296 colorName = "green"
297 }else if(buildStatusParam.toLowerCase().equals("unstable")){
298 colorCode = "#FFFF00"
299 colorName = "yellow"
300 }else if(buildStatusParam.toLowerCase().equals("failure")){
301 colorCode = "#FF0000"
302 colorName = "red"
303 }
304 if(_needNotification(notificatedTypes, buildStatusParam.toLowerCase(), jobNameParam)){
305 if(enabledNotifications.contains("slack") && jenkinsHasPlugin("slack")){
306 try{
307 slackSend color: colorCode, message: summary
308 }catch(Exception e){
309 println("Calling slack plugin failed")
310 e.printStackTrace()
311 }
312 }
313 if(enabledNotifications.contains("hipchat") && jenkinsHasPlugin("hipchat")){
314 try{
315 hipchatSend color: colorName.toUpperCase(), message: summary
316 }catch(Exception e){
317 println("Calling hipchat plugin failed")
318 e.printStackTrace()
319 }
320 }
321 if(enabledNotifications.contains("email") && mailTo != null && mailTo != "" && mailFrom != null && mailFrom != ""){
322 try{
323 mail body: summary, from: mailFrom, subject: subject, to: mailTo
324 }catch(Exception e){
325 println("Sending mail plugin failed")
326 e.printStackTrace()
327 }
328 }
329 }
Filip Pytloun49d66302017-03-06 10:26:22 +0100330}
chnyda4e5ac792017-03-14 15:24:18 +0100331
332/**
333 * Execute linux command and catch nth element
334 * @param cmd command to execute
335 * @param index index to retrieve
336 * @return index-th element
337 */
338
339def cutOrDie(cmd, index)
340{
341 def common = new com.mirantis.mk.Common()
342 def output
343 try {
344 output = sh(script: cmd, returnStdout: true)
345 def result = output.tokenize(" ")[index]
346 return result;
347 } catch (Exception e) {
348 common.errorMsg("Failed to execute cmd: ${cmd}\n output: ${output}")
349 }
350}