source: Jenkinsfile@ aa8e8301

ADT arm-eh ast-experimental enum forall-pointer-decay jacob/cs343-translation jenkins-sandbox new-ast new-ast-unique-expr pthread-emulation qualifiedEnum
Last change on this file since aa8e8301 was aa8e8301, checked in by Thierry Delisle <tdelisle@…>, 6 years ago

No longer using node('master') for build

  • Property mode set to 100644
File size: 15.5 KB
Line 
1#!groovy
2
3import groovy.transform.Field
4
5// For skipping stages
6import org.jenkinsci.plugins.pipeline.modeldefinition.Utils
7
8//===========================================================================================================
9// Main loop of the compilation
10//===========================================================================================================
11
12// Globals
13BuildDir = null
14SrcDir = null
15Settings = null
16StageName = ''
17
18// Local variables
19def err = null
20def log_needed = false
21
22currentBuild.result = "SUCCESS"
23
24try {
25 //Wrap build to add timestamp to command line
26 wrap([$class: 'TimestamperBuildWrapper']) {
27
28 Settings = prepare_build()
29
30 node(Settings.Architecture.node) {
31 BuildDir = pwd tmp: true
32 SrcDir = pwd tmp: false
33
34 clean()
35
36 checkout()
37
38 build()
39
40 test()
41
42 benchmark()
43
44 build_doc()
45
46 publish()
47 }
48 }
49}
50
51//If an exception is caught we need to change the status and remember to
52//attach the build log to the email
53catch (Exception caughtError) {
54 //rethrow error later
55 err = caughtError
56
57 echo err.toString()
58
59 //An error has occured, the build log is relevent
60 log_needed = true
61
62 //Store the result of the build log
63 currentBuild.result = "${StageName} FAILURE".trim()
64}
65
66finally {
67 //Send email with final results if this is not a full build
68 email(log_needed)
69
70 echo 'Build Completed'
71
72 /* Must re-throw exception to propagate error */
73 if (err) {
74 throw err
75 }
76}
77
78//===========================================================================================================
79// Main compilation routines
80//===========================================================================================================
81def clean() {
82 build_stage('Cleanup', true) {
83 // clean the build by wipping the build directory
84 dir(BuildDir) {
85 deleteDir()
86 }
87 }
88}
89
90//Compilation script is done here but environnement set-up and error handling is done in main loop
91def checkout() {
92 build_stage('Checkout', true) {
93 //checkout the source code and clean the repo
94 final scmVars = checkout scm
95 Settings.GitNewRef = scmVars.GIT_COMMIT
96 Settings.GitOldRef = scmVars.GIT_PREVIOUS_COMMIT
97
98 echo GitLogMessage()
99 }
100}
101
102def build() {
103 debug = true
104 release = Settings.RunAllTests || Settings.RunBenchmark
105 build_stage('Build : configure', true) {
106 // Build outside of the src tree to ease cleaning
107 dir (BuildDir) {
108 //Configure the conpilation (Output is not relevant)
109 //Use the current directory as the installation target so nothing escapes the sandbox
110 //Also specify the compiler by hand
111 targets=""
112 if( Settings.RunAllTests || Settings.RunBenchmark ) {
113 targets="--with-target-hosts='host:debug,host:nodebug'"
114 } else {
115 targets="--with-target-hosts='host:debug'"
116 }
117
118 sh "${SrcDir}/configure CXX=${Settings.Compiler.CXX} CC=${Settings.Compiler.CC} ${Settings.Architecture.flags} ${targets} --quiet"
119
120 // Configure libcfa
121 sh 'make -j 8 --no-print-directory configure-libcfa'
122 }
123 }
124
125 build_stage('Build : cfa-cpp', true) {
126 // Build outside of the src tree to ease cleaning
127 dir (BuildDir) {
128 // Build driver
129 sh 'make -j 8 --no-print-directory -C driver'
130
131 // Build translator
132 sh 'make -j 8 --no-print-directory -C src'
133 }
134 }
135
136 build_stage('Build : libcfa(debug)', debug) {
137 // Build outside of the src tree to ease cleaning
138 dir (BuildDir) {
139 sh "make -j 8 --no-print-directory -C libcfa/${Settings.Architecture.name}-debug"
140 }
141 }
142
143 build_stage('Build : libcfa(nodebug)', release) {
144 // Build outside of the src tree to ease cleaning
145 dir (BuildDir) {
146 sh "make -j 8 --no-print-directory -C libcfa/${Settings.Architecture.name}-nodebug"
147 }
148 }
149}
150
151def test() {
152 try {
153 build_stage('Test: short', !Settings.RunAllTests) {
154 dir (BuildDir) {
155 //Run the tests from the tests directory
156 sh "make --no-print-directory -C tests archiveerrors=${BuildDir}/tests/crashes/short"
157 }
158 }
159
160 build_stage('Test: full', Settings.RunAllTests) {
161 dir (BuildDir) {
162 //Run the tests from the tests directory
163 sh """make --no-print-directory -C tests timeouts="--timeout=600 --global-timeout=14400" all-tests debug=yes archiveerrors=${BuildDir}/tests/crashes/full-debug"""
164 sh """make --no-print-directory -C tests timeouts="--timeout=600 --global-timeout=14400" all-tests debug=no archiveerrors=${BuildDir}/tests/crashes/full-nodebug"""
165 }
166 }
167 }
168 catch (Exception err) {
169 echo "Archiving core dumps"
170 dir (BuildDir) {
171 archiveArtifacts artifacts: "tests/crashes/**/*", fingerprint: true
172 }
173 throw err
174 }
175}
176
177def benchmark() {
178 build_stage('Benchmark', Settings.RunBenchmark) {
179 dir (BuildDir) {
180 //Append bench results
181 sh "make --no-print-directory -C benchmark jenkins arch=${Settings.Architecture.name}"
182 }
183 }
184}
185
186def build_doc() {
187 build_stage('Documentation', Settings.BuildDocumentation) {
188 dir ('doc/user') {
189 make_doc()
190 }
191
192 dir ('doc/refrat') {
193 make_doc()
194 }
195 }
196}
197
198def publish() {
199 build_stage('Publish', true) {
200
201 if( Settings.Publish && !Settings.RunBenchmark ) { echo 'No results to publish!!!' }
202
203 def groupCompile = new PlotGroup('Compilation', 'duration (s) - lower is better', true)
204 def groupConcurrency = new PlotGroup('Concurrency', 'duration (n) - lower is better', false)
205
206 //Then publish the results
207 do_plot(Settings.RunBenchmark && Settings.Publish, 'compile' , groupCompile , false, 'Compilation')
208 do_plot(Settings.RunBenchmark && Settings.Publish, 'compile.diff' , groupCompile , true , 'Compilation (relative)')
209 do_plot(Settings.RunBenchmark && Settings.Publish, 'ctxswitch' , groupConcurrency, false, 'Context Switching')
210 do_plot(Settings.RunBenchmark && Settings.Publish, 'ctxswitch.diff', groupConcurrency, true , 'Context Switching (relative)')
211 do_plot(Settings.RunBenchmark && Settings.Publish, 'mutex' , groupConcurrency, false, 'Mutual Exclusion')
212 do_plot(Settings.RunBenchmark && Settings.Publish, 'mutex.diff' , groupConcurrency, true , 'Mutual Exclusion (relative)')
213 do_plot(Settings.RunBenchmark && Settings.Publish, 'signal' , groupConcurrency, false, 'Internal and External Scheduling')
214 do_plot(Settings.RunBenchmark && Settings.Publish, 'signal.diff' , groupConcurrency, true , 'Internal and External Scheduling (relative)')
215 }
216}
217
218//===========================================================================================================
219//Routine responsible of sending the email notification once the build is completed
220//===========================================================================================================
221@NonCPS
222def SplitLines(String text) {
223 def list = []
224
225 text.eachLine {
226 list += it
227 }
228
229 return list
230}
231
232def GitLogMessage() {
233 if (!Settings || !Settings.GitOldRef || !Settings.GitNewRef) return "\nERROR retrieveing git information!\n"
234
235 def oldRef = Settings.GitOldRef
236 def newRef = Settings.GitNewRef
237
238 def revText = sh(returnStdout: true, script: "git rev-list ${oldRef}..${newRef}").trim()
239 def revList = SplitLines( revText )
240
241 def gitUpdate = ""
242 revList.each { rev ->
243 def type = sh(returnStdout: true, script: "git cat-file -t ${rev}").trim()
244 gitUpdate = gitUpdate + " via ${rev} (${type})"
245 }
246
247 def rev = oldRef
248 def type = sh(returnStdout: true, script: "git cat-file -t ${rev}").trim()
249 gitUpdate = gitUpdate + " from ${rev} (${type})"
250
251 def gitLog = sh(returnStdout: true, script: "git rev-list --format=short ${oldRef}...${newRef}").trim()
252
253 def gitDiff = sh(returnStdout: true, script: "git diff --stat --color ${newRef} ${oldRef}").trim()
254 gitDiff = gitDiff.replace('[32m', '<span style="color: #00AA00;">')
255 gitDiff = gitDiff.replace('[31m', '<span style="color: #AA0000;">')
256 gitDiff = gitDiff.replace('[m', '</span>')
257
258 return """
259<pre>
260The branch ${env.BRANCH_NAME} has been updated.
261${gitUpdate}
262</pre>
263
264<p>Check console output at ${env.BUILD_URL} to view the results.</p>
265
266<p>- Status --------------------------------------------------------------</p>
267
268<p>BUILD# ${env.BUILD_NUMBER} - ${currentBuild.result}</p>
269
270<p>- Log -----------------------------------------------------------------</p>
271
272<pre>
273${gitLog}
274</pre>
275
276<p>-----------------------------------------------------------------------</p>
277<pre>
278Summary of changes:
279${gitDiff}
280</pre>
281"""
282}
283
284//Standard build email notification
285def email(boolean log) {
286 //Since tokenizer doesn't work, figure stuff out from the environnement variables and command line
287 //Configurations for email format
288 echo 'Notifying users of result'
289
290 def project_name = (env.JOB_NAME =~ /(.+)\/.+/)[0][1].toLowerCase()
291 def email_subject = "[${project_name} git][BUILD# ${env.BUILD_NUMBER} - ${currentBuild.result}] - branch ${env.BRANCH_NAME}"
292 def email_body = """<p>This is an automated email from the Jenkins build machine. It was
293generated because of a git hooks/post-receive script following
294a ref change which was pushed to the C\u2200 repository.</p>
295""" + GitLogMessage()
296
297 def email_to = !Settings.IsSandbox ? "cforall@lists.uwaterloo.ca" : "tdelisle@uwaterloo.ca"
298
299 if( Settings && !Settings.Silent ) {
300 //send email notification
301 emailext body: email_body, subject: email_subject, to: email_to, attachLog: log
302 } else {
303 echo "Would send email to: ${email_to}"
304 echo "With title: ${email_subject}"
305 echo "Content: \n${email_body}"
306 }
307}
308
309//===========================================================================================================
310// Helper classes/variables/routines
311//===========================================================================================================
312//Description of a compiler (Must be serializable since pipelines are persistent)
313class CC_Desc implements Serializable {
314 public String name
315 public String CXX
316 public String CC
317
318 CC_Desc(String name, String CXX, String CC) {
319 this.name = name
320 this.CXX = CXX
321 this.CC = CC
322 }
323}
324
325//Description of an architecture (Must be serializable since pipelines are persistent)
326class Arch_Desc implements Serializable {
327 public String name
328 public String flags
329 public String node
330
331 Arch_Desc(String name, String flags, String node) {
332 this.name = name
333 this.flags = flags
334 this.node = node
335 }
336}
337
338class BuildSettings implements Serializable {
339 public final CC_Desc Compiler
340 public final Arch_Desc Architecture
341 public final Boolean RunAllTests
342 public final Boolean RunBenchmark
343 public final Boolean BuildDocumentation
344 public final Boolean Publish
345 public final Boolean Silent
346 public final Boolean IsSandbox
347 public final String DescLong
348 public final String DescShort
349
350 public String GitNewRef
351 public String GitOldRef
352
353 BuildSettings(java.util.Collections$UnmodifiableMap param, String branch) {
354 switch( param.Compiler ) {
355 case 'gcc-6':
356 this.Compiler = new CC_Desc('gcc-6', 'g++-6', 'gcc-6')
357 break
358 case 'gcc-5':
359 this.Compiler = new CC_Desc('gcc-5', 'g++-5', 'gcc-5')
360 break
361 case 'gcc-4.9':
362 this.Compiler = new CC_Desc('gcc-4.9', 'g++-4.9', 'gcc-4.9')
363 break
364 case 'clang':
365 this.Compiler = new CC_Desc('clang', 'clang++', 'gcc-6')
366 break
367 default :
368 error "Unhandled compiler : ${cc}"
369 }
370
371 switch( param.Architecture ) {
372 case 'x64':
373 this.Architecture = new Arch_Desc('x64', '--host=x86_64', 'x64')
374 break
375 case 'x86':
376 this.Architecture = new Arch_Desc('x86', '--host=i386', 'x86')
377 break
378 default :
379 error "Unhandled architecture : ${arch}"
380 }
381
382 this.IsSandbox = (branch == "jenkins-sandbox")
383 this.RunAllTests = param.RunAllTests
384 this.RunBenchmark = param.RunBenchmark
385 this.BuildDocumentation = param.BuildDocumentation
386 this.Publish = param.Publish
387 this.Silent = param.Silent
388
389 def full = param.RunAllTests ? " (Full)" : ""
390 this.DescShort = "${ this.Compiler.name }:${ this.Architecture.name }${full}"
391
392 this.DescLong = """Compiler : ${ this.Compiler.name } (${ this.Compiler.CXX }/${ this.Compiler.CC })
393Architecture : ${ this.Architecture.name }
394Arc Flags : ${ this.Architecture.flags }
395Run All Tests : ${ this.RunAllTests.toString() }
396Run Benchmark : ${ this.RunBenchmark.toString() }
397Build Documentation : ${ this.BuildDocumentation.toString() }
398Publish : ${ this.Publish.toString() }
399Silent : ${ this.Silent.toString() }
400"""
401
402 this.GitNewRef = ''
403 this.GitOldRef = ''
404 }
405}
406
407class PlotGroup implements Serializable {
408 public String name
409 public String unit
410 public boolean log
411
412 PlotGroup(String name, String unit, boolean log) {
413 this.name = name
414 this.unit = unit
415 this.log = log
416 }
417}
418
419def prepare_build() {
420 // prepare the properties
421 properties ([ \
422 [$class: 'ParametersDefinitionProperty', \
423 parameterDefinitions: [ \
424 [$class: 'ChoiceParameterDefinition', \
425 description: 'Which compiler to use', \
426 name: 'Compiler', \
427 choices: 'gcc-6\ngcc-5\ngcc-4.9\nclang', \
428 defaultValue: 'gcc-6', \
429 ], \
430 [$class: 'ChoiceParameterDefinition', \
431 description: 'The target architecture', \
432 name: 'Architecture', \
433 choices: 'x64\nx86', \
434 defaultValue: 'x64', \
435 ], \
436 [$class: 'BooleanParameterDefinition', \
437 description: 'If false, only the quick test suite is ran', \
438 name: 'RunAllTests', \
439 defaultValue: false, \
440 ], \
441 [$class: 'BooleanParameterDefinition', \
442 description: 'If true, jenkins also runs benchmarks', \
443 name: 'RunBenchmark', \
444 defaultValue: false, \
445 ], \
446 [$class: 'BooleanParameterDefinition', \
447 description: 'If true, jenkins also builds documentation', \
448 name: 'BuildDocumentation', \
449 defaultValue: true, \
450 ], \
451 [$class: 'BooleanParameterDefinition', \
452 description: 'If true, jenkins also publishes results', \
453 name: 'Publish', \
454 defaultValue: false, \
455 ], \
456 [$class: 'BooleanParameterDefinition', \
457 description: 'If true, jenkins will not send emails', \
458 name: 'Silent', \
459 defaultValue: false, \
460 ], \
461 ],
462 ]])
463
464 // It's unfortunate but it looks like we need to checkout the entire repo just to get the pretty git printer
465 checkout scm
466
467 final settings = new BuildSettings(params, env.BRANCH_NAME)
468
469 currentBuild.description = settings.DescShort
470 echo settings.DescLong
471
472 return settings
473}
474
475def build_stage(String name, boolean run, Closure block ) {
476 StageName = name
477 echo " -------- ${StageName} -------- "
478 if(run) {
479 stage(name, block)
480 } else {
481 stage(name) { Utils.markStageSkippedForConditional(STAGE_NAME) }
482 }
483}
484
485def make_doc() {
486 def err = null
487 try {
488 sh 'make clean > /dev/null'
489 sh 'make > /dev/null 2>&1'
490 }
491 catch (Exception caughtError) {
492 err = caughtError //rethrow error later
493 sh 'cat build/*.log'
494 }
495 finally {
496 if (err) throw err // Must re-throw exception to propagate error
497 }
498}
499
500def do_plot(boolean new_data, String file, PlotGroup group, boolean relative, String title) {
501
502 if(new_data) {
503 echo "Publishing new data"
504 }
505
506 def series = new_data ? [[
507 file: "${file}.csv",
508 exclusionValues: '',
509 displayTableFlag: false,
510 inclusionFlag: 'OFF',
511 url: ''
512 ]] : [];
513
514 echo "file is ${BuildDir}/benchmark/${file}.csv, group ${group}, title ${title}"
515 dir("${BuildDir}/benchmark/") {
516 plot csvFileName: "cforall-${env.BRANCH_NAME}-${file}.csv",
517 csvSeries: series,
518 group: "${group.name}",
519 title: "${title}",
520 style: 'lineSimple',
521 exclZero: false,
522 keepRecords: false,
523 logarithmic: !relative && group.log,
524 numBuilds: '120',
525 useDescr: true,
526 yaxis: group.unit,
527 yaxisMaximum: '',
528 yaxisMinimum: ''
529 }
530}
Note: See TracBrowser for help on using the repository browser.