Skip to content

Instantly share code, notes, and snippets.

@realdadfish
Created January 28, 2021 15:35
Show Gist options
  • Save realdadfish/c9ba6004cdd8efdcdac77eceaa9b99f5 to your computer and use it in GitHub Desktop.
Save realdadfish/c9ba6004cdd8efdcdac77eceaa9b99f5 to your computer and use it in GitHub Desktop.
Leveraging Gradle's ArtifactView
package some.package
import nl.javadude.gradle.plugins.license.DownloadLicensesExtension
import nl.javadude.gradle.plugins.license.DownloadLicensesReportExtension
import org.gradle.api.GradleException
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.artifacts.Configuration
import org.gradle.api.attributes.Attribute
import org.gradle.api.attributes.AttributeCompatibilityRule
import org.gradle.api.attributes.CompatibilityCheckDetails
import org.gradle.kotlin.dsl.apply
import org.gradle.kotlin.dsl.closureOf
import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.dependencies
@Suppress("unused")
class LicenseReportPlugin : Plugin<Project> {
override fun apply(project: Project) {
project.configure(project, closureOf<Project> {
val extension = extensions.create("licenseReport", LicenseReportExtension::class.java)
apply(plugin = "com.github.hierynomus.license-report")
afterEvaluate {
// "dependencyConfiguration" is set to something like "compileClasspath"
val configuration = getPreparedConfiguration(extension.dependencyConfiguration)
val jsonLicenseReport = layout.buildDirectory.dir("license-report")
configure<DownloadLicensesExtension> {
dependencyConfiguration = configuration.name
report(closureOf<DownloadLicensesReportExtension> {
json.enabled = true
json.destination = jsonLicenseReport.get().asFile
xml.enabled = false
html.enabled = false
})
}
tasks.register("createLicenseReport", CreateLicenseReportTask::class.java) {
description = "Creates a custom HTML license report of our runtime dependencies"
group = "license"
dependsOn("downloadLicenses")
knownLicenses.set(extension.knownLicenses)
outputHtml.set(extension.htmlLicenseReport)
licenseReport.set(jsonLicenseReport.map { it.file(DEPENDENCY_LICENSE_REPORT) })
doLast {
logger.lifecycle("HTML report saved to {}", extension.htmlLicenseReport.asFile.get())
}
}
}
})
}
private fun Project.getPreparedConfiguration(configurationName: String): Configuration {
val configuration = configurations.findByName(configurationName)
?: throw GradleException("Dependency configuration $configurationName not found in project $name")
val artifactType = Attribute.of("artifactType", String::class.java)
// The licenses plugin can only work with configurations, while AGP has the newer "artifact view"
// paradigm implemented. This makes it impossible to resolve most of the created, variant-aware
// configurations from AGP "by hand" without getting unmatched attribute exceptions.
// We now pick one artifact that holds our dependencies and add a custom compatibility rule
// for it which basically accepts all incoming compatibility issues as long as the produced value
// on "the other side" is a JAR or AAR artifact.
configuration.attributes {
attribute(artifactType, ARTIFACT_TYPE)
}
dependencies {
attributesSchema {
getMatchingStrategy(artifactType).compatibilityRules.add(AgpAttributeCompatibility::class.java)
}
}
return configuration
}
private class AgpAttributeCompatibility : AttributeCompatibilityRule<String> {
override fun execute(details: CompatibilityCheckDetails<String>) {
if (details.consumerValue == ARTIFACT_TYPE) {
when (details.producerValue) {
"aar",
"jar" -> details.compatible()
}
}
}
}
companion object {
private const val DEPENDENCY_LICENSE_REPORT = "dependency-license.json"
private const val ARTIFACT_TYPE = "android-classes-directory"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment