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