Coverage Report - org.apache.maven.plugin.invoker.InvokerReport
 
Classes in this File Line Coverage Branch Coverage Complexity
InvokerReport
0 %
0/120
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.project.MavenProject;
 36  
 import org.apache.maven.reporting.AbstractMavenReport;
 37  
 import org.apache.maven.reporting.MavenReportException;
 38  
 import org.codehaus.plexus.i18n.I18N;
 39  
 import org.codehaus.plexus.util.ReaderFactory;
 40  
 import org.codehaus.plexus.util.StringUtils;
 41  
 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
 42  
 
 43  
 /**
 44  
  * Generate a report based on the results of the Maven invocations. <strong>Note:</strong> This mojo doesn't fork any
 45  
  * lifecycle, if you have a clean working copy, you have to use a command like
 46  
  * <code>mvn clean integration-test site</code> to ensure the build results are present when this goal is invoked.
 47  
  * 
 48  
  * @goal report
 49  
  * @author <a href="mailto:olamy@apache.org">olamy</a>
 50  
  * @threadSafe
 51  
  * @since 1.4
 52  
  */
 53  0
 public class InvokerReport
 54  
     extends AbstractMavenReport
 55  
 {
 56  
     
 57  
     /**
 58  
      * The Maven Project.
 59  
      *
 60  
      * @parameter default-value="${project}"
 61  
      * @required
 62  
      * @readonly
 63  
      */
 64  
     protected MavenProject project;
 65  
     
 66  
     /**
 67  
      * Doxia Site Renderer component.
 68  
      *
 69  
      * @component
 70  
      */
 71  
     protected Renderer siteRenderer;    
 72  
     
 73  
     /**
 74  
      * Internationalization component.
 75  
      *
 76  
      * @component
 77  
      */
 78  
     protected I18N i18n;    
 79  
     
 80  
     /**
 81  
      * The output directory for the report. Note that this parameter is only evaluated if the goal is run directly from
 82  
      * the command line. If the goal is run indirectly as part of a site generation, the output directory configured in
 83  
      * the Maven Site Plugin is used instead.
 84  
      *
 85  
      * @parameter default-value="${project.reporting.outputDirectory}"
 86  
      * @required
 87  
      */
 88  
     protected File outputDirectory;    
 89  
     
 90  
     /**
 91  
      * Base directory where all build reports have been written to.
 92  
      *
 93  
      * @parameter expression="${invoker.reportsDirectory}" default-value="${project.build.directory}/invoker-reports"
 94  
      */
 95  
     private File reportsDirectory; 
 96  
 
 97  
     /**
 98  
      * The number format used to print percent values in the report locale.
 99  
      */
 100  
     private NumberFormat percentFormat;
 101  
 
 102  
     /**
 103  
      * The number format used to print time values in the report locale.
 104  
      */
 105  
     private NumberFormat secondsFormat;
 106  
 
 107  
     protected void executeReport( Locale locale )
 108  
         throws MavenReportException
 109  
     {
 110  0
         DecimalFormatSymbols symbols = new DecimalFormatSymbols( locale );
 111  0
         percentFormat = new DecimalFormat( getText( locale, "report.invoker.format.percent" ), symbols );
 112  0
         secondsFormat = new DecimalFormat( getText( locale, "report.invoker.format.seconds" ), symbols );
 113  
 
 114  0
         Sink sink = getSink();
 115  
 
 116  0
         sink.head();
 117  
 
 118  0
         sink.title();
 119  0
         sink.text( getText( locale, "report.invoker.result.title" ) );
 120  0
         sink.title_();
 121  
 
 122  0
         sink.head_();
 123  
 
 124  0
         sink.body();
 125  
 
 126  0
         sink.section1();
 127  0
         sink.sectionTitle1();
 128  0
         sink.text( getText( locale, "report.invoker.result.title" ) );
 129  0
         sink.sectionTitle1_();
 130  0
         sink.paragraph();
 131  0
         sink.text( getText( locale, "report.invoker.result.description" ) );
 132  0
         sink.paragraph_();
 133  0
         sink.section1_();
 134  
 
 135  
         // ----------------------------------
 136  
         //  build buildJob beans
 137  
         // ----------------------------------
 138  0
         File[] reportFiles = ReportUtils.getReportFiles( reportsDirectory );
 139  0
         if ( reportFiles.length <= 0 )
 140  
         {
 141  0
             getLog().info( "no invoker report files found, skip report generation" );
 142  0
             return;
 143  
         }
 144  
 
 145  0
         List<BuildJob> buildJobs = new ArrayList<BuildJob>( reportFiles.length );
 146  0
         for ( int i = 0, size = reportFiles.length; i < size; i++ )
 147  
         {
 148  0
             File reportFile = reportFiles[i];
 149  
             try
 150  
             {
 151  0
                 BuildJobXpp3Reader reader = new BuildJobXpp3Reader();
 152  0
                 buildJobs.add( reader.read( ReaderFactory.newXmlReader( reportFile ) ) );
 153  
             }
 154  0
             catch ( XmlPullParserException e )
 155  
             {
 156  0
                 throw new MavenReportException( "Failed to parse report file: " + reportFile, e );
 157  
             }
 158  0
             catch ( IOException e )
 159  
             {
 160  0
                 throw new MavenReportException( "Failed to read report file: " + reportFile, e );
 161  0
             }
 162  
         }
 163  
 
 164  
         // ----------------------------------
 165  
         //  summary
 166  
         // ----------------------------------
 167  
         
 168  0
         constructSummarySection( buildJobs, locale );
 169  
         
 170  
         // ----------------------------------
 171  
         //  per file/it detail
 172  
         // ----------------------------------        
 173  
 
 174  0
         sink.section2();
 175  0
         sink.sectionTitle2();
 176  
 
 177  0
         sink.text( getText( locale, "report.invoker.detail.title" ) );
 178  
 
 179  0
         sink.sectionTitle2_();
 180  
 
 181  0
         sink.section2_();
 182  
 
 183  
         // detail tests table header
 184  0
         sink.table();
 185  
 
 186  0
         sink.tableRow();
 187  
         // -------------------------------------------
 188  
         // name | Result | time | message
 189  
         // -------------------------------------------
 190  0
         sinkTableHeader( sink, getText( locale, "report.invoker.detail.name" ) );
 191  0
         sinkTableHeader( sink, getText( locale, "report.invoker.detail.result" ) );
 192  0
         sinkTableHeader( sink, getText( locale, "report.invoker.detail.time" ) );
 193  0
         sinkTableHeader( sink, getText( locale, "report.invoker.detail.message" ) );
 194  
 
 195  0
         sink.tableRow_();
 196  
 
 197  0
         for ( BuildJob buildJob : buildJobs )
 198  
         {
 199  0
             renderBuildJob( buildJob, locale );
 200  
         }
 201  
 
 202  0
         sink.table_();
 203  
 
 204  0
         sink.body_();
 205  
 
 206  0
         sink.flush();
 207  0
         sink.close();
 208  0
     }
 209  
 
 210  
     private void constructSummarySection( List<? extends BuildJob> buildJobs, Locale locale )
 211  
     {
 212  0
         Sink sink = getSink();
 213  
 
 214  0
         sink.section2();
 215  0
         sink.sectionTitle2();
 216  
 
 217  0
         sink.text( getText( locale, "report.invoker.summary.title" ) );
 218  
 
 219  0
         sink.sectionTitle2_();
 220  0
         sink.section2_();
 221  
 
 222  
         // ------------------------------------------------------------------------
 223  
         // Building a table with
 224  
         // it number | succes nb | failed nb | Success rate | total time | avg time
 225  
         // ------------------------------------------------------------------------
 226  
 
 227  0
         sink.table();
 228  0
         sink.tableRow();
 229  
 
 230  0
         sinkTableHeader( sink, getText( locale, "report.invoker.summary.number" ) );
 231  0
         sinkTableHeader( sink, getText( locale, "report.invoker.summary.success" ) );
 232  0
         sinkTableHeader( sink, getText( locale, "report.invoker.summary.failed" ) );
 233  0
         sinkTableHeader( sink, getText( locale, "report.invoker.summary.success.rate" ) );
 234  0
         sinkTableHeader( sink, getText( locale, "report.invoker.summary.time.total" ) );
 235  0
         sinkTableHeader( sink, getText( locale, "report.invoker.summary.time.avg" ) );
 236  
 
 237  0
         int number = buildJobs.size();
 238  0
         int success = 0;
 239  0
         int failed = 0;
 240  0
         double totalTime = 0;
 241  
 
 242  0
         for ( BuildJob buildJob : buildJobs )
 243  
         {
 244  0
             if ( BuildJob.Result.SUCCESS.equals( buildJob.getResult() ) )
 245  
             {
 246  0
                 success++;
 247  
             }
 248  0
             else if ( !BuildJob.Result.SKIPPED.equals( buildJob.getResult() ) )
 249  
             {
 250  0
                 failed++;
 251  
             }
 252  0
             totalTime += buildJob.getTime();
 253  
         }
 254  
 
 255  0
         sink.tableRow_();
 256  0
         sink.tableRow();
 257  
 
 258  0
         sinkCell( sink, Integer.toString( number ) );
 259  0
         sinkCell( sink, Integer.toString( success ) );
 260  0
         sinkCell( sink, Integer.toString( failed ) );
 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
         StringBuffer buffer = new StringBuffer();
 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  
 }