I'm trying to do something that feels totally routine, but struggling mightily. I'm working on a plugin that sets up some basic build conventions to use in multiple projects at my company. One of the things that plugin does is apply gradle's pmd plugin. It then attempts to configure it. Up to now, I've been configuring it like this:
where pmd.xml lives in src/main/resources/com/mycompany/plugins/myplugin/pmd.xml. I'd love to hear whether there are better ways than this, but...at least it works.
I'd like to use separate config for pmdMain and pmdTest. I can remove the ruleSetConfig from the project.pmd block above and add this:
with a new pmd-test.xml in the same place as pmd-main.xml, and pmd-main.xml is simply pmd.xml renamed. So far so good.
Turns out though, that pmd-main.xml and pmd-test.xml share a bunch of rules. I'd love to not duplicate them, so I figure I'll put the common stuff in pmd-common.xml. Here's where I get stuck. I'd love to handle this within the pmd config files themselves (i.e. no change to the above), with something like:
but those make my GradleRunner tests fail like this:
Execution failed for task ':pmdMain'.
> Can't find resource 'com/locationlabs/plugins/leanjava/pmd-common.xml' for rule 'null'. Make sure the resource is a valid file or URL and is on the CLASSPATH. Here's the current classpath: /Users/david.byron/.gradle/wrapper/dists/gradle-3.3-bin/64bhckfm0iuu9gap9hg3r7ev2/gradle-3.3/lib/gradle-launcher-3.3.jar
If I ignore the GradleRunner failures use the plugin in another project, I get the same error. Here's the error and stack trace for posterity:
Caused by: net.sourceforge.pmd.RuleSetNotFoundException: Can't find resource 'com/mycompany/plugins/myplugin/pmd-common.xml' for rule 'null'. Make sure the resource is a valid file or URL and is on the CLASSPATH. Here's the current classpath: /Users/david.byron/.gradle/wrapper/dists/gradle-3.3-bin/64bhckfm0iuu9gap9hg3r7ev2/gradle-3.3/lib/gradle-launcher-3.3.jar
at net.sourceforge.pmd.RuleSetReferenceId.getInputStream(RuleSetReferenceId.java:404)
at net.sourceforge.pmd.RuleSetFactory.parseRuleSetNode(RuleSetFactory.java:241)
at net.sourceforge.pmd.RuleSetFactory.createRuleSet(RuleSetFactory.java:202)
at net.sourceforge.pmd.RuleSetFactory.createRuleSet(RuleSetFactory.java:197)
at net.sourceforge.pmd.RuleSetFactory.parseRuleSetReferenceNode(RuleSetFactory.java:359)
at net.sourceforge.pmd.RuleSetFactory.parseRuleNode(RuleSetFactory.java:317)
at net.sourceforge.pmd.RuleSetFactory.parseRuleSetNode(RuleSetFactory.java:272)
at net.sourceforge.pmd.RuleSetFactory.createRuleSet(RuleSetFactory.java:202)
at net.sourceforge.pmd.RuleSetFactory.createRuleSet(RuleSetFactory.java:197)
at net.sourceforge.pmd.RuleSetFactory.createRuleSets(RuleSetFactory.java:161)
at net.sourceforge.pmd.RuleSetFactory.createRuleSets(RuleSetFactory.java:145)
at net.sourceforge.pmd.ant.internal.PMDTaskImpl.doTask(PMDTaskImpl.java:119)
but then when I use the plugin in another project, I get:
* What went wrong:
Cannot convert URL 'jar:file:/Users/david.byron/.gradle/caches/jars-2/4x4ld1gm1mm6nh7gj3tmmiprrtphdde/myplugin-1.19-SNAPSHOT.jar!/com/mycompany/plugins/myplugin/pmd-common.xml' to a file.
* Try:
Run with --info or --debug option to get more log output.
* Exception is:
org.gradle.api.InvalidUserDataException: Cannot convert URL 'jar:file:/Users/david.byron/.gradle/caches/jars-2/4x4ld1gm1mm6nh7gj3tmmiprrtphdde/myplugin-1.19-SNAPSHOT.jar!/com/mycompany/plugins/myplugin/pmd-common.xml' to a file.
at org.gradle.api.internal.file.AbstractFileResolver.convertObjectToFile(AbstractFileResolver.java:122)
at org.gradle.api.internal.file.BaseDirFileResolver.doResolve(BaseDirFileResolver.java:76)
at org.gradle.api.internal.file.AbstractFileResolver.resolve(AbstractFileResolver.java:79)
at org.gradle.api.internal.file.AbstractFileResolver.resolve(AbstractFileResolver.java:61)
at org.gradle.api.internal.file.collections.DefaultFileCollectionResolveContext$FileCollectionConverter.convertInto(DefaultFileCollectionResolveContext.java:173)
at org.gradle.api.internal.file.collections.DefaultFileCollectionResolveContext.doResolve(DefaultFileCollectionResolveContext.java:134)
at org.gradle.api.internal.file.collections.DefaultFileCollectionResolveContext.resolveAsFileCollections(DefaultFileCollectionResolveContext.java:92)
at org.gradle.api.internal.file.collections.DefaultFileCollectionResolveContext$FileCollectionConverter.convertInto(DefaultFileCollectionResolveContext.java:157)
at org.gradle.api.internal.file.collections.DefaultFileCollectionResolveContext.doResolve(DefaultFileCollectionResolveContext.java:109)
at org.gradle.api.internal.file.collections.DefaultFileCollectionResolveContext.resolveAsFileCollections(DefaultFileCollectionResolveContext.java:92)
at org.gradle.api.internal.file.collections.DefaultFileCollectionResolveContext$FileCollectionConverter.convertInto(DefaultFileCollectionResolveContext.java:157)
at org.gradle.api.internal.file.collections.DefaultFileCollectionResolveContext.doResolve(DefaultFileCollectionResolveContext.java:109)
at org.gradle.api.internal.file.collections.DefaultFileCollectionResolveContext.resolveAsFileCollections(DefaultFileCollectionResolveContext.java:92)
at org.gradle.api.internal.file.CompositeFileCollection.getSourceCollections(CompositeFileCollection.java:172)
at org.gradle.api.internal.file.CompositeFileCollection.visitRootElements(CompositeFileCollection.java:184)
at org.gradle.api.internal.changedetection.state.AbstractFileCollectionSnapshotter.snapshot(AbstractFileCollectionSnapshotter.java:78)
at org.gradle.api.internal.changedetection.rules.AbstractNamedFileSnapshotTaskStateChanges.buildSnapshots(AbstractNamedFileSnapshotTaskStateChanges.java:87)
at org.gradle.api.internal.changedetection.rules.AbstractNamedFileSnapshotTaskStateChanges.<init>(AbstractNamedFileSnapshotTaskStateChanges.java:54)
at org.gradle.api.internal.changedetection.rules.InputFilesTaskStateChanges.<init>(InputFilesTaskStateChanges.java:28)
at org.gradle.api.internal.changedetection.rules.TaskUpToDateState.<init>(TaskUpToDateState.java:55)
... and more
I'm using gradle 3.3 and pmd 5.5.3.
Thanks much for any help here.
-DB
Last edit: David Byron 2017-03-15
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
(Note: either ruleSets or ruleSetConfig should be used, not both)
This might work, as long as you don't use custom rules. If you do, then there would be anyway another approach more recommended, see below for the maven solution.
I'm not familiar with gradle enough, so I can't definitely say, what's the root problem. I assume, that the project itself is not on the classpath for PMD. Hence PMD itself can't resolve the reference to pmd-common.xml.
With maven, you would solve this problem by creating a separate "build-tools" module, which contains your ruleset files and add this build-tools-module as a dependency to the PMD plugin. See Multimodule Configuration.
Regards,
Andreas
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I think this is more of a gradle question, so I posted https://discuss.gradle.org/t/sharing-pmd-config-between-main-and-test/21729, but that hasn't generated much of a conversation, so I'm looking for help here as well. Thanks much for your time.
-DB
I'm trying to do something that feels totally routine, but struggling mightily. I'm working on a plugin that sets up some basic build conventions to use in multiple projects at my company. One of the things that plugin does is apply gradle's pmd plugin. It then attempts to configure it. Up to now, I've been configuring it like this:
where pmd.xml lives in src/main/resources/com/mycompany/plugins/myplugin/pmd.xml. I'd love to hear whether there are better ways than this, but...at least it works.
I'd like to use separate config for pmdMain and pmdTest. I can remove the ruleSetConfig from the project.pmd block above and add this:
with a new pmd-test.xml in the same place as pmd-main.xml, and pmd-main.xml is simply pmd.xml renamed. So far so good.
Turns out though, that pmd-main.xml and pmd-test.xml share a bunch of rules. I'd love to not duplicate them, so I figure I'll put the common stuff in pmd-common.xml. Here's where I get stuck. I'd love to handle this within the pmd config files themselves (i.e. no change to the above), with something like:
or maybe
or even
but those make my GradleRunner tests fail like this:
Execution failed for task ':pmdMain'.
> Can't find resource 'com/locationlabs/plugins/leanjava/pmd-common.xml' for rule 'null'. Make sure the resource is a valid file or URL and is on the CLASSPATH. Here's the current classpath: /Users/david.byron/.gradle/wrapper/dists/gradle-3.3-bin/64bhckfm0iuu9gap9hg3r7ev2/gradle-3.3/lib/gradle-launcher-3.3.jar
If I ignore the GradleRunner failures use the plugin in another project, I get the same error. Here's the error and stack trace for posterity:
I've done a bunch of digging, but I've come up empty. I also tried keeping the xml files independent of each other (i.e. taking out the reference to pmd-common.xml from the others) and providing two files to the pmd plugin directly. I've looked at https://discuss.gradle.org/t/how-can-i-read-setup-resources-from-plugin-jar/13274 and https://discuss.gradle.org/t/best-practice-for-copying-files-from-classpath/6957 and generally done a bunch of digging, but I'm coming up empty. This gets the GradleRunner tests to pass:
but then when I use the plugin in another project, I get:
I'm using gradle 3.3 and pmd 5.5.3.
Thanks much for any help here.
-DB
Last edit: David Byron 2017-03-15
Ping. Can someone please give me a hand here? Thanks.
-DB
Hi David,
you could try to configure both rulesets directly in gradle (and not let it combine by PMD), something like:
(Note: either ruleSets or ruleSetConfig should be used, not both)
This might work, as long as you don't use custom rules. If you do, then there would be anyway another approach more recommended, see below for the maven solution.
I'm not familiar with gradle enough, so I can't definitely say, what's the root problem. I assume, that the project itself is not on the classpath for PMD. Hence PMD itself can't resolve the reference to pmd-common.xml.
With maven, you would solve this problem by creating a separate "build-tools" module, which contains your ruleset files and add this build-tools-module as a dependency to the PMD plugin. See Multimodule Configuration.
Regards,
Andreas