View Javadoc
1   package org.apache.maven.plugin.docck;
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 org.apache.maven.model.ReportPlugin;
23  import org.apache.maven.plugin.descriptor.InvalidPluginDescriptorException;
24  import org.apache.maven.plugin.descriptor.MojoDescriptor;
25  import org.apache.maven.plugin.descriptor.Parameter;
26  import org.apache.maven.plugin.descriptor.PluginDescriptor;
27  import org.apache.maven.plugin.docck.reports.DocumentationReporter;
28  import org.apache.maven.plugins.annotations.Component;
29  import org.apache.maven.plugins.annotations.LifecyclePhase;
30  import org.apache.maven.plugins.annotations.Mojo;
31  import org.apache.maven.project.MavenProject;
32  import org.apache.maven.tools.plugin.extractor.ExtractionException;
33  import org.apache.maven.tools.plugin.scanner.MojoScanner;
34  import org.codehaus.plexus.util.IOUtil;
35  import org.codehaus.plexus.util.ReaderFactory;
36  
37  import java.io.File;
38  import java.io.IOException;
39  import java.io.Reader;
40  import java.util.ArrayList;
41  import java.util.List;
42  
43  /**
44   * Checks a plugin's documentation for the standard minimums.
45   *
46   * @author jdcasey
47   */
48  @Mojo( name = "check", aggregator = true, defaultPhase = LifecyclePhase.VALIDATE, threadSafe = true )
49  public class CheckPluginDocumentationMojo
50      extends AbstractCheckDocumentationMojo
51  {
52  
53      /**
54       * Plexus component that searches for Mojos.
55       */
56      @Component
57      protected MojoScanner mojoScanner;
58  
59      // TODO: really a description of length 1 isn't all that helpful...
60      private static final int MIN_DESCRIPTION_LENGTH = 1;
61  
62      protected void checkPackagingSpecificDocumentation( MavenProject project, DocumentationReporter reporter )
63      {
64          PluginDescriptor descriptor = new PluginDescriptor();
65  
66          try
67          {
68              mojoScanner.populatePluginDescriptor( project, descriptor );
69          }
70          catch ( InvalidPluginDescriptorException e )
71          {
72              reporter.error( "Failed to parse mojo descriptors.\nError: " + e.getMessage() );
73              descriptor = null;
74          }
75          catch ( ExtractionException e )
76          {
77              reporter.error( "Failed to parse mojo descriptors.\nError: " + e.getMessage() );
78              descriptor = null;
79          }
80  
81          if ( descriptor != null )
82          {
83              @SuppressWarnings( "unchecked" )
84              List<MojoDescriptor> mojos = descriptor.getMojos();
85  
86              // ensure that all mojo classes are documented
87              if ( mojos != null && !mojos.isEmpty() )
88              {
89                  for ( MojoDescriptor mojo : mojos )
90                  {
91                      String mojoDescription = mojo.getDescription();
92  
93                      if ( mojoDescription == null || mojoDescription.trim().length() < MIN_DESCRIPTION_LENGTH )
94                      {
95                          reporter.error( "Mojo: \'" + mojo.getGoal() + "\' is missing a description." );
96                      }
97  
98                      @SuppressWarnings( "unchecked" )
99                      List<Parameter> params = mojo.getParameters();
100 
101                     // ensure that all parameters are documented
102                     if ( params != null && !params.isEmpty() )
103                     {
104                         for ( Parameter param : params )
105                         {
106                             if ( param.getRequirement() == null && param.isEditable() )
107                             {
108                                 String paramDescription = param.getDescription();
109 
110                                 if ( paramDescription == null
111                                     || paramDescription.trim().length() < MIN_DESCRIPTION_LENGTH )
112                                 {
113                                     reporter.error( "Parameter: \'" + param.getName() + "\' in mojo: \'"
114                                         + mojo.getGoal() + "\' is missing a description." );
115                                 }
116                             }
117                         }
118                     }
119                 }
120             }
121         }
122 
123         checkConfiguredReportPlugins( project, reporter );
124 
125         checkProjectSite( project, reporter );
126     }
127 
128     protected boolean approveProjectPackaging( String packaging )
129     {
130         return "maven-plugin".equals( packaging );
131     }
132 
133     private void checkProjectSite( MavenProject project, DocumentationReporter reporter )
134     {
135         File projectSiteDirectory = new File( project.getBasedir(), siteDirectory );
136 
137         // check for site.xml
138         File siteXml = new File( projectSiteDirectory, "site.xml" );
139 
140         if ( !siteXml.exists() )
141         {
142             reporter.error( "site.xml is missing." );
143         }
144         else
145         {
146             Reader streamReader = null;
147             try
148             {
149                 streamReader = ReaderFactory.newXmlReader( siteXml );
150 
151                 String siteHtml = IOUtil.toString( streamReader );
152 
153                 if ( !siteHtml.contains( "href=\"index.html\"" ) )
154                 {
155                     reporter.error( "site.xml is missing the link to: index.html \"Introduction\"." );
156                 }
157 
158                 if ( !siteHtml.contains( "href=\"usage.html\"" ) )
159                 {
160                     reporter.error( "site.xml is missing the link to: usage.html \"Usage\"." );
161                 }
162 
163                 if ( !siteHtml.contains( "href=\"plugin-info.html\"" ) )
164                 {
165                     reporter.error( "site.xml is missing the link to: plugin-info.html \"Goals\"." );
166                 }
167 
168                 if ( !siteHtml.contains( "href=\"faq.html\"" ) )
169                 {
170                     reporter.error( "site.xml is missing the link to: faq.html \"FAQ\"." );
171                 }
172             }
173             catch ( IOException e )
174             {
175                 reporter.error( "Unable to read site.xml file: \'" + siteXml.getAbsolutePath() + "\'.\nError: "
176                     + e.getMessage() );
177             }
178             finally
179             {
180                 IOUtil.close( streamReader );
181             }
182         }
183 
184         // check for index.(apt|html|xml)[.vm]
185         if ( !findFiles( projectSiteDirectory, "index" ) )
186         {
187             reporter.error( "There is no \'index\' file in your site directory (in apt|html|xml[.vm] format)." );
188         }
189 
190         // check for usage.(apt|html|xml)[.vm]
191         if ( !findFiles( projectSiteDirectory, "usage" ) )
192         {
193             reporter.error( "There is no \'usage\' file in your site directory (in apt|html|xml[.vm] format)." );
194         }
195 
196         // check for **/examples/**.(apt|html|xml)[.vm] or **/example*.(apt|html|xml)[.vm]
197         if ( !findFiles( projectSiteDirectory, "**/examples/*" ) && !findFiles( projectSiteDirectory, "**/example*" ) )
198         {
199             reporter.error( "There are no example files in your site directory (in apt|html|xml[.vm] format)."
200                 + " They should either be called \'example*.(apt|html|xml)[.vm]\'"
201                 + " or they should be located in the \'examples\' directory." );
202         }
203 
204         if ( !findFiles( projectSiteDirectory, "faq" ) )
205         {
206             reporter.error( "There is no \'faq\' file in your site directory (in apt|fml|html|xml[.vm] format)." );
207         }
208     }
209 
210     /**
211      * Checks the project configured plugins if the required report plugins are present.
212      *
213      * @param project MavenProject to check
214      * @param reporter listener
215      * @todo maybe this should be checked default for all project?
216      */
217     private void checkConfiguredReportPlugins( MavenProject project, DocumentationReporter reporter )
218     {
219         List<String> expectedPlugins = getRequiredPlugins();
220 
221         @SuppressWarnings( "unchecked" )
222         List<ReportPlugin> reportPlugins = project.getReportPlugins();
223         if ( reportPlugins != null && reportPlugins.size() > 0 )
224         {
225             for ( ReportPlugin plugin : reportPlugins )
226             {
227                 expectedPlugins.remove( plugin.getArtifactId() );
228             }
229         }
230         else
231         {
232             reporter.error( "pom.xml has no report plugins configured." );
233         }
234 
235         for ( String expectedPlugin : expectedPlugins )
236         {
237             reporter.error( "pom.xml is missing the report plugin: " + expectedPlugin + "." );
238         }
239     }
240 
241     /**
242      * Returns a List of Strings of required report plugins.
243      *
244      * @return List of report plugin artifactIds
245      */
246     private List<String> getRequiredPlugins()
247     {
248         List<String> list = new ArrayList<String>();
249 
250         list.add( "maven-javadoc-plugin" );
251         list.add( "maven-jxr-plugin" );
252 
253         return list;
254     }
255 }