diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ffe818d3..213aecd5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,11 +1,21 @@ -name: Build +name: Build and test on: push: + paths-ignore: + - '.github/**' + - '**/*.md' + tags-ignore: + - '**' branches: [ master ] pull_request: branches: [ master ] workflow_dispatch: + inputs: + skipTests: + description: "Skip Tests?" + required: true + default: "no" defaults: run: @@ -14,33 +24,43 @@ defaults: jobs: build: runs-on: ubuntu-latest - timeout-minutes: 60 + timeout-minutes: 20 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set Release version env variable run: | echo "TAG_NAME=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout)" >> $GITHUB_ENV - # if no tag exists, this is expected to fail - - name: Switch to git tag for release + # only build SNAPSHOTS, use release for tagged releases + - name: Check if tag contains SNAPSHOT if: contains(env.TAG_NAME, 'SNAPSHOT') != true run: | - git fetch --all --tags - git checkout tags/${{ env.TAG_NAME }} -b ${{ env.TAG_NAME }}-tmp-branch + echo "Tag '$TAG_NAME' does not contain 'SNAPSHOT', failing build." + exit 1 - name: Set up JDK 11 - uses: actions/setup-java@v2 + uses: actions/setup-java@v4 with: distribution: 'zulu' java-version: 11 + server-id: sonatype-nexus + server-username: MAVEN_USERNAME + server-password: MAVEN_PASSWORD + gpg-passphrase: MAVEN_GPG_PASSPHRASE + gpg-private-key: ${{ secrets.GPG_SIGNING_KEY }} - - name: Build + - name: Deploy SNAPSHOT to maven central + env: + MAVEN_USERNAME: ${{ secrets.SONATYPE_USERNAME }} + MAVEN_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }} + MAVEN_GPG_PASSPHRASE: ${{ secrets.GPG_SIGNING_PASSWORD }} + SKIP_TESTS: ${{ github.event.inputs.skipTests }} run: | - ./mvnw clean verify + ./mvnw --batch-mode $(if [ "$SKIP_TESTS" = "yes" ]; then echo "-DskipTests"; fi) clean deploy - name: Upload jar - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: sonar-pmd-plugin-${{ env.TAG_NAME }} path: sonar-pmd-plugin/target/sonar-pmd-plugin-*.jar diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 90fd53e2..42c417d1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,6 +1,9 @@ -name: Release +name: Release to Maven Central on: + push: + tags: + - '*' workflow_dispatch: defaults: @@ -10,23 +13,27 @@ defaults: jobs: release: runs-on: ubuntu-latest - timeout-minutes: 60 + timeout-minutes: 20 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 + + - uses: olegtarasov/get-tag@v2.1.3 + id: tagName + with: + tagRegex: "(.*)" - name: Set Release version env variable run: | - echo "TAG_NAME=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout)" >> $GITHUB_ENV + echo "TAG_NAME=${{ steps.tagName.outputs.tag }}" >> $GITHUB_ENV # if no tag exists, this is expected to fail - name: Switch to git tag for release - if: contains(env.TAG_NAME, 'SNAPSHOT') != true run: | - git fetch --all --tags + git fetch --all --tags -f git checkout tags/${{ env.TAG_NAME }} -b ${{ env.TAG_NAME }}-tmp-branch - name: Set up JDK 11 - uses: actions/setup-java@v2 + uses: actions/setup-java@v4 with: distribution: 'zulu' java-version: 11 @@ -42,4 +49,11 @@ jobs: MAVEN_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }} MAVEN_GPG_PASSPHRASE: ${{ secrets.GPG_SIGNING_PASSWORD }} run: | - ./mvnw --batch-mode -P release deploy + ./mvnw --batch-mode -Drevision=${{ env.TAG_NAME }} -P release clean deploy + + - name: Create GHA release + uses: ncipollo/release-action@v1 + with: + draft: true + artifacts: "sonar-pmd-plugin/target/*.jar" + bodyFile: CHANGELOG.md diff --git a/.gitignore b/.gitignore index a95e9ab7..b5dac6a1 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,5 @@ Thumbs.db # Folder config file Desktop.ini .java-version + +.flattened-pom.xml diff --git a/.mvn/wrapper/maven-wrapper.jar b/.mvn/wrapper/maven-wrapper.jar deleted file mode 100644 index c1dd12f1..00000000 Binary files a/.mvn/wrapper/maven-wrapper.jar and /dev/null differ diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties index 57bb5843..48a56c99 100644 --- a/.mvn/wrapper/maven-wrapper.properties +++ b/.mvn/wrapper/maven-wrapper.properties @@ -5,14 +5,15 @@ # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at -# +# # http://www.apache.org/licenses/LICENSE-2.0 -# +# # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.6/apache-maven-3.8.6-bin.zip -wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar +wrapperVersion=3.3.2 +distributionType=only-script +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.6/apache-maven-3.9.6-bin.zip diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index d46c1ed2..00000000 --- a/.travis.yml +++ /dev/null @@ -1,30 +0,0 @@ -os: linux -dist: focal -language: java -jdk: openjdk11 -install: true -script: ./travis.sh - -addons: - sonarcloud: - organization: "jborgers-github" - token: - secure: "U299FqcJAMNfblrZF8R/ivqRk7KNdSOdcyWI4h5dgOLlQHj+HHrF2GJB2fOVeaB53snOkCycM/ZQgqTLlS1PU2NUca3TroNXj6jpNK1Erb/TXqFMKK+rmsN+hcxudDYGnQFIVnWy4lsg72jlK3Qvktt0XyfuYjMqQbsp3zwhlxw=" - -env: - - TEST=ci - - TEST=plugin SQ_VERSION=LATEST_RELEASE[6.7] SJ_VERSION=LATEST_RELEASE[5.14] - - TEST=plugin SQ_VERSION=LATEST_RELEASE[7.9] SJ_VERSION=DEV - - TEST=plugin SQ_VERSION=LATEST_RELEASE[8.2] SJ_VERSION=DEV - - TEST=plugin SQ_VERSION=LATEST_RELEASE[8.6] SJ_VERSION=DEV - - TEST=plugin SQ_VERSION=DEV SJ_VERSION=DEV - - TEST=javadoc - -cache: - directories: - - $HOME/.m2 - -notifications: - email: - - jborgers@jpinpoint.com - - peter.paul.bakker@stokpop.nl diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b46c45d..49cf237e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,14 +1,43 @@ # Changelog -## [3.4.1-SNAPSHOT](https://github.com/jborgers/sonar-pmd/tree/master) (tbd) -[Full Changelog](https://github.com/jborgers/sonar-pmd/compare/3.4.0...master) -- nothing yet +## [3.5.2-SNAPSHOT](https://github.com/jborgers/sonar-pmd/tree/3.5.2-SNAPSHOT) (2024-xx-xx) +[Full Changelog](https://github.com/jborgers/sonar-pmd/compare/3.5.1..master) + +**Implemented highlights:** + + +## [3.5.1](https://github.com/jborgers/sonar-pmd/tree/3.5.1) (2024-05-07) +[Full Changelog](https://github.com/jborgers/sonar-pmd/compare/3.5.0..3.5.1) + +**Implemented highlights:** +- Supports latest SonarQube [9.9.4 - 10.5+] +- Supports running on Java 11 on analysis side for SQ 9.9.4 - 10.2.x +- Supports running on Java 17 for all supported versions +- Updated Sonar Plugin API+impl for SonarQube 9.9.4+ +- Upgraded various dependencies + +- ## [3.5.0](https://github.com/jborgers/sonar-pmd/tree/3.5.0) (2024-04-23) +[Full Changelog](https://github.com/jborgers/sonar-pmd/compare/3.4.0...3.5.0) + +**Contributors:** +- [jborgers](https://github.com/jborgers) +- [renewolfert](https://github.com/renewolfert) + +**Implemented highlights:** +- Updated PMD (6.55.0) (last PMD-6) #422 +- Support analyzing up to Java 20-preview (close to 21) #422 +- Java 21+ falls back to 20-preview with warning (no error) #422 +- Updated Sonar Plugin API+impl (9.8.0.63668) (SonarQube 9.8+) +- Upgraded various dependencies +- Needs Java 17, the class file version is 61 ## [3.4.0](https://github.com/jborgers/sonar-pmd/tree/3.4.0) (2022-05-11) [Full Changelog](https://github.com/jborgers/sonar-pmd/compare/3.3.1...3.4.0) **Contributors:** +- [jborgers](https://github.com/jborgers) +- [stokpop](https://github.com/stokpop) - [jensgerdes](https://github.com/jensgerdes) (Many thanks for his great maintenance and decision to transfer) **Implemented highlights:** diff --git a/README.md b/README.md index 14f269d0..b3a79280 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,8 @@ # SonarQube PMD7 Plugin [![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.sonarsource.pmd/sonar-pmd-plugin/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.sonarsource.pmd/sonar-pmd-plugin) [![Build Status](https://api.travis-ci.org/jborgers/sonar-pmd.svg?branch=master)](https://travis-ci.org/jborgers/sonar-pmd) [![SonarStatus](https://sonarcloud.io/api/project_badges/measure?project=org.sonarsource.pmd%3Asonar-pmd&metric=alert_status)](https://sonarcloud.io/dashboard?id=org.sonarsource.pmd%3Asonar-pmd) [![SonarStatus](https://sonarcloud.io/api/project_badges/measure?project=org.sonarsource.pmd%3Asonar-pmd&metric=coverage)](https://sonarcloud.io/dashboard?id=org.sonarsource.pmd%3Asonar-pmd) + +[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.sonarsource.pmd/sonar-pmd-plugin/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.sonarsource.pmd/sonar-pmd-plugin) +![Build Status](https://github.com/jborgers/sonar-pmd/actions/workflows/build.yml/badge.svg) + Sonar-PMD is a plugin that provides coding rules from [PMD](https://pmd.github.io/) for use in SonarQube. Starting April 2022, the project has found a new home. We, [jborgers](https://github.com/jborgers) and [stokpop](https://github.com/stokpop), @@ -9,6 +13,7 @@ For a list of all rules and their status, see: [RULES.md](https://github.com/jbo ## Installation The plugin should be available in the SonarQube marketplace and is preferably installed from within SonarQube (Administration --> Marketplace --> Search _pmd_). +This plugin is available again from the Marketplace with the release of version 3.4.0. Alternatively, download the [latest JAR file](https://github.com/jborgers/sonar-pmd/releases/latest), put it into the plugin directory (`./extensions/plugins`) and restart SonarQube. ## Usage @@ -20,18 +25,20 @@ Usage should be straight forward: Sonar-PMD analyzes the given source code with the Java source version defined in your Gradle or Maven project. In case you are not using one of these build tools, or if that does not match the version you are using, set the `sonar.java.source` property to tell PMD which version of Java your source code complies to. -Possible values : 1.4 to 1.8/8 to 18 +Possible values : 1.6 to 1.8/8 to 20-preview ## Table of supported versions -| PMD Plugin |2.5|2.6|3.0.0|3.1.x|3.2.x|3.3.x| 3.4.0 | -|-----------------------------|---|---|---|---|---|---|----------------| -| PMD |5.4.0|5.4.2|5.4.2|6.9.0|6.10.0|6.30.0| 6.45.0 | -| Max. supported Java Version | 1.7 | 1.8 | 1.8 | 11 | | 15| 18 | -| Min. SonarQube Version | 4.5.4 | 4.5.4 | 6.6 | | | 6.7| _8.9(*)_ / 9.3 | +| Sonar-PMD Plugin | 3.1.x | 3.3.x | 3.4.0 | 3.5.0 | 3.5.1 | 4.0.0 (planned) | +|------------------------|-------|--------|-----------------|---------------|---------------|-----------------| +| PMD | 6.9.0 | 6.30.0 | 6.45.0 | 6.55.0 | 6.55.0 | 7.2.0 | +| Max. Java Version | 11 | 15 | 18 | 20-preview *2 | 20-preview *2 | 22 | +| Min. SonarQube Version | 6.6 | 6.7 | _8.9(*1)_ / 9.3 | 9.8 | 9.9.4 | 10.0 | +| Max. SonarQube Version | | | 9.9 | 10.4 | 10.5+ | 10.5+ | -(*) Note: Plugin version 3.4.x runs in SonarQube 8.9, however, Java 17+ is only fully supported in SonarQube 9.3+. +(*1) Note: Plugin version 3.4.x runs in SonarQube 8.9, however, Java 17+ is only fully supported in SonarQube 9.3+. +(*2) Note: Supports all tested Java 21 features; on parsing errors, warns instead of breaks -A majority of the PMD rules have been rewritten in the Java plugin. Rewritten rules are marked "Deprecated" in the PMD plugin, but a [concise summary of replaced rules](http://dist.sonarsource.com/reports/coverage/pmd.html) is available. +A majority of the PMD rules have been rewritten in the Sonar Java plugin. Rewritten rules are marked "Deprecated" in the PMD plugin, but a [concise summary of replaced rules](http://dist.sonarsource.com/reports/coverage/pmd.html) is available. ## Rules on test PMD tool provides some rules that can check the code of JUnit tests. Please note that these rules (and only these rules) will be applied only on the test files of your project. @@ -42,7 +49,7 @@ Sonar-PMD is licensed under the [GNU Lesser General Public License, Version 3.0] Parts of the rule descriptions displayed in SonarQube have been extracted from [PMD](https://pmd.github.io/) and are licensed under a [BSD-style license](https://github.com/pmd/pmd/blob/master/LICENSE). ## Build and test the plugin -To build the plugin and run the integration tests: +To build the plugin and run the integration tests (use java 11): ./mvnw clean verify - \ No newline at end of file + diff --git a/RELEASE.md b/RELEASE.md index c377c998..88655dd8 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -1,29 +1,36 @@ -To release a build +# Create release -- change all `x.y.z-SNAPSHOT` to `x.y.z` in all poms -- change tag `HEAD` to `x.y.z` in scm tag in parent pom -- finish and update `CHANGELOG.md`, update `..master` to `..x.y.z` -- commit and push with comment "Release x.y.z" +To create a new release, set git tag with new version number and push the tag. +The Github Actions `release.yml` will build and release to Github actions and Maven Central. + +Make sure that all commits have been pushed and build +with `build.yml` workflow before setting and pushing the tag. + +Steps: +- create release notes in `CHANGELOG.md`, update `..master` to `..x.y.z`; and update `README.md` +- commit both - `git tag x.y.z` - `git push --tags` -- use github action `release` to deploy to maven central -- release staging repo in Sonatype ui -- change all `x.y.z` in all poms to `x.y.z+1-SNAPSHOT` -- change tag `x.y.z` in scm tag in parent pom to `HEAD` + +The release workflow will be triggered, using the git tag for `-Drevision=`. + +- manually release staging repo in [Sonatype](https://oss.sonatype.org/#welcome) for Maven Central +- manually change Github actions release from draft to final and limit the changelog here: [releases](https://github.com/jborgers/sonar-pmd/releases) + +Next prepare for next SNAPSHOT: + +- change `revision` property in `x.y.z+1-SNAPSHOT` in parent pom - prepare `CHANGELOG.md` for `x.y.z+1-SNAPSHOT` -- commit and push with comment "Prepare for release x.y.z+1-SNAPSHOT" +- commit and push with comment "Prepare release x.y.z+1-SNAPSHOT" -When release fails before "release staging in Sonatype ui" +When release fails before "release staging in Sonatype" - drop staging repo -- `git tag -d x.y.z` -- `git push origin :refs/tags/x.y.z` +- `git tag -d x.y.z` or delete tag in IntelliJ +- `git push origin :refs/tags/x.y.z` or delete tag in context menu, delete remotes - fix-commit-push and start release again with tagging steps above In GitHub: -- create release from tag via Actions -- update release notes with `CHANGELOG.md` contents -- download `sonar-pmd-plugin-x.y.z.jar` and upload in release notes - close milestone `x.y.z` - create new milestone `x.y.z+1` diff --git a/integration-test/pom.xml b/integration-test/pom.xml index 434a4a00..24a78264 100644 --- a/integration-test/pom.xml +++ b/integration-test/pom.xml @@ -25,7 +25,7 @@ org.sonarsource.pmd sonar-pmd - 3.4.1-SNAPSHOT + ${revision} integration-test @@ -42,13 +42,19 @@ org.sonarsource.orchestrator sonar-orchestrator + + org.sonarsource.orchestrator + sonar-orchestrator-junit4 + org.codehaus.sonar sonar-ws-client + provided - org.sonarsource.sonarqube + org.sonarsource.api.plugin sonar-plugin-api + provided net.sourceforge.pmd @@ -58,13 +64,17 @@ org.apache.commons commons-lang3 - 3.12.0 test + + org.sonarsource.scanner.maven + sonar-maven-plugin + ${sonar.maven.plugin.version} + org.sonarsource.sonar-packaging-maven-plugin sonar-packaging-maven-plugin diff --git a/integration-test/projects/pmd-extensions/pom.xml b/integration-test/projects/pmd-extensions/pom.xml index c6220074..9079e91b 100644 --- a/integration-test/projects/pmd-extensions/pom.xml +++ b/integration-test/projects/pmd-extensions/pom.xml @@ -11,6 +11,16 @@ UTF-8 + + + + org.sonarsource.scanner.maven + sonar-maven-plugin + 5.0.0.4389 + + + + skipSonar diff --git a/integration-test/projects/pmd-extensions/src/main/java/pmd/Bar.java b/integration-test/projects/pmd-extensions/src/main/java/pmd/Bar.java index fb8e57ae..41a9580b 100644 --- a/integration-test/projects/pmd-extensions/src/main/java/pmd/Bar.java +++ b/integration-test/projects/pmd-extensions/src/main/java/pmd/Bar.java @@ -1,5 +1,8 @@ package pmd; public class Bar extends Foo { - + public void method() { + // PMD7-MIGRATION: added to force one violation in pmdShouldHaveAccessToExternalLibrariesInItsClasspath: is this testing the correct thing? + if (true) System.out.println("violation on AvoidIfWithoutBrace"); + } } diff --git a/integration-test/projects/pmd-junit-rules/pom.xml b/integration-test/projects/pmd-junit-rules/pom.xml index d926a296..5a0c44c5 100644 --- a/integration-test/projects/pmd-junit-rules/pom.xml +++ b/integration-test/projects/pmd-junit-rules/pom.xml @@ -10,7 +10,7 @@ junit junit - 3.8 + 4.13.2 test diff --git a/integration-test/src/main/java/org/sonar/examples/pmd/MaximumMethodsCountCheck.java b/integration-test/src/main/java/org/sonar/examples/pmd/MaximumMethodsCountCheck.java index fd4be82f..1b1f284e 100644 --- a/integration-test/src/main/java/org/sonar/examples/pmd/MaximumMethodsCountCheck.java +++ b/integration-test/src/main/java/org/sonar/examples/pmd/MaximumMethodsCountCheck.java @@ -22,13 +22,14 @@ import java.util.List; -import net.sourceforge.pmd.RuleContext; -import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceBody; + +import net.sourceforge.pmd.lang.java.ast.ASTClassBody; import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; +import net.sourceforge.pmd.properties.NumericConstraints; import net.sourceforge.pmd.properties.PropertyDescriptor; import net.sourceforge.pmd.properties.PropertyFactory; -import net.sourceforge.pmd.properties.constraints.NumericConstraints; +import net.sourceforge.pmd.reporting.RuleContext; import org.sonar.api.utils.log.Logger; import org.sonar.api.utils.log.Loggers; @@ -58,10 +59,10 @@ public void end(RuleContext ctx) { } @Override - public Object visit(ASTClassOrInterfaceBody node, Object data) { - List methods = node.findDescendantsOfType(ASTMethodDeclaration.class); + public Object visit(ASTClassBody node, Object data) { + List methods = node.descendants(ASTMethodDeclaration.class).toList(); if (methods.size() > getProperty(propertyDescriptor)) { - addViolation(data, node); + asCtx(data).addViolation(node); } return super.visit(node, data); } diff --git a/integration-test/src/main/resources/org/sonar/examples/pmd/extensions.xml b/integration-test/src/main/resources/org/sonar/examples/pmd/extensions.xml index 45190044..3cadf25a 100644 --- a/integration-test/src/main/resources/org/sonar/examples/pmd/extensions.xml +++ b/integration-test/src/main/resources/org/sonar/examples/pmd/extensions.xml @@ -42,7 +42,7 @@ MAJOR Prevent use of EmptyClass class - + MINOR xpath diff --git a/integration-test/src/main/resources/org/sonar/examples/pmd/rulesets.xml b/integration-test/src/main/resources/org/sonar/examples/pmd/rulesets.xml index 0d7f8f21..b5afc8bb 100644 --- a/integration-test/src/main/resources/org/sonar/examples/pmd/rulesets.xml +++ b/integration-test/src/main/resources/org/sonar/examples/pmd/rulesets.xml @@ -1,14 +1,15 @@ + xmlns="http://pmd.sourceforge.net/ruleset/2.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 http://pmd.sourceforge.net/ruleset_2_0_0.xsd"> - + Integration test rules + class="org.sonar.examples.pmd.MaximumMethodsCountCheck" + language="java"> Avoid too many methods @@ -18,19 +19,19 @@ + ]]> Avoid if without using brace @@ -55,7 +56,7 @@ IOException should never be extended. Either use it, or extend Exception for your own business exceptions. diff --git a/integration-test/src/test/java/com/sonar/it/java/suite/PmdIT.java b/integration-test/src/test/java/com/sonar/it/java/suite/PmdIT.java index e3987d5c..84f02788 100644 --- a/integration-test/src/test/java/com/sonar/it/java/suite/PmdIT.java +++ b/integration-test/src/test/java/com/sonar/it/java/suite/PmdIT.java @@ -24,7 +24,6 @@ import com.sonar.orchestrator.build.MavenBuild; import com.sonar.orchestrator.http.HttpException; import org.apache.commons.lang3.JavaVersion; -import org.junit.Ignore; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; @@ -36,20 +35,20 @@ import java.util.stream.Collectors; import static com.sonar.it.java.suite.TestUtils.keyFor; -import static com.sonar.it.java.suite.TestUtils.keyForTest; import static org.assertj.core.api.Assertions.assertThat; class PmdIT { - private static final PmdTestOrchestrator ORCHESTRATOR = PmdTestOrchestrator.init(); + private static PmdTestOrchestrator ORCHESTRATOR; @BeforeAll static void startSonar() { + ORCHESTRATOR = PmdTestOrchestrator.init(); ORCHESTRATOR.start(); } @ParameterizedTest - @EnumSource(value = JavaVersion.class, mode = EnumSource.Mode.INCLUDE, names = {"JAVA_1_8", "JAVA_11", "JAVA_16"}) + @EnumSource(value = JavaVersion.class, mode = EnumSource.Mode.INCLUDE, names = {"JAVA_1_8", "JAVA_11", "JAVA_17", "JAVA_20"}) void testPmdExtensionsWithDifferentJavaVersions(JavaVersion version) { // given @@ -143,44 +142,6 @@ void testRuleAvoidDuplicateLiterals() { } } - /** - * SONAR-1076 - */ - @Test - void testJunitRules() { - - // given - final String projectName = "pmd-junit-rules"; - final MavenBuild build = MavenBuild - .create(TestUtils.projectPom(projectName)) - .setCleanSonarGoals(); - - try { - ORCHESTRATOR.associateProjectToQualityProfile("pmd-junit", projectName); - - // when - ORCHESTRATOR.executeBuild(build); - - // then - final List testIssues = retrieveIssues(keyForTest()); - assertThat(testIssues).hasSize(1); - assertThat(testIssues.get(0).message()).matches("This class name ends with '?Test'? but contains no test cases"); - assertThat(testIssues.get(0).ruleKey()).isEqualTo("pmd7-unit-tests:TestClassWithoutTestCases"); - - final List prodIssues = retrieveIssues(keyFor(projectName, "", "ProductionCode")); - assertThat(prodIssues).hasSize(1); - assertThat(prodIssues.get(0).message()).contains("Avoid unused private fields such as 'unused'."); - assertThat(prodIssues.get(0).ruleKey()).isEqualTo("pmd7:UnusedPrivateField"); - - } catch (HttpException e) { - System.out.println("Failed to associate Project To Quality Profile: " + e.getMessage() + " body: " + e.getBody()); - throw e; - } finally { - // Cleanup - ORCHESTRATOR.resetData(projectName); - } - } - /** * SONARPLUGINS-3318 */ @@ -199,6 +160,7 @@ void pmdShouldHaveAccessToExternalLibrariesInItsClasspath() { ORCHESTRATOR.executeBuild(build); // then + // PMD7-MIGRATION: added to force one violation in pmdShouldHaveAccessToExternalLibrariesInItsClasspath: is this testing the correct thing? final List issues = retrieveIssues(keyFor(projectName, "pmd/", "Bar")); assertThat(issues) .hasSize(1); diff --git a/integration-test/src/test/java/com/sonar/it/java/suite/orchestrator/PmdTestOrchestrator.java b/integration-test/src/test/java/com/sonar/it/java/suite/orchestrator/PmdTestOrchestrator.java index 9651046e..6c6d3b63 100644 --- a/integration-test/src/test/java/com/sonar/it/java/suite/orchestrator/PmdTestOrchestrator.java +++ b/integration-test/src/test/java/com/sonar/it/java/suite/orchestrator/PmdTestOrchestrator.java @@ -19,9 +19,9 @@ */ package com.sonar.it.java.suite.orchestrator; -import com.sonar.orchestrator.Orchestrator; import com.sonar.orchestrator.build.BuildResult; import com.sonar.orchestrator.build.MavenBuild; +import com.sonar.orchestrator.junit4.OrchestratorRule; import com.sonar.orchestrator.locator.MavenLocation; import org.sonar.wsclient.SonarClient; import org.sonar.wsclient.issue.Issue; @@ -43,10 +43,19 @@ public class PmdTestOrchestrator { private static final String SONAR_JAVA_PLUGIN_VERSION_KEY = "test.sonar.plugin.version.java"; private static final String SONAR_VERSION_KEY = "test.sonar.version"; private static final String LANGUAGE_KEY = "java"; + private static final String CENTRAL_MAVEN = "https://repo1.maven.org/maven2"; + + static { + // override jfrog as artifactory because it now doesn't have anonymous login anymore + // don't rely on configuration file, less dependencies + // issue see https://community.sonarsource.com/t/orchestrator-adding-support-for-downloading-artifacts-without-jfrog/108867 + if (System.getProperty("orchestrator.artifactory.url") == null) { + System.setProperty("orchestrator.artifactory.url", CENTRAL_MAVEN); + } + } + private final OrchestratorRule delegate; - private final Orchestrator delegate; - - private PmdTestOrchestrator(Orchestrator delegate) { + private PmdTestOrchestrator(OrchestratorRule delegate) { this.delegate = delegate; } @@ -85,8 +94,8 @@ public void associateProjectToQualityProfile(String profile, String project) { public static PmdTestOrchestrator init() { try { - final Orchestrator orchestrator = Orchestrator - .builderEnv() + final OrchestratorRule orchestrator = OrchestratorRule + .builderEnv().useDefaultAdminCredentialsForBuilds(true) .setSonarVersion(determineSonarqubeVersion()) .addPlugin(MavenLocation.create( "org.sonarsource.java", @@ -95,7 +104,6 @@ public static PmdTestOrchestrator init() { )) .addPlugin(byWildcardMavenFilename(new File("../sonar-pmd-plugin/target"), "sonar-pmd7-plugin-*.jar")) .addPlugin(byWildcardMavenFilename(new File("./target"), "integration-test-*.jar")) - .restoreProfileAtStartup(ofClasspath("/com/sonar/it/java/PmdTest/pmd-junit-rules.xml")) .restoreProfileAtStartup(ofClasspath("/com/sonar/it/java/PmdTest/pmd-extensions-profile.xml")) .restoreProfileAtStartup(ofClasspath("/com/sonar/it/java/PmdTest/pmd-backup.xml")) .restoreProfileAtStartup(ofClasspath("/com/sonar/it/java/PmdTest/pmd-all-rules.xml")) @@ -114,10 +122,10 @@ private static String deriveProjectKey(String projectName) { } private static String determineJavaPluginVersion() { - return System.getProperty(SONAR_JAVA_PLUGIN_VERSION_KEY, "DEV"); + return System.getProperty(SONAR_JAVA_PLUGIN_VERSION_KEY, "LATEST_RELEASE[7.13]"); } private static String determineSonarqubeVersion() { - return System.getProperty(SONAR_VERSION_KEY, "LATEST_RELEASE[9.4]"); + return System.getProperty(SONAR_VERSION_KEY, "LATEST_RELEASE[9.8]"); } } diff --git a/integration-test/src/test/resources/com/sonar/it/java/PmdTest/pmd-all-rules.xml b/integration-test/src/test/resources/com/sonar/it/java/PmdTest/pmd-all-rules.xml index 89cf3af6..60dd8680 100644 --- a/integration-test/src/test/resources/com/sonar/it/java/PmdTest/pmd-all-rules.xml +++ b/integration-test/src/test/resources/com/sonar/it/java/PmdTest/pmd-all-rules.xml @@ -298,12 +298,6 @@ pmd7 AvoidUsingHardCodedIP MAJOR - - - checkAddressTypes - IPv4|IPv6|IPv4 mapped IPv6 - - pmd7 @@ -335,12 +329,12 @@ MAJOR - - pmd7 - BeanMembersShouldSerialize - MAJOR - - + + + + + + pmd7 BigIntegerInstantiation @@ -430,12 +424,12 @@ MAJOR - - pmd7 - CloneMethodMustImplementCloneable - MAJOR - - + + + + + + pmd7 CloneMethodMustImplementCloneableWithTypeResolution @@ -586,7 +580,7 @@ pmd7 - DefaultLabelNotLastInSwitchStmt + DefaultLabelNotLastInSwitch MAJOR @@ -685,72 +679,72 @@ MAJOR - - pmd7 - EmptyFinallyBlock - CRITICAL - - - - pmd7 - EmptyIfStmt - CRITICAL - - - - pmd7 - EmptyInitializer - MAJOR - - + + + + + + + + + + + + + + + + + + pmd7 EmptyMethodInAbstractClassShouldBeAbstract MAJOR - - pmd7 - EmptyStatementBlock - MAJOR - - - - pmd7 - EmptyStatementNotInLoop - MAJOR - - + + + + + + + + + + + + pmd7 EmptyStaticInitializer MAJOR - - pmd7 - EmptySwitchStatements - MAJOR - - - - pmd7 - EmptySynchronizedBlock - CRITICAL - - - - pmd7 - EmptyTryBlock - MAJOR - - - - pmd7 - EmptyWhileStmt - CRITICAL - - + + + + + + + + + + + + + + + + + + + + + + + + pmd7 EqualsNull @@ -763,17 +757,17 @@ MAJOR - - pmd7 - ExcessiveClassLength - MAJOR - - - minimum - 1000 - - - + + + + + + + + + + + pmd7 ExcessiveImports @@ -785,17 +779,17 @@ - - pmd7 - ExcessiveMethodLength - MAJOR - - - minimum - 100 - - - + + + + + + + + + + + pmd7 ExcessiveParameterList @@ -899,12 +893,12 @@ MAJOR - - pmd7 - GuardLogStatement - MAJOR - - + + + + + + pmd7 GuardLogStatementJavaUtil @@ -1030,12 +1024,12 @@ - - pmd7 - LooseCoupling - MAJOR - - + + + + + + pmd7 LooseCouplingWithTypeResolution @@ -1185,7 +1179,7 @@ pmd7 - NonCaseLabelInSwitchStatement + NonCaseLabelInSwitch MAJOR @@ -1403,12 +1397,12 @@ MAJOR - - pmd7 - SimplifyBooleanExpressions - MAJOR - - + + + + + + pmd7 SimplifyBooleanReturns @@ -1525,7 +1519,7 @@ pmd7 - SwitchStmtsShouldHaveDefault + NonExhaustiveSwitch MAJOR @@ -1537,7 +1531,7 @@ pmd7 - TooFewBranchesForASwitchStatement + TooFewBranchesForSwitch MINOR diff --git a/integration-test/src/test/resources/com/sonar/it/java/PmdTest/pmd-junit-rules.xml b/integration-test/src/test/resources/com/sonar/it/java/PmdTest/pmd-junit-rules.xml deleted file mode 100644 index 311715be..00000000 --- a/integration-test/src/test/resources/com/sonar/it/java/PmdTest/pmd-junit-rules.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - pmd-junit - java - - - pmd7 - UnusedPrivateField - MAJOR - - - pmd7-unit-tests - TestClassWithoutTestCases - MAJOR - - - diff --git a/mvnw b/mvnw index 5643201c..19529ddf 100755 --- a/mvnw +++ b/mvnw @@ -19,298 +19,241 @@ # ---------------------------------------------------------------------------- # ---------------------------------------------------------------------------- -# Maven Start Up Batch script -# -# Required ENV vars: -# ------------------ -# JAVA_HOME - location of a JDK home dir +# Apache Maven Wrapper startup batch script, version 3.3.2 # # Optional ENV vars # ----------------- -# M2_HOME - location of maven2's installed home dir -# MAVEN_OPTS - parameters passed to the Java VM when running Maven -# e.g. to debug Maven itself, use -# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# JAVA_HOME - location of a JDK home dir, required when download maven via java source +# MVNW_REPOURL - repo url base for downloading maven distribution +# MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven +# MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output # ---------------------------------------------------------------------------- -if [ -z "$MAVEN_SKIP_RC" ] ; then - - if [ -f /usr/local/etc/mavenrc ] ; then - . /usr/local/etc/mavenrc - fi - - if [ -f /etc/mavenrc ] ; then - . /etc/mavenrc - fi +set -euf +[ "${MVNW_VERBOSE-}" != debug ] || set -x - if [ -f "$HOME/.mavenrc" ] ; then - . "$HOME/.mavenrc" - fi +# OS specific support. +native_path() { printf %s\\n "$1"; } +case "$(uname)" in +CYGWIN* | MINGW*) + [ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")" + native_path() { cygpath --path --windows "$1"; } + ;; +esac -fi +# set JAVACMD and JAVACCMD +set_java_home() { + # For Cygwin and MinGW, ensure paths are in Unix format before anything is touched + if [ -n "${JAVA_HOME-}" ]; then + if [ -x "$JAVA_HOME/jre/sh/java" ]; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACCMD="$JAVA_HOME/jre/sh/javac" + else + JAVACMD="$JAVA_HOME/bin/java" + JAVACCMD="$JAVA_HOME/bin/javac" -# OS specific support. $var _must_ be set to either true or false. -cygwin=false; -darwin=false; -mingw=false -case "`uname`" in - CYGWIN*) cygwin=true ;; - MINGW*) mingw=true;; - Darwin*) darwin=true - # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home - # See https://developer.apple.com/library/mac/qa/qa1170/_index.html - if [ -z "$JAVA_HOME" ]; then - if [ -x "/usr/libexec/java_home" ]; then - export JAVA_HOME="`/usr/libexec/java_home`" - else - export JAVA_HOME="/Library/Java/Home" + if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then + echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2 + echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2 + return 1 fi fi - ;; -esac - -if [ -z "$JAVA_HOME" ] ; then - if [ -r /etc/gentoo-release ] ; then - JAVA_HOME=`java-config --jre-home` + else + JAVACMD="$( + 'set' +e + 'unset' -f command 2>/dev/null + 'command' -v java + )" || : + JAVACCMD="$( + 'set' +e + 'unset' -f command 2>/dev/null + 'command' -v javac + )" || : + + if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then + echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2 + return 1 + fi fi -fi - -if [ -z "$M2_HOME" ] ; then - ## resolve links - $0 may be a link to maven's home - PRG="$0" +} - # need this for relative symlinks - while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG="`dirname "$PRG"`/$link" - fi +# hash string like Java String::hashCode +hash_string() { + str="${1:-}" h=0 + while [ -n "$str" ]; do + char="${str%"${str#?}"}" + h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296)) + str="${str#?}" done + printf %x\\n $h +} - saveddir=`pwd` +verbose() { :; } +[ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; } - M2_HOME=`dirname "$PRG"`/.. +die() { + printf %s\\n "$1" >&2 + exit 1 +} - # make it fully qualified - M2_HOME=`cd "$M2_HOME" && pwd` +trim() { + # MWRAPPER-139: + # Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds. + # Needed for removing poorly interpreted newline sequences when running in more + # exotic environments such as mingw bash on Windows. + printf "%s" "${1}" | tr -d '[:space:]' +} - cd "$saveddir" - # echo Using m2 at $M2_HOME -fi +# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties +while IFS="=" read -r key value; do + case "${key-}" in + distributionUrl) distributionUrl=$(trim "${value-}") ;; + distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;; + esac +done <"${0%/*}/.mvn/wrapper/maven-wrapper.properties" +[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in ${0%/*}/.mvn/wrapper/maven-wrapper.properties" + +case "${distributionUrl##*/}" in +maven-mvnd-*bin.*) + MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ + case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in + *AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;; + :Darwin*x86_64) distributionPlatform=darwin-amd64 ;; + :Darwin*arm64) distributionPlatform=darwin-aarch64 ;; + :Linux*x86_64*) distributionPlatform=linux-amd64 ;; + *) + echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2 + distributionPlatform=linux-amd64 + ;; + esac + distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip" + ;; +maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;; +*) MVN_CMD="mvn${0##*/mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;; +esac -# For Cygwin, ensure paths are in UNIX format before anything is touched -if $cygwin ; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --unix "$M2_HOME"` - [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --unix "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --unix "$CLASSPATH"` -fi +# apply MVNW_REPOURL and calculate MAVEN_HOME +# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ +[ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}" +distributionUrlName="${distributionUrl##*/}" +distributionUrlNameMain="${distributionUrlName%.*}" +distributionUrlNameMain="${distributionUrlNameMain%-bin}" +MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}" +MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")" + +exec_maven() { + unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || : + exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD" +} -# For Mingw, ensure paths are in UNIX format before anything is touched -if $mingw ; then - [ -n "$M2_HOME" ] && - M2_HOME="`(cd "$M2_HOME"; pwd)`" - [ -n "$JAVA_HOME" ] && - JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" +if [ -d "$MAVEN_HOME" ]; then + verbose "found existing MAVEN_HOME at $MAVEN_HOME" + exec_maven "$@" fi -if [ -z "$JAVA_HOME" ]; then - javaExecutable="`which javac`" - if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then - # readlink(1) is not available as standard on Solaris 10. - readLink=`which readlink` - if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then - if $darwin ; then - javaHome="`dirname \"$javaExecutable\"`" - javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" - else - javaExecutable="`readlink -f \"$javaExecutable\"`" - fi - javaHome="`dirname \"$javaExecutable\"`" - javaHome=`expr "$javaHome" : '\(.*\)/bin'` - JAVA_HOME="$javaHome" - export JAVA_HOME - fi - fi -fi +case "${distributionUrl-}" in +*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;; +*) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;; +esac -if [ -z "$JAVACMD" ] ; then - if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - else - JAVACMD="`\\unset -f command; \\command -v java`" - fi +# prepare tmp dir +if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then + clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; } + trap clean HUP INT TERM EXIT +else + die "cannot create temp dir" fi -if [ ! -x "$JAVACMD" ] ; then - echo "Error: JAVA_HOME is not defined correctly." >&2 - echo " We cannot execute $JAVACMD" >&2 - exit 1 -fi +mkdir -p -- "${MAVEN_HOME%/*}" -if [ -z "$JAVA_HOME" ] ; then - echo "Warning: JAVA_HOME environment variable is not set." +# Download and Install Apache Maven +verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." +verbose "Downloading from: $distributionUrl" +verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" + +# select .zip or .tar.gz +if ! command -v unzip >/dev/null; then + distributionUrl="${distributionUrl%.zip}.tar.gz" + distributionUrlName="${distributionUrl##*/}" fi -CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher +# verbose opt +__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR='' +[ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v -# traverses directory structure from process work directory to filesystem root -# first directory with .mvn subdirectory is considered project base directory -find_maven_basedir() { +# normalize http auth +case "${MVNW_PASSWORD:+has-password}" in +'') MVNW_USERNAME='' MVNW_PASSWORD='' ;; +has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;; +esac - if [ -z "$1" ] - then - echo "Path not specified to find_maven_basedir" - return 1 - fi +if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then + verbose "Found wget ... using wget" + wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl" +elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then + verbose "Found curl ... using curl" + curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl" +elif set_java_home; then + verbose "Falling back to use Java to download" + javaSource="$TMP_DOWNLOAD_DIR/Downloader.java" + targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName" + cat >"$javaSource" <<-END + public class Downloader extends java.net.Authenticator + { + protected java.net.PasswordAuthentication getPasswordAuthentication() + { + return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() ); + } + public static void main( String[] args ) throws Exception + { + setDefault( new Downloader() ); + java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() ); + } + } + END + # For Cygwin/MinGW, switch paths to Windows format before running javac and java + verbose " - Compiling Downloader.java ..." + "$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java" + verbose " - Running Downloader.java ..." + "$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")" +fi - basedir="$1" - wdir="$1" - while [ "$wdir" != '/' ] ; do - if [ -d "$wdir"/.mvn ] ; then - basedir=$wdir - break +# If specified, validate the SHA-256 sum of the Maven distribution zip file +if [ -n "${distributionSha256Sum-}" ]; then + distributionSha256Result=false + if [ "$MVN_CMD" = mvnd.sh ]; then + echo "Checksum validation is not supported for maven-mvnd." >&2 + echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 + exit 1 + elif command -v sha256sum >/dev/null; then + if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c >/dev/null 2>&1; then + distributionSha256Result=true fi - # workaround for JBEAP-8937 (on Solaris 10/Sparc) - if [ -d "${wdir}" ]; then - wdir=`cd "$wdir/.."; pwd` + elif command -v shasum >/dev/null; then + if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then + distributionSha256Result=true fi - # end of workaround - done - echo "${basedir}" -} - -# concatenates all lines of a file -concat_lines() { - if [ -f "$1" ]; then - echo "$(tr -s '\n' ' ' < "$1")" + else + echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2 + echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 + exit 1 + fi + if [ $distributionSha256Result = false ]; then + echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2 + echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2 + exit 1 fi -} - -BASE_DIR=`find_maven_basedir "$(pwd)"` -if [ -z "$BASE_DIR" ]; then - exit 1; fi -########################################################################################## -# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -# This allows using the maven wrapper in projects that prohibit checking in binary data. -########################################################################################## -if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found .mvn/wrapper/maven-wrapper.jar" - fi +# unzip and move +if command -v unzip >/dev/null; then + unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip" else - if [ "$MVNW_VERBOSE" = true ]; then - echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." - fi - if [ -n "$MVNW_REPOURL" ]; then - jarUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" - else - jarUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" - fi - while IFS="=" read key value; do - case "$key" in (wrapperUrl) jarUrl="$value"; break ;; - esac - done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" - if [ "$MVNW_VERBOSE" = true ]; then - echo "Downloading from: $jarUrl" - fi - wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" - if $cygwin; then - wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` - fi - - if command -v wget > /dev/null; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found wget ... using wget" - fi - if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then - wget "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" - else - wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" - fi - elif command -v curl > /dev/null; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found curl ... using curl" - fi - if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then - curl -o "$wrapperJarPath" "$jarUrl" -f - else - curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f - fi - - else - if [ "$MVNW_VERBOSE" = true ]; then - echo "Falling back to using Java to download" - fi - javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" - # For Cygwin, switch paths to Windows format before running javac - if $cygwin; then - javaClass=`cygpath --path --windows "$javaClass"` - fi - if [ -e "$javaClass" ]; then - if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then - if [ "$MVNW_VERBOSE" = true ]; then - echo " - Compiling MavenWrapperDownloader.java ..." - fi - # Compiling the Java class - ("$JAVA_HOME/bin/javac" "$javaClass") - fi - if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then - # Running the downloader - if [ "$MVNW_VERBOSE" = true ]; then - echo " - Running MavenWrapperDownloader.java ..." - fi - ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") - fi - fi - fi -fi -########################################################################################## -# End of extension -########################################################################################## - -export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} -if [ "$MVNW_VERBOSE" = true ]; then - echo $MAVEN_PROJECTBASEDIR + tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar" fi -MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" - -# For Cygwin, switch paths to Windows format before running java -if $cygwin; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --path --windows "$M2_HOME"` - [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --windows "$CLASSPATH"` - [ -n "$MAVEN_PROJECTBASEDIR" ] && - MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` -fi - -# Provide a "standardized" way to retrieve the CLI args that will -# work with both Windows and non-Windows executions. -MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" -export MAVEN_CMD_LINE_ARGS - -WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain +printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/mvnw.url" +mv -- "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME" -exec "$JAVACMD" \ - $MAVEN_OPTS \ - $MAVEN_DEBUG_OPTS \ - -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ - "-Dmaven.home=${M2_HOME}" \ - "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ - ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" +clean || : +exec_maven "$@" diff --git a/mvnw.cmd b/mvnw.cmd index 23b7079a..b150b91e 100644 --- a/mvnw.cmd +++ b/mvnw.cmd @@ -1,3 +1,4 @@ +<# : batch portion @REM ---------------------------------------------------------------------------- @REM Licensed to the Apache Software Foundation (ASF) under one @REM or more contributor license agreements. See the NOTICE file @@ -18,171 +19,131 @@ @REM ---------------------------------------------------------------------------- @REM ---------------------------------------------------------------------------- -@REM Maven Start Up Batch script -@REM -@REM Required ENV vars: -@REM JAVA_HOME - location of a JDK home dir +@REM Apache Maven Wrapper startup batch script, version 3.3.2 @REM @REM Optional ENV vars -@REM M2_HOME - location of maven2's installed home dir -@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands -@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending -@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven -@REM e.g. to debug Maven itself, use -@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM MVNW_REPOURL - repo url base for downloading maven distribution +@REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven +@REM MVNW_VERBOSE - true: enable verbose log; others: silence the output @REM ---------------------------------------------------------------------------- -@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' -@echo off -@REM set title of command window -title %0 -@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' -@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% - -@REM set %HOME% to equivalent of $HOME -if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") - -@REM Execute a user defined script before this one -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre -@REM check for pre script, once with legacy .bat ending and once with .cmd ending -if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* -if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* -:skipRcPre - -@setlocal - -set ERROR_CODE=0 - -@REM To isolate internal variables from possible post scripts, we use another setlocal -@setlocal - -@REM ==== START VALIDATION ==== -if not "%JAVA_HOME%" == "" goto OkJHome - -echo. -echo Error: JAVA_HOME not found in your environment. >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -:OkJHome -if exist "%JAVA_HOME%\bin\java.exe" goto init - -echo. -echo Error: JAVA_HOME is set to an invalid directory. >&2 -echo JAVA_HOME = "%JAVA_HOME%" >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -@REM ==== END VALIDATION ==== - -:init - -@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". -@REM Fallback to current working directory if not found. - -set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% -IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir - -set EXEC_DIR=%CD% -set WDIR=%EXEC_DIR% -:findBaseDir -IF EXIST "%WDIR%"\.mvn goto baseDirFound -cd .. -IF "%WDIR%"=="%CD%" goto baseDirNotFound -set WDIR=%CD% -goto findBaseDir - -:baseDirFound -set MAVEN_PROJECTBASEDIR=%WDIR% -cd "%EXEC_DIR%" -goto endDetectBaseDir - -:baseDirNotFound -set MAVEN_PROJECTBASEDIR=%EXEC_DIR% -cd "%EXEC_DIR%" - -:endDetectBaseDir - -IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig - -@setlocal EnableExtensions EnableDelayedExpansion -for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a -@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% - -:endReadAdditionalConfig - -SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" -set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" -set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" - -FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( - IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B -) - -@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -@REM This allows using the maven wrapper in projects that prohibit checking in binary data. -if exist %WRAPPER_JAR% ( - if "%MVNW_VERBOSE%" == "true" ( - echo Found %WRAPPER_JAR% - ) -) else ( - if not "%MVNW_REPOURL%" == "" ( - SET DOWNLOAD_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" - ) - if "%MVNW_VERBOSE%" == "true" ( - echo Couldn't find %WRAPPER_JAR%, downloading it ... - echo Downloading from: %DOWNLOAD_URL% - ) - - powershell -Command "&{"^ - "$webclient = new-object System.Net.WebClient;"^ - "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ - "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ - "}"^ - "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ - "}" - if "%MVNW_VERBOSE%" == "true" ( - echo Finished downloading %WRAPPER_JAR% - ) +@IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0) +@SET __MVNW_CMD__= +@SET __MVNW_ERROR__= +@SET __MVNW_PSMODULEP_SAVE=%PSModulePath% +@SET PSModulePath= +@FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @( + IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B) ) -@REM End of extension - -@REM Provide a "standardized" way to retrieve the CLI args that will -@REM work with both Windows and non-Windows executions. -set MAVEN_CMD_LINE_ARGS=%* - -%MAVEN_JAVA_EXE% ^ - %JVM_CONFIG_MAVEN_PROPS% ^ - %MAVEN_OPTS% ^ - %MAVEN_DEBUG_OPTS% ^ - -classpath %WRAPPER_JAR% ^ - "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ - %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* -if ERRORLEVEL 1 goto error -goto end - -:error -set ERROR_CODE=1 - -:end -@endlocal & set ERROR_CODE=%ERROR_CODE% - -if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost -@REM check for post script, once with legacy .bat ending and once with .cmd ending -if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" -if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" -:skipRcPost - -@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' -if "%MAVEN_BATCH_PAUSE%"=="on" pause - -if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% - -cmd /C exit /B %ERROR_CODE% +@SET PSModulePath=%__MVNW_PSMODULEP_SAVE% +@SET __MVNW_PSMODULEP_SAVE= +@SET __MVNW_ARG0_NAME__= +@SET MVNW_USERNAME= +@SET MVNW_PASSWORD= +@IF NOT "%__MVNW_CMD__%"=="" (%__MVNW_CMD__% %*) +@echo Cannot start maven from wrapper >&2 && exit /b 1 +@GOTO :EOF +: end batch / begin powershell #> + +$ErrorActionPreference = "Stop" +if ($env:MVNW_VERBOSE -eq "true") { + $VerbosePreference = "Continue" +} + +# calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties +$distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl +if (!$distributionUrl) { + Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties" +} + +switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) { + "maven-mvnd-*" { + $USE_MVND = $true + $distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip" + $MVN_CMD = "mvnd.cmd" + break + } + default { + $USE_MVND = $false + $MVN_CMD = $script -replace '^mvnw','mvn' + break + } +} + +# apply MVNW_REPOURL and calculate MAVEN_HOME +# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ +if ($env:MVNW_REPOURL) { + $MVNW_REPO_PATTERN = if ($USE_MVND) { "/org/apache/maven/" } else { "/maven/mvnd/" } + $distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace '^.*'+$MVNW_REPO_PATTERN,'')" +} +$distributionUrlName = $distributionUrl -replace '^.*/','' +$distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$','' +$MAVEN_HOME_PARENT = "$HOME/.m2/wrapper/dists/$distributionUrlNameMain" +if ($env:MAVEN_USER_HOME) { + $MAVEN_HOME_PARENT = "$env:MAVEN_USER_HOME/wrapper/dists/$distributionUrlNameMain" +} +$MAVEN_HOME_NAME = ([System.Security.Cryptography.MD5]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join '' +$MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME" + +if (Test-Path -Path "$MAVEN_HOME" -PathType Container) { + Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME" + Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" + exit $? +} + +if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) { + Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl" +} + +# prepare tmp dir +$TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile +$TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir" +$TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null +trap { + if ($TMP_DOWNLOAD_DIR.Exists) { + try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } + catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } + } +} + +New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null + +# Download and Install Apache Maven +Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." +Write-Verbose "Downloading from: $distributionUrl" +Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" + +$webclient = New-Object System.Net.WebClient +if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) { + $webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD) +} +[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 +$webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null + +# If specified, validate the SHA-256 sum of the Maven distribution zip file +$distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum +if ($distributionSha256Sum) { + if ($USE_MVND) { + Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." + } + Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash + if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) { + Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property." + } +} + +# unzip and move +Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null +Rename-Item -Path "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" -NewName $MAVEN_HOME_NAME | Out-Null +try { + Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null +} catch { + if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) { + Write-Error "fail to move MAVEN_HOME" + } +} finally { + try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } + catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } +} + +Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" diff --git a/pom.xml b/pom.xml index d0c6c944..def56e45 100644 --- a/pom.xml +++ b/pom.xml @@ -23,30 +23,27 @@ 4.0.0 org.sonarsource.pmd sonar-pmd - 3.4.1-SNAPSHOT + ${revision} SonarQube PMD7 Project pom + Sonar-PMD is a plugin that provides coding rules from PMD for use in SonarQube. scm:git:git@github.com:jborgers/sonar-pmd.git scm:git:git@github.com:jborgers/sonar-pmd.git https://github.com/jborgers/sonar-pmd - HEAD + ${revision} https://github.com/jborgers/sonar-pmd Github https://github.com/jborgers/sonar-pmd/issues - - Travis - https://travis-ci.org/jborgers/sonar-pmd - GNU LGPL 3 - http://www.gnu.org/licenses/lgpl.txt + https://www.gnu.org/licenses/lgpl.txt repo @@ -85,37 +82,43 @@ + + 3.5.2-SNAPSHOT SonarSource SA and others mailto:jborgers AT jpinpoint DOT com; peter.paul.bakker AT stokpop DOT nl - 7.0.0-SNAPSHOT - 5.8.2 - 4.5.1 - 3.22.0 - 3.12.0 + 7.8.0 + 5.11.0-M1 + 5.11.0 + 3.25.3 + 3.14.0 2.0.1 - 7.12.0.29739 - 31.1-jre + 7.30.0.34429 + 33.2.0-jre 2.7.1.392 - 1.0 + 2.0.6.1 - 1.21.0.505 - 9.4.0.54424 - 3.37.0.87 + 1.23.0.740 + 9.9.4.87374 + 9.14.0.375 + 4.9.0.1920 5.1 UTF-8 - 1.8 - 1.8 + 11 + 11 - 3.0.0-M1 - 2.22.2 - 2.22.2 - 2.5.3 - 3.2.1 - 3.2.0 - 3.0.1 - 3.9.1.2184 - 0.8.8 + 3.5.0 + 3.5.2 + 3.5.2 + 3.1.1 + 3.3.1 + 3.11.1 + 3.2.7 + 3.4.0 + 5.0.0.4389 + 0.8.12 + 1.7.0 + 1.6.0 UTF-8 sonar-pmd-plugin/target/site/jacoco/jacoco.xml @@ -130,21 +133,24 @@ - org.sonarsource.sonarqube + org.sonarsource.api.plugin sonar-plugin-api - provided ${sonar-plugin-api.version} org.sonarsource.sonarqube sonar-plugin-api-impl - test - ${sonar-plugin-api.version} + ${sonar-plugin-api-impl.version} org.sonarsource.orchestrator sonar-orchestrator ${sonar-orchestrator.version} + + + org.sonarsource.orchestrator + sonar-orchestrator-junit4 + ${sonar-orchestrator.version} test @@ -158,7 +164,7 @@ org.codehaus.sonar sonar-ws-client ${sonar-ws-client.version} - test + provided @@ -214,19 +220,78 @@ + + org.apache.maven.plugins + maven-gpg-plugin + ${maven.gpg.plugin.version} + org.sonarsource.sonar-packaging-maven-plugin sonar-packaging-maven-plugin ${version.sonar-packaging.plugin} - 6.7 - + 9.9 + + org.sonatype.plugins + nexus-staging-maven-plugin + ${nexus-staging.plugin.version} + + + maven-clean-plugin + ${maven.cleanup.plugin.version} + + + org.apache.maven.plugins + maven-enforcer-plugin + ${maven.enforcer.plugin.version} + + + org.apache.maven.plugins + maven-surefire-plugin + ${maven.surefire.plugin.version} + + + org.codehaus.mojo + flatten-maven-plugin + ${flatten.maven.plugin.version} + + + org.sonarsource.scanner.maven + sonar-maven-plugin + ${sonar.maven.plugin.version} + + + org.sonarsource.scanner.maven + sonar-maven-plugin + + + org.apache.maven.plugins + maven-enforcer-plugin + + + enforce-maven-and-java + + enforce + + + + + 3.8 + + + [11,12) + + + + + + org.sonarsource.sonar-packaging-maven-plugin sonar-packaging-maven-plugin @@ -237,6 +302,7 @@ ${buildNumber} ${timestamp} + java @@ -245,9 +311,9 @@ org.apache.maven.plugins maven-surefire-plugin - ${maven.surefire.plugin.version} random + none @@ -272,11 +338,11 @@ org.sonatype.plugins nexus-staging-maven-plugin - 1.6.13 true sonatype-nexus https://oss.sonatype.org/ + false false @@ -309,6 +375,7 @@ true 8 false + all,-missing @@ -319,6 +386,31 @@ + + org.codehaus.mojo + flatten-maven-plugin + + oss + + + + + flatten + process-resources + + flatten + + + + + flatten.clean + clean + + clean + + + + @@ -330,7 +422,6 @@ org.apache.maven.plugins maven-gpg-plugin - ${maven.gpg.plugin.version} sign-artifacts diff --git a/sonar-pmd-plugin/pom.xml b/sonar-pmd-plugin/pom.xml index de2268ff..aecb88da 100644 --- a/sonar-pmd-plugin/pom.xml +++ b/sonar-pmd-plugin/pom.xml @@ -5,7 +5,7 @@ org.sonarsource.pmd sonar-pmd - 3.4.1-SNAPSHOT + ${revision} sonar-pmd7-plugin @@ -49,12 +49,14 @@ - org.sonarsource.sonarqube + org.sonarsource.api.plugin sonar-plugin-api + provided org.sonarsource.sonarqube sonar-plugin-api-impl + test org.codehaus.staxmate @@ -121,22 +123,16 @@ ${pmd.version} - jdom - jdom - ${jdom.version} + org.jdom + jdom2 + ${jdom2.version} - - - org.sonarsource.scanner.maven - sonar-maven-plugin - ${sonar.maven.plugin.version} - org.jacoco jacoco-maven-plugin @@ -170,7 +166,6 @@ org.apache.maven.plugins maven-surefire-plugin - ${maven.surefire.plugin.version} ${surefireArgLine} @@ -189,7 +184,6 @@ org.apache.maven.plugins maven-enforcer-plugin - ${maven.enforcer.plugin.version} enforce-plugin-size diff --git a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdConfiguration.java b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdConfiguration.java index a8460dc2..757d1bf0 100644 --- a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdConfiguration.java +++ b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdConfiguration.java @@ -19,9 +19,9 @@ */ package org.sonar.plugins.pmd; -import net.sourceforge.pmd.Report; import net.sourceforge.pmd.renderers.Renderer; import net.sourceforge.pmd.renderers.XMLRenderer; +import net.sourceforge.pmd.reporting.Report; import org.sonar.api.batch.ScannerSide; import org.sonar.api.batch.fs.FileSystem; import org.sonar.api.config.Configuration; diff --git a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdConstants.java b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdConstants.java index 075e844e..40b79772 100644 --- a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdConstants.java +++ b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdConstants.java @@ -31,7 +31,7 @@ public final class PmdConstants { public static final String REPOSITORY_KOTLIN_NAME = "PMD Kotlin"; public static final String TEST_JAVA_REPOSITORY_KEY = "pmd7-unit-tests"; public static final String TEST_REPOSITORY_NAME = "PMD7 Unit Tests"; - public static final String XPATH_CLASS = "net.sourceforge.pmd.lang.rule.XPathRule"; + public static final String XPATH_CLASS = "net.sourceforge.pmd.lang.rule.xpath.XPathRule"; public static final String XPATH_EXPRESSION_PARAM = "xpath"; public static final String XPATH_MESSAGE_PARAM = "message"; @@ -43,8 +43,17 @@ public final class PmdConstants { /** * Default value for property {@link #JAVA_SOURCE_VERSION}. */ - public static final String JAVA_SOURCE_VERSION_DEFAULT_VALUE = "1.6"; + public static final String JAVA_SOURCE_VERSION_DEFAULT_VALUE = "11"; + /** + * Maximum supported value for property {@link #JAVA_SOURCE_VERSION}. For PMD 6 this is 20-preview. + */ + public static final String JAVA_SOURCE_MAXIMUM_SUPPORTED_VALUE = "20-preview"; + + /** + * Minimum UNsupported value for property {@link #JAVA_SOURCE_VERSION}. For PMD 6 this is 21. + */ + public static final String JAVA_SOURCE_MINIMUM_UNSUPPORTED_VALUE = "21"; /** * The Java Language key. */ diff --git a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdExecutor.java b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdExecutor.java index 487237b8..fc7017e5 100644 --- a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdExecutor.java +++ b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdExecutor.java @@ -19,7 +19,12 @@ */ package org.sonar.plugins.pmd; -import net.sourceforge.pmd.*; +import net.sourceforge.pmd.PMDVersion; +import net.sourceforge.pmd.lang.rule.RuleSet; +import net.sourceforge.pmd.lang.rule.RuleSetLoadException; +import net.sourceforge.pmd.lang.rule.RuleSetLoader; +import net.sourceforge.pmd.reporting.FileAnalysisListener; +import net.sourceforge.pmd.reporting.Report; import org.sonar.api.batch.ScannerSide; import org.sonar.api.batch.fs.FilePredicates; import org.sonar.api.batch.fs.FileSystem; @@ -44,6 +49,7 @@ import java.util.Collection; import java.util.List; import java.util.Optional; +import java.util.function.Consumer; @ScannerSide public class PmdExecutor { @@ -65,6 +71,10 @@ public PmdExecutor(FileSystem fileSystem, ActiveRules rulesProfile, this.settings = settings; } + private static void accept(FileAnalysisListener fal) { + LOGGER.debug("Got FileAnalysisListener: {}", fal); + } + public Report execute() { final Profiler profiler = Profiler.create(LOGGER).startInfo("Execute PMD " + PMDVersion.VERSION); final ClassLoader initialClassLoader = Thread.currentThread().getContextClassLoader(); @@ -96,14 +106,16 @@ private Report executePmd(URLClassLoader classLoader) { kotlinReport.ifPresent(this::writeDebugLine); } - final Report report = new Report(); - mainReport.ifPresent(report::merge); - testReport.ifPresent(report::merge); - kotlinReport.ifPresent(report::merge); + Consumer fileAnalysisListenerConsumer = PmdExecutor::accept; + + Report unionReport = Report.buildReport(fileAnalysisListenerConsumer); + unionReport = mainReport.map(unionReport::union).orElse(unionReport); + unionReport = testReport.map(unionReport::union).orElse(unionReport); + unionReport = kotlinReport.map(unionReport::union).orElse(unionReport); - pmdConfiguration.dumpXmlReport(report); + pmdConfiguration.dumpXmlReport(unionReport); - return report; + return unionReport; } private void writeDebugLine(Report r) { @@ -193,8 +205,17 @@ private URLClassLoader createClassloader() { } private String getSourceVersion() { - return settings.get(PmdConstants.JAVA_SOURCE_VERSION) - .orElse(PmdConstants.JAVA_SOURCE_VERSION_DEFAULT_VALUE); + String reqJavaVersion = settings.get(PmdConstants.JAVA_SOURCE_VERSION).orElse(PmdConstants.JAVA_SOURCE_VERSION_DEFAULT_VALUE); + String bareReqJavaVersion = reqJavaVersion; + if (reqJavaVersion.endsWith("-preview")) { + bareReqJavaVersion = reqJavaVersion.substring(0, reqJavaVersion.indexOf("-preview")); + } + String effectiveJavaVersion = bareReqJavaVersion; + if (Float.parseFloat(bareReqJavaVersion) >= Float.parseFloat(PmdConstants.JAVA_SOURCE_MINIMUM_UNSUPPORTED_VALUE)) { + effectiveJavaVersion = PmdConstants.JAVA_SOURCE_MAXIMUM_SUPPORTED_VALUE; + LOGGER.warn("Requested Java version " + reqJavaVersion + " ('" + PmdConstants.JAVA_SOURCE_VERSION + "') is not supported by PMD. Using maximum supported version: " + PmdConstants.JAVA_SOURCE_MAXIMUM_SUPPORTED_VALUE + "."); + } + return effectiveJavaVersion; } } diff --git a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdPriorities.java b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdPriorities.java new file mode 100644 index 00000000..3005cdb3 --- /dev/null +++ b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdPriorities.java @@ -0,0 +1,67 @@ +/* + * SonarQube PMD Plugin + * Copyright (C) 2012-2021 SonarSource SA and others + * mailto:jborgers AT jpinpoint DOT com; peter.paul.bakker AT stokpop DOT nl + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.pmd; + +import java.util.Locale; +import java.util.Objects; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import org.sonar.api.batch.rule.ActiveRule; +import org.sonar.api.rule.Severity; +import org.sonar.api.rules.RulePriority; +import org.sonar.plugins.pmd.xml.PmdRule; + +public final class PmdPriorities { + + private static final int NUM_SEVERITIES = Severity.ALL.size(); + private PmdPriorities() { + // only static methods + } + + public static org.sonar.api.rules.RulePriority sonarPrioOf(@Nonnull PmdRule pmdRule) { + return toSonarPrio(pmdRule.getPriority()); + } + + public static org.sonar.api.rules.RulePriority toSonarPrio(@Nullable Integer pmdPrioLevel) { + String severity = toSonarSeverity(pmdPrioLevel); + return (severity != null) ? RulePriority.valueOf(severity) : null; + } + + public static String toSonarSeverity(@Nullable Integer pmdPrioLevel) { + if (Objects.isNull(pmdPrioLevel)) { + return null; + } + final int index = Math.abs(NUM_SEVERITIES - pmdPrioLevel); + return (index < NUM_SEVERITIES) ? Severity.ALL.get(index) : null; + } + + public static Integer fromSonarPrio(org.sonar.api.rules.RulePriority priority) { + return Math.abs(priority.ordinal() - NUM_SEVERITIES); + } + + public static Integer fromSonarSeverity(@Nonnull String severity) { + return Math.abs(NUM_SEVERITIES - Severity.ALL.indexOf(severity)); + } + + public static Integer ofSonarRule(@Nonnull ActiveRule sonarRule) { + return fromSonarSeverity(sonarRule.severity().toUpperCase(Locale.ENGLISH)); + } +} diff --git a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdSensor.java b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdSensor.java index 5fa87811..9e1a8868 100644 --- a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdSensor.java +++ b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdSensor.java @@ -19,7 +19,7 @@ */ package org.sonar.plugins.pmd; -import net.sourceforge.pmd.RuleViolation; +import net.sourceforge.pmd.reporting.RuleViolation; import org.sonar.api.batch.fs.FilePredicates; import org.sonar.api.batch.fs.FileSystem; import org.sonar.api.batch.fs.InputFile.Type; diff --git a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdTemplate.java b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdTemplate.java index f66b5bf0..1f5d77ef 100644 --- a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdTemplate.java +++ b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdTemplate.java @@ -19,19 +19,18 @@ */ package org.sonar.plugins.pmd; -import net.sourceforge.pmd.PMD; -import net.sourceforge.pmd.PMDConfiguration; -import net.sourceforge.pmd.Report; -import net.sourceforge.pmd.RuleSet; +import net.sourceforge.pmd.*; import net.sourceforge.pmd.lang.LanguageVersion; import net.sourceforge.pmd.lang.java.JavaLanguageModule; +import net.sourceforge.pmd.lang.rule.RuleSet; import net.sourceforge.pmd.renderers.EmptyRenderer; -import net.sourceforge.pmd.util.datasource.DataSource; +import net.sourceforge.pmd.reporting.Report; import org.sonar.api.batch.fs.InputFile; import org.sonar.api.utils.log.Logger; import org.sonar.api.utils.log.Loggers; import java.nio.charset.Charset; +import java.nio.file.Paths; import java.util.*; public class PmdTemplate { @@ -41,9 +40,6 @@ public class PmdTemplate { private static Map prepareVersions() { final Map versions = new HashMap<>(); - versions.put("1.1", "1.3"); - versions.put("1.2", "1.3"); - versions.put("5", "1.5"); versions.put("6", "1.6"); versions.put("7", "1.7"); versions.put("8", "1.8"); @@ -57,7 +53,10 @@ private static Map prepareVersions() { versions.put("1.16", "16"); versions.put("1.17", "17"); versions.put("1.18", "18"); - + versions.put("1.19", "19"); + versions.put("1.19-preview", "19-preview"); + versions.put("1.20", "20"); + versions.put("1.20-preview", "20-preview"); return versions; } @@ -71,7 +70,7 @@ public static PmdTemplate create(String javaVersion, ClassLoader classloader, Ch PMDConfiguration configuration = new PMDConfiguration(); configuration.setDefaultLanguageVersion(languageVersion(javaVersion)); configuration.setClassLoader(classloader); - configuration.setSourceEncoding(charset.name()); + configuration.setSourceEncoding(charset); configuration.setFailOnViolation(false); configuration.setIgnoreIncrementalAnalysis(true); configuration.setReportFormat(EmptyRenderer.NAME); @@ -97,26 +96,13 @@ PMDConfiguration configuration() { return configuration; } - private Collection toDataSources(Iterable files) { - final Collection dataSources = new ArrayList<>(); - - files.forEach(file -> dataSources.add(new ProjectDataSource(file))); - - return dataSources; - } - public Report process(Iterable files, RuleSet ruleset) { - try { - return PMD.processFiles( - configuration, - Collections.singletonList(ruleset), - toDataSources(files), - Collections.emptyList() - ); - } - catch (Exception e) { - LOG.info("ERROR processing files: " + e.getClass().getSimpleName() + "-" + e.getMessage()); - throw new RuntimeException(e); + try (PmdAnalysis pmd = PmdAnalysis.create(configuration)) { + pmd.addRuleSet(ruleset); + for (InputFile file: files) { + pmd.files().addFile(Paths.get(file.uri())); + } + return pmd.performAnalysisAndCollectReport(); } } } diff --git a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdViolationRecorder.java b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdViolationRecorder.java index 514bada7..30d4eff3 100644 --- a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdViolationRecorder.java +++ b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdViolationRecorder.java @@ -19,7 +19,7 @@ */ package org.sonar.plugins.pmd; -import net.sourceforge.pmd.RuleViolation; +import net.sourceforge.pmd.reporting.RuleViolation; import org.sonar.api.batch.ScannerSide; import org.sonar.api.batch.fs.FileSystem; import org.sonar.api.batch.fs.InputFile; @@ -93,7 +93,7 @@ public void saveViolation(RuleViolation pmdViolation, SensorContext context) { private InputFile findResourceFor(RuleViolation violation) { return fs.inputFile( fs.predicates().hasAbsolutePath( - violation.getFilename() + violation.getFileId().getAbsolutePath() ) ); } diff --git a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/ProjectDataSource.java b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/ProjectDataSource.java index 35c48e49..c94e9a51 100644 --- a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/ProjectDataSource.java +++ b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/ProjectDataSource.java @@ -19,31 +19,53 @@ */ package org.sonar.plugins.pmd; -import net.sourceforge.pmd.util.datasource.DataSource; +import net.sourceforge.pmd.lang.LanguageVersion; +import net.sourceforge.pmd.lang.document.FileId; +import net.sourceforge.pmd.lang.document.TextFile; +import net.sourceforge.pmd.lang.document.TextFileContent; +import org.checkerframework.checker.nullness.qual.NonNull; import org.sonar.api.batch.fs.InputFile; import java.io.IOException; -import java.io.InputStream; -import java.nio.file.Paths; -public class ProjectDataSource implements DataSource { +public class ProjectDataSource implements TextFile { - private final InputFile inputFile; + private final TextFileContent textFileContent; public ProjectDataSource(InputFile inputFile) { - this.inputFile = inputFile; + try { + this.textFileContent = + TextFileContent.fromInputStream(inputFile.inputStream(), inputFile.charset()); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + +// @Override +// public InputStream getInputStream() throws IOException { +// return inputFile.inputStream(); +// } +// +// @Override +// public String getNiceFileName(boolean shortNames, String inputFileName) { +// return Paths.get(inputFile.uri()) +// .toAbsolutePath() +// .toString(); +// } + + @Override + public @NonNull LanguageVersion getLanguageVersion() { + return null; } @Override - public InputStream getInputStream() throws IOException { - return inputFile.inputStream(); + public FileId getFileId() { + return null; } @Override - public String getNiceFileName(boolean shortNames, String inputFileName) { - return Paths.get(inputFile.uri()) - .toAbsolutePath() - .toString(); + public TextFileContent readContents() throws IOException { + return textFileContent; } @Override diff --git a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/TextRangeCalculator.java b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/TextRangeCalculator.java index e376bdea..570c1910 100644 --- a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/TextRangeCalculator.java +++ b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/TextRangeCalculator.java @@ -19,13 +19,13 @@ */ package org.sonar.plugins.pmd; -import net.sourceforge.pmd.RuleViolation; +import net.sourceforge.pmd.reporting.RuleViolation; import org.sonar.api.batch.fs.InputFile; import org.sonar.api.batch.fs.TextPointer; import org.sonar.api.batch.fs.TextRange; /** - * Calculates a {@link org.sonar.api.batch.fs.TextRange} for a given {@link net.sourceforge.pmd.RuleViolation}. + * Calculates a {@link org.sonar.api.batch.fs.TextRange} for a given {@link net.sourceforge.pmd.reporting.RuleViolation}. */ class TextRangeCalculator { diff --git a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/profile/PmdProfileImporter.java b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/profile/PmdProfileImporter.java index 532d0556..b8ca1e82 100644 --- a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/profile/PmdProfileImporter.java +++ b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/profile/PmdProfileImporter.java @@ -27,7 +27,7 @@ import org.sonar.api.rules.RuleQuery; import org.sonar.api.utils.ValidationMessages; import org.sonar.plugins.pmd.PmdConstants; -import org.sonar.plugins.pmd.PmdLevelUtils; +import org.sonar.plugins.pmd.PmdPriorities; import org.sonar.plugins.pmd.xml.PmdProperty; import org.sonar.plugins.pmd.xml.PmdRule; import org.sonar.plugins.pmd.xml.PmdRuleSet; @@ -72,7 +72,7 @@ public RulesProfile importProfile(Reader pmdConfigurationFile, ValidationMessage } else { Rule rule = ruleFinder.find(RuleQuery.create().withRepositoryKey(PmdConstants.MAIN_JAVA_REPOSITORY_KEY).withConfigKey(ruleRef)); if (rule != null) { - ActiveRule activeRule = profile.activateRule(rule, PmdLevelUtils.fromLevel(pmdRule.getPriority())); + ActiveRule activeRule = profile.activateRule(rule, PmdPriorities.sonarPrioOf(pmdRule)); setParameters(activeRule, pmdRule, rule, messages); } else { messages.addWarningText("Unable to import unknown PMD rule '" + ruleRef + "'"); diff --git a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/PmdRuleSet.java b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/PmdRuleSet.java index dd77ece6..4ee078cc 100644 --- a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/PmdRuleSet.java +++ b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/PmdRuleSet.java @@ -27,11 +27,11 @@ import javax.annotation.Nullable; import org.apache.commons.lang3.StringUtils; -import org.jdom.CDATA; -import org.jdom.Document; -import org.jdom.Element; -import org.jdom.output.Format; -import org.jdom.output.XMLOutputter; +import org.jdom2.CDATA; +import org.jdom2.Document; +import org.jdom2.Element; +import org.jdom2.output.Format; +import org.jdom2.output.XMLOutputter; public class PmdRuleSet { diff --git a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/factory/ActiveRulesRuleSetFactory.java b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/factory/ActiveRulesRuleSetFactory.java index d6c7299f..95abeeef 100644 --- a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/factory/ActiveRulesRuleSetFactory.java +++ b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/factory/ActiveRulesRuleSetFactory.java @@ -19,15 +19,11 @@ */ package org.sonar.plugins.pmd.xml.factory; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; +import java.util.*; import org.sonar.api.batch.rule.ActiveRule; import org.sonar.api.batch.rule.ActiveRules; -import org.sonar.api.rules.RulePriority; -import org.sonar.plugins.pmd.PmdLevelUtils; +import org.sonar.plugins.pmd.PmdPriorities; import org.sonar.plugins.pmd.xml.PmdProperty; import org.sonar.plugins.pmd.xml.PmdRule; import org.sonar.plugins.pmd.xml.PmdRuleSet; @@ -54,11 +50,11 @@ public PmdRuleSet create() { ruleset.setDescription(String.format("Sonar Profile: %s", repositoryKey)); for (ActiveRule rule : rules) { String configKey = rule.internalKey(); - PmdRule pmdRule = new PmdRule(configKey, PmdLevelUtils.toLevel(RulePriority.valueOfString(rule.severity()))); + PmdRule pmdRule = new PmdRule(configKey, PmdPriorities.ofSonarRule(rule)); addRuleProperties(rule, pmdRule); ruleset.addRule(pmdRule); - pmdRule.processXpath(rule.internalKey()); + pmdRule.processXpath(rule.ruleKey().rule()); } return ruleset; } diff --git a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/factory/RulesProfileRuleSetFactory.java b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/factory/RulesProfileRuleSetFactory.java index ff82af8b..221bf6a4 100644 --- a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/factory/RulesProfileRuleSetFactory.java +++ b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/factory/RulesProfileRuleSetFactory.java @@ -25,7 +25,7 @@ import org.sonar.api.profiles.RulesProfile; import org.sonar.api.rules.ActiveRule; import org.sonar.api.rules.ActiveRuleParam; -import org.sonar.plugins.pmd.PmdLevelUtils; +import org.sonar.plugins.pmd.PmdPriorities; import org.sonar.plugins.pmd.xml.PmdProperty; import org.sonar.plugins.pmd.xml.PmdRule; import org.sonar.plugins.pmd.xml.PmdRuleSet; @@ -55,7 +55,7 @@ public PmdRuleSet create() { for (ActiveRule activeRule : activeRules) { if (activeRule.getRule().getRepositoryKey().equals(repositoryKey)) { String configKey = activeRule.getRule().getConfigKey(); - PmdRule rule = new PmdRule(configKey, PmdLevelUtils.toLevel(activeRule.getSeverity())); + PmdRule rule = new PmdRule(configKey, PmdPriorities.fromSonarPrio(activeRule.getSeverity())); addRuleProperties(activeRule, rule); ruleset.addRule(rule); rule.processXpath(activeRule.getRuleKey()); diff --git a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/factory/XmlRuleSetFactory.java b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/factory/XmlRuleSetFactory.java index db2d4bb1..ea1081c3 100644 --- a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/factory/XmlRuleSetFactory.java +++ b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/factory/XmlRuleSetFactory.java @@ -19,11 +19,11 @@ */ package org.sonar.plugins.pmd.xml.factory; -import org.jdom.Document; -import org.jdom.Element; -import org.jdom.JDOMException; -import org.jdom.Namespace; -import org.jdom.input.SAXBuilder; +import org.jdom2.Document; +import org.jdom2.Element; +import org.jdom2.JDOMException; +import org.jdom2.Namespace; +import org.jdom2.input.SAXBuilder; import org.sonar.api.utils.ValidationMessages; import org.sonar.api.utils.log.Logger; import org.sonar.api.utils.log.Loggers; @@ -32,6 +32,7 @@ import org.sonar.plugins.pmd.xml.PmdRuleSet; import javax.annotation.Nullable; +import javax.xml.XMLConstants; import java.io.IOException; import java.io.Reader; import java.util.List; @@ -52,7 +53,7 @@ public XmlRuleSetFactory(Reader source, ValidationMessages messages) { this.messages = messages; } - @SuppressWarnings("unchecked") + private List getChildren(Element parent, String childName, @Nullable Namespace namespace) { if (namespace == null) { return parent.getChildren(childName); @@ -98,10 +99,13 @@ public void close() throws IOException { */ @Override public PmdRuleSet create() { - final SAXBuilder parser = new SAXBuilder(); + final SAXBuilder builder = new SAXBuilder(); + // prevent XXE attacks + builder.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, ""); + builder.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, ""); final Document dom; try { - dom = parser.build(source); + dom = builder.build(source); } catch (JDOMException | IOException e) { if (messages != null) { messages.addErrorText(INVALID_INPUT + " : " + e.getMessage()); diff --git a/sonar-pmd-plugin/src/main/resources/com/sonar/sqale/pmd-model.xml b/sonar-pmd-plugin/src/main/resources/com/sonar/sqale/pmd-model.xml index f0e6358a..546953ba 100644 --- a/sonar-pmd-plugin/src/main/resources/com/sonar/sqale/pmd-model.xml +++ b/sonar-pmd-plugin/src/main/resources/com/sonar/sqale/pmd-model.xml @@ -1219,19 +1219,19 @@ min - - pmd7 - EmptyInitializer - - remediationFunction - CONSTANT_ISSUE - - - offset - 20 - min - - + + + + + + + + + + + + + pmd7 AvoidUsingVolatile diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/plugins/pmd/rules.xml b/sonar-pmd-plugin/src/main/resources/org/sonar/plugins/pmd/rules.xml index 585010f8..bcb1064c 100644 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/plugins/pmd/rules.xml +++ b/sonar-pmd-plugin/src/main/resources/org/sonar/plugins/pmd/rules.xml @@ -6,10 +6,10 @@ DEPRECATED - - MAJOR - category/java/bestpractices.xml/GuardLogStatement - + + + + MAJOR @@ -66,11 +66,11 @@ category/java/errorprone.xml/CallSuperLast - - MAJOR - category/java/errorprone.xml/EmptyInitializer - DEPRECATED - + + + + + MAJOR @@ -114,14 +114,15 @@ - - MINOR - category/java/performance.xml/TooFewBranchesForASwitchStatement - - 3 - - DEPRECATED - + + + + + + + + + MAJOR @@ -168,17 +169,19 @@ DEPRECATED - - MAJOR - category/java/bestpractices.xml/SwitchStmtsShouldHaveDefault - DEPRECATED - + + + + + + - - MAJOR - category/java/bestpractices.xml/DefaultLabelNotLastInSwitchStmt - DEPRECATED - + + + + + + MAJOR @@ -339,10 +342,10 @@ DEPRECATED - - INFO - category/java/codestyle.xml/UnnecessaryModifier - + + + + MAJOR @@ -475,36 +478,36 @@ DEPRECATED - - CRITICAL - category/java/errorprone.xml/EmptyIfStmt - DEPRECATED - + + + + + - - CRITICAL - category/java/errorprone.xml/EmptyWhileStmt - DEPRECATED - + + + + + - - MAJOR - category/java/errorprone.xml/EmptyTryBlock - DEPRECATED - + + + + + - - CRITICAL - error-handling - category/java/errorprone.xml/EmptyFinallyBlock - DEPRECATED - + + + + + + - - MAJOR - category/java/errorprone.xml/EmptySwitchStatements - DEPRECATED - + + + + + MAJOR @@ -530,22 +533,22 @@ DEPRECATED - - CRITICAL - category/java/errorprone.xml/EmptySynchronizedBlock - DEPRECATED - + + + + + MINOR category/java/codestyle.xml/UnnecessaryReturn - - MAJOR - category/java/errorprone.xml/EmptyInitializer - DEPRECATED - + + + + + CRITICAL @@ -553,21 +556,21 @@ DEPRECATED - - MAJOR - category/java/errorprone.xml/EmptyStatementNotInLoop - DEPRECATED - + + + + + - - INFO - category/java/codestyle.xml/UnnecessaryModifier - + + + + MINOR @@ -700,11 +703,12 @@ DEPRECATED - - MAJOR - category/java/errorprone.xml/NonCaseLabelInSwitchStatement - DEPRECATED - + + + + + + MAJOR @@ -942,13 +946,13 @@ DEPRECATED - - MAJOR - category/java/errorprone.xml/BeanMembersShouldSerialize - - - - + + + + + + + MAJOR @@ -956,11 +960,11 @@ DEPRECATED - - MAJOR - category/java/errorprone.xml/CloneMethodMustImplementCloneable - DEPRECATED - + + + + + MAJOR @@ -1044,15 +1048,15 @@ DEPRECATED - - MAJOR - size - category/java/design.xml/ExcessiveMethodLength - - 100 - - DEPRECATED - + + + + + + + + + MAJOR @@ -1064,15 +1068,15 @@ DEPRECATED - - MAJOR - size - category/java/design.xml/ExcessiveClassLength - - 1000 - - DEPRECATED - + + + + + + + + + MAJOR @@ -1359,9 +1363,9 @@ MAJOR category/java/bestpractices.xml/AvoidUsingHardCodedIP - - IPv4|IPv6|IPv4 mapped IPv6 - + + + DEPRECATED @@ -1591,21 +1595,21 @@ category/java/bestpractices.xml/UseVarargs - - MAJOR - category/java/errorprone.xml/EmptyStatementBlock - DEPRECATED - + + + + + MAJOR category/java/codestyle.xml/UnnecessaryFullyQualifiedName - - MAJOR - category/java/bestpractices.xml/GuardLogStatement - + + + + MAJOR @@ -1704,7 +1708,7 @@ MAJOR - net.sourceforge.pmd.lang.rule.XPathRule + net.sourceforge.pmd.lang.rule.xpath.XPathRule MULTIPLE diff --git a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdConfigurationTest.java b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdConfigurationTest.java index deeaefb6..a386049d 100644 --- a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdConfigurationTest.java +++ b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdConfigurationTest.java @@ -19,7 +19,7 @@ */ package org.sonar.plugins.pmd; -import net.sourceforge.pmd.Report; +import net.sourceforge.pmd.reporting.Report; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; @@ -40,7 +40,7 @@ class PmdConfigurationTest { - private static final Pattern PMD_XML_PATTERN = Pattern.compile("^<\\?xml version=\"1\\.0\" encoding=\"UTF-8\"\\?>$"); + private static final Pattern PMD_XML_PATTERN = Pattern.compile("^<\\?xml version=\"1\\.0\" encoding=\"UTF-8\"\\?>$"); private static final File WORK_DIR = new File("test-work-dir"); private final FileSystem fs = mock(FileSystem.class); @@ -97,7 +97,7 @@ void should_dump_xml_report() throws IOException { when(fs.workDir()).thenReturn(WORK_DIR); settings.setProperty(PmdConfiguration.PROPERTY_GENERATE_XML, true); - Path reportFile = configuration.dumpXmlReport(new Report()); + Path reportFile = configuration.dumpXmlReport(Report.buildReport(v -> {})); assertThat(reportFile.toFile()).isEqualTo(new File(WORK_DIR, "pmd-result.xml")); String pmdResultXML = String.join("", Files.readAllLines(reportFile, StandardCharsets.UTF_8)); @@ -112,7 +112,7 @@ void should_fail_to_dump_xml_report() { settings.setProperty(PmdConfiguration.PROPERTY_GENERATE_XML, true); - final Throwable thrown = catchThrowable(() -> configuration.dumpXmlReport(new Report())); + final Throwable thrown = catchThrowable(() -> configuration.dumpXmlReport(Report.buildReport(v -> {}))); assertThat(thrown) .isInstanceOf(IllegalStateException.class) @@ -121,7 +121,7 @@ void should_fail_to_dump_xml_report() { @Test void should_ignore_xml_report_when_property_is_not_set() { - Path reportFile = configuration.dumpXmlReport(new Report()); + Path reportFile = configuration.dumpXmlReport(Report.buildReport(v -> {})); assertThat(reportFile).isNull(); verifyNoMoreInteractions(fs); diff --git a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdConstantsTest.java b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdConstantsTest.java index 17e3d004..6e129fb2 100644 --- a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdConstantsTest.java +++ b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdConstantsTest.java @@ -33,11 +33,11 @@ void checkDefinedKeys() { assertThat(PmdConstants.REPOSITORY_NAME).isEqualTo("PMD7"); assertThat(PmdConstants.TEST_JAVA_REPOSITORY_KEY).isEqualTo("pmd7-unit-tests"); assertThat(PmdConstants.TEST_REPOSITORY_NAME).isEqualTo("PMD7 Unit Tests"); - assertThat(PmdConstants.XPATH_CLASS).isEqualTo("net.sourceforge.pmd.lang.rule.XPathRule"); + assertThat(PmdConstants.XPATH_CLASS).isEqualTo("net.sourceforge.pmd.lang.rule.xpath.XPathRule"); assertThat(PmdConstants.XPATH_EXPRESSION_PARAM).isEqualTo("xpath"); assertThat(PmdConstants.XPATH_MESSAGE_PARAM).isEqualTo("message"); assertThat(PmdConstants.JAVA_SOURCE_VERSION).isEqualTo("sonar.java.source"); - assertThat(PmdConstants.JAVA_SOURCE_VERSION_DEFAULT_VALUE).isEqualTo("1.6"); + assertThat(PmdConstants.JAVA_SOURCE_VERSION_DEFAULT_VALUE).isEqualTo("11"); assertThat(PmdConstants.LANGUAGE_JAVA_KEY).isEqualTo("java"); } } diff --git a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdExecutorTest.java b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdExecutorTest.java index 797bfe56..69305b98 100644 --- a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdExecutorTest.java +++ b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdExecutorTest.java @@ -19,10 +19,9 @@ */ package org.sonar.plugins.pmd; -import com.google.common.collect.ImmutableList; -import net.sourceforge.pmd.Report; -import net.sourceforge.pmd.RuleSet; -import net.sourceforge.pmd.RuleSetLoadException; +import net.sourceforge.pmd.lang.rule.RuleSet; +import net.sourceforge.pmd.lang.rule.RuleSetLoadException; +import net.sourceforge.pmd.reporting.Report; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; @@ -42,6 +41,7 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.List; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.catchThrowable; @@ -84,7 +84,7 @@ private static DefaultInputFile fileKotlin(String path, Type type) { void setUp() { pmdExecutor = Mockito.spy(realPmdExecutor); fileSystem.setEncoding(StandardCharsets.UTF_8); - settings.setProperty(PmdConstants.JAVA_SOURCE_VERSION, "1.7"); + settings.setProperty(PmdConstants.JAVA_SOURCE_VERSION, "1.8"); } @Test @@ -138,7 +138,7 @@ void should_ignore_empty_test_dir() { @Test void should_build_project_classloader_from_javaresourcelocator() throws Exception { File file = new File("x"); - when(javaResourceLocator.classpath()).thenReturn(ImmutableList.of(file)); + when(javaResourceLocator.classpath()).thenReturn(List.of(file)); pmdExecutor.execute(); ArgumentCaptor classLoaderArgument = ArgumentCaptor.forClass(URLClassLoader.class); verify(pmdExecutor).createPmdTemplate(classLoaderArgument.capture()); @@ -151,7 +151,7 @@ void should_build_project_classloader_from_javaresourcelocator() throws Exceptio void invalid_classpath_element() { File invalidFile = mock(File.class); when(invalidFile.toURI()).thenReturn(URI.create("x://xxx")); - when(javaResourceLocator.classpath()).thenReturn(ImmutableList.of(invalidFile)); + when(javaResourceLocator.classpath()).thenReturn(List.of(invalidFile)); final Throwable thrown = catchThrowable(() -> pmdExecutor.execute()); @@ -185,8 +185,8 @@ void should_execute_pmd_on_kotlin_source_files() { Report report = pmdExecutor.execute(); assertThat(report).isNotNull(); - assertThat(report.getViolations().size()).isEqualTo(1); - assertThat(report.getProcessingErrors().size()).isEqualTo(0); + assertThat(report.getViolations()).hasSize(1); + assertThat(report.getProcessingErrors()).isEmpty(); verify(pmdConfiguration).dumpXmlReport(report); } diff --git a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdLevelUtilsTest.java b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdLevelUtilsTest.java deleted file mode 100644 index 6e64d9b3..00000000 --- a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdLevelUtilsTest.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * SonarQube PMD7 Plugin - * Copyright (C) 2012-2021 SonarSource SA and others - * mailto:jborgers AT jpinpoint DOT com; peter.paul.bakker AT stokpop DOT nl - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.plugins.pmd; - -import org.junit.jupiter.api.Test; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.sonar.api.rules.RulePriority.BLOCKER; -import static org.sonar.api.rules.RulePriority.CRITICAL; -import static org.sonar.api.rules.RulePriority.INFO; -import static org.sonar.api.rules.RulePriority.MAJOR; -import static org.sonar.api.rules.RulePriority.MINOR; - -class PmdLevelUtilsTest { - @Test - void should_get_priority_from_level() { - assertThat(PmdLevelUtils.fromLevel(1)).isSameAs(BLOCKER); - assertThat(PmdLevelUtils.fromLevel(2)).isSameAs(CRITICAL); - assertThat(PmdLevelUtils.fromLevel(3)).isSameAs(MAJOR); - assertThat(PmdLevelUtils.fromLevel(4)).isSameAs(MINOR); - assertThat(PmdLevelUtils.fromLevel(5)).isSameAs(INFO); - assertThat(PmdLevelUtils.fromLevel(-1)).isNull(); - assertThat(PmdLevelUtils.fromLevel(null)).isNull(); - } - - @Test - void should_get_level_from_priority() { - assertThat(PmdLevelUtils.toLevel(BLOCKER)).isEqualTo(1); - assertThat(PmdLevelUtils.toLevel(CRITICAL)).isEqualTo(2); - assertThat(PmdLevelUtils.toLevel(MAJOR)).isEqualTo(3); - assertThat(PmdLevelUtils.toLevel(MINOR)).isEqualTo(4); - assertThat(PmdLevelUtils.toLevel(INFO)).isEqualTo(5); - } -} diff --git a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdPrioritiesTest.java b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdPrioritiesTest.java new file mode 100644 index 00000000..53c40c43 --- /dev/null +++ b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdPrioritiesTest.java @@ -0,0 +1,73 @@ +/* + * SonarQube PMD7 Plugin + * Copyright (C) 2012-2021 SonarSource SA and others + * mailto:jborgers AT jpinpoint DOT com; peter.paul.bakker AT stokpop DOT nl + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.pmd; + +import org.junit.jupiter.api.Test; +import org.sonar.api.rule.Severity; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.sonar.api.rules.RulePriority.BLOCKER; +import static org.sonar.api.rules.RulePriority.CRITICAL; +import static org.sonar.api.rules.RulePriority.INFO; +import static org.sonar.api.rules.RulePriority.MAJOR; +import static org.sonar.api.rules.RulePriority.MINOR; + +class PmdPrioritiesTest { + + @Test + void should_get_priority_from_level() { + assertThat(PmdPriorities.toSonarPrio(1)).isSameAs(BLOCKER); + assertThat(PmdPriorities.toSonarPrio(2)).isSameAs(CRITICAL); + assertThat(PmdPriorities.toSonarPrio(3)).isSameAs(MAJOR); + assertThat(PmdPriorities.toSonarPrio(4)).isSameAs(MINOR); + assertThat(PmdPriorities.toSonarPrio(5)).isSameAs(INFO); + assertThat(PmdPriorities.toSonarPrio(-1)).isNull(); + assertThat(PmdPriorities.toSonarPrio(null)).isNull(); + } + + @Test + void should_get_priority_from_level_severity() { + assertThat(PmdPriorities.toSonarSeverity(1)).isSameAs(Severity.BLOCKER); + assertThat(PmdPriorities.toSonarSeverity(2)).isSameAs(Severity.CRITICAL); + assertThat(PmdPriorities.toSonarSeverity(3)).isSameAs(Severity.MAJOR); + assertThat(PmdPriorities.toSonarSeverity(4)).isSameAs(Severity.MINOR); + assertThat(PmdPriorities.toSonarSeverity(5)).isSameAs(Severity.INFO); + assertThat(PmdPriorities.toSonarSeverity(-1)).isNull(); + assertThat(PmdPriorities.toSonarSeverity(null)).isNull(); + } + + @Test + void should_get_level_from_priority() { + assertThat(PmdPriorities.fromSonarPrio(BLOCKER)).isEqualTo(1); + assertThat(PmdPriorities.fromSonarPrio(CRITICAL)).isEqualTo(2); + assertThat(PmdPriorities.fromSonarPrio(MAJOR)).isEqualTo(3); + assertThat(PmdPriorities.fromSonarPrio(MINOR)).isEqualTo(4); + assertThat(PmdPriorities.fromSonarPrio(INFO)).isEqualTo(5); + } + + @Test + void should_get_level_from_priority_severity() { + assertThat(PmdPriorities.fromSonarSeverity(Severity.BLOCKER)).isEqualTo(1); + assertThat(PmdPriorities.fromSonarSeverity(Severity.CRITICAL)).isEqualTo(2); + assertThat(PmdPriorities.fromSonarSeverity(Severity.MAJOR)).isEqualTo(3); + assertThat(PmdPriorities.fromSonarSeverity(Severity.MINOR)).isEqualTo(4); + assertThat(PmdPriorities.fromSonarSeverity(Severity.INFO)).isEqualTo(5); + } +} diff --git a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdRulesDefinitionTest.java b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdRulesDefinitionTest.java index 03abc01b..d1b74718 100644 --- a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdRulesDefinitionTest.java +++ b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdRulesDefinitionTest.java @@ -44,7 +44,8 @@ void test() { assertThat(repository.language()).isEqualTo(PmdConstants.LANGUAGE_JAVA_KEY); List rules = repository.rules(); - assertThat(rules).hasSize(228); + // PMD-7-MIGRATION: check number of rules is correct from PMD 7.x (was 228 in PMD 6.x) + assertThat(rules).hasSize(206); for (Rule rule : rules) { assertThat(rule.key()).isNotNull(); @@ -82,11 +83,6 @@ void should_use_text_parameter_for_xpath_rule() { RulesDefinition.Repository repository = context.repository(PmdConstants.MAIN_JAVA_REPOSITORY_KEY); List rules = repository.rules(); System.out.println("rules: " + rules); - try { - Thread.sleep(3000); - } catch (InterruptedException e) { - e.printStackTrace(); - } Rule xpathRule = Iterables.find(repository.rules(), rule -> rule.key().equals("XPathRule")); diff --git a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdSensorTest.java b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdSensorTest.java index b2ae466a..ff3d25a7 100644 --- a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdSensorTest.java +++ b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdSensorTest.java @@ -19,8 +19,9 @@ */ package org.sonar.plugins.pmd; -import net.sourceforge.pmd.Report; -import net.sourceforge.pmd.RuleViolation; +import net.sourceforge.pmd.reporting.FileAnalysisListener; +import net.sourceforge.pmd.reporting.Report; +import net.sourceforge.pmd.reporting.RuleViolation; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.sonar.api.batch.fs.InputFile.Type; @@ -31,7 +32,7 @@ import org.sonar.api.batch.sensor.SensorDescriptor; import java.io.File; -import java.util.Arrays; +import java.util.function.Consumer; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.catchThrowable; @@ -196,9 +197,14 @@ private static RuleViolation violation() { } private void mockExecutorResult(RuleViolation... violations) { - final Report report = new Report(); - Arrays.stream(violations) - .forEach(report::addRuleViolation); + + Consumer fileAnalysisListenerConsumer = fal -> { + for (RuleViolation violation : violations) { + fal.onRuleViolation(violation); + } + }; + + final Report report = Report.buildReport(fileAnalysisListenerConsumer); when(executor.execute()) .thenReturn(report); diff --git a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdTemplateTest.java b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdTemplateTest.java index 464e4094..02bdebc1 100644 --- a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdTemplateTest.java +++ b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdTemplateTest.java @@ -19,7 +19,7 @@ */ package org.sonar.plugins.pmd; -import net.sourceforge.pmd.lang.LanguageVersionHandler; +import net.sourceforge.pmd.lang.Language; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; @@ -34,14 +34,14 @@ class PmdTemplateTest { @ParameterizedTest @ValueSource(strings = { - "1.2", "5", "6", "7", "8", "9", "1.9", "10", "1.10", "11", "1.11", "12", "13", "14", "15", "16", "17" + "6", "7", "8", "9", "1.9", "10", "1.10", "11", "1.11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23" }) void verifyCanHandleJavaLanguageVersion(String javaVersion) { - final LanguageVersionHandler languageVersionHandler = PmdTemplate + final Language language = PmdTemplate .languageVersion(javaVersion) - .getLanguageVersionHandler(); + .getLanguage(); - assertThat(languageVersionHandler).isNotNull(); + assertThat(language).isNotNull(); } @Test diff --git a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdViolationRecorderTest.java b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdViolationRecorderTest.java index 74d25230..8341d271 100644 --- a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdViolationRecorderTest.java +++ b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdViolationRecorderTest.java @@ -19,8 +19,9 @@ */ package org.sonar.plugins.pmd; -import net.sourceforge.pmd.Rule; -import net.sourceforge.pmd.RuleViolation; +import net.sourceforge.pmd.lang.document.FileId; +import net.sourceforge.pmd.lang.rule.Rule; +import net.sourceforge.pmd.reporting.RuleViolation; import org.junit.jupiter.api.Test; import org.sonar.api.batch.fs.FilePredicate; import org.sonar.api.batch.fs.TextRange; @@ -133,7 +134,7 @@ private RuleViolation createPmdViolation(File file, String ruleName) { final RuleViolation pmdViolation = mock(RuleViolation.class); when(rule.getName()).thenReturn(ruleName); - when(pmdViolation.getFilename()).thenReturn(file.getAbsolutePath()); + when(pmdViolation.getFileId()).thenReturn(FileId.fromPath(file.toPath())); when(pmdViolation.getBeginLine()).thenReturn(2); when(pmdViolation.getDescription()).thenReturn("Description"); when(pmdViolation.getRule()).thenReturn(rule); diff --git a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/TextRangeCalculatorTest.java b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/TextRangeCalculatorTest.java index b64d24a3..c4b2ea15 100644 --- a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/TextRangeCalculatorTest.java +++ b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/TextRangeCalculatorTest.java @@ -19,7 +19,7 @@ */ package org.sonar.plugins.pmd; -import net.sourceforge.pmd.RuleViolation; +import net.sourceforge.pmd.reporting.RuleViolation; import org.junit.jupiter.api.Test; import org.sonar.api.batch.fs.InputFile; import org.sonar.api.batch.fs.TextRange; diff --git a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/profile/PmdProfileImporterTest.java b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/profile/PmdProfileImporterTest.java index d39938f0..4025bbe8 100644 --- a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/profile/PmdProfileImporterTest.java +++ b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/profile/PmdProfileImporterTest.java @@ -55,8 +55,8 @@ private static RuleFinder createRuleFinder() { String configKey = query.getConfigKey(); String key = configKey.substring(configKey.lastIndexOf('/') + 1); Rule rule = Rule.create(query.getRepositoryKey(), key, "").setConfigKey(configKey).setSeverity(RulePriority.BLOCKER); - if (rule.getConfigKey().equals("rulesets/java/coupling.xml/ExcessiveImports")) { - rule.createParameter("minimum"); + if (rule.getConfigKey().equals("category/java/bestpractices.xml/ForLoopVariableCount")) { + rule.createParameter("maximumVariables"); } return rule; }); @@ -76,8 +76,8 @@ void should_import_simple_profile() { RulesProfile profile = importer.importProfile(reader, messages); assertThat(profile.getActiveRules()).hasSize(3); - assertThat(profile.getActiveRuleByConfigKey("pmd7", "rulesets/java/coupling.xml/ExcessiveImports")).isNotNull(); - assertThat(profile.getActiveRuleByConfigKey("pmd7", "rulesets/java/design.xml/UseNotifyAllInsteadOfNotify")).isNotNull(); + assertThat(profile.getActiveRuleByConfigKey("pmd7", "category/java/errorprone.xml/AvoidLiteralsInIfCondition")).isNotNull(); + assertThat(profile.getActiveRuleByConfigKey("pmd7", "category/java/multithreading.xml/DoubleCheckedLocking")).isNotNull(); assertThat(messages.hasErrors()).isFalse(); } @@ -96,9 +96,9 @@ void should_import_parameter() { Reader reader = read("/org/sonar/plugins/pmd/simple.xml"); RulesProfile profile = importer.importProfile(reader, messages); - ActiveRule activeRule = profile.getActiveRuleByConfigKey("pmd7", "rulesets/java/coupling.xml/ExcessiveImports"); + ActiveRule activeRule = profile.getActiveRuleByConfigKey("pmd7", "category/java/bestpractices.xml/ForLoopVariableCount"); - assertThat(activeRule.getParameter("minimum")).isEqualTo("30"); + assertThat(activeRule.getParameter("maximumVariables")).isEqualTo("5"); } @Test @@ -106,7 +106,7 @@ void should_import_default_priority() { Reader reader = read("/org/sonar/plugins/pmd/simple.xml"); RulesProfile profile = importer.importProfile(reader, messages); - ActiveRule activeRule = profile.getActiveRuleByConfigKey("pmd7", "rulesets/java/coupling.xml/ExcessiveImports"); + ActiveRule activeRule = profile.getActiveRuleByConfigKey("pmd7", "category/java/multithreading.xml/DoubleCheckedLocking"); assertThat(activeRule.getSeverity()).isSameAs(RulePriority.BLOCKER); } @@ -117,11 +117,11 @@ void should_import_priority() { RulesProfile profile = importer.importProfile(reader, messages); - ActiveRule activeRule = profile.getActiveRuleByConfigKey("pmd7", "rulesets/java/design.xml/UseNotifyAllInsteadOfNotify"); - assertThat(activeRule.getSeverity()).isSameAs(RulePriority.MINOR); - - activeRule = profile.getActiveRuleByConfigKey("pmd7", "rulesets/java/coupling.xml/CouplingBetweenObjects"); + ActiveRule activeRule = profile.getActiveRuleByConfigKey("pmd7", "category/java/errorprone.xml/AvoidLiteralsInIfCondition"); assertThat(activeRule.getSeverity()).isSameAs(RulePriority.CRITICAL); + + activeRule = profile.getActiveRuleByConfigKey("pmd7", "category/java/bestpractices.xml/ForLoopVariableCount"); + assertThat(activeRule.getSeverity()).isSameAs(RulePriority.MINOR); } @Test @@ -138,8 +138,10 @@ void should_deal_with_unsupported_property() { Reader reader = read("/org/sonar/plugins/pmd/simple.xml"); RulesProfile profile = importer.importProfile(reader, messages); - ActiveRule check = profile.getActiveRuleByConfigKey("pmd7", "rulesets/java/coupling.xml/CouplingBetweenObjects"); + ActiveRule check = profile.getActiveRuleByConfigKey("pmd7", "category/java/bestpractices.xml/ForLoopVariableCount"); + // PMD7-MIGRATION what is meaning of this check? The list of parameters is empty (but expected maximumVariables?) + // in the errors: The property 'maximumVariables' is not supported in the pmd rule: category/java/bestpractices.xml/ForLoopVariableCount assertThat(check.getParameter("threshold")).isNull(); assertThat(messages.getWarnings()).hasSize(2); } diff --git a/sonar-pmd-plugin/src/test/resources/org/sonar/plugins/pmd/export_xpath_rules.xml b/sonar-pmd-plugin/src/test/resources/org/sonar/plugins/pmd/export_xpath_rules.xml index 6c2424bd..d787fd8b 100644 --- a/sonar-pmd-plugin/src/test/resources/org/sonar/plugins/pmd/export_xpath_rules.xml +++ b/sonar-pmd-plugin/src/test/resources/org/sonar/plugins/pmd/export_xpath_rules.xml @@ -1,7 +1,7 @@ Sonar Profile: pmd7 - + 3 diff --git a/sonar-pmd-plugin/src/test/resources/org/sonar/plugins/pmd/simple.xml b/sonar-pmd-plugin/src/test/resources/org/sonar/plugins/pmd/simple.xml index 555dc5ff..5e72b60d 100644 --- a/sonar-pmd-plugin/src/test/resources/org/sonar/plugins/pmd/simple.xml +++ b/sonar-pmd-plugin/src/test/resources/org/sonar/plugins/pmd/simple.xml @@ -1,19 +1,19 @@ Sonar PMD rules - + 2 - + - - - - + - + 4 + + + 3 diff --git a/travis.sh b/travis.sh deleted file mode 100755 index 0ecf81f0..00000000 --- a/travis.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/bash - -set -eo pipefail - -case "$TEST" in - -ci) - mvn test sonar:sonar -DskipTestProjects=true - ;; - -plugin) - - # Unset environment settings defined by Travis that will collide with our integration tests - unset SONARQUBE_SCANNER_PARAMS SONAR_TOKEN SONAR_SCANNER_HOME - - # Run integration tests - mvn verify -Dtest.sonar.version=${SQ_VERSION} -Dtest.sonar.plugin.version.java=${SJ_VERSION} - ;; - -javadoc) - # Create JavaDocs to check for problems with JavaDoc generation - mvn javadoc:javadoc -DskipTests - ;; - -*) - echo "Unexpected TEST mode: $TEST" - exit 1 - ;; - -esac