Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Applying Detekt from external Gradle file fails with: Unable to load class 'com.android.build.gradle.BaseExtension' #3490

Closed
volsahin opened this issue Feb 21, 2021 · 17 comments

Comments

@volsahin
Copy link
Contributor

Steps to Reproduce

I intended to upgrade detekt version from 1.9.1 to latest 1.16.0-RC1 in android project and build failed.
The project uses classic groovy gradle files. It is nice to mention that i apply detekt as a seperate gradle script.

Here is the current detekt.gradle script

buildscript {
    ext.detektVersion = '1.9.1'
    repositories {
        jcenter()
    }
    dependencies {
        classpath "io.gitlab.arturbosch.detekt:detekt-gradle-plugin:$detektVersion"
    }
}

apply plugin: io.gitlab.arturbosch.detekt.DetektPlugin

detekt {
    // some options
}

And that is how it's applied into app
apply from: '../scripts/detekt.gradle'

As i see 1.11.1 is the latest version which can be built without a problem. Starting 12.0.0 to the latest version, build fails.
Gradle plugin versions are the latest one.

Stacktrace

FAILURE: Build failed with an exception.

* What went wrong:
A problem occurred configuring project ':app'.
> Failed to notify project evaluation listener.
   > com/android/build/gradle/BaseExtension

* Exception is:
org.gradle.api.ProjectConfigurationException: A problem occurred configuring project ':app'.
Caused by: org.gradle.internal.event.ListenerNotificationException: Failed to notify project evaluation listener.
Caused by: java.lang.NoClassDefFoundError: com/android/build/gradle/BaseExtension
	at io.gitlab.arturbosch.detekt.internal.DetektAndroid$registerDetektAndroidTasks$1.execute(DetektAndroid.kt:59)
        at io.gitlab.arturbosch.detekt.internal.DetektAndroid$registerDetektAndroidTasks$1.execute(DetektAndroid.kt:21)
Caused by: java.lang.ClassNotFoundException: com.android.build.gradle.BaseExtension
        ... 139 more

* Get more help at https://help.gradle.org

BUILD FAILED in 435ms

Also #3476 #3260 these issues experienced similar exceptions as far as i can see.

Environment

  • Version of detekt used: 1.16.0-RC1
  • Version of Gradle used (if applicable): 4.1.2
  • Version of Kotlin: 1.4.21
@chao2zhang
Copy link
Member

In your root project, did you apply both detekt plugin and kotlin-android plugin? I imagine this is an issue where we accidentally apply detekt to the root project.

@cortinico
Copy link
Member

Caused by: java.lang.ClassNotFoundException: com.android.build.gradle.BaseExtension

Which version of AGP are you on?

@volsahin
Copy link
Contributor Author

@chao2zhang actually i didn't applied it inside root project gradle. The apply from: '../../scripts/detekt.gradle' snippet is inside of a feature module of a modular application. And @cortinico as i mentioned in environment section, the plugin version is 4.1.2

@chao2zhang
Copy link
Member

chao2zhang commented Feb 24, 2021

Does your feature module apply kotlin-android but not com.android.application or other com.android.*?

@volsahin
Copy link
Contributor Author

@chao2zhang actually they are not android feature modules, they are basically gradle library modules which i develop features inside them. Because of this, the module gradle file which i applied detekt script contains

apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'

However when i add detekt dependency also to the app gradle, which contains

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'

The problem is still valid.

@chao2zhang
Copy link
Member

This looks weird. Detekt has gradle testkit integration tests for both com.android.library and com.android.application. Your build setup appears correct.

I can try to reproduce this, but as far as I know my project is also on AGP 4.1.2 and has no problem running detekt.
Is it possible if you could try to provide a simplified sample project?

@chao2zhang
Copy link
Member

I forgot to mention but https://github.com/cortinico/kotlin-android-template also works with detekt. It has both library and app modules.

@volsahin
Copy link
Contributor Author

Actually problem is not detekt but how i applied it. If i choose a standard way to implement, there are no problems.

plugins {
    id 'com.android.library'
    id 'kotlin-android'
    id("io.gitlab.arturbosch.detekt").version("1.16.0-RC1")
}

But if i choose the implementation that i mentioned in issue desc

plugins {
    id 'com.android.library'
    id 'kotlin-android'
}

apply from: '../../scripts/detekt.gradle'

Then the problem raises. It isn't very hard to convert this into working one. But i wonder why this approach fails. This line may be the problematic one apply plugin: io.gitlab.arturbosch.detekt.DetektPlugin. I'll check what changed in 12.0.0

@sigis151
Copy link

sigis151 commented Mar 3, 2021

I can back this up. We use the same initialization in a secondary gradle file and tried to update from 1.1.0 to 1.16.0 (I know this is a huge jump). But we used this approach because in our company we have many projects and we need to have the same detekt setup in all projects so copy-pasting files are faster and way more convenient for new project setup.
Maybe there is another way to setup all detekt configuration and rules in a separate gradle file?

@chao2zhang
Copy link
Member

@volsahin Could you elaborate why we need .DetektPlugin in apply plugin: "io.gitlab.arturbosch.detekt.DetektPlugin"? I am still trying to reproduce but at least apply plugin: "io.gitlab.arturbosch.detekt.DetektPlugin" works for me.

