[JIRA] (JENKINS-59337) "No such DSL method 'call'" when calling step within dynamically loaded library a second time

185 views
Skip to first unread message

skinitimski@gmail.com (JIRA)

unread,
Sep 12, 2019, 3:50:03 PM9/12/19
to jenkinsc...@googlegroups.com
Timothy Klopotoski created an issue
 
Jenkins / New Feature JENKINS-59337
"No such DSL method 'call'" when calling step within dynamically loaded library a second time
Issue Type: New Feature New Feature
Assignee: Unassigned
Attachments: consoleText-failing.txt, consoleText-success.txt
Components: workflow-cps-global-lib-plugin, workflow-cps-plugin
Created: 2019-09-12 19:49
Environment: Operating System: amazon linux 64-bit (master+workers)
Jenkins version: 2.176.2 -- master image is built from official Jenkins LTS Docker image
workflow-cps-plugin: 2.74
workflow-cps-global-lib-plugin: 2.15
Priority: Minor Minor
Reporter: Timothy Klopotoski

My team manages a large shared pipeline library, and I'm working on breaking it up. Recently we migrated to new Jenkins infrastructure and I found that my project was no longer working.

To demonstrate the problem, I have a global parent library P which dynamically loads child library C. P is globally configured and loaded explicitly in Jenkinsfile J using `@Library()`.

J --> P --> C

