Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add pmd-compat6 module for maven-pmd-plugin #4741

Merged
merged 8 commits into from Nov 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
79 changes: 15 additions & 64 deletions docs/pages/pmd/userdocs/migrating_to_pmd7.md
Expand Up @@ -3138,70 +3138,21 @@ See the use case[I'm using only built-in rules](#im-using-only-built-in-rules) a

#### Maven

* Due to some changes in PMD's API, you can't simply pull in the new PMD 7 dependency using the
approach documented in [Upgrading PMD at Runtime](https://maven.apache.org/plugins/maven-pmd-plugin/examples/upgrading-PMD-at-runtime.html).
* A new maven-pmd-plugin version, that supports PMD 7 is in the works. See [MPMD-379](https://issues.apache.org/jira/browse/MPMD-379).
* As long as no new maven-pmd-plugin version with PMD 7 support is released, you can try it out using a
SNAPSHOT version:
1. Add the Apache SNAPSHOT maven repository:
```xml
<pluginRepository>
<id>apache.snapshots</id>
<name>Apache Snapshot Repository</name>
<url>https://repository.apache.org/snapshots</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</pluginRepository>
```
2. Use the version **3.21.1-pmd-7-SNAPSHOT** of the maven-pmd-plugin
3. Override the dependencies of the plugin to use PMD 7, e.g.
```xml
<project>
<properties>
<pmdVersion>{{site.pmd.version}}</pmdVersion>
<mavenPmdPluginVersion>3.21.1-pmd-7.0.0-SNAPSHOT</mavenPmdPluginVersion>
</properties>
...
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-pmd-plugin</artifactId>
<version>${mavenPmdPluginVersion}</version>
<dependencies>
<dependency>
<groupId>net.sourceforge.pmd</groupId>
<artifactId>pmd-core</artifactId>
<version>${pmdVersion}</version>
</dependency>
<dependency>
<groupId>net.sourceforge.pmd</groupId>
<artifactId>pmd-java</artifactId>
<version>${pmdVersion}</version>
</dependency>
<dependency>
<groupId>net.sourceforge.pmd</groupId>
<artifactId>pmd-javascript</artifactId>
<version>${pmdVersion}</version>
</dependency>
<dependency>
<groupId>net.sourceforge.pmd</groupId>
<artifactId>pmd-jsp</artifactId>
<version>${pmdVersion}</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</pluginManagement>
</build>
...
</project>
```
* Due to some changes in PMD's API, you can't simply pull in the new PMD 7 dependency.
* However, there is now a compatibility module, that makes it possible to use PMD 7 with Maven. In addition to the PMD 7
dependencies documented in [Upgrading PMD at Runtime](https://maven.apache.org/plugins/maven-pmd-plugin/examples/upgrading-PMD-at-runtime.html)
you need to add additionally the following dependency (available with 7.0.0-rc4):

```xml
<dependency>
<groupId>net.sourceforge.pmd</groupId>
<artifactId>pmd-compat6</artifactId>
<version>${pmdVersion}</version>
</dependency>
```

It is important to add this dependency as the **first** in the list, so that maven-pmd-plugin sees the (old)
compatible versions of some classes.

#### Gradle

Expand Down
27 changes: 27 additions & 0 deletions docs/pages/release_notes.md
Expand Up @@ -41,6 +41,31 @@ The remaining section describes the complete release notes for 7.0.0.

#### New and Noteworthy

##### Maven PMD Plugin compatibility with PMD 7

In order to use PMD 7 with [maven-pmd-plugin](https://maven.apache.org/plugins/maven-pmd-plugin/) a new
compatibility module has been created. This allows to use PMD 7 by simply adding one additional dependency:

1. Follow the guide [Upgrading PMD at Runtime](https://maven.apache.org/plugins/maven-pmd-plugin/examples/upgrading-PMD-at-runtime.html)
2. Add additionally the following dependency:

```xml
<dependency>
<groupId>net.sourceforge.pmd</groupId>
<artifactId>pmd-compat6</artifactId>
<version>${pmdVersion}</version>
</dependency>
```

It is important to add this dependency as the **first** in the list, so that maven-pmd-plugin sees the (old)
compatible versions of some classes.

Note: This compatibility modules only works for the built-in rules, that are still available in PMD 7 (you need
to review your rulesets).
As PMD 7 revamped the Java module, if you have custom rules, you need to migrate the rules.
For more information, see the [Detailed Release Notes for PMD 7]({{ baseurl }}pmd_release_notes_pmd7.html#revamped-java)
and [Migration Guide for PMD 7]({{ baseurl }}pmd_userdocs_migrating_to_pmd7.html).

#### Rule Changes

**New Rules**
Expand All @@ -62,6 +87,7 @@ The remaining section describes the complete release notes for 7.0.0.
* miscellaneous
* [#4699](https://github.com/pmd/pmd/pull/4699): Make PMD buildable with java 21
* [#4586](https://github.com/pmd/pmd/pull/4586): Use explicit encoding in ruleset xml files
* [#4741](https://github.com/pmd/pmd/pull/4741): Add pmd-compat6 module for maven-pmd-plugin
* apex-performance
* [#4675](https://github.com/pmd/pmd/issues/4675): \[apex] New Rule: OperationWithHighCostInLoop
* java-codestyle
Expand Down Expand Up @@ -440,6 +466,7 @@ See also [Detailed Release Notes for PMD 7]({{ baseurl }}pmd_release_notes_pmd7.
* [#4586](https://github.com/pmd/pmd/pull/4586): Use explicit encoding in ruleset xml files
* [#4691](https://github.com/pmd/pmd/issues/4691): \[CVEs] Critical and High CEVs reported on PMD and PMD dependencies
* [#4699](https://github.com/pmd/pmd/pull/4699): Make PMD buildable with java 21
* [#4741](https://github.com/pmd/pmd/pull/4741): Add pmd-compat6 module for maven-pmd-plugin
* ant
* [#4080](https://github.com/pmd/pmd/issues/4080): \[ant] Split off Ant integration into a new submodule
* core
Expand Down
35 changes: 35 additions & 0 deletions pmd-compat6/README.md
@@ -0,0 +1,35 @@
# pmd-compat6

This module contains classes from PMD6, that have been removed in PMD7 and also restores
some removed methods.

The goal is, that PMD7 can be used with [Maven PMD Plugin](https://maven.apache.org/plugins/maven-pmd-plugin)
without any further changes to the plugin.

The plugin uses by default PMD Version 6.55.0, but it can be configured to
[Use a new PMD version at runtime](https://maven.apache.org/plugins/maven-pmd-plugin/examples/upgrading-PMD-at-runtime.html).

Since PMD7 introduces many incompatible changes, another module is needed to restore
compatibility. This is this module.

In order to use this compatibility module, it needs to be added as the _first_ dependency
when configuring maven-pmd-plugin.

It is as simple as adding:

```xml
<dependency>
<groupId>net.sourceforge.pmd</groupId>
<artifactId>pmd-compat6</artifactId>
<version>${pmdVersion}</version>
</dependency>
```

Note: The dependency "pmd-compat6" must be listed _first_ before pmd-core, pmd-java, and the others.

Once the default version of PMD is upgraded to PMD7 in maven-pmd-plugin
(see [MPMD-379](https://issues.apache.org/jira/projects/MPMD/issues/MPMD-379)), this
compatibility module is no longer needed.

The primary goal for this module is, to get maven-pmd-plugin working with PMD7. It might
be useful in other contexts, too, but no guarantee is given, that is works.
71 changes: 71 additions & 0 deletions pmd-compat6/pom.xml
@@ -0,0 +1,71 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>net.sourceforge.pmd</groupId>
<artifactId>pmd</artifactId>
<version>7.0.0-rc4</version>
</parent>

<artifactId>pmd-compat6</artifactId>
<version>7.0.0-SNAPSHOT</version>
<name>PMD Compatibility Classes for PMD6</name>

<properties>
<pmd.version>7.0.0-rc4</pmd.version>
<pmd.version.for.integrationtest>7.0.0-rc4</pmd.version.for.integrationtest>
<maven-pmd-plugin.version.for.integrationtest>3.21.2</maven-pmd-plugin.version.for.integrationtest>
</properties>

<dependencies>
<dependency>
<groupId>net.sourceforge.pmd</groupId>
<artifactId>pmd-core</artifactId>
<version>${pmd.version}</version>
</dependency>
<dependency>
<groupId>net.sourceforge.pmd</groupId>
<artifactId>pmd-java</artifactId>
<version>${pmd.version}</version>
</dependency>
<dependency>
<groupId>net.sourceforge.pmd</groupId>
<artifactId>pmd-javascript</artifactId>
<version>${pmd.version}</version>
</dependency>
<dependency>
<groupId>net.sourceforge.pmd</groupId>
<artifactId>pmd-jsp</artifactId>
<version>${pmd.version}</version>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-invoker-plugin</artifactId>
<version>3.6.0</version>
<configuration>
<cloneProjectsTo>${project.build.directory}/it</cloneProjectsTo>
<settingsFile>src/it/settings.xml</settingsFile>
<localRepositoryPath>${project.build.directory}/local-repo</localRepositoryPath>
<postBuildHookScript>verify.bsh</postBuildHookScript>
<streamLogsOnFailures>true</streamLogsOnFailures>
</configuration>
<executions>
<execution>
<id>integration-test</id>
<goals>
<goal>install</goal>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
4 changes: 4 additions & 0 deletions pmd-compat6/src/it/cpd-for-java/invoker.properties
@@ -0,0 +1,4 @@
invoker.goals.1 = verify
invoker.goals.2 = pmd:cpd-check -Dformat=csv
invoker.goals.3 = pmd:cpd-check -Dformat=txt
invoker.buildResult = failure
66 changes: 66 additions & 0 deletions pmd-compat6/src/it/cpd-for-java/pom.xml
@@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>net.sourceforge.pmd.pmd-compat6.it</groupId>
<artifactId>cpd-for-java</artifactId>
<version>1.0-SNAPSHOT</version>

<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-pmd-plugin</artifactId>
<version>@maven-pmd-plugin.version.for.integrationtest@</version>
<executions>
<execution>
<id>java-cpd-check</id>
<goals>
<goal>cpd-check</goal>
</goals>
</execution>
</executions>
<configuration>
<printFailingErrors>true</printFailingErrors>
<skipPmdError>false</skipPmdError>
<minimumTokens>5</minimumTokens>
</configuration>
<dependencies>
<dependency>
<groupId>net.sourceforge.pmd</groupId>
<artifactId>pmd-compat6</artifactId>
<version>@project.version@</version>
</dependency>
<dependency>
<groupId>net.sourceforge.pmd</groupId>
<artifactId>pmd-core</artifactId>
<version>@pmd.version.for.integrationtest@</version>
</dependency>
<dependency>
<groupId>net.sourceforge.pmd</groupId>
<artifactId>pmd-java</artifactId>
<version>@pmd.version.for.integrationtest@</version>
</dependency>
<dependency>
<groupId>net.sourceforge.pmd</groupId>
<artifactId>pmd-javascript</artifactId>
<version>@pmd.version.for.integrationtest@</version>
</dependency>
<dependency>
<groupId>net.sourceforge.pmd</groupId>
<artifactId>pmd-jsp</artifactId>
<version>@pmd.version.for.integrationtest@</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
</project>
@@ -0,0 +1,10 @@
package org.example;

public class ClassA {
public int method1(int a, int b, int c) {
int d = (a + b + c + 1) * 10;
int e = (a + b + c - 1) * 5;
int f = (a + b + c);
return d * e * f + d + e + f;
}
}
@@ -0,0 +1,10 @@
package org.example;

public class ClassB {
public int method1(int a, int b, int c) {
int d = (a + b + c + 1) * 10;
int e = (a + b + c - 1) * 5;
int f = (a + b + c);
return d * e * f + d + e + f;
}
}
62 changes: 62 additions & 0 deletions pmd-compat6/src/it/cpd-for-java/verify.bsh
@@ -0,0 +1,62 @@
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;

String readFile(File file) throws IOException {
StringBuilder content = new StringBuilder();
for (String line : Files.readAllLines(file.toPath(), StandardCharsets.UTF_8)) {
content.append(line).append(System.lineSeparator());
}
return content.toString();
}

File buildLogPath = new File(basedir, "build.log");
String buildLog = readFile(buildLogPath);
if (buildLog.contains("An API incompatibility was encountered while")) {
throw new RuntimeException("Executing failed due to API incompatibility");
}
if (!buildLog.contains("[INFO] CPD Failure: Found 8 lines of duplicated code at locations:")) {
throw new RuntimeException("No CPD failures detected, did CPD run?");
}
File classA = new File("cpd-for-java/src/main/java/org/example/ClassA.java");
if (!buildLog.contains(classA + " line 3")) {
throw new RuntimeException("No CPD failures detected, did CPD run?");
}

File cpdXmlReport = new File(basedir, "target/cpd.xml");
if (!cpdXmlReport.exists()) {
throw new FileNotFoundException("Could not find cpd xml report: " + cpdXmlReport);
}
String cpdXml = readFile(cpdXmlReport);
if (!cpdXml.contains("<duplication lines=\"8\" tokens=\"67\">")) {
throw new RuntimeException("Expected duplication has not been reported");
}
if (!cpdXml.contains(classA + "\"/>")) {
throw new RuntimeException("Expected duplication has not been reported");
}

File csvReport = new File(basedir, "target/cpd.csv");
if (!csvReport.exists()) {
throw new FileNotFoundException("Could not find cpd csv report: " + csvReport);
}
String csv = readFile(csvReport);
if (!csv.contains("8,67,2,3,")) {
throw new RuntimeException("Expected duplication in CSV has not been reported");
}
if (!csv.contains(classA + ",")) {
throw new RuntimeException("Expected duplication in CSV has not been reported");
}

File textReport = new File(basedir, "target/cpd.txt");
if (!textReport.exists()) {
throw new FileNotFoundException("Could not find cpd text report: " + textReport);
}
String text = readFile(textReport);
if (!text.contains("Found a 8 line (67 tokens) duplication in the following files:")) {
throw new RuntimeException("Expected duplication in TXT has not been reported");
}
if (!text.contains("Starting at line 3 of ") && !text.contains(classA.toString())) {
throw new RuntimeException("Expected duplication in TXT has not been reported");
}