2

I'm having a strange issue which I can't seem to quite understand. I have written a custom step which accepts parameters used to clone github/bitbucket repositories more easily. The step works just fine - it calls the appropriate checkout() for branches and prs, but for some reason this only works if you call it from a script { gitUtils.cloneRepo(...) }. It doesn't work in a declarative pipeline if you don't wrap it around with a script { } with a super strange exception:

WorkflowScript: 25: Expected a symbol @ line 25, column 17.
               gitUtils().getCredentials(repo)
               ^

WorkflowScript: 26: Expected a symbol @ line 26, column 17.
               gitUtils().cloneRepo(url: repo)
               ^

WorkflowScript: 27: Expected a symbol @ line 27, column 17.
               gitUtils().getRevision()
               ^

WorkflowScript: 26: Invalid parameter "url", did you mean "message"? @ line 26, column 38.
               gitUtils().cloneRepo(url: repo)
                                    ^

WorkflowScript: 27: Missing required parameter: "message" @ line 27, column 17.
               gitUtils().getRevision()

Any ideas why this is happening?

import java.lang.IllegalArgumentException

def call() {
    return this
}

def cloneRepo(Map parameters = [url: null, branch: "master", credentials: null]) {
    def url = parameters.getOrDefault("url", null)
    def branch = parameters.getOrDefault("branch", "master")
    def credentials = parameters.getOrDefault("credentials", null)

    script {
        if(!url) {
            throw new IllegalArgumentException("cloneRepo() expects url argument to be present!")
        }

        if(credentials == null) {
            credentials = getCredentials(url)
        }

        if (branch.matches("\\d+") || branch.matches("PR-\\d+")) {
            if (branch.matches("PR-\\d+")) {
                branch = branch.substring(3)
            }
            checkout changelog: false, poll: false, scm: [
                    $class: 'GitSCM',
                    branches: [[name: 'pr/' + branch]],
                    doGenerateSubmoduleConfigurations: false,
                    extensions: [[$class: 'LocalBranch', localBranch: 'pr/' + branch]],
                    submoduleCfg: [],
                    userRemoteConfigs: [[
                                                credentialsId: credentials,
                                                refspec: 'refs/pull/' + branch + '/head:pr/' + branch,
                                                url: url
                                        ]]
            ]
        } else {
            checkout changelog: false, poll: false, scm: [
                    $class: 'GitSCM',
                    branches: [[name: branch]],
                    doGenerateSubmoduleConfigurations: false,
                    extensions: [],
                    submoduleCfg: [],
                    userRemoteConfigs: [[
                                                credentialsId: credentials,
                                                url: url
                                        ]]
            ]
        }
    }
}
tftd
  • 16,203
  • 11
  • 62
  • 106

1 Answers1

3

The script{} step takes a block of Scripted Pipeline (which contains functionality provided by the Groovy language) and executes that in the Declarative Pipeline.

Since gitUtils.cloneRepo(...) is scripted pipeline block, you need to use script{} so that it can be embedded in a Declarative Pipeline step.

Sagar
  • 23,903
  • 4
  • 62
  • 62
  • 1
    Technically correct, but I'm not sure it's the case. You can have a shared library which has `Scripted Pipeline` and execute it without wrapping it in a `script` block inside a `Declarative Pipeline`. After a lot of wandering around the Jenkins documentation - it turns out that the issue is my groovy script has multiple methods (I am exposing them with `return this` from `call()`) which is not allowed outside a `script` block. [Shared Libraries - Defining global variables](https://jenkins.io/doc/book/pipeline/shared-libraries/#defining-global-variables). – tftd May 17 '18 at 12:48
  • So far I couldn't use the groovy Scripted Pipeline within DeclarativePipeline with out Script block. I had to use script especially dealing with methods. SharedLibraries should be preferred way for dealing with script blocks having non-trivial size and complexity. – Sagar May 17 '18 at 13:08
  • Interesting... Maybe I'm confused, but [this](https://gist.github.com/steve-todorov/a3563185622f45c47cda6088ce11c893#file-example-groovy) example works fine for me? I can call `example().getJobName()` in a `pipeline { }` without having to wrap it in a `script {}`. – tftd May 17 '18 at 14:16