diff --git a/.github/workflows/gradle_task.yml b/.github/workflows/gradle_task.yml index 7e7e534..ea4fc1b 100644 --- a/.github/workflows/gradle_task.yml +++ b/.github/workflows/gradle_task.yml @@ -47,10 +47,20 @@ jobs: distribution: temurin java-version: 11 + - name: Cache Gradle TestKit + id: cache-gradle-testkit + uses: actions/cache@v3 + with: + path: | + ${{ runner.temp }}/.gradle-test-kit/caches + key: gradle-testkit-${{ runner.os }} + - uses: gradle/gradle-build-action@v2 + env: + GRADLE_TESTKIT_DIR: ${{ runner.temp }}/.gradle-test-kit/caches with: gradle-home-cache-cleanup: true - arguments: ${{ inputs.gradle-task }} + arguments: ${{ inputs.gradle-task }} --scan - name: Upload build reports if: failure() diff --git a/.gitignore b/.gitignore index 09f04f3..d8726fc 100644 --- a/.gitignore +++ b/.gitignore @@ -16,7 +16,9 @@ replay_pid* ### IntelliJ ### -.idea +.idea/** +!.idea/codeStyles/ +!.idea/codeStyles/** ### Eclipse ### diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 0000000..0270e59 --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,616 @@ + + + + + diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..79ee123 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/README.md b/README.md index cab91be..c9f5ec9 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,10 @@ +[![GitHub license](https://img.shields.io/github/license/adamko-dev/kotlin-binary-compatibility-validator-mu?style=for-the-badge)](https://github.com/adamko-dev/kotlin-binary-compatibility-validator-mu/blob/main/LICENSE) +[![Gradle Plugin Portal](https://img.shields.io/gradle-plugin-portal/v/dev.adamko.kotlin.binary-compatibility-validator?style=for-the-badge)](https://plugins.gradle.org/plugin/dev.adamko.kotlin.binary-compatibility-validator) + # Kotlin Binary Compatibility Validator (Mirror Universe) -BCV-MU is a re-imagined [Gradle](https://gradle.org/) Plugin for +[BCV-MU](https://github.com/adamko-dev/kotlin-binary-compatibility-validator-mu) is a +re-imagined [Gradle](https://gradle.org/) Plugin for [Kotlin/binary-compatibility-validator](https://github.com/Kotlin/binary-compatibility-validator). This plugin validates the public JVM binary API of libraries to make sure that breaking changes are @@ -191,8 +195,8 @@ All subprojects are included by default, and can be excluded using BCV-MU config buildscript { dependencies { - // BCV-MU requires the Kotlin Gradle Plugin classes are present - classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.10") + // BCV-MU requires the Kotlin Gradle Plugin classes are present + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin-api:1.8.10") } } @@ -200,19 +204,47 @@ plugins { id("dev.adamko.kotlin.binary-compatibility-validator") version "$bcvMuVersion" } -extensions - .getByType() - .apply { - ignoredProjects.addAll( - - // ignore subprojects explicitly - ":some-subproject", - - // or ignore using a glob pattern - ":internal-dependencies:**", - ":*-tasks:**", - ) +binaryCompatibilityValidator { + ignoredProjects.addAll( + + ":", // ignore root project + ":some-subproject", // ignore subprojects explicitly + + // or ignore using a glob pattern + ":internal-dependencies:*", + ":*-tasks:**", + ) + + // set the default values for all targets in all enabled-subprojects + defaultTargetValues { + enabled.convention(true) + ignoredClasses.set(listOf("com.package.MyIgnoredClass")) + ignoredMarkers.set(listOf("com.package.MyInternalApiAnnotationMarker")) + ignoredPackages.set(listOf("com.package.my_ignored_package")) } +} + +include( + // these projects will have BCV-MU automatically applied + ":common", + ":internal-dependencies:alpha:nested", + ":internal-dependencies:alpha:nested", + ":a-task", + + // this subproject is explicitly excluded from BCV + ":some-subproject", + + // these subprojects will be excluded by glob pattern + ":internal-dependencies", + ":internal-dependencies:alpha", + ":internal-dependencies:beta", + ":x-tasks", + ":x-tasks:sub1", + ":x-tasks:sub1:sub2", + ":z-tasks", + ":z-tasks:sub1", + ":z-tasks:sub1:sub2", +) ``` ## License diff --git a/build.gradle.kts b/build.gradle.kts index 0c705ac..85f0f34 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -6,7 +6,7 @@ plugins { } group = "dev.adamko.kotlin.binary_compatibility_validator" -version = "0.0.2" +version = "0.0.3" idea { module { @@ -23,7 +23,7 @@ idea { val readmeCheck by tasks.registering { group = LifecycleBasePlugin.VERIFICATION_GROUP val readme = providers.fileContents(layout.projectDirectory.file("README.md")).asText - val minimumGradleTestVersion = libs.versions.testGradleVersion + val supportedGradleVersion = libs.versions.supportedGradleVersion val kotlinBcvVersion = libs.versions.kotlinx.bcv doLast { @@ -34,7 +34,7 @@ val readmeCheck by tasks.registering { require("kotlinxBinaryCompatibilityValidatorVersion.set(\"${kotlinBcvVersion.get()}\")" in readme) { "Incorrect BCV version in README" } - require("The minimal supported Gradle version is ${minimumGradleTestVersion.get()}" in readme) { + require("The minimal supported Gradle version is ${supportedGradleVersion.get()}" in readme) { "Incorrect Gradle version in README" } } diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 931a956..06d5b9e 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -8,6 +8,7 @@ dependencies { implementation("org.gradle.kotlin:gradle-kotlin-dsl-plugins:$expectedKotlinDslPluginsVersion") implementation(libs.gradlePlugin.pluginPublishing) + implementation(libs.gradlePlugin.shadow) } java { diff --git a/buildSrc/src/main/kotlin/buildsrc/conventions/kotlin-gradle-plugin-tests.gradle.kts b/buildSrc/src/main/kotlin/buildsrc/conventions/kotlin-gradle-plugin-tests.gradle.kts index faebe72..612895b 100644 --- a/buildSrc/src/main/kotlin/buildsrc/conventions/kotlin-gradle-plugin-tests.gradle.kts +++ b/buildSrc/src/main/kotlin/buildsrc/conventions/kotlin-gradle-plugin-tests.gradle.kts @@ -34,3 +34,12 @@ testing.suites { } } } + +tasks.withType().configureEach { + // Help speed up TestKit tests by re-using dependencies cache + // https://docs.gradle.org/current/userguide/dependency_resolution.html#sub:shared-readonly-cache + environment("GRADLE_RO_DEP_CACHE", gradle.gradleUserHomeDir.resolve("caches")) + providers.environmentVariable("GRADLE_TESTKIT_DIR").orNull?.let { + systemProperty("gradleTestKitDir", it) + } +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 3ca12c7..249494c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -8,20 +8,23 @@ kotest = "5.5.5" kotlinx-bcv = "0.13.0" gradlePluginPublishPlugin = "1.1.0" +shadowPlugin = "8.1.0" -testGradleVersion = "7.6" # the minimal supported Gradle plugin version, used in functional tests +supportedGradleVersion = "7.6" # the minimal supported Gradle plugin version, used in functional tests [libraries] javaDiffUtils = { module = "io.github.java-diff-utils:java-diff-utils", version.ref = "javaDiffUtils" } kotlinx-bcv = { module = "org.jetbrains.kotlinx:binary-compatibility-validator", version.ref = "kotlinx-bcv" } kotlin-gradlePlugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlinGradle" } +kotlin-gradlePluginApi = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin-api", version.ref = "kotlinGradle" } ## region Test Libraries kotest-bom = { module = "io.kotest:kotest-bom", version.ref = "kotest" } kotest-runnerJUnit5 = { module = "io.kotest:kotest-runner-junit5", version.ref = "kotest" } kotest-assertionsCore = { module = "io.kotest:kotest-assertions-core", version.ref = "kotest" } kotest-property = { module = "io.kotest:kotest-property", version.ref = "kotest" } +kotest-datatest = { module = "io.kotest:kotest-framework-datatest", version.ref = "kotest" } junit-bom = { module = "org.junit:junit-bom", version.ref = "junit" } junit-jupiter = { module = "org.junit.jupiter:junit-jupiter", version.ref = "junit" } @@ -29,4 +32,5 @@ junit-jupiter = { module = "org.junit.jupiter:junit-jupiter", version.ref = "jun ## region Gradle Plugins gradlePlugin-pluginPublishing = { module = "com.gradle.publish:plugin-publish-plugin", version.ref = "gradlePluginPublishPlugin" } +gradlePlugin-shadow = { module = "com.github.johnrengelman:shadow", version.ref = "shadowPlugin" } ## endregion diff --git a/modules/bcv-gradle-plugin-functional-tests/build.gradle.kts b/modules/bcv-gradle-plugin-functional-tests/build.gradle.kts index 81d1e4d..aa4051d 100644 --- a/modules/bcv-gradle-plugin-functional-tests/build.gradle.kts +++ b/modules/bcv-gradle-plugin-functional-tests/build.gradle.kts @@ -33,7 +33,7 @@ testing.suites { inputs.property("projectTestTempDir", projectTestTempDirPath) systemProperty("projectTestTempDir", projectTestTempDirPath) systemProperty("integrationTestProjectsDir", "$projectDir/projects") - systemProperty("minimumGradleTestVersion", libs.versions.testGradleVersion.get()) + systemProperty("minimumGradleTestVersion", libs.versions.supportedGradleVersion.get()) } } } @@ -54,6 +54,7 @@ testing.suites { testTask.configure { shouldRunAfter(test) dependsOn(project.configurations.testMavenPublication) + inputs.files(project.configurations.testMavenPublication) systemProperty("testMavenRepoDir", file(mavenPublishTest.testMavenRepo).canonicalPath) } diff --git a/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/kotlin/kotlinx/validation/test/AndroidLibraryTest.kt b/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/kotlin/kotlinx/validation/test/AndroidLibraryTest.kt index 6f03a8a..f168e08 100644 --- a/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/kotlin/kotlinx/validation/test/AndroidLibraryTest.kt +++ b/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/kotlin/kotlinx/validation/test/AndroidLibraryTest.kt @@ -8,7 +8,7 @@ import org.gradle.testkit.runner.TaskOutcome.SUCCESS import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test -@Disabled("Leftovers after revert of #94") +@Disabled("Leftovers after revert of https://github.com/Kotlin/binary-compatibility-validator/issues/94") internal class AndroidLibraryTest : BaseKotlinGradleTest() { // region Kotlin Android Library @@ -25,7 +25,7 @@ internal class AndroidLibraryTest : BaseKotlinGradleTest() { } runner.build { - task(":kotlin-library:apiDump") shouldHaveOutcome SUCCESS + shouldHaveRunTask(":kotlin-library:apiDump", SUCCESS) } } @@ -37,8 +37,8 @@ internal class AndroidLibraryTest : BaseKotlinGradleTest() { runner { arguments.add(":kotlin-library:apiCheck") } - }.build().apply { - task(":kotlin-library:apiCheck") shouldHaveOutcome SUCCESS + }.build { + shouldHaveRunTask(":kotlin-library:apiCheck", SUCCESS) } } @@ -58,7 +58,7 @@ internal class AndroidLibraryTest : BaseKotlinGradleTest() { } runner.build { - task(":java-library:apiDump") shouldHaveOutcome SUCCESS + shouldHaveRunTask(":java-library:apiDump", SUCCESS) } } @@ -70,8 +70,8 @@ internal class AndroidLibraryTest : BaseKotlinGradleTest() { runner { arguments.add(":java-library:apiCheck") } - }.build().apply { - task(":java-library:apiCheck") shouldHaveOutcome SUCCESS + }.build { + shouldHaveRunTask(":java-library:apiCheck", SUCCESS) } } diff --git a/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/kotlin/kotlinx/validation/test/DefaultConfigTests.kt b/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/kotlin/kotlinx/validation/test/DefaultConfigTests.kt index e6f1ad6..57306d7 100644 --- a/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/kotlin/kotlinx/validation/test/DefaultConfigTests.kt +++ b/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/kotlin/kotlinx/validation/test/DefaultConfigTests.kt @@ -26,7 +26,7 @@ internal class DefaultConfigTests : BaseKotlinGradleTest() { runner.buildAndFail { output shouldContain "Please ensure that task ':apiDump' was executed" - task(":apiCheck") shouldHaveOutcome FAILED + shouldHaveRunTask(":apiCheck", FAILED) } } @@ -43,7 +43,7 @@ internal class DefaultConfigTests : BaseKotlinGradleTest() { } runner.buildAndFail { - task(":apiCheck") shouldHaveOutcome FAILED + shouldHaveRunTask(":apiCheck", FAILED) shouldNotHaveRunTask(":check") // apiCheck fails before we can run check } } @@ -63,7 +63,7 @@ internal class DefaultConfigTests : BaseKotlinGradleTest() { } runner.build { - task(":apiCheck") shouldHaveOutcome SUCCESS + shouldHaveRunTask(":apiCheck", SUCCESS) } } @@ -86,7 +86,7 @@ internal class DefaultConfigTests : BaseKotlinGradleTest() { } runner.build { - task(":apiCheck") shouldHaveOutcome SUCCESS + shouldHaveRunTask(":apiCheck", SUCCESS) } } @@ -109,7 +109,7 @@ internal class DefaultConfigTests : BaseKotlinGradleTest() { } runner.build { - task(":apiCheck") shouldHaveOutcome SUCCESS + shouldHaveRunTask(":apiCheck", SUCCESS) } } @@ -132,7 +132,7 @@ internal class DefaultConfigTests : BaseKotlinGradleTest() { } runner.buildAndFail { - task(":apiCheck") shouldHaveOutcome FAILED + shouldHaveRunTask(":apiCheck", FAILED) // note that tabs are used as function indents! val dumpOutput = /*language=TEXT*/ """ @@ -160,7 +160,7 @@ internal class DefaultConfigTests : BaseKotlinGradleTest() { } runner.build { - task(":apiDump") shouldHaveOutcome SUCCESS + shouldHaveRunTask(":apiDump", SUCCESS) assertTrue( rootProjectApiDump.exists(), @@ -187,7 +187,7 @@ internal class DefaultConfigTests : BaseKotlinGradleTest() { } runner.build { - task(":apiDump") shouldHaveOutcome SUCCESS + shouldHaveRunTask(":apiDump", SUCCESS) val apiDumpFile = rootProjectDir.resolve("api/testproject.api") assertTrue(apiDumpFile.exists(), "api dump file ${apiDumpFile.path} should exist") @@ -217,7 +217,7 @@ internal class DefaultConfigTests : BaseKotlinGradleTest() { } runner.build { - task(":apiDump") shouldHaveOutcome SUCCESS + shouldHaveRunTask(":apiDump", SUCCESS) assertTrue(rootProjectApiDump.exists(), "api dump file should exist") @@ -242,8 +242,8 @@ internal class DefaultConfigTests : BaseKotlinGradleTest() { } runner.build { - task(":check") shouldHaveOutcome SUCCESS - task(":apiCheck") shouldHaveOutcome SUCCESS + shouldHaveRunTask(":check", SUCCESS) + shouldHaveRunTask(":apiCheck", SUCCESS) } } } diff --git a/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/kotlin/kotlinx/validation/test/IgnoredClassesTests.kt b/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/kotlin/kotlinx/validation/test/IgnoredClassesTests.kt index cf26288..0c59131 100644 --- a/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/kotlin/kotlinx/validation/test/IgnoredClassesTests.kt +++ b/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/kotlin/kotlinx/validation/test/IgnoredClassesTests.kt @@ -2,7 +2,7 @@ package kotlinx.validation.test import dev.adamko.kotlin.binary_compatibility_validator.test.utils.api.* import dev.adamko.kotlin.binary_compatibility_validator.test.utils.build -import dev.adamko.kotlin.binary_compatibility_validator.test.utils.shouldHaveOutcome +import dev.adamko.kotlin.binary_compatibility_validator.test.utils.shouldHaveRunTask import io.kotest.matchers.comparables.shouldBeEqualComparingTo import org.gradle.testkit.runner.TaskOutcome.SUCCESS import org.junit.jupiter.api.Assertions.assertTrue @@ -30,7 +30,7 @@ internal class IgnoredClassesTests : BaseKotlinGradleTest() { } runner.build { - task(":apiCheck") shouldHaveOutcome SUCCESS + shouldHaveRunTask(":apiCheck", SUCCESS) } } @@ -54,7 +54,7 @@ internal class IgnoredClassesTests : BaseKotlinGradleTest() { } runner.build { - task(":apiCheck") shouldHaveOutcome SUCCESS + shouldHaveRunTask(":apiCheck", SUCCESS) } } @@ -78,7 +78,7 @@ internal class IgnoredClassesTests : BaseKotlinGradleTest() { } runner.build { - task(":apiDump") shouldHaveOutcome SUCCESS + shouldHaveRunTask(":apiDump", SUCCESS) assertTrue(rootProjectApiDump.exists(), "api dump file should exist") diff --git a/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/kotlin/kotlinx/validation/test/InputJarTest.kt b/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/kotlin/kotlinx/validation/test/InputJarTest.kt index 4ace717..c339ff3 100644 --- a/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/kotlin/kotlinx/validation/test/InputJarTest.kt +++ b/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/kotlin/kotlinx/validation/test/InputJarTest.kt @@ -2,7 +2,7 @@ package kotlinx.validation.test import dev.adamko.kotlin.binary_compatibility_validator.test.utils.api.* import dev.adamko.kotlin.binary_compatibility_validator.test.utils.build -import dev.adamko.kotlin.binary_compatibility_validator.test.utils.shouldHaveOutcome +import dev.adamko.kotlin.binary_compatibility_validator.test.utils.shouldHaveRunTask import org.gradle.testkit.runner.TaskOutcome.SUCCESS import org.junit.jupiter.api.Test @@ -30,8 +30,8 @@ class InputJarTest : BaseKotlinGradleTest() { } runner.build { - task(":jar") shouldHaveOutcome SUCCESS - task(":apiCheck") shouldHaveOutcome SUCCESS + shouldHaveRunTask(":jar", SUCCESS) + shouldHaveRunTask(":apiCheck", SUCCESS) } } } diff --git a/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/kotlin/kotlinx/validation/test/JavaTestFixturesTest.kt b/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/kotlin/kotlinx/validation/test/JavaTestFixturesTest.kt index b1f9920..81d0eb9 100644 --- a/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/kotlin/kotlinx/validation/test/JavaTestFixturesTest.kt +++ b/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/kotlin/kotlinx/validation/test/JavaTestFixturesTest.kt @@ -22,7 +22,7 @@ class JavaTestFixturesTest : FunSpec({ test("expect :apiDump task passes") { project.runner.withArguments("apiDump").build { withClue(output) { - task(":apiDump") shouldHaveOutcome SUCCESS + shouldHaveRunTask(":apiDump", SUCCESS) } } } @@ -36,7 +36,7 @@ class JavaTestFixturesTest : FunSpec({ ) .build { withClue(output) { - task(":apiCheck") shouldHaveOutcome SUCCESS + shouldHaveRunTask(":apiCheck", SUCCESS) } } } @@ -74,7 +74,7 @@ class JavaTestFixturesTest : FunSpec({ test("expect :apiDump task passes") { project.runner.withArguments("apiDump").build { withClue(output) { - task(":apiDump") shouldHaveOutcome SUCCESS + shouldHaveRunTask(":apiDump", SUCCESS) } } } @@ -88,7 +88,7 @@ class JavaTestFixturesTest : FunSpec({ ) .build { withClue(output) { - task(":apiCheck") shouldHaveOutcome SUCCESS + shouldHaveRunTask(":apiCheck", SUCCESS) } } } @@ -125,7 +125,7 @@ private fun FunSpec.createTestFixturesProject( buildGradleKts = """ |plugins { | kotlin("jvm") version "1.7.10" - | id("dev.adamko.kotlin.binary-compatibility-validator") version "0.0.2" + | id("dev.adamko.kotlin.binary-compatibility-validator") version "0.0.3" | `java-test-fixtures` |} | diff --git a/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/kotlin/kotlinx/validation/test/MultiPlatformSingleJvmTargetTest.kt b/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/kotlin/kotlinx/validation/test/MultiPlatformSingleJvmTargetTest.kt index 4b77fd3..3f9a931 100644 --- a/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/kotlin/kotlinx/validation/test/MultiPlatformSingleJvmTargetTest.kt +++ b/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/kotlin/kotlinx/validation/test/MultiPlatformSingleJvmTargetTest.kt @@ -2,7 +2,9 @@ package kotlinx.validation.test import dev.adamko.kotlin.binary_compatibility_validator.test.utils.* import dev.adamko.kotlin.binary_compatibility_validator.test.utils.api.* -import io.kotest.matchers.comparables.shouldBeEqualComparingTo +import io.kotest.assertions.withClue +import io.kotest.matchers.file.shouldBeAFile +import io.kotest.matchers.shouldBe import io.kotest.matchers.string.shouldContain import java.io.File import org.gradle.testkit.runner.TaskOutcome.FAILED @@ -42,11 +44,10 @@ internal class MultiPlatformSingleJvmTargetTest : BaseKotlinGradleTest() { kotlin("Subsub2Class.kt", "jvmMain") { resolve("/examples/classes/Subsub2Class.kt") } - } runner.build { - task(":apiCheck") shouldHaveOutcome SUCCESS + shouldHaveRunTask(":apiCheck", SUCCESS) } } @@ -74,13 +75,28 @@ internal class MultiPlatformSingleJvmTargetTest : BaseKotlinGradleTest() { kotlin("Subsub2Class.kt", "jvmMain") { resolve("/examples/classes/Subsub2Class.kt") } - + dir("src/jvmTest/kotlin") {} + kotlin("Subsub2ClassTest.kt", "jvmTest") { + addText(/*language=kotlin*/ """ + |package com.company.test + | + |class SubSub2Test { + | fun blah() { + | println("test") + | } + |} + | + """.trimMargin() + ) + } } runner.buildAndFail { - task(":apiCheck") shouldHaveOutcome FAILED - output shouldContain "API check failed for project :testproject" - shouldNotHaveRunTask(":check") + withClue(output) { + shouldHaveRunTask(":apiCheck", FAILED) + output shouldContain "API check failed for project :testproject" + shouldNotHaveRunTask(":check") + } } } @@ -101,11 +117,10 @@ internal class MultiPlatformSingleJvmTargetTest : BaseKotlinGradleTest() { kotlin("Subsub2Class.kt", "jvmMain") { resolve("/examples/classes/Subsub2Class.kt") } - } runner.build { - task(":apiDump") shouldHaveOutcome SUCCESS + shouldHaveRunTask(":apiDump", SUCCESS) val mainExpectedApi = """ |${readResourceFile("/examples/classes/Subsub1Class.dump").trim()} @@ -115,9 +130,8 @@ internal class MultiPlatformSingleJvmTargetTest : BaseKotlinGradleTest() { | """.trimMargin() - val actual = jvmApiDump.readText().invariantNewlines() - - actual.shouldBeEqualComparingTo(mainExpectedApi) + jvmApiDump.shouldBeAFile() + jvmApiDump.readText().invariantNewlines() shouldBe mainExpectedApi } } diff --git a/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/kotlin/kotlinx/validation/test/MultipleJvmTargetsTest.kt b/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/kotlin/kotlinx/validation/test/MultipleJvmTargetsTest.kt index 5cebfe0..6cac93c 100644 --- a/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/kotlin/kotlinx/validation/test/MultipleJvmTargetsTest.kt +++ b/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/kotlin/kotlinx/validation/test/MultipleJvmTargetsTest.kt @@ -2,6 +2,7 @@ package kotlinx.validation.test import dev.adamko.kotlin.binary_compatibility_validator.test.utils.* import dev.adamko.kotlin.binary_compatibility_validator.test.utils.api.* +import io.kotest.assertions.withClue import io.kotest.matchers.file.shouldBeAFile import io.kotest.matchers.shouldBe import io.kotest.matchers.string.shouldContain @@ -52,7 +53,7 @@ internal class MultipleJvmTargetsTest : BaseKotlinGradleTest() { } runner.build { - task(":apiCheck") shouldHaveOutcome SUCCESS + shouldHaveRunTask(":apiCheck", SUCCESS) } } @@ -90,9 +91,11 @@ internal class MultipleJvmTargetsTest : BaseKotlinGradleTest() { } runner.buildAndFail { - task(":apiCheck") shouldHaveOutcome FAILED - output shouldContain "API check failed for project :testproject" - shouldNotHaveRunTask(":check") + withClue(output) { + shouldHaveRunTask(":apiCheck", FAILED) + output shouldContain "API check failed for project :testproject" + shouldNotHaveRunTask(":check") + } } } @@ -115,22 +118,21 @@ internal class MultipleJvmTargetsTest : BaseKotlinGradleTest() { } runner.build { - task(":apiDump") shouldHaveOutcome SUCCESS - - System.err.println(output) + withClue(output) { + shouldHaveRunTask(":apiDump", SUCCESS) - val anotherExpectedApi = readResourceFile("/examples/classes/Subsub1Class.dump") - anotherApiDump.shouldBeAFile() - anotherApiDump.readText().invariantNewlines().shouldBe(anotherExpectedApi) + val anotherExpectedApi = readResourceFile("/examples/classes/Subsub1Class.dump") + anotherApiDump.shouldBeAFile() + anotherApiDump.readText().invariantNewlines() shouldBe anotherExpectedApi - val mainExpectedApi = - anotherExpectedApi + readResourceFile("/examples/classes/Subsub2Class.dump") - jvmApiDump.shouldBeAFile() - jvmApiDump.readText().invariantNewlines().shouldBe(mainExpectedApi) + val mainExpectedApi = + anotherExpectedApi + readResourceFile("/examples/classes/Subsub2Class.dump") + jvmApiDump.shouldBeAFile() + jvmApiDump.readText().invariantNewlines() shouldBe mainExpectedApi + } } } private val jvmApiDump: File get() = rootProjectDir.resolve("api/jvm/testproject.api") private val anotherApiDump: File get() = rootProjectDir.resolve("api/anotherJvm/testproject.api") - } diff --git a/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/kotlin/kotlinx/validation/test/NonPublicMarkersTest.kt b/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/kotlin/kotlinx/validation/test/NonPublicMarkersTest.kt index 13bfeb2..9406296 100644 --- a/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/kotlin/kotlinx/validation/test/NonPublicMarkersTest.kt +++ b/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/kotlin/kotlinx/validation/test/NonPublicMarkersTest.kt @@ -3,6 +3,7 @@ package kotlinx.validation.test import dev.adamko.kotlin.binary_compatibility_validator.test.utils.api.* import dev.adamko.kotlin.binary_compatibility_validator.test.utils.build import dev.adamko.kotlin.binary_compatibility_validator.test.utils.shouldHaveOutcome +import dev.adamko.kotlin.binary_compatibility_validator.test.utils.shouldHaveTaskWithOutcome import org.gradle.testkit.runner.TaskOutcome.SUCCESS import org.junit.jupiter.api.Test @@ -30,7 +31,7 @@ class NonPublicMarkersTest : BaseKotlinGradleTest() { } runner.build { - task(":apiCheck") shouldHaveOutcome SUCCESS + shouldHaveTaskWithOutcome(":apiCheck", SUCCESS) } } } diff --git a/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/kotlin/kotlinx/validation/test/SettingsPluginDslTest.kt b/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/kotlin/kotlinx/validation/test/SettingsPluginDslTest.kt new file mode 100644 index 0000000..d0f9f1c --- /dev/null +++ b/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/kotlin/kotlinx/validation/test/SettingsPluginDslTest.kt @@ -0,0 +1,227 @@ +package kotlinx.validation.test + +import dev.adamko.kotlin.binary_compatibility_validator.test.utils.* +import io.kotest.assertions.asClue +import io.kotest.assertions.withClue +import io.kotest.core.spec.style.FunSpec +import io.kotest.matchers.paths.shouldBeAFile +import io.kotest.matchers.paths.shouldExist +import io.kotest.matchers.shouldBe +import io.kotest.matchers.string.shouldContain +import kotlin.io.path.readText +import org.gradle.testkit.runner.TaskOutcome.SUCCESS +import org.intellij.lang.annotations.Language + +internal class SettingsPluginDslTest : FunSpec({ + + context("when BCV-MU is applied as a settings plugin") { + + val kotlinJvmTest = TestCase( + projectType = "Kotlin/JVM", + project = kotlinJvmProjectWithBcvSettingsPlugin(), + expectedPrintedBCVTargets = """ + |name: kotlinJvm + |platformType: kotlinJvm + |enabled: true + |ignoredClasses: [com.package.MyIgnoredClass] + |ignoredMarkers: [com.package.MyInternalApiAnnotationMarker] + |ignoredPackages: [com.package.my_ignored_package] + |inputClasses: [main, main] + |inputJar: null + |------------------------------ + | + """.trimMargin() + ) + + val kotlinMultiplatformTest = TestCase( + projectType = "Kotlin/Multiplatform", + project = kotlinMultiplatformProjectWithBcvSettingsPlugin(), + expectedPrintedBCVTargets = """ + |name: jvm + |platformType: jvm + |enabled: true + |ignoredClasses: [com.package.MyIgnoredClass] + |ignoredMarkers: [com.package.MyInternalApiAnnotationMarker] + |ignoredPackages: [com.package.my_ignored_package] + |inputClasses: [main] + |inputJar: null + |------------------------------ + | + """.trimMargin() + ) + + listOf( + kotlinJvmTest, + kotlinMultiplatformTest, + ).forEach { testCase -> + context("in a ${testCase.projectType} project") { + + test("apiDump should be generated in all non-excluded subprojects") { + testCase.project.projectDir.toFile() + .walk() + .filter { it.isDirectory && it.name == "api" } + .forEach { it.deleteRecursively() } + + testCase.project.runner + .withArguments("apiDump", "--stacktrace") + .build { + output shouldContain "SUCCESSFUL" + + withClue("root project is excluded from BCV") { + shouldNotHaveRunTask(":apiDump") + } + + shouldHaveRunTask(":sub1:apiDump", SUCCESS) + shouldHaveRunTask(":sub2:apiDump", SUCCESS) + } + + testCase.project.projectDir.resolve("sub1/api/sub1.api").asClue { apiDump -> + apiDump.shouldExist() + apiDump.shouldBeAFile() + apiDump.readText().invariantNewlines() shouldBe /* language=TEXT */ """ + | + """.trimMargin() + } + + testCase.project.projectDir.resolve("sub2/api/sub2.api").asClue { apiDump -> + apiDump.shouldExist() + apiDump.shouldBeAFile() + apiDump.readText().invariantNewlines() shouldBe /* language=TEXT */ """ + | + """.trimMargin() + } + } + + test("expect the conventions set in the settings plugin are used in the subprojects") { + testCase.project.runner.withArguments("printBCVTargets", "-q", "--stacktrace").build { + output.invariantNewlines() shouldBe testCase.expectedPrintedBCVTargets + } + } + } + } + } +}) + +private data class TestCase( + val projectType: String, + val project: GradleProjectTest, + @Language("TEXT") + val expectedPrintedBCVTargets: String, +) + +private fun kotlinJvmProjectWithBcvSettingsPlugin() = + gradleKtsProjectTest("settings-plugin-dsl-test/kotlin-jvm") { + + settingsGradleKts += settingsGradleKtsWithBcvPlugin + + buildGradleKts = "\n" + + dir("sub1") { + buildGradleKts = buildGradleKtsWithKotlinJvmAndBcvConfig + } + + dir("sub2") { + buildGradleKts = buildGradleKtsWithKotlinJvmAndBcvConfig + buildGradleKts += printBcvTargetsTask + } + } + + +private fun kotlinMultiplatformProjectWithBcvSettingsPlugin() = + gradleKtsProjectTest("settings-plugin-dsl-test/kotlin-multiplatform-jvm") { + + settingsGradleKts += settingsGradleKtsWithBcvPlugin + + buildGradleKts = "\n" + + dir("sub1") { + buildGradleKts = buildGradleKtsWithKotlinMultiplatformJvmAndBcvConfig + } + + dir("sub2") { + buildGradleKts = buildGradleKtsWithKotlinMultiplatformJvmAndBcvConfig + buildGradleKts += printBcvTargetsTask + } + } + +@Language("kts") +private val settingsGradleKtsWithBcvPlugin = """ +buildscript { + dependencies { + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin-api:1.7.20") + } +} + + +plugins { + id("dev.adamko.kotlin.binary-compatibility-validator") version "0.0.3" +} + +include( + ":sub1", + ":sub2", +) + +binaryCompatibilityValidator { + ignoredProjects.add(":") + defaultTargetValues { + enabled.convention(true) + ignoredClasses.set(listOf("com.package.MyIgnoredClass")) + ignoredMarkers.set(listOf("com.package.MyInternalApiAnnotationMarker")) + ignoredPackages.set(listOf("com.package.my_ignored_package")) + } +} + +""" + +@Language("kts") +private val buildGradleKtsWithKotlinJvmAndBcvConfig = """ +plugins { + kotlin("jvm") version "1.7.20" +} + +// check that the DSL is available: +binaryCompatibilityValidator { } + +""" + +/** + * Note: the `kotlin("multiplatform")` version should be set in [settingsGradleKtsWithBcvPlugin]. + */ +@Language("kts") +private val buildGradleKtsWithKotlinMultiplatformJvmAndBcvConfig = """ +plugins { + kotlin("multiplatform") version "1.7.20" +} + +kotlin { + jvm() +} + +// check that the DSL is available: +binaryCompatibilityValidator { } + +""" + +@Language("kts") +private val printBcvTargetsTask = """ +val printBCVTargets by tasks.registering { + + val bcvTargets = binaryCompatibilityValidator.targets + + doLast { + bcvTargets.forEach { + println("name: " + it.name) + println("platformType: " + it.platformType) + println("enabled: " + it.enabled.get()) + println("ignoredClasses: " + it.ignoredClasses.get()) + println("ignoredMarkers: " + it.ignoredMarkers.get()) + println("ignoredPackages: " + it.ignoredPackages.get()) + println("inputClasses: " + it.inputClasses.files.map { f -> f.name }) + println("inputJar: " + it.inputJar.orNull) + println("------------------------------") + } + } +} + +""" diff --git a/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/kotlin/kotlinx/validation/test/SubprojectsWithPluginOnRootTests.kt b/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/kotlin/kotlinx/validation/test/SubprojectsWithPluginOnRootTests.kt index 87dbeca..72f9af0 100644 --- a/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/kotlin/kotlinx/validation/test/SubprojectsWithPluginOnRootTests.kt +++ b/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/kotlin/kotlinx/validation/test/SubprojectsWithPluginOnRootTests.kt @@ -3,7 +3,7 @@ package kotlinx.validation.test import dev.adamko.kotlin.binary_compatibility_validator.test.utils.api.* import dev.adamko.kotlin.binary_compatibility_validator.test.utils.build import dev.adamko.kotlin.binary_compatibility_validator.test.utils.invariantNewlines -import dev.adamko.kotlin.binary_compatibility_validator.test.utils.shouldHaveOutcome +import dev.adamko.kotlin.binary_compatibility_validator.test.utils.shouldHaveRunTask import io.kotest.matchers.comparables.shouldBeEqualComparingTo import io.kotest.matchers.file.shouldBeEmpty import org.gradle.testkit.runner.TaskOutcome.SUCCESS @@ -84,11 +84,11 @@ internal class SubprojectsWithPluginOnRootTests : BaseKotlinGradleTest() { } runner.build { - task(":apiCheck") shouldHaveOutcome SUCCESS - task(":sub1:apiCheck") shouldHaveOutcome SUCCESS - task(":sub1:subsub1:apiCheck") shouldHaveOutcome SUCCESS - task(":sub1:subsub2:apiCheck") shouldHaveOutcome SUCCESS - task(":sub2:apiCheck") shouldHaveOutcome SUCCESS + shouldHaveRunTask(":apiCheck", SUCCESS) + shouldHaveRunTask(":sub1:apiCheck", SUCCESS) + shouldHaveRunTask(":sub1:subsub1:apiCheck", SUCCESS) + shouldHaveRunTask(":sub1:subsub2:apiCheck", SUCCESS) + shouldHaveRunTask(":sub2:apiCheck", SUCCESS) } } @@ -121,11 +121,11 @@ internal class SubprojectsWithPluginOnRootTests : BaseKotlinGradleTest() { } runner.build { - task(":apiCheck") shouldHaveOutcome SUCCESS - task(":sub1:apiCheck") shouldHaveOutcome SUCCESS - task(":sub1:subsub1:apiCheck") shouldHaveOutcome SUCCESS - task(":sub1:subsub2:apiCheck") shouldHaveOutcome SUCCESS - task(":sub2:apiCheck") shouldHaveOutcome SUCCESS + shouldHaveRunTask(":apiCheck", SUCCESS) + shouldHaveRunTask(":sub1:apiCheck", SUCCESS) + shouldHaveRunTask(":sub1:subsub1:apiCheck", SUCCESS) + shouldHaveRunTask(":sub1:subsub2:apiCheck", SUCCESS) + shouldHaveRunTask(":sub2:apiCheck", SUCCESS) } } @@ -144,7 +144,7 @@ internal class SubprojectsWithPluginOnRootTests : BaseKotlinGradleTest() { } runner.build { - task(":sub1:apiCheck") shouldHaveOutcome SUCCESS + shouldHaveRunTask(":sub1:apiCheck", SUCCESS) } } @@ -165,7 +165,7 @@ internal class SubprojectsWithPluginOnRootTests : BaseKotlinGradleTest() { } runner.build { - task(":sub1:subsub2:apiCheck") shouldHaveOutcome SUCCESS + shouldHaveRunTask(":sub1:subsub2:apiCheck", SUCCESS) } } @@ -191,7 +191,7 @@ internal class SubprojectsWithPluginOnRootTests : BaseKotlinGradleTest() { } runner.build { - task(":sub1:subsub2:apiCheck") shouldHaveOutcome SUCCESS + shouldHaveRunTask(":sub1:subsub2:apiCheck", SUCCESS) } } @@ -233,11 +233,11 @@ internal class SubprojectsWithPluginOnRootTests : BaseKotlinGradleTest() { } runner.build { - task(":apiCheck") shouldHaveOutcome SUCCESS - task(":sub1:apiCheck") shouldHaveOutcome SUCCESS - task(":sub1:subsub1:apiCheck") shouldHaveOutcome SUCCESS - task(":sub1:subsub2:apiCheck") shouldHaveOutcome SUCCESS - task(":sub2:apiCheck") shouldHaveOutcome SUCCESS + shouldHaveRunTask(":apiCheck", SUCCESS) + shouldHaveRunTask(":sub1:apiCheck", SUCCESS) + shouldHaveRunTask(":sub1:subsub1:apiCheck", SUCCESS) + shouldHaveRunTask(":sub1:subsub2:apiCheck", SUCCESS) + shouldHaveRunTask(":sub2:apiCheck", SUCCESS) } } @@ -252,13 +252,12 @@ internal class SubprojectsWithPluginOnRootTests : BaseKotlinGradleTest() { } runner.build { - task(":sub1:apiDump") shouldHaveOutcome SUCCESS + shouldHaveRunTask(":sub1:apiDump", SUCCESS) val apiDumpFile = rootProjectDir.resolve("sub1/api/sub1.api") assertTrue(apiDumpFile.exists(), "api dump file ${apiDumpFile.path} should exist") apiDumpFile.shouldBeEmpty() - //Assertions.assertThat(apiDumpFile.readText()).isEqualToIgnoringNewLines("") } } @@ -286,40 +285,35 @@ internal class SubprojectsWithPluginOnRootTests : BaseKotlinGradleTest() { } runner.build { - task(":apiDump") shouldHaveOutcome SUCCESS - task(":sub1:apiDump") shouldHaveOutcome SUCCESS - task(":sub1:subsub1:apiDump") shouldHaveOutcome SUCCESS - task(":sub1:subsub2:apiDump") shouldHaveOutcome SUCCESS - task(":sub2:apiDump") shouldHaveOutcome SUCCESS + shouldHaveRunTask(":apiDump", SUCCESS) + shouldHaveRunTask(":sub1:apiDump", SUCCESS) + shouldHaveRunTask(":sub1:subsub1:apiDump", SUCCESS) + shouldHaveRunTask(":sub1:subsub2:apiDump", SUCCESS) + shouldHaveRunTask(":sub2:apiDump", SUCCESS) assertTrue( rootProjectApiDump.exists(), "api dump file ${rootProjectApiDump.path} should exist" ) rootProjectApiDump.shouldBeEmpty() - //Assertions.assertThat(rootProjectApiDump.readText()).isEqualToIgnoringNewLines("") val apiSub1 = rootProjectDir.resolve("sub1/api/sub1.api") assertTrue(apiSub1.exists(), "api dump file ${apiSub1.path} should exist") apiSub1.shouldBeEmpty() - //Assertions.assertThat(apiSub1.readText()).isEqualToIgnoringNewLines("") val apiSubsub1 = rootProjectDir.resolve("sub1/subsub1/api/subsub1.api") assertTrue(apiSubsub1.exists(), "api dump file ${apiSubsub1.path} should exist") val apiSubsub1Expected = readResourceFile("/examples/classes/Subsub1Class.dump") apiSubsub1.readText().invariantNewlines().shouldBeEqualComparingTo(apiSubsub1Expected) - //Assertions.assertThat(apiSubsub1.readText()).isEqualToIgnoringNewLines(apiSubsub1Expected) val apiSubsub2 = rootProjectDir.resolve("sub1/subsub2/api/subsub2.api") assertTrue(apiSubsub2.exists(), "api dump file ${apiSubsub2.path} should exist") val apiSubsub2Expected = readResourceFile("/examples/classes/Subsub2Class.dump") apiSubsub2.readText().invariantNewlines().shouldBeEqualComparingTo(apiSubsub2Expected) - //Assertions.assertThat(apiSubsub2.readText()).isEqualToIgnoringNewLines(apiSubsub2Expected) val apiSub2 = rootProjectDir.resolve("sub2/api/sub2.api") assertTrue(apiSub2.exists(), "api dump file ${apiSub2.path} should exist") apiSub2.shouldBeEmpty() - //Assertions.assertThat(apiSub2.readText()).isEqualToIgnoringNewLines("") } } } diff --git a/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/kotlin/kotlinx/validation/test/SubprojectsWithPluginOnSubTests.kt b/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/kotlin/kotlinx/validation/test/SubprojectsWithPluginOnSubTests.kt index 4f91a2c..188b88d 100644 --- a/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/kotlin/kotlinx/validation/test/SubprojectsWithPluginOnSubTests.kt +++ b/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/kotlin/kotlinx/validation/test/SubprojectsWithPluginOnSubTests.kt @@ -3,7 +3,7 @@ package kotlinx.validation.test import dev.adamko.kotlin.binary_compatibility_validator.test.utils.api.* import dev.adamko.kotlin.binary_compatibility_validator.test.utils.build import dev.adamko.kotlin.binary_compatibility_validator.test.utils.invariantNewlines -import dev.adamko.kotlin.binary_compatibility_validator.test.utils.shouldHaveOutcome +import dev.adamko.kotlin.binary_compatibility_validator.test.utils.shouldHaveRunTask import dev.adamko.kotlin.binary_compatibility_validator.test.utils.shouldNotHaveRunTask import io.kotest.matchers.comparables.shouldBeEqualComparingTo import io.kotest.matchers.file.shouldBeEmpty @@ -81,9 +81,9 @@ internal class SubprojectsWithPluginOnSubTests : BaseKotlinGradleTest() { runner.build { shouldNotHaveRunTask(":apiCheck") - task(":sub1:apiCheck") shouldHaveOutcome SUCCESS - task(":sub1:subsub1:apiCheck") shouldHaveOutcome SUCCESS - task(":sub1:subsub2:apiCheck") shouldHaveOutcome SUCCESS + shouldHaveRunTask(":sub1:apiCheck", SUCCESS) + shouldHaveRunTask(":sub1:subsub1:apiCheck", SUCCESS) + shouldHaveRunTask(":sub1:subsub2:apiCheck", SUCCESS) shouldNotHaveRunTask(":sub2:apiCheck") } } @@ -112,9 +112,9 @@ internal class SubprojectsWithPluginOnSubTests : BaseKotlinGradleTest() { runner.build { shouldNotHaveRunTask(":apiCheck") - task(":sub1:apiCheck") shouldHaveOutcome SUCCESS - task(":sub1:subsub1:apiCheck") shouldHaveOutcome SUCCESS - task(":sub1:subsub2:apiCheck") shouldHaveOutcome SUCCESS + shouldHaveRunTask(":sub1:apiCheck", SUCCESS) + shouldHaveRunTask(":sub1:subsub1:apiCheck", SUCCESS) + shouldHaveRunTask(":sub1:subsub2:apiCheck", SUCCESS) shouldNotHaveRunTask(":sub2:apiCheck") } } @@ -134,7 +134,7 @@ internal class SubprojectsWithPluginOnSubTests : BaseKotlinGradleTest() { } runner.build { - task(":sub1:apiCheck") shouldHaveOutcome SUCCESS + shouldHaveRunTask(":sub1:apiCheck", SUCCESS) } } @@ -155,7 +155,7 @@ internal class SubprojectsWithPluginOnSubTests : BaseKotlinGradleTest() { } runner.build { - task(":sub1:subsub2:apiCheck") shouldHaveOutcome SUCCESS + shouldHaveRunTask(":sub1:subsub2:apiCheck", SUCCESS) } } @@ -181,7 +181,7 @@ internal class SubprojectsWithPluginOnSubTests : BaseKotlinGradleTest() { } runner.build { - task(":sub1:subsub2:apiCheck") shouldHaveOutcome SUCCESS + shouldHaveRunTask(":sub1:subsub2:apiCheck", SUCCESS) } } @@ -218,9 +218,9 @@ internal class SubprojectsWithPluginOnSubTests : BaseKotlinGradleTest() { runner.build { shouldNotHaveRunTask(":apiCheck") - task(":sub1:apiCheck") shouldHaveOutcome SUCCESS - task(":sub1:subsub1:apiCheck") shouldHaveOutcome SUCCESS - task(":sub1:subsub2:apiCheck") shouldHaveOutcome SUCCESS + shouldHaveRunTask(":sub1:apiCheck", SUCCESS) + shouldHaveRunTask(":sub1:subsub1:apiCheck", SUCCESS) + shouldHaveRunTask(":sub1:subsub2:apiCheck", SUCCESS) shouldNotHaveRunTask(":sub2:apiCheck") } } @@ -236,13 +236,12 @@ internal class SubprojectsWithPluginOnSubTests : BaseKotlinGradleTest() { } runner.build { - task(":sub1:apiDump") shouldHaveOutcome SUCCESS + shouldHaveRunTask(":sub1:apiDump", SUCCESS) val apiDumpFile = rootProjectDir.resolve("sub1/api/sub1.api") assertTrue(apiDumpFile.exists(), "api dump file ${apiDumpFile.path} should exist") apiDumpFile.shouldBeEmpty() - //Assertions.assertThat(apiDumpFile.readText()).isEqualToIgnoringNewLines("") } } @@ -271,9 +270,9 @@ internal class SubprojectsWithPluginOnSubTests : BaseKotlinGradleTest() { runner.build { shouldNotHaveRunTask(":apiDump") - task(":sub1:apiDump") shouldHaveOutcome SUCCESS - task(":sub1:subsub1:apiDump") shouldHaveOutcome SUCCESS - task(":sub1:subsub2:apiDump") shouldHaveOutcome SUCCESS + shouldHaveRunTask(":sub1:apiDump", SUCCESS) + shouldHaveRunTask(":sub1:subsub1:apiDump", SUCCESS) + shouldHaveRunTask(":sub1:subsub2:apiDump", SUCCESS) shouldNotHaveRunTask(":sub2:apiDump") assertFalse( @@ -284,19 +283,16 @@ internal class SubprojectsWithPluginOnSubTests : BaseKotlinGradleTest() { val apiSub1 = rootProjectDir.resolve("sub1/api/sub1.api") assertTrue(apiSub1.exists(), "api dump file ${apiSub1.path} should exist") apiSub1.shouldBeEmpty() - //Assertions.assertThat(apiSub1.readText()).isEqualToIgnoringNewLines("") val apiSubsub1 = rootProjectDir.resolve("sub1/subsub1/api/subsub1.api") assertTrue(apiSubsub1.exists(), "api dump file ${apiSubsub1.path} should exist") val apiSubsub1Expected = readResourceFile("/examples/classes/Subsub1Class.dump") apiSubsub1.readText().invariantNewlines().shouldBeEqualComparingTo(apiSubsub1Expected) - //Assertions.assertThat(apiSubsub1.readText()).isEqualToIgnoringNewLines(apiSubsub1Expected) val apiSubsub2 = rootProjectDir.resolve("sub1/subsub2/api/subsub2.api") assertTrue(apiSubsub2.exists(), "api dump file ${apiSubsub2.path} should exist") val apiSubsub2Expected = readResourceFile("/examples/classes/Subsub2Class.dump") apiSubsub2.readText().invariantNewlines().shouldBeEqualComparingTo(apiSubsub2Expected) - //Assertions.assertThat(apiSubsub2.readText()).isEqualToIgnoringNewLines(apiSubsub2Expected) val apiSub2 = rootProjectDir.resolve("sub2/api/sub2.api") assertFalse(apiSub2.exists(), "api dump file ${apiSub2.path} should NOT exist") diff --git a/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/resources/examples/gradle/base/androidJavaLibrary.gradle.kts b/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/resources/examples/gradle/base/androidJavaLibrary.gradle.kts index 3c37362..7d7c399 100644 --- a/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/resources/examples/gradle/base/androidJavaLibrary.gradle.kts +++ b/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/resources/examples/gradle/base/androidJavaLibrary.gradle.kts @@ -6,7 +6,7 @@ plugins { id("com.android.library") //id("org.jetbrains.kotlinx.binary-compatibility-validator") - id("dev.adamko.kotlin.binary-compatibility-validator") version "0.0.2" + id("dev.adamko.kotlin.binary-compatibility-validator") version "0.0.3" } android { diff --git a/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/resources/examples/gradle/base/androidKotlinLibrary.gradle.kts b/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/resources/examples/gradle/base/androidKotlinLibrary.gradle.kts index 2e76013..b3bddc2 100644 --- a/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/resources/examples/gradle/base/androidKotlinLibrary.gradle.kts +++ b/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/resources/examples/gradle/base/androidKotlinLibrary.gradle.kts @@ -7,7 +7,7 @@ plugins { id("com.android.library") id("kotlin-android") //id("org.jetbrains.kotlinx.binary-compatibility-validator") - id("dev.adamko.kotlin.binary-compatibility-validator") version "0.0.2" + id("dev.adamko.kotlin.binary-compatibility-validator") version "0.0.3" } android { diff --git a/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/resources/examples/gradle/base/androidProjectRoot.gradle.kts b/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/resources/examples/gradle/base/androidProjectRoot.gradle.kts index 636d63c..7c3e861 100644 --- a/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/resources/examples/gradle/base/androidProjectRoot.gradle.kts +++ b/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/resources/examples/gradle/base/androidProjectRoot.gradle.kts @@ -3,7 +3,7 @@ plugins { id("com.android.library").version("7.2.2").apply(false) id("org.jetbrains.kotlin.android").version("1.7.10").apply(false) //id("org.jetbrains.kotlinx.binary-compatibility-validator").apply(false) - id("dev.adamko.kotlin.binary-compatibility-validator") version "0.0.2" apply false + id("dev.adamko.kotlin.binary-compatibility-validator") version "0.0.3" apply false } tasks.register("clean", Delete::class) { diff --git a/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/resources/examples/gradle/base/multiplatformWithJvmTargets.gradle.kts b/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/resources/examples/gradle/base/multiplatformWithJvmTargets.gradle.kts index 9232ac6..932ffe3 100644 --- a/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/resources/examples/gradle/base/multiplatformWithJvmTargets.gradle.kts +++ b/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/resources/examples/gradle/base/multiplatformWithJvmTargets.gradle.kts @@ -6,7 +6,7 @@ plugins { kotlin("multiplatform") version "1.5.20" //id("org.jetbrains.kotlinx.binary-compatibility-validator") - id("dev.adamko.kotlin.binary-compatibility-validator") version "0.0.2" + id("dev.adamko.kotlin.binary-compatibility-validator") version "0.0.3" } //repositories { diff --git a/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/resources/examples/gradle/base/multiplatformWithSingleJvmTarget.gradle.kts b/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/resources/examples/gradle/base/multiplatformWithSingleJvmTarget.gradle.kts index f39008b..b934e1c 100644 --- a/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/resources/examples/gradle/base/multiplatformWithSingleJvmTarget.gradle.kts +++ b/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/resources/examples/gradle/base/multiplatformWithSingleJvmTarget.gradle.kts @@ -4,9 +4,9 @@ */ plugins { - kotlin("multiplatform") version "1.5.20" + kotlin("multiplatform") version "1.7.20" //id("org.jetbrains.kotlinx.binary-compatibility-validator") - id("dev.adamko.kotlin.binary-compatibility-validator") version "0.0.2" + id("dev.adamko.kotlin.binary-compatibility-validator") version "0.0.3" } //repositories { diff --git a/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/resources/examples/gradle/base/withPlugin-noKotlinVersion.gradle.kts b/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/resources/examples/gradle/base/withPlugin-noKotlinVersion.gradle.kts index da1aad9..fa7826c 100644 --- a/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/resources/examples/gradle/base/withPlugin-noKotlinVersion.gradle.kts +++ b/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/resources/examples/gradle/base/withPlugin-noKotlinVersion.gradle.kts @@ -6,7 +6,7 @@ plugins { kotlin("jvm") //id("org.jetbrains.kotlinx.binary-compatibility-validator") - id("dev.adamko.kotlin.binary-compatibility-validator") version "0.0.2" + id("dev.adamko.kotlin.binary-compatibility-validator") version "0.0.3" } //repositories { diff --git a/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/resources/examples/gradle/base/withPlugin.gradle.kts b/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/resources/examples/gradle/base/withPlugin.gradle.kts index c8fc10a..8c3cf71 100644 --- a/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/resources/examples/gradle/base/withPlugin.gradle.kts +++ b/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/resources/examples/gradle/base/withPlugin.gradle.kts @@ -6,7 +6,7 @@ plugins { kotlin("jvm") version "1.7.20" //id("org.jetbrains.kotlinx.binary-compatibility-validator") - id("dev.adamko.kotlin.binary-compatibility-validator") version "0.0.2" + id("dev.adamko.kotlin.binary-compatibility-validator") version "0.0.3" } //repositories { diff --git a/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/resources/examples/gradle/configuration/nonPublicMarkers/markers.gradle.kts b/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/resources/examples/gradle/configuration/nonPublicMarkers/markers.gradle.kts index f4e2da4..2195984 100644 --- a/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/resources/examples/gradle/configuration/nonPublicMarkers/markers.gradle.kts +++ b/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/resources/examples/gradle/configuration/nonPublicMarkers/markers.gradle.kts @@ -1,9 +1,4 @@ -/* - * 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. - */ - configure { - nonPublicMarkers.add("foo.HiddenField") - nonPublicMarkers.add("foo.HiddenProperty") + ignoredMarkers.add("foo.HiddenField") + ignoredMarkers.add("foo.HiddenProperty") } diff --git a/modules/bcv-gradle-plugin-functional-tests/src/functionalTest2/kotlin/DefaultConfigTests.kt b/modules/bcv-gradle-plugin-functional-tests/src/functionalTest2/kotlin/DefaultConfigTests.kt index 9daf892..d21c144 100644 --- a/modules/bcv-gradle-plugin-functional-tests/src/functionalTest2/kotlin/DefaultConfigTests.kt +++ b/modules/bcv-gradle-plugin-functional-tests/src/functionalTest2/kotlin/DefaultConfigTests.kt @@ -23,7 +23,7 @@ internal class DefaultConfigTests : FunSpec({ buildGradleKts += """ |plugins { | kotlin("jvm") version "1.7.20" - | id("dev.adamko.kotlin.binary-compatibility-validator") version "0.0.2" + | id("dev.adamko.kotlin.binary-compatibility-validator") version "0.0.3" |} | """.trimMargin() diff --git a/modules/bcv-gradle-plugin-functional-tests/src/testFixtures/kotlin/GradleTestKitUtils.kt b/modules/bcv-gradle-plugin-functional-tests/src/testFixtures/kotlin/GradleTestKitUtils.kt index 544905a..471e1cf 100644 --- a/modules/bcv-gradle-plugin-functional-tests/src/testFixtures/kotlin/GradleTestKitUtils.kt +++ b/modules/bcv-gradle-plugin-functional-tests/src/testFixtures/kotlin/GradleTestKitUtils.kt @@ -6,6 +6,7 @@ import dev.adamko.kotlin.binary_compatibility_validator.test.utils.GradleProject import java.io.File import java.nio.file.Path import java.nio.file.Paths +import kotlin.io.path.name import kotlin.properties.PropertyDelegateProvider import kotlin.properties.ReadOnlyProperty import kotlin.properties.ReadWriteProperty @@ -26,10 +27,21 @@ class GradleProjectTest( baseDir: Path = funcTestTempDir, ) : this(projectDir = baseDir.resolve(testProjectName)) - val runner: GradleRunner = GradleRunner.create().withProjectDir(projectDir.toFile()) + val runner: GradleRunner = GradleRunner.create() + .withProjectDir(projectDir.toFile()) + .apply { + gradleTestKitDir?.let { + println("Using Gradle TestKit dir $it") + withTestKitDir(it.toFile()) + } + } + + val projectName by projectDir::name companion object { + val gradleTestKitDir: Path? by optionalSystemProperty(Paths::get) + /** file-based Maven Repo that contains the published plugin */ private val testMavenRepoDir: Path by systemProperty(Paths::get) val testMavenRepoPathString @@ -50,14 +62,25 @@ class GradleProjectTest( private fun systemProperty() = systemProperty { it } + private fun optionalSystemProperty( + convert: (String) -> T? + ): PropertyDelegateProvider> = + PropertyDelegateProvider { _: Any?, property -> + val systemProp = System.getProperty(property.name) + val value = if (systemProp != null) convert(systemProp) else null + ReadOnlyProperty { _, _ -> value } + } + private fun systemProperty( - convert: (String) -> T, - ) = ReadOnlyProperty { _, property -> - val value = requireNotNull(System.getProperty(property.name)) { - "system property ${property.name} is unavailable" + convert: (String) -> T & Any + ): PropertyDelegateProvider> = + PropertyDelegateProvider { _: Any?, property -> + val systemProp = requireNotNull(System.getProperty(property.name)) { + "system property ${property.name} is unavailable" + } + val converted = convert(systemProp) + ReadOnlyProperty { _, _ -> converted } } - convert(value) - } } } @@ -76,7 +99,7 @@ fun gradleKtsProjectTest( return GradleProjectTest(baseDir = baseDir, testProjectName = testProjectName).apply { settingsGradleKts = """ - |rootProject.name = "$testProjectName" + |rootProject.name = "$projectName" | |@Suppress("UnstableApiUsage") |dependencyResolutionManagement { @@ -225,27 +248,27 @@ fun ProjectDirectoryScope.findFiles(matcher: (File) -> Boolean): Sequence projectDir.toFile().walk().filter(matcher) -/** Set the content of `settings.gradle.kts` */ +/** Get or set the content of `settings.gradle.kts` */ @delegate:Language("kts") var ProjectDirectoryScope.settingsGradleKts: String by TestProjectFileDelegate("settings.gradle.kts") -/** Set the content of `build.gradle.kts` */ +/** Get or set the content of `build.gradle.kts` */ @delegate:Language("kts") var ProjectDirectoryScope.buildGradleKts: String by TestProjectFileDelegate("build.gradle.kts") -/** Set the content of `settings.gradle` */ +/** Get or set the content of `settings.gradle` */ @delegate:Language("groovy") var ProjectDirectoryScope.settingsGradle: String by TestProjectFileDelegate("settings.gradle") -/** Set the content of `build.gradle` */ +/** Get or set the content of `build.gradle` */ @delegate:Language("groovy") var ProjectDirectoryScope.buildGradle: String by TestProjectFileDelegate("build.gradle") -/** Set the content of `gradle.properties` */ +/** Get or set the content of `gradle.properties` */ @delegate:Language("properties") var ProjectDirectoryScope.gradleProperties: String by TestProjectFileDelegate("gradle.properties") diff --git a/modules/bcv-gradle-plugin-functional-tests/src/testFixtures/kotlin/api/TestDsl.kt b/modules/bcv-gradle-plugin-functional-tests/src/testFixtures/kotlin/api/TestDsl.kt index c3a0dc3..5a1422d 100644 --- a/modules/bcv-gradle-plugin-functional-tests/src/testFixtures/kotlin/api/TestDsl.kt +++ b/modules/bcv-gradle-plugin-functional-tests/src/testFixtures/kotlin/api/TestDsl.kt @@ -1,5 +1,6 @@ package dev.adamko.kotlin.binary_compatibility_validator.test.utils.api +import dev.adamko.kotlin.binary_compatibility_validator.test.utils.GradleProjectTest import dev.adamko.kotlin.binary_compatibility_validator.test.utils.GradleProjectTest.Companion.minimumGradleTestVersion import dev.adamko.kotlin.binary_compatibility_validator.test.utils.GradleProjectTest.Companion.testMavenRepoPathString import dev.adamko.kotlin.binary_compatibility_validator.test.utils.invariantNewlines @@ -56,6 +57,12 @@ fun BaseKotlinGradleTest.test(fn: BaseKotlinScope.() -> Unit): GradleRunner { .withProjectDir(rootProjectDir) .withGradleVersion(minimumGradleTestVersion) .withArguments(baseKotlinScope.runner.arguments) + .apply { + GradleProjectTest.gradleTestKitDir?.let { + println("Using Gradle TestKit dir $it") + withTestKitDir(it.toFile()) + } + } } /** diff --git a/modules/bcv-gradle-plugin/build.gradle.kts b/modules/bcv-gradle-plugin/build.gradle.kts index 9251700..d7c6a7c 100644 --- a/modules/bcv-gradle-plugin/build.gradle.kts +++ b/modules/bcv-gradle-plugin/build.gradle.kts @@ -6,14 +6,16 @@ plugins { buildsrc.conventions.`kotlin-gradle-plugin` buildsrc.conventions.`maven-publish-test` `java-test-fixtures` -// buildsrc.conventions.`gradle-plugin-variants` + //com.github.johnrengelman.shadow + //buildsrc.conventions.`gradle-plugin-variants` } dependencies { implementation(libs.javaDiffUtils) compileOnly(libs.kotlinx.bcv) - compileOnly(libs.kotlin.gradlePlugin) +// compileOnly(libs.kotlin.gradlePlugin) + compileOnly(libs.kotlin.gradlePluginApi) testFixturesApi(gradleTestKit()) @@ -73,9 +75,16 @@ configurations attributes { attribute( GRADLE_PLUGIN_API_VERSION_ATTRIBUTE, - objects.named(libs.versions.testGradleVersion.get()) + objects.named(libs.versions.supportedGradleVersion.get()) ) } } skipTestFixturesPublications() + +// Shadow plugin doesn't seem to help with https://github.com/adamko-dev/kotlin-binary-compatibility-validator-mu/issues/1 +//tasks.shadowJar { +// minimize() +// isEnableRelocation = false +// archiveClassifier.set("") +//} diff --git a/modules/bcv-gradle-plugin/src/main/kotlin/BCVPlugin.kt b/modules/bcv-gradle-plugin/src/main/kotlin/BCVPlugin.kt index 92d0cbd..9c1bc01 100644 --- a/modules/bcv-gradle-plugin/src/main/kotlin/BCVPlugin.kt +++ b/modules/bcv-gradle-plugin/src/main/kotlin/BCVPlugin.kt @@ -4,7 +4,7 @@ import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.api.initialization.Settings import org.gradle.api.plugins.PluginAware -import org.gradle.kotlin.dsl.apply +import org.gradle.kotlin.dsl.* abstract class BCVPlugin : Plugin { diff --git a/modules/bcv-gradle-plugin/src/main/kotlin/BCVProjectPlugin.kt b/modules/bcv-gradle-plugin/src/main/kotlin/BCVProjectPlugin.kt index 2a86e8e..accd60b 100644 --- a/modules/bcv-gradle-plugin/src/main/kotlin/BCVProjectPlugin.kt +++ b/modules/bcv-gradle-plugin/src/main/kotlin/BCVProjectPlugin.kt @@ -17,9 +17,9 @@ import org.gradle.api.tasks.SourceSet import org.gradle.internal.component.external.model.TestFixturesSupport.TEST_FIXTURE_SOURCESET_NAME import org.gradle.kotlin.dsl.* import org.gradle.language.base.plugins.LifecycleBasePlugin -import org.jetbrains.kotlin.gradle.dsl.KotlinAndroidProjectExtension -import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType +import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSetContainer +import org.jetbrains.kotlin.gradle.plugin.KotlinTargetsContainer abstract class BCVProjectPlugin @Inject constructor( @@ -95,9 +95,6 @@ abstract class BCVProjectPlugin @Inject constructor( private fun createExtension(project: Project): BCVProjectExtension { val extension = project.extensions.create(EXTENSION_NAME, BCVProjectExtension::class).apply { enabled.convention(true) - ignoredPackages.convention(emptySet()) - ignoredMarkers.convention(emptySet()) - ignoredClasses.convention(emptySet()) outputApiDir.convention(layout.projectDirectory.dir(API_DIR)) projectName.convention(providers.provider { project.name }) kotlinxBinaryCompatibilityValidatorVersion.convention("0.13.0") @@ -106,10 +103,10 @@ abstract class BCVProjectPlugin @Inject constructor( extension.targets.configureEach { enabled.convention(true) ignoredClasses.convention(extension.ignoredClasses) - ignoredMarkers.convention(extension.ignoredMarkers.apply { + ignoredMarkers.convention( @Suppress("DEPRECATION") - addAll(extension.nonPublicMarkers) - }) + extension.ignoredMarkers.orElse(extension.nonPublicMarkers) + ) ignoredPackages.convention(extension.ignoredPackages) } @@ -141,11 +138,10 @@ abstract class BCVProjectPlugin @Inject constructor( extension: BCVProjectExtension, ) { project.pluginManager.withPlugin("kotlin-android") { - val androidExtension = project.extensions.getByType() - - extension.targets.create(androidExtension.target.name) { - androidExtension.target.compilations.all { - inputClasses.from(this) + val kotlinSourceSetsContainer = project.extensions.getByType() + kotlinSourceSetsContainer.sourceSets.all { + extension.targets.create(name) { + inputClasses.from(kotlin.classesDirectory) } } } @@ -156,19 +152,28 @@ abstract class BCVProjectPlugin @Inject constructor( extension: BCVProjectExtension, ) { project.pluginManager.withPlugin("kotlin-multiplatform") { - val kotlinExtension = project.extensions.getByType() - val kotlinJvmTargets = kotlinExtension.targets.matching { - it.platformType in arrayOf(KotlinPlatformType.jvm, KotlinPlatformType.androidJvm) - } - - kotlinJvmTargets.all { - extension.targets.create(targetName) { - enabled.convention(true) - compilations.all { - inputClasses.from(output.classesDirs) + val kotlinTargetsContainer = project.extensions.getByType() + + kotlinTargetsContainer.targets + .matching { + it.platformType in arrayOf(KotlinPlatformType.jvm, KotlinPlatformType.androidJvm) + }.all { + val targetPlatformType = platformType + + extension.targets.register(targetName) { + enabled.convention(true) + compilations + .matching { + when (targetPlatformType) { + KotlinPlatformType.jvm -> it.name == "main" + KotlinPlatformType.androidJvm -> it.name == "release" + else -> false + } + }.all { + inputClasses.from(output.classesDirs) + } } } - } } } diff --git a/modules/bcv-gradle-plugin/src/main/kotlin/BCVSettingsPlugin.kt b/modules/bcv-gradle-plugin/src/main/kotlin/BCVSettingsPlugin.kt index de1604b..1386b97 100644 --- a/modules/bcv-gradle-plugin/src/main/kotlin/BCVSettingsPlugin.kt +++ b/modules/bcv-gradle-plugin/src/main/kotlin/BCVSettingsPlugin.kt @@ -1,18 +1,32 @@ package dev.adamko.kotlin.binary_compatibility_validator import dev.adamko.kotlin.binary_compatibility_validator.internal.globToRegex +import dev.adamko.kotlin.binary_compatibility_validator.targets.BCVTargetSpec +import javax.inject.Inject import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.api.initialization.Settings +import org.gradle.api.model.ObjectFactory import org.gradle.api.provider.SetProperty -import org.gradle.kotlin.dsl.apply -import org.gradle.kotlin.dsl.create +import org.gradle.kotlin.dsl.* -abstract class BCVSettingsPlugin : Plugin { +abstract class BCVSettingsPlugin @Inject constructor( + private val objects: ObjectFactory +) : Plugin { override fun apply(settings: Settings) { - val extension = settings.extensions.create("bcvSettings", Extension::class).apply { + val extension = settings.extensions.create( + "bcvSettings", + objects.newInstance(), + ).apply { ignoredProjects.convention(emptySet()) + + defaultTargetValues { + enabled.convention(true) + ignoredClasses.convention(emptySet()) + ignoredMarkers.convention(emptySet()) + ignoredPackages.convention(emptySet()) + } } settings.gradle.beforeProject { @@ -22,11 +36,24 @@ abstract class BCVSettingsPlugin : Plugin { } ) { project.pluginManager.apply(BCVProjectPlugin::class) + project.extensions.configure { + enabled.convention(extension.defaultTargetValues.enabled) + ignoredClasses.convention(extension.defaultTargetValues.ignoredClasses) + ignoredMarkers.convention(extension.defaultTargetValues.ignoredMarkers) + ignoredPackages.convention(extension.defaultTargetValues.ignoredPackages) + } } } } - interface Extension { + abstract class Extension @Inject constructor( + + /** + * Set [BCVTargetSpec] values that will be used as defaults for all + * [BCVProjectExtension.targets] in subprojects. + */ + val defaultTargetValues: BCVTargetSpec + ) { /** * Paths of projects. @@ -37,6 +64,10 @@ abstract class BCVSettingsPlugin : Plugin { * - `*` will match zero, or many characters, excluding `:` * - `**` will match 0 to many characters, including `:` */ - val ignoredProjects: SetProperty + abstract val ignoredProjects: SetProperty + + + fun defaultTargetValues(configure: BCVTargetSpec.() -> Unit) = + defaultTargetValues.configure() } } diff --git a/modules/bcv-gradle-plugin/src/main/kotlin/internal/gradleAccessors.kt b/modules/bcv-gradle-plugin/src/main/kotlin/internal/gradleAccessors.kt index 7f02865..9f7a061 100644 --- a/modules/bcv-gradle-plugin/src/main/kotlin/internal/gradleAccessors.kt +++ b/modules/bcv-gradle-plugin/src/main/kotlin/internal/gradleAccessors.kt @@ -2,7 +2,7 @@ package dev.adamko.kotlin.binary_compatibility_validator.internal import org.gradle.api.Project import org.gradle.api.tasks.SourceSetContainer -import org.gradle.kotlin.dsl.getByType +import org.gradle.kotlin.dsl.* internal val Project.sourceSets: SourceSetContainer diff --git a/modules/bcv-gradle-plugin/src/testFixtures/kotlin/kotestGradleAssertions.kt b/modules/bcv-gradle-plugin/src/testFixtures/kotlin/kotestGradleAssertions.kt index 9e10b56..76e10a9 100644 --- a/modules/bcv-gradle-plugin/src/testFixtures/kotlin/kotestGradleAssertions.kt +++ b/modules/bcv-gradle-plugin/src/testFixtures/kotlin/kotestGradleAssertions.kt @@ -34,6 +34,17 @@ infix fun BuildResult?.shouldHaveRunTask(taskPath: String): BuildTask { return this?.task(taskPath)!! } +/** Assert that a task ran, with an [expected outcome][expectedOutcome]. */ +fun BuildResult?.shouldHaveRunTask( + taskPath: String, + expectedOutcome: TaskOutcome +): BuildTask { + this should haveTask(taskPath) + val task = this?.task(taskPath)!! + task should haveOutcome(expectedOutcome) + return task +} + /** * Assert that a task did not run. *