source: Jenkinsfile @ ab8315f

ADTarm-ehast-experimentalenumforall-pointer-decayjacob/cs343-translationjenkins-sandboxnew-astnew-ast-unique-exprpthread-emulationqualifiedEnum
Last change on this file since ab8315f was ab8315f, checked in by Thierry Delisle <tdelisle@…>, 5 years ago

Jenkins will now display short tests and full tests as 2 different stages

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