Skip to content

Commit

Permalink
Merge branch 'develop' into gh-pages
Browse files Browse the repository at this point in the history
  • Loading branch information
fzhinkin committed Apr 4, 2024
2 parents ea29a29 + f8e3ded commit 50f3340
Show file tree
Hide file tree
Showing 10 changed files with 205 additions and 10 deletions.
7 changes: 7 additions & 0 deletions src/functionalTest/kotlin/kotlinx/validation/api/Assert.kt
Expand Up @@ -31,6 +31,13 @@ internal fun BuildResult.assertTaskSkipped(task: String) {
assertTaskOutcome(TaskOutcome.SKIPPED, task)
}

/**
* Helper `fun` for asserting a [TaskOutcome] to be equal to [TaskOutcome.UP_TO_DATE]
*/
internal fun BuildResult.assertTaskUpToDate(task: String) {
assertTaskOutcome(TaskOutcome.UP_TO_DATE, task)
}

private fun BuildResult.assertTaskOutcome(taskOutcome: TaskOutcome, taskName: String) {
assertEquals(taskOutcome, task(taskName)?.outcome)
}
Expand Down
8 changes: 4 additions & 4 deletions src/functionalTest/kotlin/kotlinx/validation/api/TestDsl.kt
Expand Up @@ -148,8 +148,8 @@ internal fun FileContainer.emptyApiFile(projectName: String) {
apiFile(projectName) {}
}

