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