C contains steps X and Y; X calls Y twice. (see [stepFromChild.groovy](https://github.com/skinitimski/library.child/blob/master/vars/stepFromChild.groovy))

P contains step Z which calls X. (see [fail.groovy](https://github.com/skinitimski/library.parent/blob/master/vars/fail.groovy#L14))

When J calls X() X(), no problem.

But when J calls Z (which in turn calls X() X()), the second call to X results in "java.lang.NoSuchMethodError: No such DSL method 'call' found among steps ..." (even though globals very clearly includes X, and `call` isn't the right method name – see consoleText-failing.txt).

On an older Jenkins, I see no failure (see attached log consoleText-sucess.txt)

So far I have found no workaround to this problem.

Steps to reproduce, given a Jenkins instance with a valid GitHub credential and plugins installed:

1. Configure a global library in "Manage Jenkins" called 'timski', pointing at https://github.com/skinitimski/library.parent
2. Create a Pipeline job with the following pipeline script:

@Library('timski@master') _

env.SECRET_ID = 'github-credential-id' // TODO: replace this with the id of a valid GitHub credential

fail()

3. Run the job and observe a failure.

Add Comment Add Comment
 
This message was sent by Atlassian Jira (v7.13.6#713006-sha1:cc4451f)
Atlassian logo

skinitimski@gmail.com (JIRA)

unread,
Sep 12, 2019, 5:00:02 PM9/12/19
to jenkinsc...@googlegroups.com

skinitimski@gmail.com (JIRA)

unread,
Sep 12, 2019, 5:02:02 PM9/12/19
to jenkinsc...@googlegroups.com
Timothy Klopotoski updated an issue
My team manages a large shared pipeline library, and I'm working on breaking it up. Recently we migrated to new Jenkins infrastructure and I found that my project was no longer working.

To demonstrate the problem, I have a global parent library *P* which [dynamically loads|https://jenkins.io/doc/book/pipeline/shared-libraries/#loading-libraries-dynamically] child library *C*. P is [globally configured|https://jenkins.io/doc/book/pipeline/shared-libraries/#global-shared-libraries] and loaded explicitly in Jenkinsfile *J* using `@Library()`.

*J --> P --> C*

C contains steps X and Y; X calls Y twice. (see [stepFromChild.groovy
]( | https://github.com/skinitimski/library.child/blob/master/vars/stepFromChild.groovy ] ) )

P contains step Z which calls X. (see [fail.groovy
]( | https://github.com/skinitimski/library.parent/blob/master/vars/fail.groovy#L14 ] ) )

When J calls X() X(), no problem.

But when J calls Z (which in turn calls X() X()), the second call to X results in "java.lang.NoSuchMethodError: No such DSL method 'call' found among steps ..." (even though globals very clearly includes X, and `call` isn't the right method name -- see _consoleText-failing.txt_).

On an older Jenkins, I see no failure (see attached log _consoleText-sucess.txt_)


So far I have found no workaround to this problem.

*Steps to reproduce, given a Jenkins instance with a valid GitHub credential and plugins installed:*


1. Configure a global library in "Manage Jenkins" called 'timski', pointing at https://github.com/skinitimski/library.parent
2. Create a Pipeline job with the following pipeline script:

bq. @Library('timski@master') _
bq.
bq. env.SECRET_ID = 'github-credential-id' // TODO: replace this with the id of a valid GitHub credential
bq.
bq. fail()


3. Run the job and observe a failure.

skinitimski@gmail.com (JIRA)

unread,
Sep 12, 2019, 5:02:02 PM9/12/19
to jenkinsc...@googlegroups.com
Timothy Klopotoski updated an issue
My team manages a large shared pipeline library, and I'm working on breaking it up. Recently we migrated to new Jenkins infrastructure and I found that my project was no longer working.

To demonstrate the problem, I have a global parent library *P* which [dynamically loads|https://jenkins.io/doc/book/pipeline/shared-libraries/#loading-libraries-dynamically] child library *C*. P is [globally configured|https://jenkins.io/doc/book/pipeline/shared-libraries/#global-shared-libraries] and loaded explicitly in Jenkinsfile *J* using `@Library()`.

*J --> P --> C*

C contains steps X and Y; X calls Y twice. (see [stepFromChild.groovy|https://github.com/skinitimski/library.child/blob/master/vars/stepFromChild.groovy])

P contains step Z which calls X. (see [fail.groovy|https://github.com/skinitimski/library.parent/blob/master/vars/fail.groovy#L14])


When J calls X() X(), no problem.

But when J calls Z (which in turn calls X() X()), the second call to X results in "java.lang.NoSuchMethodError: No such DSL method 'call' found among steps ..." (even though globals very clearly includes X, and `call` isn't the right method name -- see _consoleText-failing.txt_).

On an older Jenkins, I see no failure (see attached log _consoleText-sucess.txt_)

So far I have found no workaround to this problem.

*Steps to reproduce, given a Jenkins instance with a valid GitHub credential and plugins installed:*

1. Configure a global library in "Manage Jenkins" called 'timski', pointing at https://github.com/skinitimski/library.parent
2. Create a Pipeline job with the following pipeline script:

bq. @Library('timski@master') _
bq.

bq.
env.SECRET_ID = 'github-credential-id' // TODO: replace this with the id of a valid GitHub credential
bq.

bq.
fail()


3. Run the job and observe a failure.

skinitimski@gmail.com (JIRA)

unread,
Sep 12, 2019, 6:45:12 PM9/12/19
to jenkinsc...@googlegroups.com
Timothy Klopotoski commented on Bug JENKINS-59337
 
Re: "No such DSL method 'call'" when calling step within dynamically loaded library a second time

It is worth noting that there are other ways to produce the issue, but above was the most trivial way I could find so far.

skinitimski@gmail.com (JIRA)

unread,
Sep 13, 2019, 12:19:02 AM9/13/19
to jenkinsc...@googlegroups.com
Timothy Klopotoski updated an issue
Change By: Timothy Klopotoski
My team manages a large shared pipeline library, and I'm working on breaking it up. Recently we migrated to new Jenkins infrastructure and I found that my project was no longer working.

To demonstrate the problem, I have a global parent library *P* which [dynamically loads|https://jenkins.io/doc/book/pipeline/shared-libraries/#loading-libraries-dynamically] child library *C*. P is [globally configured|https://jenkins.io/doc/book/pipeline/shared-libraries/#global-shared-libraries] and loaded explicitly in Jenkinsfile *J* using `@Library()`.

*J --> P --> C*

C contains steps X and Y; X calls Y twice. (see [stepFromChild.groovy|https://github.com/skinitimski/library.child/blob/master/vars/stepFromChild.groovy])

P contains step Z which loads C, calls Y twice, then calls X . (see [fail.groovy|https://github.com/skinitimski/library.parent/blob/master/vars/fail.groovy#L14]) .

When J imports P and calls X() X() Z.

When J runs
, no problem Z calls Y twice successfully .

But when
J calls Z (which in turn calls X( which calls Y twice ) X()) , the second call to X Y results in "java.lang.NoSuchMethodError: No such DSL method 'call' found among steps ..." (even though globals very clearly includes X, and `call` isn't the right method name called methods -- see _consoleText-failing.txt_).

On an older Jenkins
(2.121.1 , workflow-cps 2.58 workflow-global-lib 2.9), I see no failure (see attached log _consoleText-sucess.txt_)


So far I have found no workaround to this problem.

*Steps to reproduce, given a Jenkins instance with a valid GitHub credential and plugins installed:*

1. Configure a global library in "Manage Jenkins" called 'timski', pointing at https://github.com/skinitimski/library.parent
2. Create a Pipeline job with the following pipeline script:

bq. @Library('timski@master') _
bq. env.SECRET_ID = 'github-credential-id' // TODO: replace this with the id of a valid GitHub credential
bq. fail()

3. Run the job and observe a failure.

skinitimski@gmail.com (JIRA)

unread,
Sep 24, 2019, 5:48:03 PM9/24/19
to jenkinsc...@googlegroups.com
 
Re: "No such DSL method 'call'" when calling step within dynamically loaded library a second time

If I modify the Jenkinsfile to import the parent and the child library, so that the dynamic import is redundant (i.e, it prints "Only using first definition of library child"), everything works.

So, this problem seems scoped to libraries dynamically loaded using the `library` step.

skinitimski@gmail.com (JIRA)

unread,
Oct 7, 2019, 6:34:02 PM10/7/19
to jenkinsc...@googlegroups.com

We've found a workaround to this problem.

As a convention, with extensibility in mind, my team always uses the following signature when writing [custom steps](https://jenkins.io/doc/book/pipeline/shared-libraries/#defining-custom-steps):

```
def call(Map args) {
```

This allows us to add optional step parameters later. We use this even for parameterless steps, in case we want to accept new parameters later on.

The workaround is to change the signature to explicitly accept no parameters (`def call() {`). This results in no errors.

It still seems to me that using the named args signature *should* work.

skinitimski@gmail.com (JIRA)

unread,
Oct 7, 2019, 6:36:02 PM10/7/19
to jenkinsc...@googlegroups.com
Timothy Klopotoski edited a comment on Bug JENKINS-59337
We've found a workaround to this problem.

As a convention, with extensibility in mind, my team always uses the following signature when writing [custom steps ]( | https://jenkins.io/doc/book/pipeline/shared-libraries/#defining-custom-steps ) ] :

```
{{ def call(Map args) { }}
```

This allows us to add optional step parameters later. We use this even for parameterless steps, in case we want to accept new parameters later on.

The workaround is to change the signature to explicitly accept no parameters (`def call() {`). This results in no errors.

It still seems to me that using the named args signature * * should* * work.

tomscommerce@yahoo.com (JIRA)

unread,
Feb 5, 2020, 12:30:02 PM2/5/20
to jenkinsc...@googlegroups.com

tomscommerce@yahoo.com (JIRA)

unread,
Feb 5, 2020, 12:31:03 PM2/5/20
to jenkinsc...@googlegroups.com
Tom Turner commented on Bug JENKINS-59337
 
Re: "No such DSL method 'call'" when calling step within dynamically loaded library a second time

My work recently updated to 2.190.3.2 and I can confirm duplicate calls to the same declarative function can break shared libraries.  I ended up with the same workaround of removing the argument in the call() method but also needed to do another change.

Changing

def call(body) {

to

def call() {

The other change involved removing an apostrophe in an echo. 

echo "an apostrophe's apostrophe causes DSL failure"

Attached is the stack trace.jenkins-dsl-error.txt

tomscommerce@yahoo.com (JIRA)

unread,
Feb 5, 2020, 2:38:02 PM2/5/20
to jenkinsc...@googlegroups.com

I took a look at the stack trace and the "call" seems to emanate from here, line 134

https://github.com/jenkinsci/script-security-plugin/blob/master/src/main/java/org/jenkinsci/plugins/scriptsecurity/sandbox/groovy/SandboxInterceptor.java#L128-L137

The if NOT probably returns false and then the word "call" is passed.

// Allow calling closure variables from a script binding as methods
if (receiver instanceof Script) {
Script s = (Script) receiver;
if (s.getBinding().hasVariable(method)) {
Object var = s.getBinding().getVariable(method);
if (!InvokerHelper.getMetaClass(var).respondsTo(var, "call", (Object[]) args).isEmpty())

{ return onMethodCall(invoker, var, "call", args); }

}
}

tomscommerce@yahoo.com (JIRA)

unread,
Feb 5, 2020, 2:50:03 PM2/5/20
to jenkinsc...@googlegroups.com

We received this from Jenkins Support

Can you check to make sure you are loading this Shared Library implicitly as being referred to within the documentation above or explicitly by making a call using the @Library function in your Script?

Also, from the snippet being presented it appears that the Call method is attempting to be setup within the Groovy Script itself as detailed in the method presented in the documentation linked here: https://jenkins.io/doc/book/pipeline/shared-libraries/#defining-custom-steps

The Call method is noticeably malformed, please put the entire method declaration on the same line with the def and also body should be initialized with a type such as String or Closure.

With that noted it is best practices for both Support to most efficiently answer your questions as well as from your user point of view in managing tickets and keeping track of their history to keep questions/issues to a 1-to-1 ratio per ticket.

Because of that please do feel free to open another ticket to review this Shared Library error if it is still occurring after this information is used by also uploading the Jenkinsfile/Pipeline Script from the example job that is failing with this error.

tomscommerce@yahoo.com (JIRA)

unread,
Feb 5, 2020, 3:07:02 PM2/5/20
to jenkinsc...@googlegroups.com

To answer the above question, we load the shared libraries explicitly in the Jenkinsfile in the first line, like this.

@Library(['devkit-jenkins-lib@master','DCT-jenkins-shared@develop']) _

 

The DSL method was defined like this (based on examples in this page, about 6 months ago.  https://jenkins.io/doc/book/pipeline/shared-libraries/)

//var/isNPM.groovy

def call(body) {

I also tried:

def call(Closure body) {

and

def call(String body) {

but only this works

def call() {

 

Thankfully, my DSL method doesn't require any arguments passed to it.

 

Note that calls to this isNPM() method work fine throughout the script.  It is only after making some other calls in the flow (to some shell scripts), that subsequent calls to isNPM() fail.  

Reply all
Reply to author
Forward
0 new messages