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 }