Coverage Report - org.apache.maven.plugin.invoker.InvokerReport
 
Classes in this File Line Coverage Branch Coverage Complexity
InvokerReport
0%
0/123
0%
0/20
2,077
 
 1  
 package org.apache.maven.plugin.invoker;
 2  
 
 3  
 /*
 4  
  * Licensed to the Apache Software Foundation (ASF) under one
 5  
  * or more contributor license agreements.  See the NOTICE file
 6  
  * distributed with this work for additional information
 7  
  * regarding copyright ownership.  The ASF licenses this file
 8  
  * to you under the Apache License, Version 2.0 (the
 9  
  * "License"); you may not use this file except in compliance
 10  
  * with the License.  You may obtain a copy of the License at
 11  
  *
 12  
  *    http://www.apache.org/licenses/LICENSE-2.0
 13  
  *
 14  
  * Unless required by applicable law or agreed to in writing,
 15  
  * software distributed under the License is distributed on an
 16  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 17  
  * KIND, either express or implied.  See the License for the
 18  
  * specific language governing permissions and limitations
 19  
  * under the License.
 20  
  */
 21  
 
 22  
 import java.io.File;
 23  
 import java.io.IOException;
 24  
 import java.text.DecimalFormat;
 25  
 import java.text.DecimalFormatSymbols;
 26  
 import java.text.NumberFormat;
 27  
 import java.util.ArrayList;
 28  
 import java.util.List;
 29  
 import java.util.Locale;
 30  
 
 31  
 import org.apache.maven.doxia.sink.Sink;
 32  
 import org.apache.maven.doxia.siterenderer.Renderer;
 33  
 import org.apache.maven.plugin.invoker.model.BuildJob;
 34  
 import org.apache.maven.plugin.invoker.model.io.xpp3.BuildJobXpp3Reader;
 35  
 import org.apache.maven.plugins.annotations.Component;
 36  
 import org.apache.maven.plugins.annotations.Mojo;
 37  
 import org.apache.maven.plugins.annotations.Parameter;
 38  
 import org.apache.maven.project.MavenProject;
 39  
 import org.apache.maven.reporting.AbstractMavenReport;
 40  
 import org.apache.maven.reporting.MavenReportException;
 41  
 import org.codehaus.plexus.i18n.I18N;
 42  
 import org.codehaus.plexus.util.ReaderFactory;
 43  
 import org.codehaus.plexus.util.StringUtils;
 44  
 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
 45  
 
 46  
 /**
 47  
  * Generate a report based on the results of the Maven invocations. <strong>Note:</strong> This mojo doesn't fork any
 48  
  * lifecycle, if you have a clean working copy, you have to use a command like
 49  
  * <code>mvn clean integration-test site</code> to ensure the build results are present when this goal is invoked.
 50  
  * 
 51  
  * @author Olivier Lamy
 52  
  * @since 1.4
 53  
  */
 54  
 @Mojo( name = "report", threadSafe = true )
 55  0
 public class InvokerReport
 56  
     extends AbstractMavenReport
 57  
 {
 58  
     
 59  
     /**
 60  
      * The Maven Project.
 61  
      */
 62  
     @Component
 63  
     protected MavenProject project;
 64  
     
 65  
     /**
 66  
      * Doxia Site Renderer component.
 67  
      */
 68  
     @Component
 69  
     protected Renderer siteRenderer;    
 70  
     
 71  
     /**
 72  
      * Internationalization component.
 73  
      */
 74  
     @Component
 75  
     protected I18N i18n;    
 76  
     
 77  
     /**
 78  
      * The output directory for the report. Note that this parameter is only evaluated if the goal is run directly from
 79  
      * the command line. If the goal is run indirectly as part of a site generation, the output directory configured in
 80  
      * the Maven Site Plugin is used instead.
 81  
      */
 82  
     @Parameter( defaultValue = "${project.reporting.outputDirectory}", required = true )
 83  
     protected File outputDirectory;    
 84  
     
 85  
     /**
 86  
      * Base directory where all build reports have been written to.
 87  
      */
 88  
     @Parameter( defaultValue = "${project.build.directory}/invoker-reports", property = "invoker.reportsDirectory" )
 89  
     private File reportsDirectory; 
 90  
 
 91  
     /**
 92  
      * The number format used to print percent values in the report locale.
 93  
      */
 94  
     private NumberFormat percentFormat;
 95  
 
 96  
     /**
 97  
      * The number format used to print time values in the report locale.
 98  
      */
 99  
     private NumberFormat secondsFormat;
 100  
 
 101  
     protected void executeReport( Locale locale )
 102  
         throws MavenReportException
 103  
     {
 104  0
         DecimalFormatSymbols symbols = new DecimalFormatSymbols( locale );
 105  0
         percentFormat = new DecimalFormat( getText( locale, "report.invoker.format.percent" ), symbols );
 106  0
         secondsFormat = new DecimalFormat( getText( locale, "report.invoker.format.seconds" ), symbols );
 107  
 
 108  0
         Sink sink = getSink();
 109  
 
 110  0
         sink.head();
 111  
 
 112  0
         sink.title();
 113  0
         sink.text( getText( locale, "report.invoker.result.title" ) );
 114  0
         sink.title_();
 115  
 
 116  0
         sink.head_();
 117  
 
 118  0
         sink.body();
 119  
 
 120  0
         sink.section1();
 121  0
         sink.sectionTitle1();
 122  0
         sink.text( getText( locale, "report.invoker.result.title" ) );
 123  0
         sink.sectionTitle1_();
 124  0
         sink.paragraph();
 125  0
         sink.text( getText( locale, "report.invoker.result.description" ) );
 126  0
         sink.paragraph_();
 127  0
         sink.section1_();
 128  
 
 129  
         // ----------------------------------
 130  
         //  build buildJob beans
 131  
         // ----------------------------------
 132  0
         File[] reportFiles = ReportUtils.getReportFiles( reportsDirectory );
 133  0
         if ( reportFiles.length <= 0 )
 134  
         {
 135  0
             getLog().info( "no invoker report files found, skip report generation" );
 136  0
             return;
 137  
         }
 138  
 
 139  0
         List<BuildJob> buildJobs = new ArrayList<BuildJob>( reportFiles.length );
 140  0
         for ( File reportFile : reportFiles )
 141  
         {
 142  
             try
 143  
             {
 144  0
                 BuildJobXpp3Reader reader = new BuildJobXpp3Reader();
 145  0
                 buildJobs.add( reader.read( ReaderFactory.newXmlReader( reportFile ) ) );
 146  
             }
 147  0
             catch ( XmlPullParserException e )
 148  
             {
 149  0
                 throw new MavenReportException( "Failed to parse report file: " + reportFile, e );
 150  
             }
 151  0
             catch ( IOException e )
 152  
             {
 153  0
                 throw new MavenReportException( "Failed to read report file: " + reportFile, e );
 154  0
             }
 155  
         }
 156  
 
 157  
         // ----------------------------------
 158  
         //  summary
 159  
         // ----------------------------------
 160  
         
 161  0
         constructSummarySection( buildJobs, locale );
 162  
         
 163  
         // ----------------------------------
 164  
         //  per file/it detail
 165  
         // ----------------------------------        
 166  
 
 167  0
         sink.section2();
 168  0
         sink.sectionTitle2();
 169  
 
 170  0
         sink.text( getText( locale, "report.invoker.detail.title" ) );
 171  
 
 172  0
         sink.sectionTitle2_();
 173  
 
 174  0
         sink.section2_();
 175  
 
 176  
         // detail tests table header
 177  0
         sink.table();
 178  
 
 179  0
         sink.tableRow();
 180  
         // -------------------------------------------
 181  
         // name | Result | time | message
 182  
         // -------------------------------------------
 183  0
         sinkTableHeader( sink, getText( locale, "report.invoker.detail.name" ) );
 184  0
         sinkTableHeader( sink, getText( locale, "report.invoker.detail.result" ) );
 185  0
         sinkTableHeader( sink, getText( locale, "report.invoker.detail.time" ) );
 186  0
         sinkTableHeader( sink, getText( locale, "report.invoker.detail.message" ) );
 187  
 
 188  0
         sink.tableRow_();
 189  
 
 190  0
         for ( BuildJob buildJob : buildJobs )
 191  
         {
 192  0
             renderBuildJob( buildJob, locale );
 193  
         }
 194  
 
 195  0
         sink.table_();
 196  
 
 197  0
         sink.body_();
 198  
 
 199  0
         sink.flush();
 200  0
         sink.close();
 201  0
     }
 202  
 
 203  
     private void constructSummarySection( List<? extends BuildJob> buildJobs, Locale locale )
 204  
     {
 205  0
         Sink sink = getSink();
 206  
 
 207  0
         sink.section2();
 208  0
         sink.sectionTitle2();
 209  
 
 210  0
         sink.text( getText( locale, "report.invoker.summary.title" ) );
 211  
 
 212  0
         sink.sectionTitle2_();
 213  0
         sink.section2_();
 214  
 
 215  
         // ------------------------------------------------------------------------
 216  
         // Building a table with
 217  
         // it number | succes nb | failed nb | Success rate | total time | avg time
 218  
         // ------------------------------------------------------------------------
 219  
 
 220  0
         sink.table();
 221  0
         sink.tableRow();
 222  
 
 223  0
         sinkTableHeader( sink, getText( locale, "report.invoker.summary.number" ) );
 224  0
         sinkTableHeader( sink, getText( locale, "report.invoker.summary.success" ) );
 225  0
         sinkTableHeader( sink, getText( locale, "report.invoker.summary.failed" ) );
 226  0
         sinkTableHeader( sink, getText( locale, "report.invoker.summary.skipped" ) );
 227  0
         sinkTableHeader( sink, getText( locale, "report.invoker.summary.success.rate" ) );
 228  0
         sinkTableHeader( sink, getText( locale, "report.invoker.summary.time.total" ) );
 229  0
         sinkTableHeader( sink, getText( locale, "report.invoker.summary.time.avg" ) );
 230  
 
 231  0
         int number = buildJobs.size();
 232  0
         int success = 0;
 233  0
         int failed = 0;
 234  0
         int skipped = 0;
 235  0
         double totalTime = 0;
 236  
 
 237  0
         for ( BuildJob buildJob : buildJobs )
 238  
         {
 239  0
             if ( BuildJob.Result.SUCCESS.equals( buildJob.getResult() ) )
 240  
             {
 241  0
                 success++;
 242  
             }
 243  0
             else if ( BuildJob.Result.SKIPPED.equals( buildJob.getResult() ) )
 244  
             {
 245  0
                 skipped++;
 246  
             }
 247  
             else
 248  
             {
 249  0
                 failed++;
 250  
             }
 251  0
             totalTime += buildJob.getTime();
 252  
         }
 253  
 
 254  0
         sink.tableRow_();
 255  0
         sink.tableRow();
 256  
 
 257  0
         sinkCell( sink, Integer.toString( number ) );
 258  0
         sinkCell( sink, Integer.toString( success ) );
 259  0
         sinkCell( sink, Integer.toString( failed ) );
 260  0
         sinkCell( sink, Integer.toString( skipped ) );
 261  
 
 262  0
         if ( success + failed > 0 )
 263  
         {
 264  0
             sinkCell( sink, percentFormat.format( (double) success / ( success + failed ) ) );
 265  
         }
 266  
         else
 267  
         {
 268  0
             sinkCell( sink, "" );
 269  
         }
 270  
 
 271  0
         sinkCell( sink, secondsFormat.format( totalTime ) );
 272  
 
 273  0
         sinkCell( sink, secondsFormat.format( totalTime / number ) );
 274  
 
 275  0
         sink.tableRow_();
 276  0
         sink.table_();
 277  
 
 278  0
     }
 279  
 
 280  
     private void renderBuildJob( BuildJob buildJob, Locale locale )
 281  
     {
 282  0
         Sink sink = getSink();
 283  0
         sink.tableRow();
 284  0
         StringBuilder buffer = new StringBuilder();
 285  0
         if ( !StringUtils.isEmpty( buildJob.getName() ) && !StringUtils.isEmpty( buildJob.getDescription() ) )
 286  
         {
 287  0
             buffer.append( buildJob.getName() );
 288  0
             buffer.append( " : " );
 289  0
             buffer.append( buildJob.getDescription() );
 290  
         }
 291  
         else
 292  
         {
 293  0
             buffer.append( buildJob.getProject() );
 294  
         }
 295  0
         sinkCell( sink, buffer.toString() );
 296  
         // FIXME image
 297  0
         sinkCell( sink, buildJob.getResult() );
 298  0
         sinkCell( sink, secondsFormat.format( buildJob.getTime() ) );
 299  0
         sinkCell( sink, buildJob.getFailureMessage() );
 300  0
         sink.tableRow_();
 301  0
     }
 302  
 
 303  
     protected String getOutputDirectory()
 304  
     {
 305  0
         return outputDirectory.getAbsolutePath();
 306  
     }
 307  
 
 308  
     protected MavenProject getProject()
 309  
     {
 310  0
         return project;
 311  
     }
 312  
 
 313  
     protected Renderer getSiteRenderer()
 314  
     {
 315  0
         return siteRenderer;
 316  
     }
 317  
 
 318  
     public String getDescription( Locale locale )
 319  
     {
 320  0
         return getText( locale, "report.invoker.result.description" );
 321  
     }
 322  
 
 323  
     public String getName( Locale locale )
 324  
     {
 325  0
         return getText( locale, "report.invoker.result.name" );
 326  
     }
 327  
 
 328  
     public String getOutputName()
 329  
     {
 330  0
         return "invoker-report";
 331  
     }
 332  
 
 333  
     public boolean canGenerateReport()
 334  
     {
 335  0
         return ReportUtils.getReportFiles( reportsDirectory ).length > 0;
 336  
     }
 337  
 
 338  
     private String getText( Locale locale, String key )
 339  
     {
 340  0
         return i18n.getString( "invoker-report", locale, key );
 341  
     }
 342  
 
 343  
     private void sinkTableHeader( Sink sink, String header )
 344  
     {
 345  0
         sink.tableHeaderCell();
 346  0
         sink.text( header );
 347  0
         sink.tableHeaderCell_();
 348  0
     }
 349  
 
 350  
     private void sinkCell( Sink sink, String text )
 351  
     {
 352  0
         sink.tableCell();
 353  0
         sink.text( text );
 354  0
         sink.tableCell_();
 355  0
     }
 356  
 
 357  
 }