Skip to content

Commit

Permalink
CpsFlowExecution, CpsScriptTest: recognize also Groovy (JSL step or c…
Browse files Browse the repository at this point in the history
…lass) for MethodTooLargeException handling

And re-word logging (impacted class name, possible excerpts from trace).
Not only WorkflowScript (pipeline) suffers from this, see examples
in #817

Signed-off-by: Jim Klimov <[email protected]>
  • Loading branch information
jimklimov committed Jun 26, 2024
1 parent 20213ea commit f23b610
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -730,14 +730,58 @@ private CpsScript parseScript() throws IOException {
throw x;
}

String msg = "FAILED to parse WorkflowScript (the pipeline script) due to MethodTooLargeException";
// Collect the relevant part of stack trace through groovy (JSL),
// if any, which the pipeline developer can impact and fix.
// Some real-life sample patterns are posted in
// https://github.com/jenkinsci/workflow-cps-plugin/pull/817
String overflowedClassName = null;
List<String> overflowedClassNameMentionsList = new ArrayList<String>();
// groovyjarjarasm.asm.MethodTooLargeException: Method too large: cloudBranch.___cps___586328 ()Lcom/cloudbees/groovy/cps/impl/CpsFunction;
final Pattern MTLE_CLASSNAME_PATTERN = Pattern.compile("^.*MethodTooLargeException.*: ([^\\s.]+)\\.___cps___\\d+.*$");
Pattern CLASSNAME_MENTIONS_PATTERN = Pattern.compile("^\\s+at .*(WorkflowScript.*|\\.groovy):\\d+\\).*$");
for (String l : xLines) {
if (!(l.isBlank())) {
if (overflowedClassName == null) {
Matcher matcher = MTLE_CLASSNAME_PATTERN.matcher(l);
if (matcher.find()) {
try {
overflowedClassName = matcher.group(1);
if (!(mtlEx.getMessage().contains(overflowedClassName)))
overflowedClassNameMentionsList.add(l);

// Update the matching pattern in case we manage
// to spot our problematic source in the stack trace
CLASSNAME_MENTIONS_PATTERN = Pattern.compile("^\\s+at .*(WorkflowScript.*|" + overflowedClassName + ".*|\\.groovy):\\d+\\).*$");
continue;
} catch (Throwable ignored) {
}
}
}

Matcher matcher = CLASSNAME_MENTIONS_PATTERN.matcher(l);
if (matcher.find()) {
overflowedClassNameMentionsList.add(l);
}
}
}

if (overflowedClassName == null)
overflowedClassName = "WorkflowScript (the pipeline script) or one of its constituents";

String msg = "FAILED to parse " + overflowedClassName + " due to MethodTooLargeException";
if (ecCount > 1) {
msg += " (and other issues)";
}
// Short message suffices, not much that a pipeline developer
// can do with the stack trace into the guts of groovy
msg += "; please refactor to simplify code structure and/or move logic to a Jenkins Shared Library: ";
msg += mtlEx.getMessage();
msg += "; please refactor to simplify code structure";
if (overflowedClassName.contains("WorkflowScript"))
msg += " and/or move logic to a Jenkins Shared Library";
msg += ": " + mtlEx.getMessage();
if (!(overflowedClassNameMentionsList.isEmpty())) {
msg += "\nGroovy code trail (mentions of pipeline WorkflowScript and/or your JSL in larger stack trace):\n"
+ String.join("\n", overflowedClassNameMentionsList);
}

// Make a full note in server log
LOGGER.log(Level.FINER, xStr);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ public void evaluateShallSandbox() throws Exception {
r.assertLogContains("MethodTooLargeException", b);

// "Prettier" explanation added by CpsFlowExecution.parseScript():
r.assertLogContains("FAILED to parse WorkflowScript (the pipeline script) due to MethodTooLargeException", b);
r.assertLogContains("FAILED to parse WorkflowScript due to MethodTooLargeException", b);

/*
// Report as of release 3880.vb_ef4b_5cfd270 (Feb 2024)
Expand Down

0 comments on commit f23b610

Please sign in to comment.