bmuschko / gradle-clover-plugin

Gradle plugin for generating a code coverage report using Clover
Apache License 2.0
74 stars 50 forks source link

clover plugin not finding my customized sourceSet locations #1

Closed dlethin closed 12 years ago

dlethin commented 12 years ago

Hi. I'm trying out your plugin but unfortunately its not working out of the box in my build, and I'm not sure if its the plugin or how I have my build set up. I tried to download and look at the source for this plugin, but I'm unfamiliar with the Gradle "Actions" class, so the logic was not immediately obvious to me.

I'm trying to run this in a multimodule buld. The first error I get is:

The specified source directory '/Users/dlethin/bld/perforce/psd/dlethin_gp_gradle/IMS/gopayment/server/src/main/java' does not exist. It won't be included in Clover instrumentation. The specified source directory '/Users/dlethin/bld/perforce/psd/dlethin_gp_gradle/IMS/gopayment/server/src/test/java' does not exist. It won't be included in Clover instrumentation.

The thing is, that is not where my source location is defined.

In my root project I have the following code snip --

def leafProjects = subprojects.findAll { it.childProjects.size() == 0 }

configure(leafProjects) {

apply plugin: 'java' apply plugin: 'eclipse' apply plugin: 'clover'

repositories { ... }

clover { licenseFile = rootProject.file('clover.license') }

dependencies { testRuntime 'com.cenqua.clover:clover:3.1.0@jar' } }

Essentially defining closures common to all my subprojects.

Then in my leaf projects, I define things specific to that project. In the case of the above project which is failing to be instrumented, I have:

