jenkinsci / JenkinsPipelineUnit

Framework for unit testing Jenkins pipelines
MIT License
1.54k stars 394 forks source link

callstack indentation wrong when overriding sh with vars/sh.groovy #130

Open chrismaes87 opened 5 years ago

chrismaes87 commented 5 years ago

I used the strategy described here: https://brokenco.de/2017/08/03/overriding-builtin-steps-pipeline.html to override the default sh steps. I thus have quite exactly the proposed vars/sh.groovy file in my jenkins library:

def call(Map params = [:]) {
    String script = params.script
    Boolean returnStatus = params.get('returnStatus', false)
    Boolean returnStdout = params.get('returnStdout', false)
    String encoding = params.get('encoding', null)

    timeout(time: 2, unit: 'HOURS') {
        ansiColor('xterm') {
            timestamps {
                return labelledShell(script: "hostname; " + script,
                    label: script,
                    returnStatus: returnStatus,
                    returnStdout: returnStdout,
                    encoding: encoding)
            }
        }
    }
}
/* Convenience overload */
def call(String script) {
    return call(script: script)
}

I am using the BaseRegressionTest class to avoid regressions. However my automatic build fails because the indentation of the underlying steps inside sh.groovy don't have exactly the same depth as on my pc. Example: on my pc I get this callstack:

myPipelineTestAndPublish.sh(./gradlew test)
   sh.timeout({time=2, unit=HOURS}, groovy.lang.Closure)
      sh.ansiColor(xterm, groovy.lang.Closure)
      sh.timestamps(groovy.lang.Closure)
      sh.labelledShell({script=hostname; ./gradlew test, label=./gradlew test, returnStatus=false, returnStdout=false, encoding=null})

and on the jenkins node I would get:

myPipelineTestAndPublish.sh(./gradlew test)
   sh.timeout({time=2, unit=HOURS}, groovy.lang.Closure)
      sh.ansiColor(xterm, groovy.lang.Closure)
         sh.timestamps(groovy.lang.Closure)
      sh.labelledShell({script=hostname; ./gradlew test, label=./gradlew test, returnStatus=false, returnStdout=false, encoding=null})

or something similar. Note also that none of both outputs are correct, since all steps are enclosed in one another, so the right output would be:

myPipelineTestAndPublish.sh(./gradlew test)
   sh.timeout({time=2, unit=HOURS}, groovy.lang.Closure)
      sh.ansiColor(xterm, groovy.lang.Closure)
         sh.timestamps(groovy.lang.Closure)
            sh.labelledShell({script=hostname; ./gradlew test, label=./gradlew test, returnStatus=false, returnStdout=false, encoding=null})

I have been trying for hours to get this right, but am quite out of ideas. Trouble is the library and sh.groovy work just fine, I'm just having a lot of trouble getting the unit-tests reproducible (and correct).

chrismaes87 commented 5 years ago

maybe an important note: all other commands are prefixed with my library name, only this one is prefixed with the name of the JenkinsFile that I loaded with loadScript

MyPipeline.steps(groovy.lang.Closure)
   MyPipeline.withEnv([CHANGE_TARGET=merge-base], groovy.lang.Closure)
      MyPipeline.script(groovy.lang.Closure)
         myPipelineTestAndPublish.sh(./gradlew test)
            sh.timeout({time=2, unit=HOURS}, groovy.lang.Closure)
               sh.ansiColor(xterm, groovy.lang.Closure)
               sh.timestamps(groovy.lang.Closure)
               sh.labelledShell({script=hostname; ./gradlew test, label=./gradlew test, returnStatus=false, returnStdout=false, encoding=null})
stchar commented 5 years ago

@chrismaes87, hi may I ask you to submit a PR with test case to reproduce the issue

chrismaes87 commented 5 years ago

This will be rather complicated to give a simple reproducible case... the indentation changed several times on my pc and also between my pc and jenkins build nodes; but it seemed rather arbitrary.

For the moment I am thinking about changing my whole code to scripted pipeline instead of DSL for more advanced behavior, so I'm not even sure I will keep using the JenkinsPipelineUnit.

stchar commented 4 years ago

Are intendants on the same host have the same formatting no matter how many times you run it? Any information about the difference between hosts (os, jdk) would be helpful.

chrismaes87 commented 4 years ago

I have since left that company so I can no longer reproduce this. The indendation was the same each time on the same host. One host was an opensuse15.0, the other might have been centos7, but I'm not sure about that anymore.