fix: handle catchError+sh(returnStatus:true)+error() via FlowGraph traversal#109
fix: handle catchError+sh(returnStatus:true)+error() via FlowGraph traversal#109lidiams96 wants to merge 1 commit intojenkinsci:mainfrom
Conversation
panicking
left a comment
There was a problem hiding this comment.
@lidiams96 you should wait the other merge request land. We should avoid multiple changes
src/main/java/io/jenkins/plugins/explain_error/PipelineLogExtractor.java
Outdated
Show resolved
Hide resolved
src/main/java/io/jenkins/plugins/explain_error/PipelineLogExtractor.java
Outdated
Show resolved
Hide resolved
src/main/java/io/jenkins/plugins/explain_error/PipelineLogExtractor.java
Outdated
Show resolved
Hide resolved
src/main/java/io/jenkins/plugins/explain_error/PipelineLogExtractor.java
Outdated
Show resolved
Hide resolved
2d96b05 to
d9ca03b
Compare
|
@panicking Thanks for the review feedback on the BFS approach. I've adopted your suggestion and simplified private FlowNode findImmediateParentWithLog(FlowNode errorOrigin) {
List<FlowNode> parents = errorOrigin.getParents();
if (parents.size() == 1) {
FlowNode parent = parents.get(0);
if (parent.getAction(LogAction.class) != null) {
return parent;
}
}
return null;
}This is cleaner and avoids unnecessary BFS traversal. The All 133 tests still pass. |
There was a problem hiding this comment.
Pull request overview
Fixes a regression in Pipeline failure log extraction for the catchError + sh(returnStatus:true) + error() pattern by enhancing FlowGraph-based Strategy 1 so it can still locate the sh step log even when the failing error() node has no LogAction.
Changes:
- Add a Strategy 1 fallback that, when an
ErrorActionorigin has noLogAction, checks the origin’s immediate parent for aLogAction. - Update Strategy 1 documentation to describe the additional fallback behavior.
- Add an integration test covering
catchError(buildResult: 'FAILURE')withsh(returnStatus:true)followed byerror().
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
src/main/java/io/jenkins/plugins/explain_error/PipelineLogExtractor.java |
Adds a FlowGraph fallback helper and hooks it into Strategy 1 to capture sh logs for the returnStatus:true + error() pattern. |
src/test/java/io/jenkins/plugins/explain_error/PipelineLogExtractorTest.java |
Adds an integration test ensuring the sh output is extracted for the regression scenario. |
src/main/java/io/jenkins/plugins/explain_error/PipelineLogExtractor.java
Outdated
Show resolved
Hide resolved
src/main/java/io/jenkins/plugins/explain_error/PipelineLogExtractor.java
Outdated
Show resolved
Hide resolved
src/main/java/io/jenkins/plugins/explain_error/PipelineLogExtractor.java
Outdated
Show resolved
Hide resolved
src/test/java/io/jenkins/plugins/explain_error/PipelineLogExtractorTest.java
Outdated
Show resolved
Hide resolved
|
@lidiams96 are you addressing all the comments? I mean try to avoid to go up with node that are failing form waningclass and squash the commit because in the second you fix a problem in the first one. |
655812c to
f7cd09f
Compare
|
@panicking Done — commits squashed into one. Regarding the |
f7cd09f to
0d109a6
Compare
src/main/java/io/jenkins/plugins/explain_error/PipelineLogExtractor.java
Outdated
Show resolved
Hide resolved
…aversal When Strategy 1 finds a node with ErrorAction but no LogAction (i.e. the error() step in a catchError+sh(returnStatus:true)+error() pattern), look at the immediate parent. In Jenkins CPS, Groovy control-flow constructs (if, def, variable assignments) are transparent to the FlowGraph, so the immediate parent of error() is the preceding sh step that holds the actual failure output. The lookup is guarded by parents.size()==1 to rule out parallel-merge join points where the relevant log cannot be determined unambiguously. It only activates when logAction==null && errorAction!=null, so WarningAction nodes are never affected. Adds integration test catchError_returnStatusPattern_siblingShLogExtractedViaFlowGraph. Relates to: jenkinsci#105 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
0d109a6 to
323e0f4
Compare
|
@panicking were you able to test it? Is there anything I can help with from my side? |
Tonight. I'm at embedded world |
Hi @panicking, just checking if you had a chance to test this. |
Summary
Fixes the regression introduced by #106 for the
catchError + sh(returnStatus:true) + error()pipeline pattern, as discussed in #105.The problem
In this pattern:
The FlowGraph structure is:
shstep → hasLogAction(the actual failure output), noErrorAction(returnStatus:truesuppresses it)error()step → hasErrorAction, noLogAction(only carries the message string)Strategy 1 finds
error()viaErrorActionbut skips it becauselogAction == null. Theshstep is invisible since it has noErrorActionorWarningAction. The result falls back torun.getLog(maxLines).The fix
When Strategy 1 finds a node with
ErrorActionbut noLogAction, instead of skipping it,findImmediateParentWithLogchecks the immediate parent of theerror()node. In Jenkins CPS, Groovy control-flow constructs (if,def, variable assignments) are transparent to the FlowGraph — only Jenkins steps create FlowNodes. This means the immediate parent oferror()is the precedingshstep, which holds the actual failure output.The method only proceeds when
error()has exactly one parent, which rules out parallel-merge join points where the relevant log cannot be determined unambiguously.This only activates when the normal path (
originhasLogAction) does not work, as requested in #105.Changes
PipelineLogExtractor.java: newfindImmediateParentWithLogmethod + one-line hook ingetFailedStepLogPipelineLogExtractorTest.java: integration test coveringbuildResult: 'FAILURE'caseTest plan
catchError_returnStatusPattern_immediateParentShLogExtractedpassescatchError+sh(returnStatus:true)+error()patternRelates to: #105
🤖 Generated with Claude Code