Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

314 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Codacy Badge Build Status

Codacy PMD

This is the docker engine we use at Codacy to have pmd support. You can also create a docker to integrate the tool and language of your choice! Check the Docs section for more information.

Usage

Publish the docker

sbt 'set version in Docker := "dev"' 'set name := "pmd"' docker:publishLocal
Docker Image Versioning
Repository Branch Docker Image
master codacy-pmd
pmd-legacy codacy-pmdjava

Run the docker

docker run --user=docker --rm=true -v <PATH-TO-CODE>:/src -v <PATH-TO>/ruleset.xml:/src/ruleset.xml codacy/pmd:dev

Make sure all the volumes mounted have the right permissions for user docker

Generate Docs

  1. Update toolVersionKey in build.sbt

  2. Run the DocGenerator

sbt "runMain com.codacy.pmd.DocGenerator"

Docs

Tool Developer Guide

Tool Developer Guide - Using Scala

Test

We use the codacy-plugins-test to test our external tools integration. You can follow the instructions there to make sure your tool is working as expected.

Agent Playbook: Updating This Repository End-to-End

This section is written for an AI coding agent (or a human) tasked with updating this repo — most commonly bumping the wrapped PMD version, but also base image / sbt / CircleCI orb bumps. Follow it top to bottom; it tells you what to change, how to regenerate derived files, how to test locally, and how to interpret CI so you can iterate on failures without guessing.

1. What this repository is

This is a Codacy engine: a Scala (2.13, sbt build) wrapper around PMD, built on codacy-engine-scala-seed, packaged as a Docker image that Codacy's platform runs against a customer's source code. PMD itself is pulled in as a set of ordinary sbt/Maven library dependencies (pmd-core, pmd-java, pmd-apex, pmd-jsp, pmd-javascript, pmd-plsql, pmd-vm, pmd-xml, pmd-visualforce, plus a forced rhino version) — there is no separate git clone of the PMD repo at build time.

