koral-- / gradle-pitest-plugin

Gradle plugin for PIT Mutation Testing in Android projects
Apache License 2.0
74 stars 8 forks source link

Incompatibility with new Kotlin versions #125

Open ivanvillarfreire opened 3 months ago

ivanvillarfreire commented 3 months ago

Good morning.

First of all, I want to sincerely appreciate the good work it's being done here over the years.

I want to comment here what it seems to be some kind of incompatibility with at least the following versions:

------------------------------------------------------------
Gradle 8.6
------------------------------------------------------------

Build time:   2024-02-02 16:47:16 UTC
Revision:     d55c486870a0dc6f6278f53d21381396d0741c6e

Kotlin:       1.9.20
Groovy:       3.0.17
Ant:          Apache Ant(TM) version 1.10.13 compiled on January 4 2023
JVM:          17.0.7 (Homebrew 17.0.7+0)
OS:           Mac OS X 13.0 aarch64

The problem in fact is pretty simple to see, on a build.gradle.kts file, if you include this section:

  packaging {
      resources.excludes.add("META-INF/{AL2.0,LGPL2.1}")
      resources.excludes.add("META-INF/LICENSE.md")
      resources.excludes.add("META-INF/LICENSE-notice.md")
  }

The gradle sync fails already with the errors:

applicationandroid/build.gradle.kts:139:5: Unresolved reference: packaging
applicationandroid/build.gradle.kts:140:19: Unresolved reference: excludes

The feeling I get, but I could be totally wrong, is that internally Pitest does some kind of packaging too but there is some new way to call that function and Pitest is not able to do it right.

The "good thing" is that if we comment the packaging section, it works just fine:

image

And a ./gradlew pitest:

image
koral-- commented 3 months ago

Could you share a reproducer project?

ivanvillarfreire commented 3 months ago

Attached a project. No code, just the build.gradle files.

To see the problem, you just need to uncomment the packaging section on applicationAndroid/build.gradle.kts file:

image

If you uncomment the section and try to build the project, fails with the error I said. If it's commented, no error is seen.

example.zip

koral-- commented 3 months ago

Does it work if you place this in the top-level build.gradle.kts?:

plugins {
  // any other plugins if needed
  id("pl.droidsonroids.pitest") version "0.2.18" apply false
}

and this in the app build.gradle.kts:

plugins {
  // any other plugins if needed
  id("pl.droidsonroids.pitest")
}
ivanvillarfreire commented 3 months ago

Good morning.

Just tried right now, same error.

koral-- commented 3 months ago

I've just tried and it seems to work: https://github.com/koral--/pitest-125-issue/blob/main/build.gradle.kts https://github.com/koral--/pitest-125-issue/blob/main/app/build.gradle.kts#L5

ivanvillarfreire commented 3 months ago

Good morning.

That's a different project right?

If I do that on the example project that I sended last week, I receive this new error:

Could not find com.android.tools.build:gradle:7.3.1.
Searched in the following locations:
  - https://plugins.gradle.org/m2/com/android/tools/build/gradle/7.3.1/gradle-7.3.1.pom
If the artifact you are trying to retrieve can be found in the repository but without metadata in 'Maven POM' format, you need to adjust the 'metadataSources { ... }' of the repository declaration.
Required by:
    project :buildSrc > pl.droidsonroids.pitest:pl.droidsonroids.pitest.gradle.plugin:0.2.18 > pl.droidsonroids.gradle:gradle-pitest-plugin:0.2.18
koral-- commented 3 months ago

Yes, that's a different project. I was able to reproduce the issue with the packaging block in the meantime without using it.

Could not find com.android.tools.build:gradle:7.3.1.
Searched in the following locations:
  - https://plugins.gradle.org/m2/com/android/tools/build/gradle/7.3.1/gradle-7.3.1.pom

It seems that the google() repository is missing. It should be added to the buildscript dependencies like this: https://github.com/koral--/gradle-pitest-plugin/blob/master/src/funcTest/resources/testProjects/junit5kotlin/build.gradle#L6

ivanvillarfreire commented 3 months ago

I think that breaks somehow the dependencies on the other build.gradle.kts.

Meaning, if we implement this:

buildSrc/build.gradle.kts:

plugins {
    `kotlin-dsl`
    id("pl.droidsonroids.pitest") version "0.2.18" apply true
}

buildscript {
    repositories {
        google()
        gradlePluginPortal()
        mavenCentral()
    }

    dependencies {
        classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.21")
        classpath("de.mannodermaus.gradle.plugins:android-junit5:1.8.2.1")
    }
}

repositories {
    mavenCentral()
    gradlePluginPortal()
    google()
}

dependencies {
    implementation("com.android.tools.build:gradle:8.1.1")
    implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.21")
    implementation("com.diffplug.spotless:spotless-plugin-gradle:6.8.0")
    implementation("org.jacoco:org.jacoco.core:0.8.10")
    implementation("org.jfrog.buildinfo:build-info-extractor-gradle:4.32.0")
    implementation("com.github.ben-manes:gradle-versions-plugin:0.47.0")
    implementation("com.google.dagger:hilt-android-gradle-plugin:2.46")
}

applicationAndroid/build.gradle.kts:

import Configuration.Environments
import org.gradle.api.Action
import pl.droidsonroids.gradle.pitest.PitestPluginExtension