sourceSets { main { java { srcDir 'src/java'
} test { java { srcDir 'test/java' } }

Note the setup is due to conforming my build.grade to a legacy codebase.

Any advice on how to get the clover plugin working with my build? Thanks. (And thanks for sharing your plugin on github..)

bmuschko commented 12 years ago

At the moment I am not quite sure where the error lies. The plugin uses the expression project.sourceSets.main.java.srcDirs and project.sourceSets.test.java.srcDirs so whenever you redefine the paths it should use the correct directory. I am not quite sure if I understand your project's directory structure yet. You have a multi-module build. Each of the modules might have a different source and test path. Do you define the sourceSets for each of the submodules or on the parent build.gradle? It looks to me as if you only redefine them in the submodules. Is that correct?

Does the report get created correct for at least one of the modules? Where do you run your build from?

dlethin commented 12 years ago

Thanks for the comment, Brian. I think I got past this problem (and onto the next one...). The issue is that in my root project I am an defining some configuration comment to all my projects (like using the clover plugin, defining the repositories to use. Then each project's gradle defines it unique configuration elements ( like there sourceSets). The problem I have is that in my root project I am defining each java project to use the clover plugin BEFORE my child projects build.gradle file is executed where, so it picks up the default sourceSets gradle provides instead of my custom one.

To work around this, I had to modify my root project to do the following:

def leafProjects = subprojects.findAll { it.childProjects.size() == 0 }

configure(leafProjects) {

apply plugin: 'java' apply plugin: 'eclipse'

repositories { ... }

beforeEvaluate { project -> project.apply(plugin: 'clover')

clover {
  licenseFile = rootProject.file('clover.license')
}

dependencies {
  testRuntime 'com.cenqua.clover:clover:3.1.0@jar'
}

} }

Now the source code is correctly getting instrumented. My next problem I'm trying to track down is that the instrumented code is not compiling because it can't resolve my dependencies. My build defines some custom configurations, and then modifies the sourceSets to include the new configuration on the classpath, like this:

configurations { providedNonFiltered }

dependencies { providedNonFiltered "path.to:dependency:1.0" }

sourceSets { main { compileClasspath += configurations.providedNonFiltered } }

However, when the instrumented code gets compiled, dependencies in my providedNonFiltered configuraton are not on the classpath, so it fails.

I'll try now to track down this issue, but would appreciate any clues you might have is something is immediately obvious.

dlethin commented 12 years ago

OK. I found the the problem. The InstrumentCodeAction hard-codes the classpath used to compile the instrumented code to project.configurations.testRuntime

This unfortunately doesn't work for my project, as I need it to compile against project.sourceSets.test.compileClasspath. I worked around this issue with a cloned copy of the source and modified the plugin, adding a field to the cloverConvention object which specifics the compileClasspath -- defaulting it to testCompile classpath.

Is this something I might be able to patch into your code? I've got to figure out a bit more on how to do this with git/github. I've only consumed projects from the repository -- never hosted or patched them.

dlethin commented 12 years ago

Ok, I figured out how to work git/github and forked the project in order to commit a change to support custom compileClasspaths. I would guess the next thing I have to do is figure out how to issue a pull request to have this enhancement added. There are a few additional tweaks I was hoping to explore at some point too --

Thanks again for cranking all these plugins for the gradle community. I'm also in parallel working with your cargo plugin. In fact you added some features for me already that I haven't gotten back to trying yet...

bmuschko commented 12 years ago

I had a look at my project again that defines a new configuration for a provided scope. I extended my testRuntime configuration by my custom configuration. Here's how I would try it in your project:

configurations {
    providedNonFiltered
    testRuntime.extendsFrom providedNonFiltered
}

You are correct. At the moment the plugin always just uses project.sourceSets.test.compileClasspath. I was thinking that we could introduce a classpath configuration property to assign additional JARs or configurations. The classpath would then be added to automatically to testRuntime.

All of your suggestions sound good. I am looking forward to any of your contributions.

Feel free to open separate issues for your feature requests.

Thanks! Feedback like yours keeps me going. :-)

dlethin commented 12 years ago

[just replying to email notification. Not sure this will work...]

I definitely agree upon adding a 'classpath' configuration property. In my fork of the plugin, I just happened to call it 'compileClasspath' and defaulted it to configurations.testRuntime. If you choose to set it, it replaces the value set as opposed to adding it to testRuntime as you suggest. Your suggestion about how to modify my build to confirm to your plugins requirements on how the classpath is set up won't really work. I had worked closely with some of the gradle engineers at a conference recently on my build and set up my configurations and sourceSets in a specific way so as to take advantage of autowiring some of my custom sourceCode generation tasks. I think a good strategy for plugins is to make the plugin as flexible as can be. In the case of gradle, there are so many different ways someone might have their configuration and sourceSets setup. If you make your plugin as flexible as possible, then it would be much easier for builds like mine to integrate with it vs having to change our our build works so that we can use the plugin.

This is the similar reasoning behind my suggestion to change how the aggregateReport task works. I'm guessing I could probably get this working by defining my root project to be a java project, but this doesn't seem like the right approach that I have to modify my projects structure to use the plugin. My root project doesn't produce any java artifacts, so it seems confusing that I should have to apply the java plugin.

Please feel free to take as an example the change I committed in my fork. My preference of course would not be to maintain a fork that deviates from your main code.

I'll take a look at some of the other suggestions below in the near future. I've got to move on to a few other things before I get back to this.

Thanks again.

Doug

PS -- I ran into another interesting integration issue with this plugin and my build. Looks like the cloverGenerateReport task will automatically depend on any task of type Test, forcing them to run. In my build, in addition to the standard test task that comes with the java plugin, I have a another task of type Task that is not directly wired to the java build, but is more of a convenience to my developers that want to run an alternate testng suite. The problem is that as a result of running the cloverGenerateReport, this extra test task gets run. Which I don't directly want. And when it does happen, it ends up repeating the instrumentation of the same test code because the instrumentation action doesn't take advantage of any of gradle's incremental build capabilities. This leads two two other suggestions -- provide a way to to override the list of Test tasks to run, and also modifying the implementation to reduce the duplication of instrumenting the code.

On Dec 10, 2011, at 10:02 AM, Benjamin Muschko wrote:

I had a look at my project again that defines a new configuration for a provided scope. I extended my testRuntime configuration by my custom configuration. Here's how I would try it in your project:

configurations { providedNonFiltered testRuntime.extendsFrom providedNonFiltered }

You are correct. At the moment the plugin always just uses project.sourceSets.test.compileClasspath. I was thinking that we could introduce a classpath configuration property to assign additional JARs or configurations. The classpath would then be added to automatically to testRuntime.

All of your suggestions sound good. I am looking forward to any of your contributions.

  • Clover history - definitely desirable!
  • Aggregate Clover report without the Java plugin applied - is this really a problem? I just had a look at the code again. The plugin simply applies the Java plugin if it's not there. Do you get an error message otherwise?
  • For integration tests I'd probably just write specific tasks that run your instrumented classes in a Servlet container. Which container are you using? Jetty? There might be a way of doing this without having to build a JAR.

Thanks! Feedback like yours keeps me going. :-)


Reply to this email directly or view it on GitHub: https://github.com/bmuschko/gradle-clover-plugin/issues/1#issuecomment-3091208

bmuschko commented 12 years ago

Great, thanks for your feedback. I am going to have a look at all of this probably sometime this week.

bmuschko commented 12 years ago

I will close this ticket as I created separate issues for your requests. Feel free to add comments or new issues if I missed something.