source: Jenkinsfile @ 7ed1d8f

ADTarm-ehast-experimentalenumforall-pointer-decayjacob/cs343-translationnew-astnew-ast-unique-exprpthread-emulationqualifiedEnum
Last change on this file since 7ed1d8f was dcf1979, checked in by Thierry Delisle <tdelisle@…>, 4 years ago

Jenkins file now calls autogen.sh before building

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