internal fun BaseKotlinScope.runner(fn: Runner.() -> Unit) {
val runner = Runner()
internal fun BaseKotlinScope.runner(withConfigurationCache: Boolean = true, fn: Runner.() -> Unit) {
val runner = Runner(withConfigurationCache)
fn(runner)

this.runner = runner
Expand Down Expand Up @@ -188,9 +188,9 @@ internal class AppendableScope(val filePath: String) {
val files: MutableList<String> = mutableListOf()
}

internal class Runner {
internal class Runner(withConfigurationCache: Boolean = true) {
val arguments: MutableList<String> = mutableListOf<String>().apply {
if (!koverEnabled) {
if (!koverEnabled && withConfigurationCache) {
// Configuration cache is incompatible with javaagents being enabled for Gradle
// See https://github.com/gradle/gradle/issues/25979
add("--configuration-cache")
Expand Down
@@ -0,0 +1,54 @@
/*
* Copyright 2016-2024 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 kotlinx.validation.test

import kotlinx.validation.api.*
import kotlinx.validation.api.resolve
import kotlinx.validation.api.test
import org.assertj.core.api.Assertions
import org.junit.Test

class JvmProjectTests : BaseKotlinGradleTest() {
@Test
fun `apiDump for a project with generated sources only`() {
val runner = test {
buildGradleKts {
resolve("/examples/gradle/base/withPlugin.gradle.kts")
resolve("/examples/gradle/configuration/generatedSources/generatedJvmSources.gradle.kts")
}
// TODO: enable configuration cache back when we start skipping tasks correctly
runner(withConfigurationCache = false) {
arguments.add(":apiDump")
}
}
runner.build().apply {
assertTaskSuccess(":apiDump")

val expectedApi = readFileList("/examples/classes/GeneratedSources.dump")
Assertions.assertThat(rootProjectApiDump.readText()).isEqualToIgnoringNewLines(expectedApi)
}
}

@Test
fun `apiCheck for a project with generated sources only`() {
val runner = test {
buildGradleKts {
resolve("/examples/gradle/base/withPlugin.gradle.kts")
resolve("/examples/gradle/configuration/generatedSources/generatedJvmSources.gradle.kts")
}
apiFile(projectName = rootProjectDir.name) {
resolve("/examples/classes/GeneratedSources.dump")
}
// TODO: enable configuration cache back when we start skipping tasks correctly
runner(withConfigurationCache = false) {
arguments.add(":apiCheck")
}
}
runner.build().apply {
assertTaskSuccess(":apiCheck")
}
}
}
Expand Up @@ -669,4 +669,33 @@ internal class KlibVerificationTests : BaseKotlinGradleTest() {
}
runner.build()
}

@Test
fun `apiDump for a project with generated sources only`() {
val runner = test {
baseProjectSetting()
additionalBuildConfig("/examples/gradle/configuration/generatedSources/generatedSources.gradle.kts")
// TODO: enable configuration cache back when we start skipping tasks correctly
runner(withConfigurationCache = false) {
arguments.add(":apiDump")
}
}
checkKlibDump(runner.build(), "/examples/classes/GeneratedSources.klib.dump")
}

@Test
fun `apiCheck for a project with generated sources only`() {
val runner = test {
baseProjectSetting()
additionalBuildConfig("/examples/gradle/configuration/generatedSources/generatedSources.gradle.kts")
abiFile(projectName = "testproject") {
resolve("/examples/classes/GeneratedSources.klib.dump")
}
// TODO: enable configuration cache back when we start skipping tasks correctly
runner(withConfigurationCache = false) {
arguments.add(":apiCheck")
}
}
assertApiCheckPassed(runner.build())
}
}
@@ -1,16 +1,17 @@
/*
* Copyright 2016-2021 JetBrains s.r.o.
* Copyright 2016-2024 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 kotlinx.validation.test

import kotlinx.validation.api.*
import org.assertj.core.api.Assertions.assertThat
import org.gradle.testkit.runner.TaskOutcome
import org.junit.Test
import java.io.File

internal class MultiPlatformSingleJvmKlibTargetTest : BaseKotlinGradleTest() {
internal class MultiPlatformSingleJvmTargetTest : BaseKotlinGradleTest() {
private fun BaseKotlinScope.createProjectHierarchyWithPluginOnRoot() {
settingsGradleKts {
resolve("/examples/gradle/settings/settings-name-testproject.gradle.kts")
Expand Down Expand Up @@ -116,6 +117,45 @@ internal class MultiPlatformSingleJvmKlibTargetTest : BaseKotlinGradleTest() {
}
}

@Test
fun testApiDumpPassesForEmptyProject() {
val runner = test {
buildGradleKts {
resolve("/examples/gradle/base/multiplatformWithSingleJvmTarget.gradle.kts")
}

runner {
arguments.add(":apiDump")
}
}

runner.build().apply {
assertTaskSkipped(":jvmApiDump")
assertTaskUpToDate(":apiDump")
}
}

@Test
fun testApiCheckPassesForEmptyProject() {
val runner = test {
buildGradleKts {
resolve("/examples/gradle/base/multiplatformWithSingleJvmTarget.gradle.kts")
}

emptyApiFile(projectName = rootProjectDir.name)

runner {
arguments.add(":apiCheck")
}
}

runner.build().apply {
assertTaskSkipped(":jvmApiCheck")
assertTaskUpToDate(":apiCheck")

}
}

private val jvmApiDump: File get() = rootProjectDir.resolve("$API_DIR/testproject.api")

}
@@ -0,0 +1,5 @@
public final class Generated {
public fun <init> ()V
public final fun helloCreator ()I
}

@@ -0,0 +1,12 @@
// Klib ABI Dump
// Targets: [androidNativeArm32, androidNativeArm64, androidNativeX64, androidNativeX86, linuxArm64, linuxX64, mingwX64]
// Rendering settings:
// - Signature version: 2
// - Show manifest properties: true
// - Show declarations: true

// Library unique name: <testproject>
final class /Generated { // /Generated|null[0]
constructor <init>() // /Generated.<init>|<init>(){}[0]
final fun helloCreator(): kotlin/Int // /Generated.helloCreator|helloCreator(){}[0]
}
@@ -0,0 +1,21 @@
abstract class GenerateSourcesTask : org.gradle.api.DefaultTask() {
@get:org.gradle.api.tasks.OutputDirectory
abstract val outputDirectory: org.gradle.api.file.DirectoryProperty

@org.gradle.api.tasks.TaskAction
fun generate() {
outputDirectory.asFile.get().mkdirs()
outputDirectory.file("Generated.kt").get().asFile.writeText("""
public class Generated { public fun helloCreator(): Int = 42 }
""".trimIndent())
}
}

val srcgen = project.tasks.register("generateSources", GenerateSourcesTask::class.java)
srcgen.configure {
outputDirectory.set(project.layout.buildDirectory.get().dir("generated").dir("kotlin"))
}

project.sourceSets.getByName("main") {
kotlin.srcDir(srcgen)
}
@@ -0,0 +1,22 @@
abstract class GenerateSourcesTask : org.gradle.api.DefaultTask() {
@get:org.gradle.api.tasks.OutputDirectory
abstract val outputDirectory: org.gradle.api.file.DirectoryProperty

@org.gradle.api.tasks.TaskAction
fun generate() {
outputDirectory.asFile.get().mkdirs()
outputDirectory.file("Generated.kt").get().asFile.writeText("""
public class Generated { public fun helloCreator(): Int = 42 }
""".trimIndent())
}
}

val srcgen = project.tasks.register("generateSources", GenerateSourcesTask::class.java)
srcgen.configure {
outputDirectory.set(project.layout.buildDirectory.get().dir("generated").dir("kotlin"))
}

val kotlin = project.extensions.getByType(org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension::class.java)
kotlin.sourceSets.getByName("commonMain") {
kotlin.srcDir(srcgen)
}
13 changes: 9 additions & 4 deletions src/main/kotlin/BinaryCompatibilityValidatorPlugin.kt
Expand Up @@ -219,9 +219,7 @@ private fun Project.configureKotlinCompilation(

val apiBuild = task<KotlinApiBuildTask>(targetConfig.apiTaskName("Build")) {
// Do not enable task for empty umbrella modules
isEnabled = apiCheckEnabled(projectName, extension)
val hasSourcesPredicate = compilation.hasAnySourcesPredicate()
onlyIf { hasSourcesPredicate.get() }
isEnabled = apiCheckEnabled(projectName, extension) && compilation.hasAnySources()
// 'group' is not specified deliberately, so it will be hidden from ./gradlew tasks
description =
"Builds Kotlin API for 'main' compilations of $projectName. Complementary task and shouldn't be called manually"
Expand Down Expand Up @@ -398,9 +396,16 @@ private class KlibValidationPipelineBuilder(
commonApiCheck.configure { it.dependsOn(klibCheck) }

klibDump.configure { it.dependsOn(klibMergeInferred) }
// Extraction task depends on supportedTargets() provider which returns a set of targets supported
// by the host compiler and having some sources. A set of sources for a target may change until the actual
// klib compilation will take place, so we may observe incorrect value if check source sets earlier.
// Merge task already depends on compilations, so instead of adding each compilation task to the extraction's
// dependency set, we can depend on the merge task itself.
klibExtractAbiForSupportedTargets.configure {
it.dependsOn(klibMerge)
}
klibCheck.configure {
it.dependsOn(klibExtractAbiForSupportedTargets)
it.dependsOn(klibMerge)
}

project.configureTargets(klibApiDir, klibMerge, klibMergeInferred)
Expand Down

0 comments on commit 50f3340

Please sign in to comment.