View Javadoc

1   package org.apache.maven.plugin.checkstyle;
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.plugin.AbstractMojo;
23  import org.apache.maven.plugin.MojoExecutionException;
24  import org.apache.maven.plugin.MojoFailureException;
25  import org.codehaus.plexus.util.ReaderFactory;
26  import org.codehaus.plexus.util.xml.pull.MXParser;
27  import org.codehaus.plexus.util.xml.pull.XmlPullParser;
28  import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
29  
30  import java.io.BufferedReader;
31  import java.io.File;
32  import java.io.IOException;
33  import java.io.Reader;
34  
35  /**
36   * Perform a violation check against the last Checkstyle run to see if there are
37   * any violations. It reads the Checkstyle output file, counts the number of
38   * violations found and displays it on the console.
39   *
40   * @author <a href="mailto:joakim@erdfelt.net">Joakim Erdfelt</a>
41   * @version $Id: CheckstyleViolationCheckMojo.html 816654 2012-05-08 13:54:20Z hboutemy $
42   * @goal check
43   * @phase verify
44   * @execute goal="checkstyle"
45   * @requiresDependencyResolution compile
46   */
47  public class CheckstyleViolationCheckMojo
48      extends AbstractMojo
49  {
50      /**
51       * Specifies the path and filename to save the Checkstyle output. The format
52       * of the output file is determined by the <code>outputFileFormat</code>
53       * parameter.
54       *
55       * @parameter expression="${checkstyle.output.file}"
56       *            default-value="${project.build.directory}/checkstyle-result.xml"
57       */
58      private File outputFile;
59  
60      /**
61       * Specifies the format of the output to be used when writing to the output
62       * file. Valid values are "plain" and "xml".
63       *
64       * @parameter expression="${checkstyle.output.format}" default-value="xml"
65       */
66      private String outputFileFormat;
67  
68      /**
69       * Do we fail the build on a violation?
70       *
71       * @parameter expression="${checkstyle.failOnViolation}"
72       *            default-value="true"
73       */
74      private boolean failOnViolation;
75  
76      /**
77       * The maximum number of allowed violations. The execution fails only if the
78       * number of violations is above this limit.
79       *
80       * @parameter expression="${checkstyle.maxAllowedViolations}" default-value="0"
81       * @since 2.3
82       */
83      private int maxAllowedViolations = 0;
84  
85      /**
86       * The lowest severity level that is considered a violation.
87       * Valid values are "error", "warning" and "info".
88       *
89       * @parameter expression="${checkstyle.violationSeverity}" default-value="error"
90       * @since 2.2
91       */
92      private String violationSeverity = "error";
93  
94      /**
95       * Skip entire check.
96       *
97       * @parameter expression="${checkstyle.skip}" default-value="false"
98       * @since 2.2
99       */
100     private boolean skip;
101 
102     /**
103      * Output the detected violations to the console.
104      *
105      * @parameter expression="${checkstyle.console}" default-value="false"
106      * @since 2.3
107      */
108     private boolean logViolationsToConsole;
109 
110     /** {@inheritDoc} */
111     public void execute()
112         throws MojoExecutionException, MojoFailureException
113     {
114         if ( !skip )
115         {
116             if ( !"xml".equals( outputFileFormat ) )
117             {
118                 throw new MojoExecutionException( "Output format is '" + outputFileFormat
119                     + "', checkstyle:check requires format to be 'xml'." );
120             }
121 
122             if ( !outputFile.exists() )
123             {
124                 getLog().info(
125                                "Unable to perform checkstyle:check, "
126                                    + "unable to find checkstyle:checkstyle outputFile." );
127                 return;
128             }
129 
130             try
131             {
132                 XmlPullParser xpp = new MXParser();
133                 Reader freader = ReaderFactory.newXmlReader( outputFile );
134                 BufferedReader breader = new BufferedReader( freader );
135                 xpp.setInput( breader );
136 
137                 int violations = countViolations( xpp );
138                 if ( violations > maxAllowedViolations )
139                 {
140                     if ( failOnViolation )
141                     {
142                         String msg = "You have " + violations + " Checkstyle violation"
143                             + ( ( violations > 1 ) ? "s" : "" ) + ".";
144                         if ( maxAllowedViolations > 0 )
145                         {
146                             msg += " The maximum number of allowed violations is " + maxAllowedViolations + ".";
147                         }
148                         throw new MojoFailureException( msg );
149                     }
150 
151                     getLog().warn( "checkstyle:check violations detected but failOnViolation set to false" );
152                 }
153             }
154             catch ( IOException e )
155             {
156                 throw new MojoExecutionException( "Unable to read Checkstyle results xml: "
157                     + outputFile.getAbsolutePath(), e );
158             }
159             catch ( XmlPullParserException e )
160             {
161                 throw new MojoExecutionException( "Unable to read Checkstyle results xml: "
162                     + outputFile.getAbsolutePath(), e );
163             }
164         }
165     }
166 
167     private int countViolations( XmlPullParser xpp )
168         throws XmlPullParserException, IOException
169     {
170         int count = 0;
171 
172         int eventType = xpp.getEventType();
173         String file = "";
174         while ( eventType != XmlPullParser.END_DOCUMENT )
175         {
176             if ( eventType == XmlPullParser.START_TAG && "file".equals( xpp.getName() ) )
177             {
178                 file = xpp.getAttributeValue( "", "name" );
179                 file = file.substring( file.lastIndexOf( File.separatorChar ) + 1 );
180             }
181 
182             if ( eventType == XmlPullParser.START_TAG && "error".equals( xpp.getName() )
183                 && isViolation( xpp.getAttributeValue( "", "severity" ) ) )
184             {
185                 if ( logViolationsToConsole )
186                 {
187                     StringBuffer stb = new StringBuffer();
188                     stb.append( file );
189                     stb.append( '[' );
190                     stb.append( xpp.getAttributeValue( "", "line" ) );
191                     stb.append( ':' );
192                     stb.append( xpp.getAttributeValue( "", "column" ) );
193                     stb.append( "] " );
194                     stb.append( xpp.getAttributeValue( "", "message" ) );
195                     getLog().error( stb.toString() );
196                 }
197                 count++;
198             }
199             eventType = xpp.next();
200         }
201 
202         return count;
203     }
204 
205     /**
206      * Checks if the given severity is considered a violation.
207      *
208      * @param severity The severity to check
209      * @return <code>true</code> if the given severity is a violation, otherwise <code>false</code>
210      */
211     private boolean isViolation( String severity )
212     {
213         if ( "error".equals( severity ) )
214         {
215             return "error".equals( violationSeverity ) || "warning".equals( violationSeverity )
216                 || "info".equals( violationSeverity );
217         }
218         else if ( "warning".equals( severity ) )
219         {
220             return "warning".equals( violationSeverity ) || "info".equals( violationSeverity );
221         }
222         else if ( "info".equals( severity ) )
223         {
224             return "info".equals( violationSeverity );
225         }
226         else
227         {
228             return false;
229         }
230     }
231 }