blob: e6a9c3398848bbe894d1da10b28e1bb5d27d848e [file] [log] [blame] [edit]
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Integration test project that analyzes an external dependency: see libraryToRunAgainst.
// Set INTEGRATION=true to enable.
import com.android.build.api.attributes.BuildTypeAttr
plugins {
id("com.android.library") // needed for bootClasspath and AAR transforms to work
}
repositories {
google()
mavenCentral()
}
// Create two configurations used in dependencies {} block.
val runner: Configuration by configurations.creating
val libraryToRunAgainst: Configuration by configurations.creating {
isCanBeResolved = false
isCanBeConsumed = false
}
dependencies {
libraryToRunAgainst("androidx.compose.foundation:foundation:1.4.3")
runner(project(":metalava"))
}
android { // minimal set up to make com.android.library plugin work
compileSdkVersion = "android-33"
namespace = "com.android.tools.metalava.integration"
}
/**
* Configuration used to resolve source jars for projects in libraryToRunAgainst
*/
val sources: Configuration by configurations.creating {
extendsFrom(libraryToRunAgainst)
attributes {
attribute(Usage.USAGE_ATTRIBUTE, project.objects.named(Usage.JAVA_RUNTIME))
attribute(Category.CATEGORY_ATTRIBUTE, project.objects.named(Category.DOCUMENTATION))
attribute(DocsType.DOCS_TYPE_ATTRIBUTE, project.objects.named(DocsType.SOURCES))
attribute(
LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE,
project.objects.named(LibraryElements.JAR)
)
}
}
fun Configuration.setResolveClasspathForUsage(usage: String) {
isCanBeConsumed = false
attributes {
attribute(Usage.USAGE_ATTRIBUTE, project.objects.named<Usage>(usage))
attribute(Category.CATEGORY_ATTRIBUTE, project.objects.named<Category>(Category.LIBRARY))
attribute(BuildTypeAttr.ATTRIBUTE, project.objects.named<BuildTypeAttr>("release"))
}
extendsFrom(sources)
}
/**
* Configuration used to resolve compile classpath for projects in libraryToRunAgainst
*/
val sourcesCompileClasspath: Configuration by configurations.creating {
setResolveClasspathForUsage(Usage.JAVA_API)
}
/**
* Configuration used to resolve runtime classpath for projects in libraryToRunAgainst
*/
val sourcesRuntimeClasspath: Configuration by configurations.creating {
setResolveClasspathForUsage(Usage.JAVA_RUNTIME)
}
/**
* Full classpath of all the dependencies needed to analyze projects in libraryToRunAgainst
* This includes android.jar, compile and runtime jars
*/
val sourceDependencyClasspath: FileCollection = files(android.bootClasspath) +
sourcesCompileClasspath.incoming.artifactView {
attributes {
attribute(Attribute.of("artifactType", String::class.java), "android-classes")
}
}.files + sourcesRuntimeClasspath.incoming.artifactView {
attributes {
attribute(Attribute.of("artifactType", String::class.java), "android-classes")
}
}.files
@CacheableTask
abstract class MetalavaRunner : DefaultTask() {
@get:Inject
abstract val execOperations: ExecOperations
@get:[InputFiles PathSensitive(PathSensitivity.NONE)]
abstract var sources: File
@get:[InputFile PathSensitive(PathSensitivity.NONE)]
abstract val apiLintBaseline: RegularFileProperty
@get:Classpath
abstract val dependencyClasspath: ConfigurableFileCollection
@get:Classpath
abstract val metalavaClasspath: ConfigurableFileCollection
@get:OutputFile
abstract val signatureFile: RegularFileProperty
@TaskAction
fun doThings() {
// An approximation of AndroidX usage of metalava for tracking public
// api surface of a library and running API lint against it.
execOperations.javaexec {
mainClass.set("com.android.tools.metalava.Driver")
classpath = metalavaClasspath
args = listOf(
"--source-path",
sources.absolutePath,
"--api",
signatureFile.get().asFile.absolutePath,
"--classpath",
dependencyClasspath.files.joinToString(File.pathSeparator),
"--hide-annotation",
"androidx.annotation.RestrictTo",
"--show-unannotated",
"--api-lint",
"--baseline",
apiLintBaseline.get().asFile.absolutePath,
"--hide",
listOf(
"Enum",
"StartWithLower",
"MissingJvmstatic",
"ArrayReturn",
"UserHandleName",
).joinToString(),
)
}
}
}
interface Injected {
@get:Inject val archiveOperations: ArchiveOperations
}
/**
* A task that will extract all of the source jars that are added to libraryToRunAgainst
* configuration.
*/
val copyInputSources = tasks.register<Sync>("copyInputSources") {
// Store archiveOperations into a local variable to prevent access to project object
// during the task execution, as that breaks configuration caching.
val archiveOperations = project.objects.newInstance<Injected>().archiveOperations
from(
sources.incoming.artifactView { }.files.elements.map { jars ->
jars.map { jar ->
archiveOperations.zipTree(jar)
}
}
)
into(layout.buildDirectory.dir("inputSources"))
}
tasks.register<MetalavaRunner>("run") {
dependsOn(copyInputSources)
sources = copyInputSources.get().destinationDir
dependencyClasspath.from(sourceDependencyClasspath)
metalavaClasspath.from(runner)
signatureFile.set(layout.buildDirectory.file("current.txt"))
apiLintBaseline.set(layout.projectDirectory.file("api_lint.ignore"))
outputs.upToDateWhen { false }
}