Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 10 additions & 6 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,16 @@
<artifactId>workflow-step-api</artifactId>
</dependency>

<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-api</artifactId>
</dependency>

<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-job</artifactId>
</dependency>

<!-- Commons Lang3 API -->
<dependency>
<groupId>io.jenkins.plugins</groupId>
Expand All @@ -99,12 +109,6 @@
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-job</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-durable-task-step</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@
import jenkins.model.RunAction2;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import java.util.logging.Logger;
import javax.servlet.ServletException;
import net.sf.json.JSONObject;

import org.jenkinsci.plugins.workflow.job.WorkflowRun;
import org.kohsuke.stapler.StaplerRequest2;
import org.kohsuke.stapler.StaplerResponse2;
import org.kohsuke.stapler.interceptor.RequirePOST;
Expand Down Expand Up @@ -86,7 +89,7 @@ public void doExplainConsoleError(StaplerRequest2 req, StaplerResponse2 rsp) thr
}

// Fetch the last N lines of the log
java.util.List<String> logLines = run.getLog(maxLines);
List<String> logLines = PipelineLogExtractor.getFailedStepLog(run, maxLines);
String errorText = String.join("\n", logLines);

ErrorExplainer explainer = new ErrorExplainer();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import java.util.logging.Logger;
import java.util.regex.Pattern;
import org.apache.commons.lang3.StringUtils;
import org.jenkinsci.plugins.workflow.job.WorkflowRun;

/**
* Service class responsible for explaining errors using AI.
Expand Down Expand Up @@ -60,7 +61,7 @@ public void explainError(Run<?, ?> run, TaskListener listener, String logPattern
}

private String extractErrorLogs(Run<?, ?> run, String logPattern, int maxLines) throws IOException {
List<String> logLines = run.getLog(maxLines);
List<String> logLines = PipelineLogExtractor.getFailedStepLog(run, maxLines);

if (StringUtils.isBlank(logPattern)) {
// Return last few lines if no pattern specified
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package io.jenkins.plugins.explain_error;

import org.jenkinsci.plugins.workflow.job.WorkflowRun;

import edu.umd.cs.findbugs.annotations.NonNull;

import org.jenkinsci.plugins.workflow.flow.FlowExecution;
import org.jenkinsci.plugins.workflow.graph.FlowNode;
import org.jenkinsci.plugins.workflow.graph.FlowGraphWalker;
import org.jenkinsci.plugins.workflow.actions.ErrorAction;
import org.jenkinsci.plugins.workflow.actions.LogAction;
import hudson.console.AnnotatedLargeText;
import hudson.console.ConsoleNote;
import hudson.model.Run;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

public class PipelineLogExtractor {

private static List<String> readLimitedLog(AnnotatedLargeText<? extends FlowNode> logText,
int maxLines) {
StringWriter writer = new StringWriter();
try {
long offset = logText.writeLogTo(0, writer);
if (offset <= 0) {
return Collections.emptyList();
}
String cleanLog = ConsoleNote.removeNotes(writer.toString());
BufferedReader reader = new BufferedReader(new StringReader(cleanLog));
LinkedList<String> queue = new LinkedList<>();
String line;
while ((line = reader.readLine()) != null) {
if (queue.size() >= maxLines) {
queue.removeFirst();
}
line = line.replace("\n", "").replace("\r", "");
queue.add(line);
}
return new ArrayList<>(queue);
} catch (Exception e) {
e.printStackTrace();
}
return Collections.emptyList();

Check warning on line 50 in src/main/java/io/jenkins/plugins/explain_error/PipelineLogExtractor.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered lines

Lines 25-50 are not covered by tests
}

/**
* Extracts the log output of the specific step that caused the pipeline failure.
* @param run The pipeline build
* @return The log text of the failed step, or null if no failed step with a log is found.
* @throws IOException
*/
public static List<String> getFailedStepLog(@NonNull Run<?, ?> run, int maxLines) throws IOException {

if (run instanceof WorkflowRun) {
FlowExecution execution = ((WorkflowRun) run).getExecution();

FlowGraphWalker walker = new FlowGraphWalker(execution);
for (FlowNode node : walker) {
ErrorAction errorAction = node.getAction(ErrorAction.class);
if (errorAction != null) {

Check warning on line 67 in src/main/java/io/jenkins/plugins/explain_error/PipelineLogExtractor.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 67 is only partially covered, one branch is missing
FlowNode nodeThatThrewException = ErrorAction.findOrigin(errorAction.getError(), execution);
if (nodeThatThrewException == null) {
continue;
}
LogAction logAction = nodeThatThrewException.getAction(LogAction.class);
if (logAction != null) {
AnnotatedLargeText<? extends FlowNode> logText = logAction.getLogText();
List<String> result = readLimitedLog(logText, maxLines);
if (result == null || result.isEmpty())
{
continue;
}
return result;

Check warning on line 80 in src/main/java/io/jenkins/plugins/explain_error/PipelineLogExtractor.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered lines

Lines 68-80 are not covered by tests
}
}
}
}

return run.getLog(maxLines);
}
}
Loading