Search code examples
jenkinsgroovyversion-controljenkins-pipelinepipeline

MissingMethodException: No signature of method: p.call() when configuring Jenkins Pipeline script from SCM that targets Scripted Pipeline Jenkinsfile


I have written a Scripted Pipeline in Jenkins that executes correctly when I choose the "Pipeline script" option and paste the text directly into the Job. We need to use a Scripted Pipeline as some of our Stage names are dynamically generated and Declarative Pipelines only allow for string literals and not interpolated strings:

https://issues.jenkins.io/browse/JENKINS-43820

I would like to store this Scripted Pipeline in our repository as a Jenkinsfile as it will be used by multiple Jobs and I would like any future changes to be made effective in all Jobs (instead of having to copy and paste the changes manually into every Job that uses the script).

In the Jenkins docs, it says that a Jenkinsfile can be both Declarative and Scripted:

https://www.jenkins.io/doc/book/pipeline/#:~:text=A%20Jenkinsfile%20can%20be%20written,of%20syntax%20%2D%20Declarative%20and%20Scripted.

However, when I target the "Pipeline script from SCM" at my Scripted Pipeline Jenkinsfile I get the following error message:

hudson.remoting.ProxyException: groovy.lang.MissingMethodException: No signature of method: pipeline.call() is applicable for argument types: () values: []

Which implies that it is expecting a Declarative Pipeline and not a Scripted Pipeline:

How to fix 'hudson.remoting.ProxyException: groovy.lang.MissingMethodException: No signature of method: testFunc.call() '

What configuration will enable a Scripted Pipeline Jenkinsfile from SCM?

Is there something I need to add to the Jenkinsfile itself?

I have simplified our Scripted Pipeline Jenkinsfile below for privacy but the core components are there (the dynamic stage name is usually wrapped in an each-loop to better utilise this functionality):

String service

node("master") {
    stage("Clean Workspace") {
        deleteDir()
    }

    stage("Get Service From Job Build") {
        service = getServiceFromJobName env.JOB_NAME.toString()
    }

    stage("Checkout '$service'") {
        checkoutRepo service, "master"
    }
}

private def checkoutRepo(String repo, String branch) {
    checkout([
            $class                           : "GitSCM",
            branches                         : [[name: branch]],
            doGenerateSubmoduleConfigurations: false,
            extensions                       : [[$class: "WipeWorkspace"]],
            submoduleCfg                     : [],
            userRemoteConfigs                : [[credentialsId: [CREDS GO HERE],
                                                 url          : "[GIT GOES HERE]/${repo}.git"
                                                ]]
    ])
}

private static String getServiceFromJobName(String jobName) {
    String job = jobName.tokenize("/").pop()
    job.replace(" Service", "")
}

Or is there something in Jenkins to configure that I am unaware of?

I have removed our git details for privacy but this is our Jenkins Pipeline script from SCM configuration:

Jenkins Pipeline script from SCM configuration


Solution

  • I found a fix for this issue by nesting my Scripted Pipeline and Dynamic Stage Names within a Declarative Pipeline in the Scripts section of a Static-Named Stage:

    String service
    
    def call() {
        pipeline {
            agent any
            
            stages {
                stage("Clean Workspace") {
                    steps {
                        deleteDir()
                    }
                }
    
                stage("Get Service From Job Build") {
                    steps {
                        script {
                            service = getServiceFromJobName env.JOB_NAME.toString()
    
                            stage("Checkout '$service'") {
                                checkoutRepo service, "master"
                            }
                        }
                    }
                }
            }
        }
    }
    
    private def checkoutRepo(String repo, String branch) {
        checkout([
                $class                           : "GitSCM",
                branches                         : [[name: branch]],
                doGenerateSubmoduleConfigurations: false,
                extensions                       : [[$class: "WipeWorkspace"]],
                submoduleCfg                     : [],
                userRemoteConfigs                : [[credentialsId: [CREDS GO HERE],
                                                     url          : "[GIT GOES HERE]/${repo}.git"
                                                    ]]
        ])
    }
    
    private static String getServiceFromJobName(String jobName) {
        String job = jobName.tokenize("/").pop()
        job.replace(" Service", "")
    }

    Credit goes here:

    https://issues.jenkins.io/browse/JENKINS-61280