diff --git a/src/main/java/com/sonyericsson/jenkins/plugins/bfa/BuildFailureScanner.java b/src/main/java/com/sonyericsson/jenkins/plugins/bfa/BuildFailureScanner.java index 3e9afcd7..3763a849 100644 --- a/src/main/java/com/sonyericsson/jenkins/plugins/bfa/BuildFailureScanner.java +++ b/src/main/java/com/sonyericsson/jenkins/plugins/bfa/BuildFailureScanner.java @@ -171,7 +171,8 @@ public static void scanIfNotScanned(final Run build, final PrintStream scanLog) * @param scanLog log to write information to. */ public static void scan(Run build, PrintStream scanLog) { - build.addOrReplaceAction(new ScanLogAction()); + ScanLogAction scanLogAction = new ScanLogAction(); + build.addOrReplaceAction(scanLogAction); try { Collection causes = PluginImpl.getInstance().getKnowledgeBase().getCauses(); List foundCauseListToLog = findCauses(causes, build, scanLog); @@ -262,7 +263,10 @@ public static void scan(Run build, PrintStream scanLog) { } } } catch (Exception e) { + scanLogAction.setExceptionMessage(e.toString()); logger.log(Level.SEVERE, "Could not scan build " + build, e); + } finally { + scanLogAction.finished(); } } @@ -591,8 +595,12 @@ private static List parseSingleLineCauses(Run build, build, reader, LOG_FILE_NAME)); - } catch (IOException e) { + } catch (Exception e) { logToScanLog(scanLog, "Exception during parsing file: " + e); + ScanLogAction logAction = build.getAction(ScanLogAction.class); + if (logAction != null && logAction.getExceptionMessage() == null) { + logAction.setExceptionMessage(e.toString()); + } } finally { if (reader != null) { try { diff --git a/src/main/java/com/sonyericsson/jenkins/plugins/bfa/ScanLogAction.java b/src/main/java/com/sonyericsson/jenkins/plugins/bfa/ScanLogAction.java index 417b915a..aa3c3e85 100644 --- a/src/main/java/com/sonyericsson/jenkins/plugins/bfa/ScanLogAction.java +++ b/src/main/java/com/sonyericsson/jenkins/plugins/bfa/ScanLogAction.java @@ -7,10 +7,15 @@ import java.nio.charset.StandardCharsets; import jenkins.model.RunAction2; import org.apache.commons.io.FileUtils; +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.NoExternalUse; +import org.kohsuke.stapler.export.Exported; +import org.kohsuke.stapler.export.ExportedBean; /** * The Action for adding a link to the analysis for each run. */ +@ExportedBean public class ScanLogAction implements RunAction2 { /** @@ -20,6 +25,12 @@ public class ScanLogAction implements RunAction2 { private transient Run run; + private long startTime = System.currentTimeMillis(); + + private Long endTime; + + private String exceptionMessage; + /** * {@inheritDoc} */ @@ -64,6 +75,48 @@ public String getLogText() throws IOException { return FileUtils.readFileToString(new File(run.getRootDir(), FILE_NAME), StandardCharsets.UTF_8); } + /** + * The start time of the current scan. + * @return time in milliseconds {@link System#currentTimeMillis} + */ + @Exported + public long getStartTime() { + return startTime; + } + + /** + * The end time of the current scan. + * @return time in milliseconds {@link System#currentTimeMillis} + */ + @Exported + public Long getEndTime() { + return endTime; + } + + /** + * To call when the scan is finished. + */ + @Restricted(NoExternalUse.class) + protected void finished() { + this.endTime = System.currentTimeMillis(); + } + + /** + * Get the exception message if any. + * @return the first exception faced during scan + */ + public String getExceptionMessage() { + return exceptionMessage; + } + + /** + * Set an exception. + * @param exceptionMessage the exception message to set + */ + public void setExceptionMessage(String exceptionMessage) { + this.exceptionMessage = exceptionMessage; + } + /** * {@inheritDoc} */ diff --git a/src/test/java/com/sonyericsson/jenkins/plugins/bfa/BuildFailureScannerHudsonTest.java b/src/test/java/com/sonyericsson/jenkins/plugins/bfa/BuildFailureScannerHudsonTest.java index 39654d23..c24fc9e9 100644 --- a/src/test/java/com/sonyericsson/jenkins/plugins/bfa/BuildFailureScannerHudsonTest.java +++ b/src/test/java/com/sonyericsson/jenkins/plugins/bfa/BuildFailureScannerHudsonTest.java @@ -129,6 +129,12 @@ public void testOneIndicationFound() throws Exception { FreeStyleBuild build = future.get(10, TimeUnit.SECONDS); jenkins.assertBuildStatus(Result.FAILURE, build); + ScanLogAction scanLogAction = build.getAction(ScanLogAction.class); + assertNotNull(scanLogAction); + assertNotNull(scanLogAction.getStartTime()); + assertNotNull(scanLogAction.getEndTime()); + assertNull(scanLogAction.getExceptionMessage()); + FailureCauseBuildAction action = build.getAction(FailureCauseBuildAction.class); assertNotNull(action); List causeListFromAction = action.getFoundFailureCauses(); @@ -155,6 +161,31 @@ public void testOneIndicationFound() throws Exception { assertEquals(1, metricRegistry.counter("jenkins_bfa.cause.Error").getCount()); } + /** + * Test when an exception occurred during scan. + * @throws Exception if so. + */ + @Test + public void testExceptionDuringParsing() throws Exception { + FreeStyleProject project = createProject(); + + FailureCause failureCause = configureCauseAndIndication(new BuildLogIndication("(wrong pattern")); + + QueueTaskFuture future = project.scheduleBuild2(0, new Cause.UserIdCause()); + + FreeStyleBuild build = future.get(10, TimeUnit.SECONDS); + jenkins.assertBuildStatus(Result.FAILURE, build); + + ScanLogAction scanLogAction = build.getAction(ScanLogAction.class); + assertNotNull(scanLogAction); + assertNotNull(scanLogAction.getStartTime()); + assertNotNull(scanLogAction.getEndTime()); + assertNotNull(scanLogAction.getExceptionMessage()); + + FailureCauseBuildAction action = build.getAction(FailureCauseBuildAction.class); + assertNotNull(action); + } + /** * Happy test that should find one generic failure indication in the build. *