Skip to content

Commit

Permalink
AndroidLibrarySupport: Add Java Android library support
Browse files Browse the repository at this point in the history
Fixes: #94
  • Loading branch information
realbarisbasturk authored and qwwdfsad committed Oct 20, 2022
1 parent 0a88ad6 commit 6f1ceb4
Show file tree
Hide file tree
Showing 5 changed files with 138 additions and 3 deletions.
12 changes: 12 additions & 0 deletions src/functionalTest/kotlin/kotlinx/validation/api/TestDsl.kt
Expand Up @@ -47,6 +47,18 @@ internal fun FileContainer.kotlin(classFileName: String, sourceSet:String = "mai
file(fileName, fn)
}

/**
* same as [file][FileContainer.file], but prepends "src/${sourceSet}/java" before given `classFileName`
*/
internal fun FileContainer.java(classFileName: String, sourceSet:String = "main", fn: AppendableScope.() -> Unit) {
require(classFileName.endsWith(".java")) {
"ClassFileName must end with '.java'"
}

val fileName = "src/${sourceSet}/java/$classFileName"
file(fileName, fn)
}

/**
* Shortcut for creating a `build.gradle.kts` by using [file][FileContainer.file]
*/
Expand Down
Expand Up @@ -44,7 +44,32 @@ internal class AndroidLibraryTest : BaseKotlinGradleTest() {

//region Java Android Library

// TODO #94 Java Android Library functional test cases
@Test
fun `Given a Java Android Library, when api is dumped, then task should be successful`() {
val runner = test {
createProjectWithSubModules()
runner {
arguments.add(":java-library:apiDump")
arguments.add("--full-stacktrace")
}
}

runner.build().apply {
assertTaskSuccess(":java-library:apiDump")
}
}

@Test
fun `Given a Java Android Library, when api is checked, then it should match the expected`() {
test {
createProjectWithSubModules()
runner {
arguments.add(":java-library:apiCheck")
}
}.build().apply {
assertTaskSuccess(":java-library:apiCheck")
}
}

//endregion

Expand Down Expand Up @@ -76,7 +101,12 @@ internal class AndroidLibraryTest : BaseKotlinGradleTest() {
buildGradleKts {
resolve("examples/gradle/base/androidJavaLibrary.gradle.kts")
}
// TODO #94 Add sample Java class and expected api dump file
java("JavaLib.java") {
resolve("examples/classes/JavaLib.java")
}
apiFile(projectName = "java-library") {
resolve("examples/classes/JavaLib.dump")
}
}
}

Expand Down
12 changes: 12 additions & 0 deletions src/functionalTest/resources/examples/classes/JavaLib.dump
@@ -0,0 +1,12 @@
public final class examples/classes/JavaLib {
public fun <init> ()V
public fun foo ()Ljava/lang/String;
}

public final class org/jetbrains/kotlinx/android/java/library/BuildConfig {
public static final field BUILD_TYPE Ljava/lang/String;
public static final field DEBUG Z
public static final field LIBRARY_PACKAGE_NAME Ljava/lang/String;
public fun <init> ()V
}

18 changes: 18 additions & 0 deletions src/functionalTest/resources/examples/classes/JavaLib.java
@@ -0,0 +1,18 @@
/*
* Copyright 2016-2022 JetBrains s.r.o.
* Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file.
*/

package examples.classes;

public final class JavaLib {

public String foo() {
return "foo";
}

private String bar() {
return "bar";
}

}
65 changes: 64 additions & 1 deletion src/main/kotlin/BinaryCompatibilityValidatorPlugin.kt
Expand Up @@ -5,10 +5,12 @@

package kotlinx.validation

import com.android.build.gradle.LibraryExtension
import org.gradle.api.*
import org.gradle.api.plugins.*
import org.gradle.api.provider.*
import org.gradle.api.tasks.*
import org.gradle.api.tasks.compile.JavaCompile
import org.jetbrains.kotlin.gradle.dsl.*
import org.jetbrains.kotlin.gradle.plugin.*
import java.io.*
Expand Down Expand Up @@ -108,15 +110,43 @@ class BinaryCompatibilityValidatorPlugin : Plugin<Project> {
private fun configureAndroidPlugin(
project: Project,
extension: ApiValidationExtension
) {
val kotlinPluginPresent = project.plugins
.withType(KotlinAndroidPluginWrapper::class.java)
.isEmpty().not()

if (kotlinPluginPresent) {
configureAndroidPluginForKotlinLibrary(project, extension)
} else {
configureAndroidPluginForJavaLibrary(project, extension)
}
}

private fun configureAndroidPluginForKotlinLibrary(
project: Project,
extension: ApiValidationExtension
) = configurePlugin("kotlin-android", project, extension) {
val androidExtension = project.extensions.getByName("kotlin") as KotlinAndroidProjectExtension
val androidExtension = project.extensions
.getByName("kotlin") as KotlinAndroidProjectExtension
androidExtension.target.compilations.matching {
it.compilationName == "release"
}.all {
project.configureKotlinCompilation(it, extension, useOutput = true)
}
}

private fun configureAndroidPluginForJavaLibrary(
project: Project,
extension: ApiValidationExtension
) = configurePlugin("com.android.library", project, extension) {
val androidExtension = project.extensions.getByType(LibraryExtension::class.java)
androidExtension.libraryVariants.matching {
it.name == "release"
}.all {
project.configureJavaCompilation(it.javaCompileProvider, extension)
}
}

private fun configureKotlinPlugin(
project: Project,
extension: ApiValidationExtension
Expand Down Expand Up @@ -212,6 +242,39 @@ internal val Project.apiValidationExtensionOrNull: ApiValidationExtension?
.map { it.extensions.findByType(ApiValidationExtension::class.java) }
.firstOrNull { it != null }

private fun Project.configureJavaCompilation(
configurableFileCollection: TaskProvider<JavaCompile>,
extension: ApiValidationExtension,
targetConfig: TargetConfig = TargetConfig(this),
) {
val projectName = project.name
val apiDirProvider = targetConfig.apiDir
val apiBuildDir = apiDirProvider.map { buildDir.resolve(it) }

val apiBuild = task<KotlinApiBuildTask>(targetConfig.apiTaskName("Build"), extension) {
isEnabled = apiCheckEnabled(projectName, extension)
// 'group' is not specified deliberately, so it will be hidden from ./gradlew tasks
description = "Builds Java API for 'main' compilations of $projectName. " +
"Complementary task and shouldn't be called manually"
inputClassesDirs = files(provider<Any> {
if (isEnabled) configurableFileCollection.get().outputs.files
else emptyList<Any>()
})
inputDependencies = files(provider<Any> {
if (isEnabled) configurableFileCollection.get().outputs.files
else emptyList<Any>()
})
outputApiDir = apiBuildDir.get()
}

configureCheckTasks(
apiBuildDir,
apiBuild,
extension,
targetConfig
)
}

fun apiCheckEnabled(projectName: String, extension: ApiValidationExtension): Boolean =
projectName !in extension.ignoredProjects && !extension.validationDisabled

Expand Down

0 comments on commit 6f1ceb4

Please sign in to comment.