source: Jenkinsfile@ 94c9b810

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 94c9b810 was 94c9b810, checked in by Thierry Delisle <tdelisle@…>, 7 years ago

I though classes where like java...

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