View Javadoc
1   package org.apache.maven.plugins.surefire.report;
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.util.ArrayList;
24  import java.util.Iterator;
25  import java.util.List;
26  import java.util.Locale;
27  import java.util.ResourceBundle;
28  import org.apache.maven.model.ReportPlugin;
29  import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
30  import org.apache.maven.plugins.annotations.Parameter;
31  import org.apache.maven.project.MavenProject;
32  import org.apache.maven.reporting.AbstractMavenReport;
33  import org.apache.maven.reporting.MavenReportException;
34  import org.apache.maven.shared.utils.PathTool;
35  
36  import static java.util.Collections.addAll;
37  import static org.apache.maven.plugins.surefire.report.SurefireReportParser.hasReportFiles;
38  import static org.apache.maven.shared.utils.StringUtils.isEmpty;
39  
40  /**
41   * Abstract base class for reporting test results using Surefire.
42   *
43   * @author Stephen Connolly
44   */
45  public abstract class AbstractSurefireReportMojo
46      extends AbstractMavenReport
47  {
48  
49      /**
50       * If set to false, only failures are shown.
51       *
52       * @noinspection UnusedDeclaration
53       */
54      @Parameter( defaultValue = "true", required = true, property = "showSuccess" )
55      private boolean showSuccess;
56  
57      /**
58       * Directories containing the XML Report files that will be parsed and rendered to HTML format.
59       *
60       * @noinspection UnusedDeclaration
61       */
62      @Parameter
63      private File[] reportsDirectories;
64  
65      /**
66       * (Deprecated, use reportsDirectories) This directory contains the XML Report files that will be parsed and
67       * rendered to HTML format.
68       *
69       * @noinspection UnusedDeclaration
70       */
71      @Deprecated
72      @Parameter
73      private File reportsDirectory;
74  
75      /**
76       * The projects in the reactor for aggregation report.
77       *
78       * @noinspection MismatchedQueryAndUpdateOfCollection, UnusedDeclaration
79       */
80      @Parameter( defaultValue = "${reactorProjects}", readonly = true )
81      private List<MavenProject> reactorProjects;
82  
83      /**
84       * Location of the Xrefs to link.
85       *
86       * @noinspection UnusedDeclaration
87       */
88      @Parameter( defaultValue = "${project.reporting.outputDirectory}/xref-test" )
89      private File xrefLocation;
90  
91      /**
92       * Whether to link the XRef if found.
93       *
94       * @noinspection UnusedDeclaration
95       */
96      @Parameter( defaultValue = "true", property = "linkXRef" )
97      private boolean linkXRef;
98  
99      /**
100      * Whether to build an aggregated report at the root, or build individual reports.
101      *
102      * @noinspection UnusedDeclaration
103      */
104     @Parameter( defaultValue = "false", property = "aggregate" )
105     private boolean aggregate;
106 
107     private List<File> resolvedReportsDirectories;
108 
109     /**
110      * Whether the report should be generated or not.
111      *
112      * @return {@code true} if and only if the report should be generated.
113      * @since 2.11
114      */
115     protected boolean isSkipped()
116     {
117         return false;
118     }
119 
120     /**
121      * Whether the report should be generated when there are no test results.
122      *
123      * @return {@code true} if and only if the report should be generated when there are no result files at all.
124      * @since 2.11
125      */
126     protected boolean isGeneratedWhenNoResults()
127     {
128         return false;
129     }
130 
131     /**
132      * {@inheritDoc}
133      */
134     public void executeReport( Locale locale )
135         throws MavenReportException
136     {
137         if ( !hasReportDirectories() )
138         {
139             return;
140         }
141 
142         new SurefireReportGenerator( getReportsDirectories(), locale, showSuccess, determineXrefLocation(),
143                                            getConsoleLogger() )
144                 .doGenerateReport( getBundle( locale ), getSink() );
145     }
146 
147     @Override
148     public boolean canGenerateReport()
149     {
150         return hasReportDirectories() && super.canGenerateReport();
151     }
152 
153     private boolean hasReportDirectories()
154     {
155         if ( isSkipped() )
156         {
157             return false;
158         }
159 
160         final List<File> reportsDirectories = getReportsDirectories();
161 
162         if ( reportsDirectories == null )
163         {
164             return false;
165         }
166 
167         if ( !isGeneratedWhenNoResults() )
168         {
169             boolean atLeastOneDirectoryExists = false;
170             for ( Iterator<File> i = reportsDirectories.iterator(); i.hasNext() && !atLeastOneDirectoryExists; )
171             {
172                 atLeastOneDirectoryExists = hasReportFiles( i.next() );
173             }
174             if ( !atLeastOneDirectoryExists )
175             {
176                 return false;
177             }
178         }
179         return true;
180     }
181 
182     private List<File> getReportsDirectories()
183     {
184         if ( resolvedReportsDirectories != null )
185         {
186             return resolvedReportsDirectories;
187         }
188 
189         resolvedReportsDirectories = new ArrayList<File>();
190 
191         if ( this.reportsDirectories != null )
192         {
193             addAll( resolvedReportsDirectories, this.reportsDirectories );
194         }
195         //noinspection deprecation
196         if ( reportsDirectory != null )
197         {
198             //noinspection deprecation
199             resolvedReportsDirectories.add( reportsDirectory );
200         }
201         if ( aggregate )
202         {
203             if ( !project.isExecutionRoot() )
204             {
205                 return null;
206             }
207             if ( this.reportsDirectories == null )
208             {
209                 for ( MavenProject mavenProject : getProjectsWithoutRoot() )
210                 {
211                     resolvedReportsDirectories.add( getSurefireReportsDirectory( mavenProject ) );
212                 }
213             }
214             else
215             {
216                 // Multiple report directories are configured.
217                 // Let's see if those directories exist in each sub-module to fix SUREFIRE-570
218                 String parentBaseDir = getProject().getBasedir().getAbsolutePath();
219                 for ( MavenProject subProject : getProjectsWithoutRoot() )
220                 {
221                     String moduleBaseDir = subProject.getBasedir().getAbsolutePath();
222                     for ( File reportsDirectory1 : this.reportsDirectories )
223                     {
224                         String reportDir = reportsDirectory1.getPath();
225                         if ( reportDir.startsWith( parentBaseDir ) )
226                         {
227                             reportDir = reportDir.substring( parentBaseDir.length() );
228                         }
229                         File reportsDirectory = new File( moduleBaseDir, reportDir );
230                         if ( reportsDirectory.exists() && reportsDirectory.isDirectory() )
231                         {
232                             getConsoleLogger().debug( "Adding report dir : " + moduleBaseDir + reportDir );
233                             resolvedReportsDirectories.add( reportsDirectory );
234                         }
235                     }
236                 }
237             }
238         }
239         else
240         {
241             if ( resolvedReportsDirectories.isEmpty() )
242             {
243 
244                 resolvedReportsDirectories.add( getSurefireReportsDirectory( project ) );
245             }
246         }
247         return resolvedReportsDirectories;
248     }
249 
250     /**
251      * Gets the default surefire reports directory for the specified project.
252      *
253      * @param subProject the project to query.
254      * @return the default surefire reports directory for the specified project.
255      */
256     protected abstract File getSurefireReportsDirectory( MavenProject subProject );
257 
258     private List<MavenProject> getProjectsWithoutRoot()
259     {
260         List<MavenProject> result = new ArrayList<MavenProject>();
261         for ( MavenProject subProject : reactorProjects )
262         {
263             if ( !project.equals( subProject ) )
264             {
265                 result.add( subProject );
266             }
267         }
268         return result;
269 
270     }
271 
272     private String determineXrefLocation()
273     {
274         String location = null;
275 
276         if ( linkXRef )
277         {
278             String relativePath = PathTool.getRelativePath( getOutputDirectory(), xrefLocation.getAbsolutePath() );
279             if ( isEmpty( relativePath ) )
280             {
281                 relativePath = ".";
282             }
283             relativePath = relativePath + "/" + xrefLocation.getName();
284             if ( xrefLocation.exists() )
285             {
286                 // XRef was already generated by manual execution of a lifecycle binding
287                 location = relativePath;
288             }
289             else
290             {
291                 // Not yet generated - check if the report is on its way
292                 for ( Object o : project.getReportPlugins() )
293                 {
294                     ReportPlugin report = (ReportPlugin) o;
295 
296                     String artifactId = report.getArtifactId();
297                     if ( "maven-jxr-plugin".equals( artifactId ) || "jxr-maven-plugin".equals( artifactId ) )
298                     {
299                         location = relativePath;
300                     }
301                 }
302             }
303 
304             if ( location == null )
305             {
306                 getConsoleLogger().warning( "Unable to locate Test Source XRef to link to - DISABLED" );
307             }
308         }
309         return location;
310     }
311 
312     /**
313      * {@inheritDoc}
314      */
315     public String getName( Locale locale )
316     {
317         return getBundle( locale ).getString( "report.surefire.name" );
318     }
319 
320     /**
321      * {@inheritDoc}
322      */
323     public String getDescription( Locale locale )
324     {
325         return getBundle( locale ).getString( "report.surefire.description" );
326     }
327 
328     /**
329      * {@inheritDoc}
330      */
331     public abstract String getOutputName();
332 
333     private ResourceBundle getBundle( Locale locale )
334     {
335         return ResourceBundle.getBundle( "surefire-report", locale, getClass().getClassLoader() );
336     }
337 
338     protected final ConsoleLogger getConsoleLogger()
339     {
340         return new PluginConsoleLogger( getLog() );
341     }
342 }