View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.plugins.pmd;
20  
21  import java.io.File;
22  import java.io.FileInputStream;
23  import java.io.IOException;
24  import java.io.InputStream;
25  import java.util.ArrayList;
26  import java.util.List;
27  
28  import org.apache.maven.plugin.MojoExecutionException;
29  import org.apache.maven.plugin.MojoFailureException;
30  import org.apache.maven.plugins.annotations.Execute;
31  import org.apache.maven.plugins.annotations.LifecyclePhase;
32  import org.apache.maven.plugins.annotations.Mojo;
33  import org.apache.maven.plugins.annotations.Parameter;
34  import org.apache.maven.plugins.pmd.model.PmdErrorDetail;
35  import org.apache.maven.plugins.pmd.model.PmdFile;
36  import org.apache.maven.plugins.pmd.model.Violation;
37  import org.apache.maven.plugins.pmd.model.io.xpp3.PmdXpp3Reader;
38  import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
39  
40  /**
41   * Fails the build if there were any PMD violations in the source code.
42   *
43   * @version $Id$
44   * @since 2.0
45   */
46  @Mojo(name = "check", defaultPhase = LifecyclePhase.VERIFY, threadSafe = true)
47  @Execute(goal = "pmd")
48  public class PmdViolationCheckMojo extends AbstractPmdViolationCheckMojo<Violation> {
49      /**
50       * Default constructor. Initializes with the correct {@link ExcludeViolationsFromFile}.
51       */
52      public PmdViolationCheckMojo() {
53          super(new ExcludeViolationsFromFile());
54      }
55  
56      /**
57       * What priority level to fail the build on.
58       * PMD violations are assigned a priority from 1 (most severe) to 5 (least severe) according the
59       * the rule's priority.
60       * Violations at or less than this priority level are considered failures and will fail
61       * the build if {@code failOnViolation=true} and the count exceeds {@code maxAllowedViolations}.
62       * The other violations will be regarded as warnings and will be displayed in the build output
63       * if {@code verbose=true}.
64       * Setting a value of 5 will treat all violations as failures, which may cause the build to fail.
65       * Setting a value of 1 will treat all violations as warnings.
66       * Only values from 1 to 5 are valid.
67       */
68      @Parameter(property = "pmd.failurePriority", defaultValue = "5", required = true)
69      private int failurePriority = 5;
70  
71      /**
72       * Skip the PMD checks. Most useful on the command line via "-Dpmd.skip=true".
73       */
74      @Parameter(property = "pmd.skip", defaultValue = "false")
75      private boolean skip;
76  
77      /**
78       * {@inheritDoc}
79       */
80      public void execute() throws MojoExecutionException, MojoFailureException {
81          if (skip) {
82              getLog().info("Skipping PMD execution");
83              return;
84          }
85  
86          executeCheck("pmd.xml", "violation", "PMD violation", failurePriority);
87      }
88  
89      /**
90       * {@inheritDoc}
91       */
92      protected void printError(Violation item, String severity) {
93  
94          StringBuilder buff = new StringBuilder(100);
95          buff.append("PMD ").append(severity).append(": ");
96          if (item.getViolationClass() != null) {
97              if (item.getViolationPackage() != null) {
98                  buff.append(item.getViolationPackage());
99                  buff.append(".");
100             }
101             buff.append(item.getViolationClass());
102         } else {
103             buff.append(item.getFileName());
104         }
105         buff.append(":");
106         buff.append(item.getBeginline());
107         buff.append(" Rule:").append(item.getRule());
108         buff.append(" Priority:").append(item.getPriority());
109         buff.append(" ").append(item.getText()).append(".");
110 
111         this.getLog().info(buff.toString());
112     }
113 
114     @Override
115     protected List<Violation> getErrorDetails(File pmdFile) throws XmlPullParserException, IOException {
116         try (InputStream in = new FileInputStream(pmdFile)) {
117             PmdXpp3Reader reader = new PmdXpp3Reader();
118             PmdErrorDetail details = reader.read(in, false);
119             List<Violation> violations = new ArrayList<>();
120             for (PmdFile file : details.getFiles()) {
121                 String fullPath = file.getName();
122 
123                 for (Violation violation : file.getViolations()) {
124                     violation.setFileName(getFilename(fullPath, violation.getViolationPackage()));
125                     violations.add(violation);
126                 }
127             }
128             return violations;
129         }
130     }
131 
132     @Override
133     protected int getPriority(Violation errorDetail) {
134         return errorDetail.getPriority();
135     }
136 
137     @Override
138     protected ViolationDetails<Violation> newViolationDetailsInstance() {
139         return new ViolationDetails<>();
140     }
141 
142     private String getFilename(String fullpath, String pkg) {
143         int index = fullpath.lastIndexOf(File.separatorChar);
144 
145         while (pkg != null && !pkg.isEmpty()) {
146             index = fullpath.substring(0, index).lastIndexOf(File.separatorChar);
147 
148             int dot = pkg.indexOf('.');
149 
150             if (dot < 0) {
151                 break;
152             }
153             pkg = pkg.substring(dot + 1);
154         }
155 
156         return fullpath.substring(index + 1);
157     }
158 }