The docs/ directory (src/main/resources/docs/) is machine-consumed configuration, same family as other Codacy engines:

  • docs/patterns.json — the full list of PMD rules ("patterns"), their parameters/defaults, and which are enabled by default. Generated file, do not hand-edit.
  • docs/description/description.json + docs/description/*.md — human-readable titles/descriptions per pattern, used in the Codacy UI. Generated file, do not hand-edit.
  • docs/tests/* and docs/multiple-tests/* — fixtures used by codacy-plugins-test to validate the engine against real code samples.
  • docs/tool-description.md — short blurb about the tool, hand-maintained.

All the generated artifacts above come from DocGenerator (src/main/scala/com/codacy/pmd/DocGenerator.scala, run via sbt "runMain com.codacy.pmd.DocGenerator"). Unlike some sibling Codacy engines, it does not clone an external GitHub repo — it reads the ruleset XML files bundled as classpath resources inside the pmd-* jars that were just resolved for the new toolVersionKey, via ResourceHelper/Languages/RuleSets. It also regenerates src/main/scala/com.codacy/pmd/RuleSets.scala (marked AUTOGENERATED: DO NOT CHANGE HERE). This means an sbt dependency resolution (network access to Maven Central) is enough — no separate git clone or pandoc is needed here.

2. Files that encode versions — check all of these on every update

File What it controls What to check
build.sbttoolVersionKey The PMD version bundled and used to generate docs/patterns.json Bump to the target PMD release. Confirm all pmd-* artifacts (pmd-core, pmd-java, pmd-apex, pmd-jsp, pmd-javascript, pmd-plsql, pmd-vm, pmd-xml, pmd-visualforce) still publish that version on Maven Central — PMD has occasionally dropped/renamed a module between majors (e.g. pmd-vm had no PMD 7 release at the time of this repo's PMD-7 attempt and had to be commented out).
build.sbtorg.mozilla % rhino forced version Workaround for pmd/pmd#2081 Only touch if instructed or if the PMD bump reintroduces that bug; otherwise leave as-is.
build.sbtcodacy-engine-scala-seed dependency Codacy's engine SDK/base library Check Maven Central if asked to bump it; not tied to PMD bumps.
build.sbtdockerBaseImage JRE the packaged app runs on (currently amazoncorretto:11-alpine3.18) Only bump if the new PMD version raises its minimum JDK requirement (check PMD's release notes) or if asked explicitly.
build.sbtscalaVersion Scala compiler version Rarely tied to a PMD bump; bump only if asked or if the build fails to resolve.
project/build.properties sbt version Sometimes bumped alongside major tool bumps; check only if the build itself fails to load.
.circleci/config.ymlcodacy/base orb Shared CircleCI steps (checkout, versioning, sbt build, docker publish, tagging) Check the latest published version, or use git log -p .circleci/config.yml for prior bump history as a fallback reference.
.circleci/config.ymlcodacy/plugins-test orb Runs codacy-plugins-test in CI after the image is built Same as above.

Look at recent bump commits for the shape of a typical diff: git log --oneline --all | grep -iE "bump|update pmd", then git show <hash>. Routine PMD point-releases (e.g. commit feb32e8, "bump pmd to latest version 6.55.0") touch only build.sbt plus the regenerated docs/description/*.md, docs/description/description.json, and docs/patterns.json. Major PMD version bumps are riskier: commit 98efa78 ("Bump to PMD 7") also touched .circleci/config.yml (orb bumps), project/build.properties, dockerBaseImage, added/removed pmd-* module dependencies, and even touched a Java helper class (CodacyInMemoryRenderer.java) — and it was subsequently reverted in commit 8b17d55 ("Revert tool (#128)": "Revert PMD to version 7. Version 7 will be launched as a different tool") because of a real regression (duplicated violations on the same file/line). Treat a major-version PMD bump as substantially higher risk than a point-release bump, and be prepared for it to need dedicated engine-code changes, not just a version string change.

3. Step-by-step update procedure

  1. Bump the version(s) in build.sbt (toolVersionKey, and dockerBaseImage/scalaVersion/project/build.properties only if actually required) and .circleci/config.yml orbs, as scoped by the task.
  2. Regenerate the docs. Requires network access to resolve the new PMD jars from Maven Central (no separate git clone or pandoc needed):
    sbt "runMain com.codacy.pmd.DocGenerator"
    This rewrites docs/patterns.json, docs/description/description.json, docs/description/*.md, and src/main/scala/com.codacy/pmd/RuleSets.scala. Review the diff for new/removed/renamed rules and stale fixtures under docs/tests//docs/multiple-tests/. Watch the console output for Ruleset ... is missing from rulesets.properties warnings.
  3. Format and compile:
    sbt "scalafmt::test; test:scalafmt::test; sbt:scalafmt::test"
    sbt "set Docker / version := \"latest\"; Docker / publishLocal"
    (This is the same sequence CI's publish_docker_local job runs.)
  4. Run codacy-plugins-test locally before pushing. CI runs it with run_multiple_tests: true, meaning both the single-pattern/json tests (docs/tests/) and the multiple-tests suite (docs/multiple-tests/) — clone https://github.com/codacy/codacy-plugins-test and run the corresponding DockerTest commands against your local codacy-pmd:latest image.
  5. Iterate on failures, re-running only the relevant test command after each fix.
  6. Commit the version bump(s) together with the regenerated docs/ and RuleSets.scala files in one change.
  7. Push and open a PR. CI (CircleCI only — the GitHub Actions workflows in .github/workflows/ are unrelated Jira-ticket-sync automation, not build/test) runs codacy/checkout_and_version -> publish_docker_local (runs DocGenerator again + scalafmt + docker build) -> plugins_test -> codacy/publish_docker (master only) -> codacy/tag_version.
  8. Poll the PR's real CI checks until they all pass — local validation is NOT the finish line. After every push, run gh pr checks <pr-url> and keep re-polling (short sleep while any check is pending) until all checks finish. If a check fails, fetch its actual log (the CircleCI job log — don't guess), find the true root cause, fix it, push again (never --no-verify, never force-push), and re-poll. Repeat until every check is green. This repo has direct history of a version bump that looked fine in isolation but caused a real regression only caught downstream (the PMD 7 bump merged, then had to be reverted for producing duplicated violations) — treat any test or behavior change surfaced by CI as a real signal to investigate, not noise to suppress. Only stop iterating when every check passes, or you hit a genuine product/infra decision that needs a human — in which case explain it in the PR rather than guessing.

4. Common failure modes and fixes

Symptom Likely cause Fix
scalafmt::test fails in CI/locally Generated or hand-edited Scala/Java file not formatted Run sbt scalafmt then re-run the check command
sbt fails to resolve a pmd-* module for the new version Module renamed/removed/not yet released for that PMD line (seen with pmd-vm on the PMD 7 attempt) Check PMD's Maven Central listing for that release; comment out or adjust the dependency as needed, matching the shape of commit 98efa78
pattern/json DockerTest fails Rule renamed/removed/added upstream between PMD versions Re-run DocGenerator; confirm the change matches PMD's release notes
multiple DockerTest fails, especially around duplicate/overlapping violations Renderer/engine behavior regression on major PMD bumps (this is exactly what caused the PMD 7 revert) Do not just patch the fixture — verify the underlying violation output is actually correct before updating expectations
CI codacy/publish_docker/tag_version don't run on your branch Expected — gated to default branch (master) only Nothing to fix

5. Definition of done

  • Version bump(s) reflected in all files that encode them (build.sbt, .circleci/config.yml, and project/build.properties/dockerBaseImage if actually needed).
  • docs/patterns.json, docs/description/*, and RuleSets.scala regenerated via DocGenerator and committed, with fixture inconsistencies under docs/tests//docs/multiple-tests/ resolved.
  • Local scalafmt/compile/docker build commands pass.
  • codacy-plugins-test (single and multiple-tests) pass locally against the freshly built image.
  • After pushing and opening/updating the PR, every CI check on it is green. Poll gh pr checks <pr-url> and iterate on any failure (fetch the real CI log, fix, push, re-poll) until all pass — a passing local build is not sufficient, and this repo has a concrete precedent (the PMD 7 revert) of a merged bump turning out to be wrong in practice.

What is Codacy?

Codacy is an Automated Code Review Tool that monitors your technical debt, helps you improve your code quality, teaches best practices to your developers, and helps you save time in Code Reviews.

Among Codacy’s features:

  • Identify new Static Analysis issues
  • Commit and Pull Request Analysis with GitHub, BitBucket/Stash, GitLab (and also direct git repositories)
  • Auto-comments on Commits and Pull Requests
  • Integrations with Slack, HipChat, Jira, YouTrack
  • Track issues in Code Style, Security, Error Proneness, Performance, Unused Code and other categories

Codacy also helps keep track of Code Coverage, Code Duplication, and Code Complexity.

Codacy supports PHP, Python, Ruby, Java, JavaScript, and Scala, among others.

Free for Open Source

Codacy is free for Open Source projects.