package hudson.plugins.mibsr.parser; import hudson.model.AbstractBuild; import hudson.util.IOException2; import org.apache.maven.plugin.invoker.model.BuildJob; import org.apache.maven.plugin.invoker.model.io.xpp3.BuildJobXpp3Reader; import org.codehaus.plexus.util.xml.pull.XmlPullParserException; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; import java.io.BufferedInputStream; import java.io.FileInputStream; import java.io.IOException; import java.io.Serializable; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Set; import java.util.SortedMap; import java.util.TreeMap; import java.util.TreeSet; /** * TODO javadoc. * * @author Stephen Connolly * @since 25-Feb-2008 21:33:40 */ public class BuildJobs implements Serializable { // ------------------------------ FIELDS ------------------------------ private AbstractBuild<?, ?> owner; private SortedMap<String, BuildJob> buildJobs = new TreeMap<String, BuildJob>(); private String name; public final Set<String> SUCCESSFUL = fixedTreeSet( BuildJob.Result.SUCCESS ); public final Set<String> UNSUCCESSFUL = fixedTreeSet( BuildJob.Result.ERROR, BuildJob.Result.FAILURE_PRE_HOOK, BuildJob.Result.FAILURE_BUILD, BuildJob.Result.FAILURE_POST_HOOK ); public final Set<String> SKIPPED = fixedTreeSet( BuildJob.Result.SKIPPED ); private static <T> Set<T> fixedTreeSet( T... elements ) { return Collections.unmodifiableSet( new TreeSet<T>( Arrays.asList( elements ) ) ); } /** * Gets the version of a string that's URL-safe. */ public static String makeSafe( String unsafe ) { StringBuffer buf = new StringBuffer( unsafe ); for ( int i = 0; i < buf.length(); i++ ) { char ch = buf.charAt( i ); if ( !Character.isJavaIdentifierPart( ch ) ) { buf.setCharAt( i, '_' ); } } return buf.toString(); } // -------------------------- STATIC METHODS -------------------------- public static BuildJobs parse( String[] inFiles ) throws IOException { BuildJobs results = new BuildJobs(); FileInputStream fis = null; BufferedInputStream bis = null; BuildJobXpp3Reader reader = new BuildJobXpp3Reader(); for ( String inFile : inFiles ) { try { fis = new FileInputStream( inFile ); bis = new BufferedInputStream( fis ); results.add( reader.read( bis ) ); } catch ( XmlPullParserException e ) { throw new IOException2( "Could not parse build job buildJobs file " + inFile, e ); } finally { if ( bis != null ) { bis.close(); } if ( fis != null ) { fis.close(); } } } return results; } public void add( BuildJob r ) { String key = makeSafe( r.getProject() ); if ( buildJobs.containsKey( key ) ) { int num = 1; while ( buildJobs.containsKey( key + num ) ) { num++; } key = key + num; } buildJobs.put( key, r ); } public static BuildJobs total( BuildJobs... results ) { return total( Arrays.asList( results ) ); } public static BuildJobs total( Collection<BuildJobs> results ) { if ( results.isEmpty() ) { return new BuildJobs(); } else if ( results.size() == 1 ) { return results.iterator().next(); } else { BuildJobs merged = new BuildJobs(); for ( BuildJobs result : results ) { merged.addAll( result.buildJobs.values() ); } return merged; } } // --------------------------- CONSTRUCTORS --------------------------- public BuildJobs() { } public BuildJob getDynamic( String name, StaplerRequest req, StaplerResponse resp ) { return buildJobs.get( name ); } // --------------------- GETTER / SETTER METHODS --------------------- public AbstractBuild<?, ?> getOwner() { return owner; } public void setOwner( AbstractBuild<?, ?> owner ) { this.owner = owner; } // ------------------------ CANONICAL METHODS ------------------------ public boolean equals( Object o ) { if ( this == o ) { return true; } if ( o == null || getClass() != o.getClass() ) { return false; } BuildJobs buildJobs = (BuildJobs) o; if ( owner != null ? !owner.equals( buildJobs.owner ) : buildJobs.owner != null ) { return false; } if ( this.buildJobs != null ? !this.buildJobs.equals( buildJobs.buildJobs ) : buildJobs.buildJobs != null ) { return false; } return true; } public int hashCode() { int result; result = ( owner != null ? owner.hashCode() : 0 ); return result; } public String toString() { return "BuildJobs{" + '}'; } public String toSummary() { return "<ul>" + "Build Jobs" + "</ul>"; } private static String diff( long a, long b, String name ) { if ( a == b ) { return ""; } else if ( a < b ) { return "<li>" + name + " (+" + ( b - a ) + ")</li>"; } else { // if (a < b) return "<li>" + name + " (-" + ( a - b ) + ")</li>"; } } public String toSummary( BuildJobs totals ) { return "<ul>" + diff( totals.getTotalCount(), getTotalCount(), "integration tests" ) + diff( totals.getPassCount(), getPassCount(), "successful" ) + diff( totals.getSkipCount(), getSkipCount(), "skipped" ) + diff( totals.getErrorCount(), getErrorCount(), "error" ) + diff( totals.getFailCount(), getFailCount(), "total failing" ) + diff( totals.getFailInitCount(), getFailInitCount(), "failing before run" ) + diff( totals.getFailRunCount(), getFailRunCount(), "failing during run" ) + diff( totals.getFailRunCount(), getFailRunCount(), "failing after run" ) + "</ul>"; } public void set( BuildJobs that ) { this.name = that.name; this.buildJobs = new TreeMap<String, BuildJob>( that.buildJobs ); } public int getPassCount() { return getCount( BuildJob.Result.SUCCESS ); } private int getCount( String... resultTypes ) { int total = 0; for ( BuildJob result : buildJobs.values() ) { for ( String resultType : resultTypes ) { if ( result.getResult().equalsIgnoreCase( resultType ) ) { total++; } } } return total; } private double getTime( String... resultTypes ) { double total = 0; for ( BuildJob result : buildJobs.values() ) { for ( String resultType : resultTypes ) { if ( result.getResult().equalsIgnoreCase( resultType ) ) { total += result.getTime(); } } } return Math.round( total * 10.0 ) / 10.0; } public double getPassTime() { return getTime( BuildJob.Result.SUCCESS ); } public int getSkipCount() { return getCount( BuildJob.Result.SKIPPED ); } public double getSkipTime() { return getTime( BuildJob.Result.SKIPPED ); } public int getErrorCount() { return getCount( BuildJob.Result.ERROR ); } public double getErrorTime() { return getTime( BuildJob.Result.ERROR ); } public int getFailInitCount() { return getCount( BuildJob.Result.FAILURE_PRE_HOOK ); } public double getFailInitTime() { return getTime( BuildJob.Result.FAILURE_PRE_HOOK ); } public int getFailRunCount() { return getCount( BuildJob.Result.FAILURE_BUILD ); } public double getFailRunTime() { return getTime( BuildJob.Result.FAILURE_BUILD ); } public int getFailValidateCount() { return getCount( BuildJob.Result.FAILURE_POST_HOOK ); } public double getFailValidateTime() { return getTime( BuildJob.Result.FAILURE_POST_HOOK ); } public int getFailCount() { return getCount( BuildJob.Result.FAILURE_PRE_HOOK, BuildJob.Result.FAILURE_BUILD, BuildJob.Result.FAILURE_POST_HOOK ); } public double getFailTime() { return getTime( BuildJob.Result.FAILURE_PRE_HOOK, BuildJob.Result.FAILURE_BUILD, BuildJob.Result.FAILURE_POST_HOOK ); } public int getTotalCount() { return buildJobs.size(); } public double getTotalTime() { double total = 0; for ( BuildJob result : buildJobs.values() ) { total += result.getTime(); } return Math.round( total * 10.0 ) / 10.0; } public Collection<BuildJob> getBuildJobs() { return buildJobs.values(); } public void addAll( Collection<BuildJob> results ) { for ( BuildJob job : results ) { add( job ); } } public void clear() { buildJobs.clear(); } public String getCssClass( BuildJob result ) { if ( BuildJob.Result.SUCCESS.equalsIgnoreCase( result.getResult() ) ) { return "result-passed"; } if ( BuildJob.Result.SKIPPED.equalsIgnoreCase( result.getResult() ) ) { return "result-skipped"; } if ( BuildJob.Result.ERROR.equalsIgnoreCase( result.getResult() ) ) { return "result-failed"; } return "result-failed"; } public static enum ResultType { SUCCESS( BuildJob.Result.SUCCESS ), SKIPPED( BuildJob.Result.SKIPPED ), ERROR( BuildJob.Result.ERROR ), FAILURE_PRE_HOOK( BuildJob.Result.FAILURE_PRE_HOOK ), FAILURE_BUILD( BuildJob.Result.FAILURE_BUILD ), FAILURE_POST_HOOK( BuildJob.Result.FAILURE_POST_HOOK ),; private final String xmlValue; ResultType( String xmlValue ) { this.xmlValue = xmlValue; } } }