Sharing pmd config between main and test


(David Byron) #1

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:

def pmdConfigStream = MyPlugin.class.getResource('pmd.xml')
def pmdConfig = pmdConfigStream.text
project.pmd {
    ruleSets = []
    ruleSetConfig = project.resources.text.fromString(pmdConfig)
}

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:

project.tasks.pmdMain {
    def pmdMainConfigStream = LeanJavaPlugin.class.getResource('pmd-main.xml')
    def pmdMainConfig = pmdMainConfigStream.text
    ruleSetConfig = project.resources.text.fromString(pmdMainConfig)
}

project.tasks.pmdTest {
    def pmdTestConfigStream = LeanJavaPlugin.class.getResource('pmd-test.xml')
    def pmdTestConfig = pmdTestConfigStream.text
    ruleSetConfig = project.resources.text.fromString(pmdTestConfig)
}

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:

    
        Main Rules
    
       
       
    

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:

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)

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 How can I read setup resources from plugin jar? and Best practice for copying files from classpath and generally done a bunch of digging, but I’m coming up empty. This gets the GradleRunner tests to pass:

project.tasks.pmdMain {
    def pmdCommonConfig = LeanJavaPlugin.class.getResource('pmd-common.xml')
    def pmdMainConfig = LeanJavaPlugin.class.getResource('pmd-main.xml')
    ruleSetFiles = project.files(pmdCommonConfig, pmdMainConfig)
}

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


(Jordan Lee) #2

Getting the same “org.gradle.api.InvalidUserDataException: Cannot convert URL …” error after we started using gradle 3.4