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