adamko-dev / dokkatoo

Generates documentation for Kotlin Gradle projects (based on Dokka)
https://adamko-dev.github.io/dokkatoo/
Apache License 2.0
71 stars 7 forks source link

Error: "Could not determine the dependencies of task ':<project>:dokkatooGenerateModuleHtml'." #122

Open EdricChan03 opened 1 year ago

EdricChan03 commented 1 year ago

I'm trying to add Dokkatoo generation to this Android project (see the feat/dokkatoo branch of my fork). However, running the :dokkatooGeneratePublicationHtml task results in the following Gradle error:

Expand to view error

``` Could not determine the dependencies of task ':material3:dokkatooGenerateModuleHtml'. > Could not resolve all task dependencies for configuration ':material3:releaseCompileClasspath'. > The consumer was configured to find a component for use during compile-time, preferably optimized for Android, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'release', attribute 'com.android.build.api.attributes.AgpVersionAttr' with value '8.1.1', attribute 'org.jetbrains.kotlin.platform.type' with value 'androidJvm'. However we cannot choose between the following variants of project :core: - Configuration ':core:releaseApiElements' variant android-classes-jar declares a component for use during compile-time, preferably optimized for Android, as well as attribute 'com.android.build.api.attributes.AgpVersionAttr' with value '8.1.1', attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'release', attribute 'org.jetbrains.kotlin.platform.type' with value 'androidJvm': - Unmatched attributes: - Provides attribute 'artifactType' with value 'android-classes-jar' but the consumer didn't ask for it - Provides attribute 'com.android.build.gradle.internal.attributes.VariantAttr' with value 'release' but the consumer didn't ask for it - Provides a library but the consumer didn't ask for it - Provides its elements packaged as a jar but the consumer didn't ask for it - Configuration ':core:releaseApiElements' variant android-lint declares a component for use during compile-time, preferably optimized for Android, as well as attribute 'com.android.build.api.attributes.AgpVersionAttr' with value '8.1.1', attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'release', attribute 'org.jetbrains.kotlin.platform.type' with value 'androidJvm': - Unmatched attributes: - Provides attribute 'artifactType' with value 'android-lint' but the consumer didn't ask for it - Provides attribute 'com.android.build.gradle.internal.attributes.VariantAttr' with value 'release' but the consumer didn't ask for it - Provides a library but the consumer didn't ask for it - Provides its elements packaged as a jar but the consumer didn't ask for it - Configuration ':core:releaseApiElements' variant android-lint-local-aar declares a component for use during compile-time, preferably optimized for Android, as well as attribute 'com.android.build.api.attributes.AgpVersionAttr' with value '8.1.1', attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'release', attribute 'org.jetbrains.kotlin.platform.type' with value 'androidJvm': - Unmatched attributes: - Provides attribute 'artifactType' with value 'android-lint-local-aar' but the consumer didn't ask for it - Provides attribute 'com.android.build.gradle.internal.attributes.VariantAttr' with value 'release' but the consumer didn't ask for it - Provides a library but the consumer didn't ask for it - Configuration ':core:releaseApiElements' variant android-lint-model-metadata declares a component for use during compile-time, preferably optimized for Android, as well as attribute 'com.android.build.api.attributes.AgpVersionAttr' with value '8.1.1', attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'release', attribute 'org.jetbrains.kotlin.platform.type' with value 'androidJvm': - Unmatched attributes: - Provides attribute 'artifactType' with value 'android-lint-model-metadata' but the consumer didn't ask for it - Provides attribute 'com.android.build.gradle.internal.attributes.VariantAttr' with value 'release' but the consumer didn't ask for it - Provides a library but the consumer didn't ask for it - Configuration ':core:releaseApiElements' variant android-lint-variant-dependencies-model declares a component for use during compile-time, preferably optimized for Android, as well as attribute 'com.android.build.api.attributes.AgpVersionAttr' with value '8.1.1', attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'release', attribute 'org.jetbrains.kotlin.platform.type' with value 'androidJvm': - Unmatched attributes: - Provides attribute 'artifactType' with value 'android-lint-variant-dependencies-model' but the consumer didn't ask for it - Provides attribute 'com.android.build.gradle.internal.attributes.VariantAttr' with value 'release' but the consumer didn't ask for it - Provides a library but the consumer didn't ask for it - Configuration ':core:releaseApiElements' variant android-lint-variant-dependencies-partial-results declares a component for use during compile-time, preferably optimized for Android, as well as attribute 'com.android.build.api.attributes.AgpVersionAttr' with value '8.1.1', attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'release', attribute 'org.jetbrains.kotlin.platform.type' with value 'androidJvm': - Unmatched attributes: - Provides attribute 'artifactType' with value 'android-lint-variant-dependencies-partial-results' but the consumer didn't ask for it - Provides attribute 'com.android.build.gradle.internal.attributes.VariantAttr' with value 'release' but the consumer didn't ask for it - Provides a library but the consumer didn't ask for it - Configuration ':core:releaseApiElements' variant android-manifest declares a component for use during compile-time, preferably optimized for Android, as well as attribute 'com.android.build.api.attributes.AgpVersionAttr' with value '8.1.1', attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'release', attribute 'org.jetbrains.kotlin.platform.type' with value 'androidJvm': - Unmatched attributes: - Provides attribute 'artifactType' with value 'android-manifest' but the consumer didn't ask for it - Provides attribute 'com.android.build.gradle.internal.attributes.VariantAttr' with value 'release' but the consumer didn't ask for it - Provides a library but the consumer didn't ask for it - Configuration ':core:releaseApiElements' variant android-renderscript declares a component for use during compile-time, preferably optimized for Android, as well as attribute 'com.android.build.api.attributes.AgpVersionAttr' with value '8.1.1', attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'release', attribute 'org.jetbrains.kotlin.platform.type' with value 'androidJvm': - Unmatched attributes: - Provides attribute 'artifactType' with value 'android-renderscript' but the consumer didn't ask for it - Provides attribute 'com.android.build.gradle.internal.attributes.VariantAttr' with value 'release' but the consumer didn't ask for it - Provides a library but the consumer didn't ask for it - Configuration ':core:releaseApiElements' variant android-symbol-with-package-name declares a component for use during compile-time, preferably optimized for Android, as well as attribute 'com.android.build.api.attributes.AgpVersionAttr' with value '8.1.1', attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'release', attribute 'org.jetbrains.kotlin.platform.type' with value 'androidJvm': - Unmatched attributes: - Provides attribute 'artifactType' with value 'android-symbol-with-package-name' but the consumer didn't ask for it - Provides attribute 'com.android.build.gradle.internal.attributes.VariantAttr' with value 'release' but the consumer didn't ask for it - Provides a library but the consumer didn't ask for it - Configuration ':core:releaseApiElements' variant jar declares a component for use during compile-time, preferably optimized for Android, as well as attribute 'com.android.build.api.attributes.AgpVersionAttr' with value '8.1.1', attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'release', attribute 'org.jetbrains.kotlin.platform.type' with value 'androidJvm': - Unmatched attributes: - Provides attribute 'artifactType' with value 'jar' but the consumer didn't ask for it - Provides attribute 'com.android.build.gradle.internal.attributes.VariantAttr' with value 'release' but the consumer didn't ask for it - Provides a library but the consumer didn't ask for it - Provides its elements packaged as a jar but the consumer didn't ask for it ```

