source: Jenkinsfile @ 8ecb590

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

More obscure tentative for skipped builds

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