plugins {
    id(Plugins.Android.APPLICATION)
    id(Plugins.Kotlin.ANDROID)
    id(Plugins.Kotlin.KAPT)
    id(Plugins.Kotlin.PARCELIZE)
    id(Plugins.Hilt.ANDROID)
    id("pl.droidsonroids.pitest")
    id("org.jetbrains.kotlin.kapt")
}

val useArchetypeModule = project.properties["useArchetypeModule"]

android {
    fun org.gradle.api.Project.pitest(configure: Action<PitestPluginExtension>): Unit =
        (this as org.gradle.api.plugins.ExtensionAware).extensions.configure("pitest", configure)

// Configure the Pitest plugin
    pitest {
        targetClasses.set(listOf("com.whatever.applicationandroid.*"))
        // Configure other properties as needed
        mutators.set(listOf("DEFAULTS"))
        excludedTestClasses.set(listOf(""))
        //targetTests.set(listOf("com.whatever.libandroidpre.data.datasource.*"))
        threads.set(4)
        outputFormats.set(listOf("XML", "HTML"))
        timestampedReports.set(false)
        verbose.set(true)
        pitestVersion.set("1.11.0")
        junit5PluginVersion.set("1.1.2")
    }

    // Ensure Pitest tasks run after relevant compile tasks
    tasks.withType<pl.droidsonroids.gradle.pitest.PitestTask> {
        mustRunAfter("compileDESReleaseKotlin","compilePROReleaseKotlin","compileDESReleaseJavaWithJavac")
    }
    namespace = Configuration.Android.namespace
    compileSdk = Configuration.Android.compileSdk

    defaultConfig {
        minSdk = Configuration.Android.DefaultConfig.minSdk
        targetSdk = Configuration.Android.DefaultConfig.targetSdk
        versionCode = Configuration.Android.DefaultConfig.versionCode
        versionName = Configuration.Android.DefaultConfig.versionName

        testInstrumentationRunner = Configuration.Android.DefaultConfig.testInstrumentationRunner

        buildConfigField("String", "JIRA_KEY", "\"${Configuration.jiraKey}\"")
        buildConfigField("String", "ARTIFACT_ID", "\"${Configuration.artifactId}\"")

        addManifestPlaceholders(
            mapOf(
                "appIcon" to "@drawable/ic_launcher",
                "appIconRound" to "@drawable/ic_launcher",
                "itxAuthority" to Configuration.artifactId
            )
        )
    }

    signingConfigs {

    }

    flavorDimensions.add(FlavorDimension.environment)

    productFlavors {
        with(Environments.Development) {
            create(name) {
                dimension = FlavorDimension.environment
            }
        }
        with(Environments.Preproduction) {
            create(name) {
                dimension = FlavorDimension.environment
            }
        }
        with(Environments.Production) {
            create(name) {
                dimension = FlavorDimension.environment
            }
        }
    }

    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_17
        targetCompatibility = JavaVersion.VERSION_17
    }

    kotlinOptions {
        jvmTarget = JavaVersion.VERSION_17.toString()
    }

    buildFeatures {
        compose = true
        buildConfig = true
    }

    composeOptions {
        kotlinCompilerExtensionVersion = "1.4.7"
    }

    packaging {
        resources.excludes.add("META-INF/{AL2.0,LGPL2.1}")
        resources.excludes.add("META-INF/LICENSE.md")
        resources.excludes.add("META-INF/LICENSE-notice.md")
    }

    configurations.all {
        // Enabled jacoco for all configurations.
        resolutionStrategy {
            eachDependency {
                if (requested.group == "org.jacoco") useVersion(libs.versions.jacoco.get())
            }
        }

        // Don't cache changing modules at all.
        resolutionStrategy.cacheChangingModulesFor(0, "seconds")
    }
}

dependencies {
    kapt(libs.bundles.hilt.compiler)
    implementation(libs.bundles.hilt)

    testImplementation(libs.bundles.unit.test)
    androidTestImplementation(libs.bundles.ui.test)
    debugImplementation(libs.bundles.debug)

    // Add Kotlin plugin dependencies
    testImplementation("org.jetbrains.kotlin:kotlin-reflect:2.0.0")
    implementation("com.arcmutate:pitest-kotlin-plugin:1.3.0")

    // Add JUnit 5 dependencies
    testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.2")
    testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.9.2")
}

Fails with a different error:

A problem occurred configuring project ':buildSrc'.
> Could not get unknown property 'android' for project ':buildSrc' of type org.gradle.api.Project.

* Try:
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.

* Exception is:
org.gradle.api.ProjectConfigurationException: A problem occurred configuring project ':buildSrc'.
    at org.gradle.configuration.project.LifecycleProjectEvaluator.wrapException(LifecycleProjectEvaluator.java:84)
    at org.gradle.configuration.project.LifecycleProjectEvaluator.addConfigurationFailure(LifecycleProjectEvaluator.java:77)
    at org.gradle.configuration.project.LifecycleProjectEvaluator.access$400(LifecycleProjectEvaluator.java:55)
    at 
koral-- commented 3 months ago

OK, I'll investigate exactly that case.

koral-- commented 1 month ago

I was able to successfully run pitest task in the project from example.zip using plugin version 0.2.19 (just released), with the following modifications: