source: Jenkinsfile@ d2c58be

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

Trying to eliminate redundant checkouts

  • 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 BuildSettings(java.util.Collections$UnmodifiableMap param, java.util.TreeMap scmVars) {
126 switch( param.Compiler ) {
127 case 'gcc-6':
128 this.Compiler = new CC_Desc('gcc-6', 'g++-6', 'gcc-6')
129 break
130 case 'gcc-5':
131 this.Compiler = new CC_Desc('gcc-5', 'g++-5', 'gcc-5')
132 break
133 case 'gcc-4.9':
134 this.Compiler = new CC_Desc('gcc-4.9', 'g++-4.9', 'gcc-4.9')
135 break
136 case 'clang':
137 this.Compiler = new CC_Desc('clang', 'clang++', 'gcc-6')
138 break
139 default :
140 error "Unhandled compiler : ${cc}"
141 }
142
143 switch( param.Architecture ) {
144 case 'x64':
145 this.Architecture = new Arch_Desc('x64', '--host=x86_64')
146 break
147 case 'x86':
148 this.Architecture = new Arch_Desc('x86', '--host=i386')
149 break
150 default :
151 error "Unhandled architecture : ${arch}"
152 }
153
154 this.RunAllTests = param.RunAllTests
155 this.RunBenchmark = param.RunBenchmark
156 this.BuildDocumentation = param.BuildDocumentation
157 this.Publish = param.Publish
158 this.Silent = param.Silent
159 this.IsSandbox = scmVars.GIT_BRANCH == "jenkins-sandbox"
160 this.Branch = scmVars.GIT_BRANCH
161 this.Commit = scmVars.GIT_COMMIT
162 this.PrevCommit = scmVars.GIT_PREVIOUS_COMMIT
163 this.RepoUrl = scmVars.GIT_URL
164
165 def full = param.RunAllTests ? " (Full)" : ""
166 this.DescShort = "${ this.Compiler.cc_name }:${ this.Architecture.name }${full}"
167
168 this.DescLong = """Compiler : ${ this.Compiler.cc_name } (${ this.Compiler.cpp_cc }/${ this.Compiler.cfa_cc })
169Architecture : ${ this.Architecture.name }
170Arc Flags : ${ this.Architecture.flags }
171Run All Tests : ${ this.RunAllTests.toString() }
172Run Benchmark : ${ this.RunBenchmark.toString() }
173Build Documentation : ${ this.BuildDocumentation.toString() }
174Publish : ${ this.Publish.toString() }
175Silent : ${ this.Silent.toString() }
176"""
177 }
178}
179
180def prepare_build() {
181 // prepare the properties
182 properties ([ \
183 [$class: 'ParametersDefinitionProperty', \
184 parameterDefinitions: [ \
185 [$class: 'ChoiceParameterDefinition', \
186 description: 'Which compiler to use', \
187 name: 'Compiler', \
188 choices: 'gcc-6\ngcc-5\ngcc-4.9\nclang', \
189 defaultValue: 'gcc-6', \
190 ], \
191 [$class: 'ChoiceParameterDefinition', \
192 description: 'The target architecture', \
193 name: 'Architecture', \
194 choices: 'x64\nx86', \
195 defaultValue: 'x64', \
196 ], \
197 [$class: 'BooleanParameterDefinition', \
198 description: 'If false, only the quick test suite is ran', \
199 name: 'RunAllTests', \
200 defaultValue: false, \
201 ], \
202 [$class: 'BooleanParameterDefinition', \
203 description: 'If true, jenkins also runs benchmarks', \
204 name: 'RunBenchmark', \
205 defaultValue: false, \
206 ], \
207 [$class: 'BooleanParameterDefinition', \
208 description: 'If true, jenkins also builds documentation', \
209 name: 'BuildDocumentation', \
210 defaultValue: true, \
211 ], \
212 [$class: 'BooleanParameterDefinition', \
213 description: 'If true, jenkins also publishes results', \
214 name: 'Publish', \
215 defaultValue: false, \
216 ], \
217 [$class: 'BooleanParameterDefinition', \
218 description: 'If true, jenkins will not send emails', \
219 name: 'Silent', \
220 defaultValue: false, \
221 ], \
222 ],
223 ]])
224
225 // Collect git information
226 final scmVars = checkout scm
227
228 echo env.CHANGE_ID
229 echo env.CHANGE_URL
230 echo env.CHANGE_TITLE
231 echo env.CHANGE_AUTHOR
232 echo env.CHANGE_AUTHOR_DISPLAY_NAME
233 echo env.CHANGE_AUTHOR_EMAIL
234 echo env.CHANGE_TARGET
235
236 final settings = new BuildSettings(params, scmVars)
237
238 currentBuild.description = settings.DescShort
239 echo settings.DescLong
240
241 return settings
242}
243
244def build_stage(String name, Closure block ) {
245 stage_name = name
246 stage(name, block)
247}
248
249def notify_server(int wait) {
250 sh """curl --silent --show-error --data "wait=${wait}" -X POST https://cforall.uwaterloo.ca:8082/jenkins/notify > /dev/null || true"""
251 return
252}
253
254def make_doc() {
255 def err = null
256 try {
257 sh 'make clean > /dev/null'
258 sh 'make > /dev/null 2>&1'
259 }
260 catch (Exception caughtError) {
261 err = caughtError //rethrow error later
262 sh 'cat *.log'
263 }
264 finally {
265 if (err) throw err // Must re-throw exception to propagate error
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.