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   * @since 2.0
44   */
45  @Mojo(name = "check", defaultPhase = LifecyclePhase.VERIFY, threadSafe = true)
46  @Execute(goal = "pmd")
47  public class PmdViolationCheckMojo extends AbstractPmdViolationCheckMojo<Violation> {
48      /**
49       * Default constructor. Initializes with the correct {@link ExcludeViolationsFromFile}.
50       */
51      public PmdViolationCheckMojo() {
52          super(new ExcludeViolationsFromFile());
53      }
54  
55      /**
56       * What priority level to fail the build on.
57       * PMD violations are assigned a priority from 1 (most severe) to 5 (least severe) according
58       * to the rule's priority.
59       * Violations at or less than this priority level are considered failures and will fail
60       * the build if {@code failOnViolation=true} and the count exceeds {@code maxAllowedViolations}.
61       * The other violations will be regarded as warnings and will be displayed in the build output
62       * if {@code verbose=true}.
63       * Setting a value of 5 will treat all violations as failures, which may cause the build to fail.
64       * Setting a value of 1 will treat all violations as warnings.
65       * Only values from 1 to 5 are valid.
66       */
67      @Parameter(property = "pmd.failurePriority", defaultValue = "5", required = true)
68      private int failurePriority = 5;
69  
70      /**
71       * Skip the PMD checks. Most useful on the command line via "-Dpmd.skip=true".
72       */
73      @Parameter(property = "pmd.skip", defaultValue = "false")
74      private boolean skip;
75  
76      /**
77       * {@inheritDoc}
78       */
79      public void execute() throws MojoExecutionException, MojoFailureException {
80          if (skip) {
81              getLog().info("Skipping PMD execution");
82              return;
83          }
84  
85          executeCheck("pmd.xml", "PMD", "violation", failurePriority);
86      }
87  
88      /**
89       * {@inheritDoc}
90       */
91      protected void printError(Violation item, String severity) {
92  
93          StringBuilder buff = new StringBuilder(100);
94          buff.append("PMD ").append(severity).append(": ");
95          if (item.getViolationClass() != null) {
96              if (item.getViolationPackage() != null) {
97                  buff.append(item.getViolationPackage());
98                  buff.append(".");
99              }
100             buff.append(item.getViolationClass());
101         } else {
102             buff.append(item.getFileName());
103         }
104         buff.append(":");
105         buff.append(item.getBeginline());
106         buff.append(" Rule:").append(item.getRule());
107         buff.append(" Priority:").append(item.getPriority());
108         buff.append(" ").append(item.getText()).append(".");
109 
110         this.getLog().warn(buff.toString());
111     }
112 
113     @Override
114     protected List<Violation> getErrorDetails(File pmdFile) throws XmlPullParserException, IOException {
115         try (InputStream in = new FileInputStream(pmdFile)) {
116             PmdXpp3Reader reader = new PmdXpp3Reader();
117             PmdErrorDetail details = reader.read(in, false);
118             List<Violation> violations = new ArrayList<>();
119             for (PmdFile file : details.getFiles()) {
120                 String fullPath = file.getName();
121 
122                 for (Violation violation : file.getViolations()) {
123                     violation.setFileName(getFilename(fullPath, violation.getViolationPackage()));
124                     violations.add(violation);
125                 }
126             }
127             return violations;
128         }
129     }
130 
131     @Override
132     protected int getPriority(Violation errorDetail) {
133         return errorDetail.getPriority();
134     }
135 
136     @Override
137     protected ViolationDetails<Violation> newViolationDetailsInstance() {
138         return new ViolationDetails<>();
139     }
140 
141     private String getFilename(String fullpath, String pkg) {
142         int index = fullpath.lastIndexOf(File.separatorChar);
143 
144         while (pkg != null && !pkg.isEmpty()) {
145             index = fullpath.substring(0, index).lastIndexOf(File.separatorChar);
146 
147             int dot = pkg.indexOf('.');
148 
149             if (dot < 0) {
150                 break;
151             }
152             pkg = pkg.substring(dot + 1);
153         }
154 
155         return fullpath.substring(index + 1);
156     }
157 }