(I've also experienced this issue with another project that is yet to be synced)

The version of Dokkatoo used is 2.0.0. Here's a Gradle Build Scan if necessary

aSemy commented 10 months ago

Thanks for the report, and the example project. I've checked it out and I can reproduce the problem. I think it's something to do with the :material3 subproject having a library variant.

// material3/build.gradle.kts

// ...

kotlin {
    // ...

    androidTarget {
        publishLibraryVariants("release")
    }
}

I suspect the fix will be setting 'artifactType' to 'jar' somewhere in DokkatooAndroidAdapter, but I'm not sure where. I'll try experimenting, but I'm not an Android developer so help would be appreciated!

aSemy commented 10 months ago

I think this is a Gradle bug https://github.com/gradle/gradle/issues/27265. For some reason Gradle forgets about the 'artifactType' being set to 'jar'.

MirzaUkas commented 9 months ago

Hi, any update on this issue? currently, I have a custom build variant in my library modules.

aSemy commented 9 months ago

hi @MirzaUkas - I don't have any updates.

Dokkatoo needs to get all of the compile-time dependencies of a project. For Android project here's the code that does it:

https://github.com/adamko-dev/dokkatoo/blob/87679993a6504e16a8fabd6836471cdafd467bdf/modules/dokkatoo-plugin/src/main/kotlin/adapters/DokkatooAndroidAdapter.kt#L169-L213

However Gradle seems to get confused and it can't discriminate between all the different options. It also ignores lenient(true) which is supposed to ignore these errors.

I'd be grateful if you could take a look! Maybe Dokkatoo isn't using the Gradle API correctly. And I'm not an Android developer, so maybe there's a better way to fetch the dependencies?

As a workaround, maybe I could disable this bit of code, or catch & log the error. But that would probably result in Error class: unknown class appearing in the generated docs.

aSemy commented 9 months ago

I've done a little bit more digging!

There are apparently two problems:

  1. the Could not determine the dependencies of task ':dokkatooGenerateModuleHtml' error is triggered in DokkatooKotlinAdapter, not in DokkatooAndroidAdapter as I thought!

    https://github.com/adamko-dev/dokkatoo/blob/80cc32cff60cecfa5ad915de1244b6c3a3879f0c/modules/dokkatoo-plugin/src/main/kotlin/adapters/DokkatooKotlinAdapter.kt#L299-L300

    If I comment out compilation.compileDependencyFiles then generation succeeds (but of course the docs contains Error class: unknown class)

  2. DokkatooAndroidAdapter isn't fetching all JARs. This is where my lack of Android knowledge will show. How can I fetch all the JARs/Classes used to compile an Android source set? What's the difference between an AAR and a JAR?

EdricChan03 commented 9 months ago

What's the difference between an AAR and a JAR?

An AAR provides additional resources (strings/dimensions/string arrays/etc, styles, layouts, drawables, etc), any additional manifest declarations (e.g. a library might want to declare a runtime permission, which can then be added into the library's AndroidManifest.xml file to be merged into the resulting Android application), and other Android-specific stuff I might not be aware of.

How can I fetch all the JARs/Classes used to compile an Android source set?

I think this might be possible if you hook into the AndroidComponentsExtension (or its variants, e.g. LibraryAndroidComponentsExtension for modules that apply com.android.library, ApplicationAndroidComponentsExtension for modules that apply com.android.application) that Google provides as part of AGP, where you can access lazy configuration-compatible properties/providers via the onVariants DSL? (Further up they also define the other build points) They have a section in the docs on hooking up to the artifacts that AGP would produce. Personally, I'm not certain if you can actually access the data though, but hope that helps

aSemy commented 9 months ago

Thanks @EdricChan03! The AARs don't sound relevant for Dokka so I can leave them out.

I think accessing the compilation of an Android project works fine at the moment. The bigger problem is getting the compile-time dependencies as JARs with Java classes.

Looking at your example project, I can see in TopAppBarMenuItems the Modifier class. In IntelliJ I can ctrl+click on that class and then see where it comes from

image

/Users/me/.local/state/gradle/caches/transforms-3/78818b83fcc8d01bda1c8f99abed49cb/transformed/ui-release/jars/classes.jar

The question is how do I get that file...

As a very quick and hacky example, if you copy this into the project's build.gradle.kts, this roughly shows what Dokkatoo is doing to fetch the compile-time classpath for Kotlin projects.

afterEvaluate {
  val kotlinCompileDependencyFiles =
    kotlin.targets.flatMap { target ->
      target.compilations.flatMap { compilation ->
        configurations.named(compilation.compileDependencyConfigurationName)
          .map {
            it.incoming
              .artifactView {
//            lenient(true)
                attributes {
                  attribute(Attribute.of("artifactType", String::class.java), "jar")
                }
              }
              .artifacts
              .artifactFiles
          }
          .get()
      }
    }
  println(kotlinCompileDependencyFiles.joinToString("\n") { " - ${it.name}" })
}

which prints


 - kotlin-stdlib-jdk8-1.9.10.jar
 - kotlin-stdlib-jdk7-1.9.10.jar
 - kotlin-stdlib-1.9.10.jar
 - annotations-13.0.jar
 - kotlin-stdlib-jdk8-1.9.10.jar
 - kotlin-stdlib-jdk7-1.9.10.jar
 - kotlin-stdlib-1.9.10.jar
 - annotations-13.0.jar
 - kotlin-stdlib-jdk8-1.9.10.jar
 - kotlin-stdlib-jdk7-1.9.10.jar
 - kotlin-stdlib-1.9.10.jar
 - annotations-13.0.jar
 - kotlin-stdlib-jdk8-1.9.10.jar
 - kotlin-stdlib-jdk7-1.9.10.jar
 - kotlin-stdlib-1.9.10.jar
 - annotations-13.0.jar
 - kotlin-stdlib-jdk8-1.9.10.jar
 - kotlin-stdlib-jdk7-1.9.10.jar
 - kotlin-stdlib-1.9.10.jar
 - annotations-13.0.jar
 - core-metadata-1.0.jar
 - material3-metadata-1.5.3.jar
 - material-ripple-metadata-1.5.3.jar
 - foundation-metadata-1.5.3.jar
 - animation-metadata-1.5.3.jar
 - animation-core-metadata-1.5.3.jar
 - foundation-layout-metadata-1.5.3.jar
 - material-icons-core-metadata-1.5.3.jar
 - ui-metadata-1.5.3.jar
 - ui-text-metadata-1.5.3.jar
 - ui-graphics-metadata-1.5.3.jar
 - ui-unit-metadata-1.5.3.jar
 - runtime-saveable-metadata-1.5.3.jar
 - ui-geometry-metadata-1.5.3.jar
 - runtime-metadata-1.5.3.jar
 - ui-util-metadata-1.5.3.jar
 - kotlinx-datetime-metadata-0.4.0-all.jar
 - skiko-metadata-0.7.77.jar
 - kotlinx-coroutines-core-metadata-1.6.4-all.jar
 - kotlinx-serialization-core-metadata-1.3.2-all.jar
 - atomicfu-metadata-0.17.3-all.jar
 - kotlin-stdlib-1.8.20.jar
 - kotlin-stdlib-common-1.9.10.jar
 - annotations-13.0.jar

And for some reason it's missing ui-android.

aSemy commented 9 months ago

androidComponents.onVariants {} doesn't seem to help either...

Copy this into an Android project's build.gradle.kts and run gradle logAndroidComponentsCompileClasspath

// build.gradle.kts

/** Aggregate compile classpath from all Android components */
val androidComponentsCompileClasspath = objects.fileCollection()

androidComponents {
  onVariants { variant ->

    fun collect(artifactType: String) {
      val artifactTypeFiles = variant.compileConfiguration.incoming
        .artifactView {
          attributes {
            attribute(
              Attribute.of("artifactType", String::class.java),
              artifactType,
            )
          }
//          withVariantReselection()
//          lenient(true)
        }
        .artifacts
        .resolvedArtifacts
        .map { artifacts -> artifacts.map(ResolvedArtifactResult::getFile) }

      androidComponentsCompileClasspath.from(artifactTypeFiles)
    }

    collect("android-classes-jar")
    collect("android-lint")
    collect("android-lint-local-aar")
    collect("android-manifest")
    collect("android-renderscript")
    collect("android-symbol-with-package-name")
    collect("jar")
    collect("r-class-jar")
  }
}

val logAndroidComponentsCompileClasspath by tasks.registering {
  group = project.name
  val cc = androidComponentsCompileClasspath
  inputs.files(cc).withPropertyName("cc")
  doLast {
    println(cc.joinToString("\n") { " - ${it.invariantSeparatorsPath}" })
  }
}

 - […]/compose-menuprovider-example/core/build/intermediates/compile_library_classes_jar/debug/classes.jar
 - […]/transformed/material3-1.1.1-api.jar
 - […]/transformed/material-icons-core-1.4.1-api.jar
 - […]/transformed/material-ripple-1.4.1-api.jar
 - […]/transformed/animation-core-release-api.jar
 - […]/transformed/animation-release-api.jar
 - […]/transformed/foundation-layout-release-api.jar
 - […]/transformed/foundation-release-api.jar
 - […]/transformed/ui-unit-release-api.jar
 - […]/transformed/ui-geometry-release-api.jar
 - […]/transformed/ui-text-release-api.jar
 - […]/transformed/ui-graphics-release-api.jar
 - […]/transformed/ui-release-api.jar
 - […]/transformed/runtime-saveable-release-api.jar
 - […]/transformed/runtime-release-api.jar
 - […]gradle/caches/[…]/kotlinx-coroutines-core-jvm-1.6.4.jar
 - […]gradle/caches/[…]/kotlinx-coroutines-android-1.6.4.jar
 - […]gradle/caches/[…]/kotlin-stdlib-jdk8-1.9.10.jar
 - […]gradle/caches/[…]/kotlin-stdlib-jdk7-1.9.10.jar
 - […]gradle/caches/[…]/annotation-jvm-1.6.0.jar
 - […]gradle/caches/[…]/kotlin-stdlib-1.9.10.jar
 - […]gradle/caches/[…]/annotations-13.0.jar
 - […]/compose-menuprovider-example/core/build/intermediates/lint_publish_jar/global/lint.jar
 - […]/transformed/material3-1.1.1/jars/lint.jar
 - […]/transformed/animation-core-release/jars/lint.jar
 - […]/transformed/animation-release/jars/lint.jar
 - […]/transformed/foundation-release/jars/lint.jar
 - […]/transformed/ui-graphics-release/jars/lint.jar
 - […]/transformed/ui-release/jars/lint.jar
 - […]/transformed/runtime-saveable-release/jars/lint.jar
 - […]/transformed/runtime-release/jars/lint.jar
 - […]/compose-menuprovider-example/core/build/intermediates/local_aar_for_lint/debug/out.aar
 - […]/compose-menuprovider-example/core/build/intermediates/merged_manifest/debug/AndroidManifest.xml
 - […]/transformed/material3-1.1.1/AndroidManifest.xml
 - […]/transformed/material-icons-core-1.4.1/AndroidManifest.xml
 - […]/transformed/material-ripple-1.4.1/AndroidManifest.xml
 - […]/transformed/animation-core-release/AndroidManifest.xml
 - […]/transformed/animation-release/AndroidManifest.xml
 - […]/transformed/foundation-layout-release/AndroidManifest.xml
 - […]/transformed/foundation-release/AndroidManifest.xml
 - […]/transformed/ui-unit-release/AndroidManifest.xml
 - […]/transformed/ui-geometry-release/AndroidManifest.xml
 - […]/transformed/ui-text-release/AndroidManifest.xml
 - […]/transformed/ui-graphics-release/AndroidManifest.xml
 - […]/transformed/ui-release/AndroidManifest.xml
 - […]/transformed/runtime-saveable-release/AndroidManifest.xml
 - […]/transformed/runtime-release/AndroidManifest.xml
 - […]/compose-menuprovider-example/core/build/intermediates/renderscript_headers/debug/out
 - […]/compose-menuprovider-example/core/build/intermediates/symbol_list_with_package_name/debug/package-aware-r.txt
 - […]/transformed/androidx.compose.material3-r.txt
 - […]/transformed/androidx.compose.material.icons-r.txt
 - […]/transformed/androidx.compose.material.ripple-r.txt
 - […]/transformed/androidx.compose.animation.core-r.txt
 - […]/transformed/androidx.compose.animation-r.txt
 - […]/transformed/androidx.compose.foundation.layout-r.txt
 - […]/transformed/androidx.compose.foundation-r.txt
 - […]/transformed/androidx.compose.ui.unit-r.txt
 - […]/transformed/androidx.compose.ui.geometry-r.txt
 - […]/transformed/androidx.compose.ui.text-r.txt
 - […]/transformed/androidx.compose.ui.graphics-r.txt
 - […]/transformed/androidx.compose.ui-r.txt
 - […]/transformed/androidx.compose.runtime.saveable-r.txt
 - […]/transformed/androidx.compose.runtime-r.txt
 - […]/compose-menuprovider-example/core/build/intermediates/full_jar/debug/full.jar
 - […]/transformed/material3-1.1.1/jars/classes.jar
 - […]/transformed/material-icons-core-1.4.1/jars/classes.jar
 - […]/transformed/material-ripple-1.4.1/jars/classes.jar
 - […]/transformed/animation-core-release/jars/classes.jar
 - […]/transformed/animation-release/jars/classes.jar
 - […]/transformed/foundation-layout-release/jars/classes.jar
 - […]/transformed/foundation-release/jars/classes.jar
 - […]/transformed/ui-unit-release/jars/classes.jar
 - […]/transformed/ui-geometry-release/jars/classes.jar
 - […]/transformed/ui-text-release/jars/classes.jar
 - […]/transformed/ui-graphics-release/jars/classes.jar
 - […]/transformed/ui-release/jars/classes.jar
 - […]/transformed/runtime-saveable-release/jars/classes.jar
 - […]/transformed/runtime-release/jars/classes.jar
 - […]/compose-menuprovider-example/core/build/intermediates/compile_r_class_jar/debug/R.jar
 - […]/compose-menuprovider-example/core/build/intermediates/compile_library_classes_jar/release/classes.jar
 - […]/compose-menuprovider-example/core/build/intermediates/local_aar_for_lint/release/out.aar
 - […]/compose-menuprovider-example/core/build/intermediates/merged_manifest/release/AndroidManifest.xml
 - […]/compose-menuprovider-example/core/build/intermediates/renderscript_headers/release/out
 - […]/compose-menuprovider-example/core/build/intermediates/symbol_list_with_package_name/release/package-aware-r.txt
 - […]/compose-menuprovider-example/core/build/intermediates/full_jar/release/full.jar
 - […]/compose-menuprovider-example/core/build/intermediates/compile_r_class_jar/release/R.jar
aSemy commented 8 months ago

I have a lead: transformed/ui-release/jars/classes.jar above does contain the required classes! However, it's not being passed to Dokka. In fact I only see one classes.jar being passed to Dokka. Maybe jars with duplicate names are being de-duplicated somewhere?

aSemy commented 8 months ago

hi @EdricChan03 and @MirzaUkas, I've made some adjustments to how Dokkatoo handles Android projects in #150. Could you check the 2.1.0-SNAPSHOT to see if it helps?

You'll have to add Maven Central snapshots as a plugin repo:

repositories {
  // add Maven Central snapshot repository
  maven("https://s01.oss.sonatype.org/content/repositories/snapshots/") {
    name = "MavenCentralSnapshots"
    mavenContent { snapshotsOnly() }
  }
}

I expect that you won't receive an error about Gradle resolution, however you might see 'unknown class' in the rendered docs.

MirzaUkas commented 8 months ago

Hi, after upgrading to 2.1.0 I don't get this issue again. I can run dokkatooGeneratePublicationHtml with multivariant module/library. Thank you @aSemy

aSemy commented 8 months ago

That's wonderful to hear, thanks for the update @MirzaUkas!