source: Jenkinsfile@ e507c11

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

Jenkins now builds translator and libraries in several steps to improve stage view in jenkins

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