source: Jenkinsfile @ 4f9e706

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

Testing what can happen outside of nodes

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