source: Jenkinsfile @ ddee972

arm-ehjacob/cs343-translationjenkins-sandboxnew-astnew-ast-unique-expr
Last change on this file since ddee972 was ddee972, checked in by Thierry Delisle <tdelisle@…>, 2 years ago

Small syntax fix

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