source: Jenkinsfile @ e966ec0

ADTaaron-thesisarm-ehast-experimentalcleanup-dtorsdeferred_resndemanglerenumforall-pointer-decayjacob/cs343-translationjenkins-sandboxnew-astnew-ast-unique-exprno_listpersistent-indexerpthread-emulationqualifiedEnum
Last change on this file since e966ec0 was e966ec0, checked in by Thierry Delisle <tdelisle@…>, 6 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.