New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[JENKINS-26481] [JENKINS-27421] Use GroovyCategorySupport to invoke CpsDefaultGroovyMethods (w/o DGMPatcher) & IteratorHack #124
[JENKINS-26481] [JENKINS-27421] Use GroovyCategorySupport to invoke CpsDefaultGroovyMethods (w/o DGMPatcher) & IteratorHack #124
Conversation
…sDefaultGroovyMethods without hacks like DGMPatcher.
@@ -146,10 +157,33 @@ public StepExecution getStep() { | |||
this.step = step; | |||
} | |||
|
|||
/** TODO pending full coverage in {@link CpsDefaultGroovyMethods} */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Such as is added in cloudbees/groovy-cps#52, but that mixes in other stuff which we do not need.
outcome = program.run0(o); | ||
outcome = GroovyCategorySupport.use(Arrays.<Class>asList(CpsDefaultGroovyMethods.class, CpsDefaultGroovyMethodsExt.class), new Closure<Outcome>(null) { | ||
@Override public Outcome call() { | ||
return program.run0(o); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is just for experimentation; probably we would rather want to have a change in groovy-cps
which
- fleshes out
CpsDefaultGroovyMethods
- calls
GroovyCategorySupport.use
from insideContinuable.run0
for (int i = 0; i < args.length; i++) { | ||
if (args[i] instanceof CpsClosure && parameterTypes.length > i && parameterTypes[i] == Closure.class) { | ||
throw new UnsupportedOperationException("Calling " + method + " on a CPS-transformed closure is not yet supported (JENKINS-26481); encapsulate in a @NonCPS method, or use Java-style loops"); | ||
if (false) { // TODO be more discriminating |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Builder b = new Builder(loc("each")); | ||
CpsFunction f = new CpsFunction(Arrays.asList("self", "closure"), b.block( | ||
b.staticCall(-1, CpsDefaultGroovyMethods.class, "each", | ||
b.staticCall(-1, InvokerHelper.class, "asIterator", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just delegates to the Iterator
overload.
…work around unserializable iterators, map entries, etc.
|
||
@Override public Pickle writeReplace(Object object) { | ||
if (ACCEPTED_TYPES.contains(object.getClass().getName())) { | ||
return new Replacement(object); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Supersedes jenkinsci/pipeline-plugin#372.
@@ -219,12 +219,8 @@ public void stop(Throwable cause) throws Exception { | |||
SemaphoreStep.success("new-one/1", null); | |||
SemaphoreStep.success("new-two/1", null); | |||
story.j.waitForCompletion(b); | |||
/* TODO desired behavior: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now we can have the “desired behavior” from #77.
Hmm, seems
Looking into that. |
Seems that merely calling |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is some nifty
resumeValue = null; | ||
outcome = program.run0(o); | ||
outcome = GroovyCategorySupport.use(Arrays.<Class>asList(CpsDefaultGroovyMethods.class, CpsDefaultGroovyMethodsExt.class, IteratorHack.class), new Closure<Outcome>(null) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given the black magic here, it'd be nice to have some comments explaining what exactly is going on. =)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall, this is great, but it needs some more tests for additional methods like Map.each
, collect
, collectEntries
, eachLine
... I can get those added today, though. Expect a PR to @jglick's branch.
Absolutely we would like more test coverage. As to
seems I forgot to deploy to the Jenkins repo. Will fix. |
|
Had the same failures on Java 7 (and again with the right Java 8 version) so they look legit. |
Yes, somehow these changes seem to be suppressing the sandbox, so will need to figure out why that is. |
And it looks like |
npm errors are making CI more or less useless in this repository, so I need to take a detour to try using yarn instead. |
Seems that as of the last build, all tests passed, and we just bombed out due to npm (cf. #128). |
I think this was in reference to the upstream PR, and those tests were already added.
Seems to be causing a failure in |
Never mind, that seems to be a regression in 2.31; I will look into it, but not a blocker for this. |
This pull request originates from a CloudBees employee. At CloudBees, we require that all pull requests be reviewed by other CloudBees employees before we seek to have the change accepted. If you want to learn more about our process please see this explanation. |
pom.xml
Outdated
@@ -62,8 +62,7 @@ | |||
</pluginRepository> | |||
</pluginRepositories> | |||
<properties> | |||
<jenkins.version>1.642.3</jenkins.version> | |||
<jenkins-test-harness.version>2.19</jenkins-test-harness.version> | |||
<jenkins.version>2.7.3</jenkins.version> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did not seem practical to support Groovy 1.x, since we have to choose a Groovy release to generate CpsDefaultGroovyMethods
from. Too old, and we do not cover enough methods; too new, and it may not link against an older Groovy core.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 strongly. Especially given that Blue Ocean and Declarative require 2.7.3, so we've got that as the "default" baseline these days anyway.
pom.xml
Outdated
@@ -234,6 +233,12 @@ | |||
</exclusion> | |||
</exclusions> | |||
</dependency> | |||
<dependency> | |||
<groupId>org.jenkins-ci.plugins</groupId> | |||
<artifactId>credentials</artifactId> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is #135.
@@ -76,21 +68,4 @@ private boolean permits(Class<?> declaringClass) { | |||
return permits(field.getDeclaringClass()) || delegate.permitsStaticFieldSet(field, value); | |||
} | |||
|
|||
/** | |||
* Blocks accesses to some {@link DefaultGroovyMethods}, or any other binary method taking a closure, until JENKINS-26481 is fixed. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes there could be other Closure
-taking binary methods which we are not translating, but it is too cumbersome to track them. Better to spend time implementing the more general, and precise, JENKINS-31314.
assertThat("SubversionSCM.workspaceUpdater is mentioned as an attribute of a value of GenericSCMStep.delegate", html, containsString("workspaceUpdater")); | ||
assertThat("CheckoutUpdater is mentioned as an option", html, containsString("CheckoutUpdater")); | ||
assertThat("GitSCM.submoduleCfg is mentioned as an attribute of a value of GenericSCMStep.scm", html, containsString("submoduleCfg")); | ||
assertThat("CleanBeforeCheckout is mentioned as an option", html, containsString("CleanBeforeCheckout")); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just related to jenkins-test-harness
bump (no more detached plugins).
} | ||
Set<Map.Entry<K, V>> entries = new LinkedHashSet<>(); | ||
for (Map.Entry<K, V> entry : map.entrySet()) { | ||
// TODO return an object holding references to the map and the key and delegating all calls accordingly |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These impls are not intended to be perfect or complete, just good enough to let typical script usages pass, where previously they would not.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I forget - does this all enable for (a : listOfA) { ... }
and the like?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, see IteratorHackTest
. Prior to this PR, ArrayList.iterator
was safe but nothing else (and in particular I had no idea how to support iterating Map
s and the like—the trick did not generalize well). Now most common interface methods in this category should work, and on any implementation class.
pom.xml
Outdated
@@ -62,8 +62,7 @@ | |||
</pluginRepository> | |||
</pluginRepositories> | |||
<properties> | |||
<jenkins.version>1.642.3</jenkins.version> | |||
<jenkins-test-harness.version>2.19</jenkins-test-harness.version> | |||
<jenkins.version>2.7.3</jenkins.version> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 strongly. Especially given that Blue Ocean and Declarative require 2.7.3, so we've got that as the "default" baseline these days anyway.
} | ||
Set<Map.Entry<K, V>> entries = new LinkedHashSet<>(); | ||
for (Map.Entry<K, V> entry : map.entrySet()) { | ||
// TODO return an object holding references to the map and the key and delegating all calls accordingly |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I forget - does this all enable for (a : listOfA) { ... }
and the like?
@reviewbybees done @kohsuke are you out there? |
Downstream of cloudbees/groovy-cps#56.
JENKINS-26481: supersedes #14 and most of cloudbees/groovy-cps#51. Seems to demonstrate that we never actually needed all the horrifying stuff in
DGMPatcher
. And seems to work in any Groovy version we support. (Pending integration of 2.5.0 in Jenkins core, we will however hit GROOVY-6263.)Also JENKINS-27421: a more maintainable workaround for serialization issues.
Really the technique is quite general: any time you find a (non-
static
) method somewhere (typically in either the Java Platform or the GDK) which is not amenable to being called from Pipeline script (particularly CPS-transformed parts), we can replace its implementation with something else of our choice.Tasks, including upstream:
CpsDefaultGroovyMethods
Closure
-based methodsList.iterator
Map.entrySet
Set.iterator
List.listIterator
Closure
-based methodsGroovyClassLoaderWhitelist
to check onlyClosure
-based methods defined outside the supported receivers, as in [JENKINS-34064] Making fix work in Jenkins 2 #14Subsumes #135.
@reviewbybees if you are feeling adventurous