source: Jenkinsfile@ e966ec0

ADT aaron-thesis arm-eh ast-experimental cleanup-dtors deferred_resn demangler enum forall-pointer-decay jacob/cs343-translation jenkins-sandbox new-ast new-ast-unique-expr no_list persistent-indexer pthread-emulation qualifiedEnum
Last change on this file since e966ec0 was e966ec0, checked in by Thierry Delisle <tdelisle@…>, 7 years ago

better error handling

  • Property mode set to 100644
File size: 12.4 KB
Line 
1#!groovy
2
3//===========================================================================================================
4// Main loop of the compilation
5//===========================================================================================================
6node ('master'){
7
8 def err = null
9 def log_needed = false
10
11 Settings = null
12
13 stage_name = ''
14
15 gitRefOldValue = ''
16 gitRefNewValue = ''
17
18 builddir = pwd tmp: true
19 srcdir = pwd tmp: false
20
21 currentBuild.result = "SUCCESS"
22
23 try {
24 //Wrap build to add timestamp to command line
25 wrap([$class: 'TimestamperBuildWrapper']) {
26
27 notify_server(0)
28
29 Settings = prepare_build()
30
31 clean()
32
33 checkout()
34
35 notify_server(0)
36
37 build()
38
39 test()
40
41 benchmark()
42
43 build_doc()
44
45 publish()
46
47 notify_server(45)
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
53 catch (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 = "${stage_name} FAILURE".trim()
64 }
65
66 finally {
67 //Send email with final results if this is not a full build
68 if( Settings && !Settings.Silent ) {
69 echo 'Notifying users of result'
70 email(currentBuild.result, log_needed, bIsSandbox)
71 }
72
73 echo 'Build Completed'
74
75 /* Must re-throw exception to propagate error */
76 if (err) {
77 throw err
78 }
79 }
80}
81
82//===========================================================================================================
83// Helper classes/variables/routines
84//===========================================================================================================
85class BuildSettings implements Serializable {
86 public final CC_Desc Compiler
87 public final Arch_Desc Architecture
88 public final Boolean RunAllTests
89 public final Boolean RunBenchmark
90 public final Boolean BuildDocumentation
91 public final Boolean Publish
92 public final Boolean Silent
93 public final Boolean IsSandbox
94 public final String Branch
95 public final String Commit
96 public final String PrevCommit
97 public final String RepoUrl
98 public final String DescLong
99 public final String DescShort
100
101 BuildSettings(java.util.Collections$UnmodifiableMap param, java.util.TreeMap scmVars) {
102 echo "${env}"
103
104 this.Compiler = compiler_from_params( params.Compiler )
105 this.Architecture = architecture_from_params( params.Architecture )
106 this.RunAllTests = params.RunAllTests
107 this.RunBenchmark = params.RunBenchmark
108 this.BuildDocumentation = params.BuildDocumentation
109 this.Publish = params.Publish
110 this.Silent = params.Silent
111 this.IsSandbox = scmVars.GIT_BRANCH == "jenkins-sandbox"
112 this.Branch = scmVars.GIT_BRANCH
113 this.Commit = scmVars.GIT_COMMIT
114 this.PrevCommit = scmVars.GIT_PREVIOUS_COMMIT
115 this.RepoUrl = scmVars.GIT_URL
116
117 def full = params.RunAllTests ? " (Full)" : ""
118 this.DescShort = "${ this.Compiler.cc_name }:${ this.Architecture.name }${full}"
119
120 this.DescLong """Compiler : ${ this.Compiler.cc_name } (${ this.Compiler.cpp_cc }/${ this.Compiler.cfa_cc })
121Architecture : ${ this.Architecture.name }
122Arc Flags : ${ this.Architecture.flags }
123Run All Tests : ${ this.RunAllTests.toString() }
124Run Benchmark : ${ this.RunBenchmark.toString() }
125Build Documentation : ${ this.BuildDocumentation.toString() }
126Publish : ${ this.Publish.toString() }
127Silent : ${ this.Silent.toString() }
128"""
129 }
130}
131
132def prepare_build() {
133 // prepare the properties
134 properties ([ \
135 [$class: 'ParametersDefinitionProperty', \
136 parameterDefinitions: [ \
137 [$class: 'ChoiceParameterDefinition', \
138 description: 'Which compiler to use', \
139 name: 'Compiler', \
140 choices: 'gcc-6\ngcc-5\ngcc-4.9\nclang', \
141 defaultValue: 'gcc-6', \
142 ], \
143 [$class: 'ChoiceParameterDefinition', \
144 description: 'The target architecture', \
145 name: 'Architecture', \
146 choices: 'x64\nx86', \
147 defaultValue: 'x64', \
148 ], \
149 [$class: 'BooleanParameterDefinition', \
150 description: 'If false, only the quick test suite is ran', \
151 name: 'RunAllTests', \
152 defaultValue: false, \
153 ], \
154 [$class: 'BooleanParameterDefinition', \
155 description: 'If true, jenkins also runs benchmarks', \
156 name: 'RunBenchmark', \
157 defaultValue: false, \
158 ], \
159 [$class: 'BooleanParameterDefinition', \
160 description: 'If true, jenkins also builds documentation', \
161 name: 'BuildDocumentation', \
162 defaultValue: true, \
163 ], \
164 [$class: 'BooleanParameterDefinition', \
165 description: 'If true, jenkins also publishes results', \
166 name: 'Publish', \
167 defaultValue: false, \
168 ], \
169 [$class: 'BooleanParameterDefinition', \
170 description: 'If true, jenkins will not send emails', \
171 name: 'Silent', \
172 defaultValue: false, \
173 ], \
174 ],
175 ]])
176
177 // Collect git information
178 final scmVars = checkout scm
179
180 final settings = new BuildSettings(params, scmVars)
181
182 currentBuild.description = settings.DescShort
183 echo settings.DescLong
184
185 return settings
186}
187
188def build_stage(String name, Closure block ) {
189 stage_name = name
190 stage(name, block)
191}
192
193def notify_server(int wait) {
194 sh """curl --silent --show-error --data "wait=${wait}" -X POST https://cforall.uwaterloo.ca:8082/jenkins/notify > /dev/null || true"""
195 return
196}
197
198def make_doc() {
199 def err = null
200 try {
201 sh 'make clean > /dev/null'
202 sh 'make > /dev/null 2>&1'
203 }
204 catch (Exception caughtError) {
205 err = caughtError //rethrow error later
206 sh 'cat *.log'
207 }
208 finally {
209 if (err) throw err // Must re-throw exception to propagate error
210 }
211}
212
213//Description of a compiler (Must be serializable since pipelines are persistent)
214class CC_Desc implements Serializable {
215 public String cc_name
216 public String cpp_cc
217 public String cfa_cc
218
219 CC_Desc(String cc_name, String cpp_cc, String cfa_cc) {
220 this.cc_name = cc_name
221 this.cpp_cc = cpp_cc
222 this.cfa_cc = cfa_cc
223 }
224}
225
226def compiler_from_params(cc) {
227 switch( cc ) {
228 case 'gcc-6':
229 return new CC_Desc('gcc-6', 'g++-6', 'gcc-6')
230 break
231 case 'gcc-5':
232 return new CC_Desc('gcc-5', 'g++-5', 'gcc-5')
233 break
234 case 'gcc-4.9':
235 return new CC_Desc('gcc-4.9', 'g++-4.9', 'gcc-4.9')
236 break
237 case 'clang':
238 return new CC_Desc('clang', 'clang++', 'gcc-6')
239 break
240 default :
241 error "Unhandled compiler : ${cc}"
242 }
243}
244
245//Description of an architecture (Must be serializable since pipelines are persistent)
246class Arch_Desc implements Serializable {
247 public String name
248 public String flags
249
250 Arch_Desc(String name, String flags) {
251 this.name = name
252 this.flags = flags
253 }
254}
255
256def architecture_from_params( arch ) {
257 switch( arch ) {
258 case 'x64':
259 return new Arch_Desc('x64', '--host=x86_64')
260 break
261 case 'x86':
262 return new Arch_Desc('x86', '--host=i386')
263 break
264 default :
265 error "Unhandled architecture : ${arch}"
266 }
267}
268
269//===========================================================================================================
270// Main compilation routines
271//===========================================================================================================
272def clean() {
273 build_stage('Cleanup') {
274 // clean the build by wipping the build directory
275 dir(builddir) {
276 deleteDir()
277 }
278
279 //Clean all temporary files to make sure no artifacts of the previous build remain
280 sh 'git clean -fdqx'
281
282 //Reset the git repo so no local changes persist
283 sh 'git reset --hard'
284 }
285}
286
287//Compilation script is done here but environnement set-up and error handling is done in main loop
288def checkout() {
289 build_stage('Checkout') {
290 //checkout the source code and clean the repo
291 checkout scm
292 }
293}
294
295def build() {
296 build_stage('Build') {
297 // Build outside of the src tree to ease cleaning
298 dir (builddir) {
299 //Configure the conpilation (Output is not relevant)
300 //Use the current directory as the installation target so nothing escapes the sandbox
301 //Also specify the compiler by hand
302 targets=""
303 if( Settings.RunAllTests ) {
304 targets="--with-target-hosts='host:debug,host:nodebug'"
305 } else {
306 targets="--with-target-hosts='host:debug'"
307 }
308
309 sh "${srcdir}/configure CXX=${Settings.Compiler.cpp_cc} ${Settings.Architecture.flags} ${targets} --with-backend-compiler=${Settings.Compiler.cfa_cc} --quiet"
310
311 //Compile the project
312 sh 'make -j 8 --no-print-directory'
313 }
314 }
315}
316
317def test() {
318 build_stage('Test') {
319
320 dir (builddir) {
321 //Run the tests from the tests directory
322 if ( Settings.RunAllTests ) {
323 sh 'make --no-print-directory -C tests all-tests debug=yes'
324 sh 'make --no-print-directory -C tests all-tests debug=no '
325 }
326 else {
327 sh 'make --no-print-directory -C tests'
328 }
329 }
330 }
331}
332
333def benchmark() {
334 build_stage('Benchmark') {
335
336 if( !Settings.RunBenchmark ) return
337
338 dir (builddir) {
339 //Append bench results
340 sh "make --no-print-directory -C benchmark jenkins githash=${gitRefNewValue} arch=${Settings.Architecture} | tee ${srcdir}/bench.json"
341 }
342 }
343}
344
345def build_doc() {
346 build_stage('Documentation') {
347
348 if( !Settings.BuildDocumentation ) return
349
350 dir ('doc/user') {
351 make_doc()
352 }
353
354 dir ('doc/refrat') {
355 make_doc()
356 }
357 }
358}
359
360def publish() {
361 build_stage('Publish') {
362
363 if( !Settings.Publish ) return
364
365 //Then publish the results
366 sh 'curl --silent --show-error -H \'Content-Type: application/json\' --data @bench.json https://cforall.uwaterloo.ca:8082/jenkins/publish > /dev/null || true'
367 }
368}
369
370//===========================================================================================================
371//Routine responsible of sending the email notification once the build is completed
372//===========================================================================================================
373def gitBranchUpdate(String gitRefOldValue, String gitRefNewValue) {
374 def update = ""
375 sh "git rev-list ${gitRefOldValue}..${gitRefNewValue} > GIT_LOG";
376 readFile('GIT_LOG').eachLine { rev ->
377 sh "git cat-file -t ${rev} > GIT_TYPE"
378 def type = readFile('GIT_TYPE')
379
380 update += " via ${rev} (${type})\n"
381 }
382 def rev = gitRefOldValue
383 sh "git cat-file -t ${rev} > GIT_TYPE"
384 def type = readFile('GIT_TYPE')
385
386 update += " from ${rev} (${type})\n"
387 return update
388
389def output=readFile('result').trim()
390echo "output=$output";
391}
392
393//Standard build email notification
394def email(String status, boolean log, boolean bIsSandbox) {
395 //Since tokenizer doesn't work, figure stuff out from the environnement variables and command line
396 //Configurations for email format
397 def project_name = (env.JOB_NAME =~ /(.+)\/.+/)[0][1].toLowerCase()
398
399 def gitLog = 'Error retrieving git logs'
400 def gitDiff = 'Error retrieving git diff'
401 def gitUpdate = 'Error retrieving update'
402
403 try {
404 gitUpdate = gitBranchUpdate(Settings.PrevCommit, Settings.Commit)
405
406 sh "git rev-list --format=short ${Settings.PrevCommit}...${Settings.Commit} > GIT_LOG"
407 gitLog = readFile('GIT_LOG')
408
409 sh "git diff --stat ${Settings.Commit} ${Settings.PrevCommit} > GIT_DIFF"
410 gitDiff = readFile('GIT_DIFF')
411 }
412 catch (Exception error) {
413 echo error.toString()
414 echo error.getMessage()
415 }
416
417 def email_subject = "[${project_name} git][BUILD# ${env.BUILD_NUMBER} - ${status}] - branch ${env.BRANCH_NAME}"
418 def email_body = """This is an automated email from the Jenkins build machine. It was
419generated because of a git hooks/post-receive script following
420a ref change was pushed to the repository containing
421the project "UNNAMED PROJECT".
422
423The branch ${env.BRANCH_NAME} has been updated.
424${gitUpdate}
425
426Check console output at ${env.BUILD_URL} to view the results.
427
428- Status --------------------------------------------------------------
429
430BUILD# ${env.BUILD_NUMBER} - ${status}
431
432- Log -----------------------------------------------------------------
433${gitLog}
434-----------------------------------------------------------------------
435Summary of changes:
436${gitDiff}
437"""
438
439 def email_to = "cforall@lists.uwaterloo.ca"
440
441 if( !bIsSandbox ) {
442 //send email notification
443 emailext body: email_body, subject: email_subject, to: email_to, attachLog: log
444 } else {
445 echo "Would send email to: ${email_to}"
446 echo "With title: ${email_subject}"
447 echo "Content: \n${email_body}"
448 }
449}
Note: See TracBrowser for help on using the repository browser.