szpak / gradle-pitest-plugin

Gradle plugin for PIT Mutation Testing
http://gradle-pitest-plugin.solidsoft.info/
212 stars 57 forks source link

When subprojects have missing reports, aggregation fails #292

Open ghost opened 2 years ago

ghost commented 2 years ago

Assuming a gradle project where some subprojects

We will have some subprojects with to files to aggregate.

When attempting to run pitestReport on such a project then the following error is shown

Execution failed for task ':pitestReportAggregate'.
> A failure occurred while executing info.solidsoft.gradle.pitest.AggregateReportGenerator
   > /... snip .../build/reports/pitest/linecoverage.xml does not exist or is not a file

This is due to the check in ReportAggregator.Builder when a file is added to aggregation it must exist.

Whilst it is fairly easily to "hack" AggregateReportTask to strip out subprojects for which pitest is disabled, the failWhenNoMutations issue is trickier as this needs to be checked at task execution time.

So AggregateReportTask needs to determine whether reports are missing for a particular subproject and whether that should be an error or not.

Proposal

aSemy commented 2 years ago

Can the aggregator task can be changed to depend on Pitest tasks, not projects with the Pitest plugin? I think that's what's tripping the agggregation up. I think the Gradle-ey way of doing this would to put the file-gathering work that is currently in PitestAggregatorPlugin in the aggregator task.

The Pitest task can be altered to explicitly output the required files (mutationFiles and lineCoverageFiles), then the aggregator task can depend on the tasks dependsOn(tasks.withType<PitestTask>()) and aggregate the files from the tasks.

I'm not sure that the worker queue is required.

JoaoCipriano commented 1 year ago

A workaround for this failure is to apply the Pitest plugin and settings only to the subprojects that will be tested. I created an internal method to make it clearer and easier to understand.

This solution worked for me because the method getProjectsWithPitestPlugin() of the class PitestAggregatorPlugin retrieve only the subprojects with the plugin; I believe that must work in almost every case.

The solution:

plugins {
    id 'info.solidsoft.pitest' version '1.9.11' apply false
}

apply plugin: 'info.solidsoft.pitest.aggregator'

subprojects {  
    apply plugin: 'java'    

    if (shouldApplyPitestPlugin(project.name)) {  
        apply plugin: 'info.solidsoft.pitest'  

        pitest {  
            junit5PluginVersion = '1.0.0' 
            useClasspathFile = true  

            outputFormats = [ "XML", "HTML" ]  
            exportLineCoverage = true  
            timestampedReports = false  
        }  
    }
}

static def shouldApplyPitestPlugin(projectName) {  
    def subProjectsToIgnorePitestPlugin = [  
        'module-without-any-test-1', 'module-without-any-test-2'
    ]  
    return !(projectName in subProjectsToIgnorePitestPlugin)  
}