@sigis151 @volsahin I am also trying to find problematic commits between 1.11.1 and 1.12.0 - There are also 1.11.2 and 1.12.0-RC1, would you mind checking if those versions work or not?

@chao2zhang
Copy link
Member

My suspicion is that we introduced android plugin configuration in 1.12.0 - #2787, which may conflict with the existing android projects setup.

@sigis151
Copy link

sigis151 commented Mar 3, 2021

1.11.1 and 1.12.0-RC1 syncs correctly and 1.12.0 fails with said error

@chao2zhang
Copy link
Member

chao2zhang commented Mar 3, 2021

I guess we have verified that it is extremely likely to be broken with #2787. Would you mind sharing a sample project? I have tried to use apply plugin in my sample project but still couldn't reproduce.

Meanwhile, I can open a new PR to allow folks to opt-out DetektAndroid setup.

@sigis151
Copy link

sigis151 commented Mar 5, 2021

fos sample I have

quality.gradle
buildscript {
    repositories {
        jcenter()
        maven { url "https://plugins.gradle.org/m2/" }
    }
    dependencies {
        classpath "io.gitlab.arturbosch.detekt:detekt-gradle-plugin:1.1.0"
        classpath 'de.aaschmid:gradle-cpd-plugin:3.1'
    }
}
apply plugin: io.gitlab.arturbosch.detekt.DetektPlugin
apply plugin: 'jacoco'
apply plugin: de.aaschmid.gradle.plugins.cpd.CpdPlugin

cpd {
    language = 'kotlin'
    toolVersion = '6.26.0'
}

cpdCheck {
    minimumTokenCount = 50
    ignoreFailures = true
    source = files('src/main/kotlin', 'src/main/java')
}

detekt {
    input = files("$projectDir")
    config = files("$projectDir/config/detekt/default-detekt-config.yml")
}
dependencies {
    detektPlugins "io.gitlab.arturbosch.detekt:detekt-formatting:1.1.0"
}

jacoco {
    toolVersion = "0.8.1"
    reportsDir = file("$buildDir/reports/jacoco")
}

tasks.withType(Test).whenTaskAdded {
    it.jacoco.classDumpDir = file("$project.buildDir/jacoco/dump")
}

And in main app/build.gradle at the top of it, I apply these plugins

apply plugin: 'com.android.application'
...
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
apply from: 'config/quality.gradle'
...

@schalkms
Copy link
Member

@chao2zhang is this issue fixed with PR #3511? Is there anything else left to do in order to close this issue?

@cortinico cortinico changed the title Unable to load class 'com.android.build.gradle.BaseExtension' Applying Detekt from external Gradle file fails with: Unable to load class 'com.android.build.gradle.BaseExtension' Jul 21, 2021
@cortinico
Copy link
Member

@chao2zhang is this issue fixed with PR #3511? Is there anything else left to do in order to close this issue?

Nope is still not solved. The root cause is applying detekt from an external build file (say detekt.gradle). We need to investigate why this is happening and try to come up with a solution or a workaround

@cortinico
Copy link
Member

Heyo 👋 I got some time to look into this.

The reason why you're experiencing a java.lang.NoClassDefFoundError: com/android/build/gradle/BaseExtension is that detekt needs a classpath dependency on AGP if used from external build files (i.e. a detekt.gradle or similar).

The reason is that Detekt added support for Android & Multiplatform targets in recent versions. Since we don't want to impose a transitive dependency on AGP, we declared it as a compileOnly dependency. If you use an external script file, you need to specify the dependencies that the other plugins need to run (in our case AGP/KGP).

As a side note, I would like to discourage usage of external build files, for a variety of reasons:

  1. They don't play well with Gradle Kotlin DSL
  2. They force you to add those extra classpath dependencies, hence another version to bump
  3. They are preventing Detekt gradle plugin from working correctly (i.e. you still won't have the detektMain, detektTest and other convenience tasks that we create for Android projects).

Instead please consider using precompiled script plugins. See https://docs.gradle.org/current/userguide/custom_plugins.html#sec:precompiled_plugins

If you don't need the Detekt Android support, you can disable it entirely using the capability offered in #3511

Below you can find the updated the snippet you provided @sigis151. They work correctly for me locally:

top level build.gradle

buildscript {
    repositories {
        google()
        mavenCentral()
    }

    dependencies {
        classpath "com.android.tools.build:gradle:4.2.0"
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.32"
    }
}

allprojects {
    repositories {
        mavenCentral()
        google()
    }
}

app build.gradle

apply from: '../quality.gradle'

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'

android {
    compileSdkVersion = 30
    defaultConfig {
        minSdkVersion 21
        targetSdkVersion 30
        versionCode = 1
        versionName = "1.0"
    }
}

quality.gradle

buildscript {
    repositories {
        gradlePluginPortal()
        google()
    }
    dependencies {
        classpath "com.android.tools.build:gradle:4.2.0"
        classpath "io.gitlab.arturbosch.detekt:detekt-gradle-plugin:1.17.1"
    }
}

apply plugin: io.gitlab.arturbosch.detekt.DetektPlugin

detekt {
    input = files("$projectDir")
    config = files("$projectDir/config/detekt/default-detekt-config.yml")
}

dependencies {
    detektPlugins "io.gitlab.arturbosch.detekt:detekt-formatting:1.17.1"
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants