blob: 8da0f3e7bdfe56699038209f66769ac6a9b786d3 [file] [log] [blame]
Jakub Josef79ecec32017-02-17 14:36:28 +01001package com.mirantis.mk
2
Jakub Josefb41c8d52017-03-24 13:52:24 +01003import static groovy.json.JsonOutput.prettyPrint
4import static groovy.json.JsonOutput.toJson
Jakub Josef79ecec32017-02-17 14:36:28 +01005/**
6 *
7 * Common functions
8 *
9 */
10
11/**
12 * Generate current timestamp
13 *
14 * @param format Defaults to yyyyMMddHHmmss
15 */
16def getDatetime(format="yyyyMMddHHmmss") {
17 def now = new Date();
18 return now.format(format, TimeZone.getTimeZone('UTC'));
19}
20
21/**
Jakub Josef79ecec32017-02-17 14:36:28 +010022 * Return workspace.
23 * Currently implemented by calling pwd so it won't return relevant result in
24 * dir context
25 */
26def getWorkspace() {
27 def workspace = sh script: 'pwd', returnStdout: true
28 workspace = workspace.trim()
29 return workspace
30}
31
32/**
Filip Pytloun81c864d2017-03-21 15:19:30 +010033 * Get UID of jenkins user.
34 * Must be run from context of node
35 */
36def getJenkinsUid() {
37 return sh (
38 script: 'id -u',
39 returnStdout: true
40 ).trim()
41}
42
43/**
44 * Get GID of jenkins user.
45 * Must be run from context of node
46 */
47def getJenkinsGid() {
48 return sh (
49 script: 'id -g',
50 returnStdout: true
51 ).trim()
52}
53
54/**
Jakub Josef79ecec32017-02-17 14:36:28 +010055 * Get credentials from store
56 *
57 * @param id Credentials name
58 */
Jakub Josef3d9d9ab2017-03-14 15:09:03 +010059def getCredentials(id, cred_type = "username_password") {
60 def credClass;
61 if(cred_type == "username_password"){
62 credClass = com.cloudbees.plugins.credentials.common.StandardUsernamePasswordCredentials.class
63 }else if(cred_type == "key"){
64 credClass = com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey.class
65 }
Jakub Josef79ecec32017-02-17 14:36:28 +010066 def creds = com.cloudbees.plugins.credentials.CredentialsProvider.lookupCredentials(
Jakub Josef3d9d9ab2017-03-14 15:09:03 +010067 credClass,
Jakub Josef79ecec32017-02-17 14:36:28 +010068 jenkins.model.Jenkins.instance
69 )
70
71 for (Iterator<String> credsIter = creds.iterator(); credsIter.hasNext();) {
72 c = credsIter.next();
73 if ( c.id == id ) {
74 return c;
75 }
76 }
77
78 throw new Exception("Could not find credentials for ID ${id}")
79}
80
81/**
82 * Abort build, wait for some time and ensure we will terminate
83 */
84def abortBuild() {
85 currentBuild.build().doStop()
86 sleep(180)
87 // just to be sure we will terminate
88 throw new InterruptedException()
89}
90
91/**
Jakub Josefb41c8d52017-03-24 13:52:24 +010092 * Return pretty-printed string representation of given item
93 * @param item item to be pretty-printed (list, map, whatever)
94 * @return pretty-printed string
95 */
96def prettyPrint(item){
97 return prettyPrint(toJson(item)).replace('\\n', System.getProperty('line.separator'))
98}
99
100/**
Jakub Josef79ecec32017-02-17 14:36:28 +0100101 * Print informational message
102 *
103 * @param msg
104 * @param color Colorful output or not
105 */
106def infoMsg(msg, color = true) {
107 printMsg(msg, "cyan")
108}
109
110/**
111 * Print error message
112 *
113 * @param msg
114 * @param color Colorful output or not
115 */
116def errorMsg(msg, color = true) {
117 printMsg(msg, "red")
118}
119
120/**
121 * Print success message
122 *
123 * @param msg
124 * @param color Colorful output or not
125 */
126def successMsg(msg, color = true) {
127 printMsg(msg, "green")
128}
129
130/**
131 * Print warning message
132 *
133 * @param msg
134 * @param color Colorful output or not
135 */
136def warningMsg(msg, color = true) {
Jakub Josef0e7bd632017-03-16 16:25:05 +0100137 printMsg(msg, "yellow")
Jakub Josef79ecec32017-02-17 14:36:28 +0100138}
139
140/**
Jakub Josef952ae0b2017-03-14 19:04:21 +0100141 * Print debug message, this message will show only if DEBUG global variable is present
142 * @param msg
143 * @param color Colorful output or not
144 */
145def debugMsg(msg, color = true){
146 def debugEnabled
147 try {
148 debugEnabled = DEBUG
149 } catch (MissingPropertyException e) {
150 debugEnabled = false
151 }
152 if(debugEnabled){
Jakub Josef74b34692017-03-15 12:10:57 +0100153 printMsg("[DEBUG] ${msg}", "red")
Jakub Josef952ae0b2017-03-14 19:04:21 +0100154 }
155}
156
157/**
Jakub Josef79ecec32017-02-17 14:36:28 +0100158 * Print message
159 *
160 * @param msg Message to be printed
161 * @param level Level of message (default INFO)
162 * @param color Color to use for output or false (default)
163 */
164def printMsg(msg, color = false) {
165 colors = [
166 'red' : '\u001B[31m',
167 'black' : '\u001B[30m',
168 'green' : '\u001B[32m',
169 'yellow': '\u001B[33m',
170 'blue' : '\u001B[34m',
171 'purple': '\u001B[35m',
172 'cyan' : '\u001B[36m',
173 'white' : '\u001B[37m',
174 'reset' : '\u001B[0m'
175 ]
176 if (color != false) {
177 wrap([$class: 'AnsiColorBuildWrapper']) {
178 print "${colors[color]}${msg}${colors.reset}"
179 }
180 } else {
181 print "[${level}] ${msg}"
182 }
183}
184
185/**
186 * Traverse directory structure and return list of files
187 *
188 * @param path Path to search
189 * @param type Type of files to search (groovy.io.FileType.FILES)
190 */
191@NonCPS
192def getFiles(path, type=groovy.io.FileType.FILES) {
193 files = []
194 new File(path).eachFile(type) {
195 files[] = it
196 }
197 return files
198}
199
200/**
201 * Helper method to convert map into form of list of [key,value] to avoid
202 * unserializable exceptions
203 *
204 * @param m Map
205 */
206@NonCPS
207def entries(m) {
208 m.collect {k, v -> [k, v]}
209}
210
211/**
212 * Opposite of build-in parallel, run map of steps in serial
213 *
214 * @param steps Map of String<name>: CPSClosure2<step>
215 */
216def serial(steps) {
217 stepsArray = entries(steps)
218 for (i=0; i < stepsArray.size; i++) {
219 s = stepsArray[i]
220 dummySteps = ["${s[0]}": s[1]]
221 parallel dummySteps
222 }
223}
224
225/**
226 * Get password credentials from store
227 *
228 * @param id Credentials name
229 */
230def getPasswordCredentials(id) {
231 def creds = com.cloudbees.plugins.credentials.CredentialsProvider.lookupCredentials(
232 com.cloudbees.plugins.credentials.common.StandardUsernamePasswordCredentials.class,
233 jenkins.model.Jenkins.instance
234 )
235
236 for (Iterator<String> credsIter = creds.iterator(); credsIter.hasNext();) {
237 c = credsIter.next();
238 if ( c.id == id ) {
239 return c;
240 }
241 }
242
243 throw new Exception("Could not find credentials for ID ${id}")
244}
245
246/**
247 * Get SSH credentials from store
248 *
249 * @param id Credentials name
250 */
251def getSshCredentials(id) {
252 def creds = com.cloudbees.plugins.credentials.CredentialsProvider.lookupCredentials(
253 com.cloudbees.plugins.credentials.common.StandardUsernameCredentials.class,
254 jenkins.model.Jenkins.instance
255 )
256
257 for (Iterator<String> credsIter = creds.iterator(); credsIter.hasNext();) {
258 c = credsIter.next();
259 if ( c.id == id ) {
260 return c;
261 }
262 }
263
264 throw new Exception("Could not find credentials for ID ${id}")
265}
Jakub Josef79ecec32017-02-17 14:36:28 +0100266
267/**
268 * Tests Jenkins instance for existence of plugin with given name
269 * @param pluginName plugin short name to test
270 * @return boolean result
271 */
272@NonCPS
273def jenkinsHasPlugin(pluginName){
274 return Jenkins.instance.pluginManager.plugins.collect{p -> p.shortName}.contains(pluginName)
275}
276
277@NonCPS
278def _needNotification(notificatedTypes, buildStatus, jobName) {
279 if(notificatedTypes && notificatedTypes.contains("onchange")){
280 if(jobName){
281 def job = Jenkins.instance.getItem(jobName)
282 def numbuilds = job.builds.size()
283 if (numbuilds > 0){
284 //actual build is first for some reasons, so last finished build is second
285 def lastBuild = job.builds[1]
286 if(lastBuild){
287 if(lastBuild.result.toString().toLowerCase().equals(buildStatus)){
288 println("Build status didn't changed since last build, not sending notifications")
289 return false;
290 }
291 }
292 }
293 }
294 }else if(!notificatedTypes.contains(buildStatus)){
295 return false;
296 }
297 return true;
298}
299
300/**
301 * Send notification to all enabled notifications services
302 * @param buildStatus message type (success, warning, error), null means SUCCESSFUL
303 * @param msgText message text
304 * @param enabledNotifications list of enabled notification types, types: slack, hipchat, email, default empty
305 * @param notificatedTypes types of notifications will be sent, default onchange - notificate if current build result not equal last result;
306 * otherwise use - ["success","unstable","failed"]
307 * @param jobName optional job name param, if empty env.JOB_NAME will be used
308 * @param buildNumber build number param, if empty env.JOB_NAME will be used
309 * @param buildUrl build url param, if empty env.JOB_NAME will be used
310 * @param mailFrom mail FROM param, if empty "jenkins" will be used, it's mandatory for sending email notifications
311 * @param mailTo mail TO param, it's mandatory for sending email notifications
312 */
313def sendNotification(buildStatus, msgText="", enabledNotifications = [], notificatedTypes=["onchange"], jobName=null, buildNumber=null, buildUrl=null, mailFrom="jenkins", mailTo=null){
314 // Default values
315 def colorName = 'blue'
316 def colorCode = '#0000FF'
317 def buildStatusParam = buildStatus != null && buildStatus != "" ? buildStatus : "SUCCESS"
318 def jobNameParam = jobName != null && jobName != "" ? jobName : env.JOB_NAME
319 def buildNumberParam = buildNumber != null && buildNumber != "" ? buildNumber : env.BUILD_NUMBER
320 def buildUrlParam = buildUrl != null && buildUrl != "" ? buildUrl : env.BUILD_URL
321 def subject = "${buildStatusParam}: Job '${jobNameParam} [${buildNumberParam}]'"
322 def summary = "${subject} (${buildUrlParam})"
323
324 if(msgText != null && msgText != ""){
325 summary+="\n${msgText}"
326 }
327 if(buildStatusParam.toLowerCase().equals("success")){
328 colorCode = "#00FF00"
329 colorName = "green"
330 }else if(buildStatusParam.toLowerCase().equals("unstable")){
331 colorCode = "#FFFF00"
332 colorName = "yellow"
333 }else if(buildStatusParam.toLowerCase().equals("failure")){
334 colorCode = "#FF0000"
335 colorName = "red"
336 }
337 if(_needNotification(notificatedTypes, buildStatusParam.toLowerCase(), jobNameParam)){
338 if(enabledNotifications.contains("slack") && jenkinsHasPlugin("slack")){
339 try{
340 slackSend color: colorCode, message: summary
341 }catch(Exception e){
342 println("Calling slack plugin failed")
343 e.printStackTrace()
344 }
345 }
346 if(enabledNotifications.contains("hipchat") && jenkinsHasPlugin("hipchat")){
347 try{
348 hipchatSend color: colorName.toUpperCase(), message: summary
349 }catch(Exception e){
350 println("Calling hipchat plugin failed")
351 e.printStackTrace()
352 }
353 }
354 if(enabledNotifications.contains("email") && mailTo != null && mailTo != "" && mailFrom != null && mailFrom != ""){
355 try{
356 mail body: summary, from: mailFrom, subject: subject, to: mailTo
357 }catch(Exception e){
358 println("Sending mail plugin failed")
359 e.printStackTrace()
360 }
361 }
362 }
Filip Pytloun49d66302017-03-06 10:26:22 +0100363}
chnyda4e5ac792017-03-14 15:24:18 +0100364
365/**
366 * Execute linux command and catch nth element
367 * @param cmd command to execute
368 * @param index index to retrieve
369 * @return index-th element
370 */
371
372def cutOrDie(cmd, index)
373{
374 def common = new com.mirantis.mk.Common()
375 def output
376 try {
377 output = sh(script: cmd, returnStdout: true)
378 def result = output.tokenize(" ")[index]
379 return result;
380 } catch (Exception e) {
381 common.errorMsg("Failed to execute cmd: ${cmd}\n output: ${output}")
382 }
Filip Pytloun81c864d2017-03-21 15:19:30 +0100383}
Tomáš Kukrál767dd732017-03-23 10:38:59 +0100384
385/**
386 * Check variable contains keyword
387 * @param variable keywork is searched (contains) here
388 * @param keyword string to look for
389 * @return True if variable contains keyword (case insensitive), False if do not contains or any of input isn't a string
390 */
391
392def checkContains(variable, keyword) {
Jakub Josef7a8dea22017-03-23 19:51:32 +0100393 if(env.getEnvironment().containsKey(variable)){
394 return env[variable] && env[variable].toLowerCase().contains(keyword.toLowerCase())
Tomáš Kukrál767dd732017-03-23 10:38:59 +0100395 } else {
Tomáš Kukrálc76c1e02017-03-23 19:06:59 +0100396 return false
Tomáš Kukrál767dd732017-03-23 10:38:59 +0100397 }
398}
Jakub Josefa877db52017-04-05 14:22:30 +0200399
400/**
401 * Parse JSON string to hashmap
402 * @param jsonString input JSON string
403 * @return created hashmap
404 */
405def parseJSON(jsonString){
406 def m = [:]
407 def lazyMap = new JsonSlurper().parseText(output)
408 m.putAll(lazyMap)
409 return m
410}