source: Jenkinsfile @ aa8e8301

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

No longer using node('master') for build

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