<% def lastSuccesfulBuild = build.previousNotFailedBuild def failed = build.result != hudson.model.Result.SUCCESS def currResult = build.result def prevResult = build.previousBuild?.result ?: null def consecutiveSuccess = currResult == hudson.model.Result.SUCCESS && prevResult == hudson.model.Result.SUCCESS def builds = [] def changes = [] def count = 0 if(consecutiveSuccess){ builds << build def changeItems = build.changeSet.items count += changeItems.length changes += changeItems as List }else{ while(lastSuccesfulBuild){ builds << lastSuccesfulBuild def changeItems = lastSuccesfulBuild.changeSet.items count += changeItems.length changes += changeItems as List lastSuccesfulBuild = lastSuccesfulBuild.nextBuild } } %>

Build Result - $BUILD_STATUS

Build Information

Modifications since last successful build:  (${count})

<% changes.eachWithIndex { item, index -> %> <% if (index) { %>
<% } %> ${item.revision} by ${item.author} on ${item.date}
${item.msg}
<% } %>
<% if(build.testResultAction) { def rootUrl = hudson.model.Hudson.instance.rootUrl def testResult = build.testResultAction def jobName = build.parent.name def lastBuildSuccessRate = String.format("%.2f",(testResult.totalCount-testResult.result.failCount)*100f/(testResult.totalCount)) def lastBuildDuration = String.format("%.2f",(testResult.result.duration )) def startedPassing = [] def startedFailing = [] def failing = [] def previousFailedTestCases = new HashSet() def currentFailedTestCase = new HashSet() if(build.previousBuild?.testResultAction){ build.previousBuild.testResultAction.failedTests.each { previousFailedTestCases << it.fullName } } testResult.failedTests.each{tr -> def packageName = tr.packageName def className = tr.simpleName def testName = tr.safeName def displayName = tr.fullName currentFailedTestCase << displayName def url = "${rootUrl}job/$jobName/lastBuild/testReport/$packageName/$className/$testName" if(tr.age == 1){ startedFailing << [displayName:displayName,url:url,age:1] } else{ failing << [displayName:displayName,url:url,age:tr.age] } } startedPassing = previousFailedTestCases - currentFailedTestCase startedFailing = startedFailing.sort {it.displayName} failing = failing.sort {it.displayName} startedPassing = startedPassing.sort() %>

Test Results

Summary -

<% if (startedPassing) {%>

The Good - The following testcases started passing. Good work!

<% def row = 0 startedPassing.each { %> <% } %>
${it.split(/\./)[-1]} ${it.split(/\./)[0..-2].join('.')}
<% } %> <% if (startedFailing) {%>

The Bad - The following testcases started FAILING. ${count?'Did the last change cause it?':''}

<% def row = 0 startedFailing.each { %> <% } %>
${it.displayName.split(/\./)[-1]} ${it.displayName.split(/\./)[0..-2].join('.')}
<% } %> <% if (failing) {%>

The Ugly - The following testcases are still failing. Someone should look into it!

<% def row = 0 failing.each { %> <% } %>
TestClassConsecutive
Failed
Builds
${it.displayName.split(/\./)[-1]} ${it.displayName.split(/\./)[0..-2].join('.')} $it.age
<% } %> <% if (testResult.failedTests) { %>

Unit Test Error Details

<% testResult.failedTests.each {tr -> %>
Test: $tr.name
Class: $tr.className
<% def row = 0; tr.errorStackTrace.readLines().each {line -> %>
$line
<% } %>
<% } %> <% } %> <% } %> <% if(failed) {%>

Server Logs

${build.getLog(100).join('
')} <% } %>