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.xml.pull.MXParser;
26  import org.codehaus.plexus.util.xml.pull.XmlPullParser;
27  import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
28  
29  import java.io.BufferedReader;
30  import java.io.File;
31  import java.io.FileInputStream;
32  import java.io.IOException;
33  import java.io.InputStreamReader;
34  import java.io.Reader;
35  
36  /**
37   * Perform a violation check against the last Checkstyle run to see if there are
38   * any violations. It reads the Checkstyle output file, counts the number of
39   * violations found and displays it on the console.
40   *
41   * @author <a href="mailto:joakim@erdfelt.net">Joakim Erdfelt</a>
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 lowest severity level that is considered a violation.
78       * Valid values are "error", "warning" and "info".
79       *
80       * @parameter expression="${checkstyle.violationSeverity}" default-value="error"
81       * @since 2.2
82       */
83      private String violationSeverity = "error";
84  
85      /**
86       * Skip entire check.
87       *
88       * @parameter expression="${checkstyle.skip}" default-value="false"
89       * @since 2.2
90       */
91      private boolean skip;
92  
93      /**
94       * @see org.apache.maven.plugin.Mojo#execute()
95       */
96      public void execute()
97          throws MojoExecutionException, MojoFailureException
98      {
99          if ( !skip )
100         {
101             if ( !"xml".equals( outputFileFormat ) )
102             {
103                 throw new MojoExecutionException( "Output format is '" + outputFileFormat
104                     + "', checkstyle:check requires format to be 'xml'." );
105             }
106 
107             if ( !outputFile.exists() )
108             {
109                 getLog().info(
110                                "Unable to perform checkstyle:check, "
111                                    + "unable to find checkstyle:checkstyle outputFile." );
112                 return;
113             }
114 
115             try
116             {
117                 XmlPullParser xpp = new MXParser();
118                 // TODO: use ReaderFactory.newXmlReader() when plexus-utils can be upgraded
119                 Reader freader = new InputStreamReader( new FileInputStream( outputFile ), "UTF-8" );
120                 BufferedReader breader = new BufferedReader( freader );
121                 xpp.setInput( breader );
122 
123                 int violations = countViolations( xpp );
124                 if ( violations > 0 )
125                 {
126                     if ( failOnViolation )
127                     {
128                         throw new MojoFailureException( "You have " + violations + " Checkstyle violation"
129                             + ( ( violations > 1 ) ? "s" : "" ) + "." );
130                     }
131 
132                     getLog().warn( "checkstyle:check violations detected but failOnViolation set to false" );
133                 }
134             }
135             catch ( IOException e )
136             {
137                 throw new MojoExecutionException( "Unable to read Checkstyle results xml: "
138                     + outputFile.getAbsolutePath(), e );
139             }
140             catch ( XmlPullParserException e )
141             {
142                 throw new MojoExecutionException( "Unable to read Checkstyle results xml: "
143                     + outputFile.getAbsolutePath(), e );
144             }
145         }
146     }
147 
148     private int countViolations( XmlPullParser xpp )
149         throws XmlPullParserException, IOException
150     {
151         int count = 0;
152 
153         int eventType = xpp.getEventType();
154         while ( eventType != XmlPullParser.END_DOCUMENT )
155         {
156             if ( eventType == XmlPullParser.START_TAG && "error".equals( xpp.getName() )
157                 && isViolation( xpp.getAttributeValue( "", "severity" ) ) )
158             {
159                 count++;
160             }
161             eventType = xpp.next();
162         }
163 
164         return count;
165     }
166 
167     /**
168      * Checks if the given severity is considered a violation.
169      *
170      * @param severity The severity to check
171      * @return <code>true</code> if the given severity is a violation, otherwise <code>false</code>
172      */
173     private boolean isViolation( String severity )
174     {
175         if ( "error".equals( severity ) )
176         {
177             return "error".equals( violationSeverity ) || "warning".equals( violationSeverity )
178                 || "info".equals( violationSeverity );
179         }
180         else if ( "warning".equals( severity ) )
181         {
182             return "warning".equals( violationSeverity ) || "info".equals( violationSeverity );
183         }
184         else if ( "info".equals( severity ) )
185         {
186             return "info".equals( violationSeverity );
187         }
188         else
189         {
190             return false;
191         }
192     }
193 }