Skip to content

Commit

Permalink
add basic Gradle integration test scaffolding
Browse files Browse the repository at this point in the history
  • Loading branch information
RBusarow committed Nov 18, 2023
1 parent 18ae172 commit 12283a0
Show file tree
Hide file tree
Showing 16 changed files with 584 additions and 26 deletions.
31 changes: 31 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,37 @@ jobs :
name : insrumentation-test-results
path : ./**/build/reports/androidTests/connected/**

plugin-integration-tests :
name : Instrumentation tests
runs-on : macos-latest
timeout-minutes : 20
strategy :
# Allow tests to continue on other devices if they fail on one device.
fail-fast : false
matrix :
kotlin-version : [ 1.8.22, 1.9.10 ]
agp-version : [ 7.3.1, 8.1.0 ]
gradle-version : [ 7.6.1, 8.2.1, 8.4 ]

steps :
- uses : actions/checkout@v3
- uses : actions/setup-java@v3
with :
distribution : 'temurin'
java-version : '11'
check-latest : true

- name : Gradle integration tests
run : ./gradlew integrationTest --stacktrace -Doverride_kotlin=${{ matrix.kotlin-version }} -Doverride_gradle=${{ matrix.kotlin-version }} -Doverride_agp=${{ matrix.agp-version }}

- name : Upload Test Results
uses : actions/upload-artifact@v3
if : ${{ failure() }}
with :
# Use the Kotlin version to prevent overrides.
name : test-results-gradle-integration-${{ matrix.kotlin-version }}-${{ matrix.gradle-version }}-${{ matrix.agp-version }}
path : ./**/build/reports/tests/

gradle-wrapper-validation :
name : "Validate the Gradle Wrapper"
runs-on : ubuntu-latest
Expand Down
4 changes: 4 additions & 0 deletions build-logic/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ gradlePlugin {
id = "com.squareup.anvil.publish"
implementationClass = "com.squareup.anvil.PublishConventionPlugin"
}
itegration {
id = "com.squareup.anvil.itegration-tests"
implementationClass = "com.squareup.anvil.IntegrationTestsConventionPlugin"
}
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
* Copyright (C) 2023 Rick Busarow
* 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.
*/

package com.squareup.anvil

import com.rickbusarow.kgx.applyOnce
import com.rickbusarow.kgx.dependsOn
import com.rickbusarow.kgx.javaExtension
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.tasks.SourceSet
import org.gradle.api.tasks.testing.Test
import org.gradle.language.base.plugins.LifecycleBasePlugin
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension

abstract class IntegrationTestsConventionPlugin : Plugin<Project> {
override fun apply(target: Project) {
target.plugins.applyOnce("idea")

val integrationTestSourceSet = target.javaExtension
.sourceSets
.register(INTEGRATION_TEST) { ss ->

ss.compileClasspath += target.javaSourceSet("main")
.output
.plus(target.javaSourceSet("test").output)
.plus(target.configurations.getByName("testRuntimeClasspath"))

ss.runtimeClasspath += ss.output + ss.compileClasspath
}

target.configurations.register("${INTEGRATION_TEST}Compile") {
it.extendsFrom(target.configurations.getByName("testCompileOnly"))
}
target.configurations.register("${INTEGRATION_TEST}Runtime") {
it.extendsFrom(target.configurations.getByName("testRuntimeOnly"))
}

val integrationTestTask = target.tasks
.register(INTEGRATION_TEST, Test::class.java) { task ->

task.group = "verification"
task.description = "tests the '$INTEGRATION_TEST' source set"

task.useJUnitPlatform()

val mainSourceSet = target.javaSourceSet("main")

val ss = integrationTestSourceSet.get()

task.testClassesDirs = ss.output.classesDirs
task.classpath = ss.runtimeClasspath
task.inputs.files(ss.output.classesDirs)
task.inputs.files(mainSourceSet.allSource)
}

target.tasks.named(LifecycleBasePlugin.CHECK_TASK_NAME).dependsOn(integrationTestTask)

target.extensions.configure(KotlinJvmProjectExtension::class.java) { kotlin ->
val compilations = kotlin.target.compilations

compilations.getByName(INTEGRATION_TEST) {
it.associateWith(compilations.getByName("main"))
}
}
}

private fun Project.javaSourceSet(name: String): SourceSet {
return javaExtension.sourceSets.getByName(name)
}

companion object {
private const val INTEGRATION_TEST = "integrationTest"
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.squareup.anvil

import com.rickbusarow.kgx.mustRunAfter
import com.vanniktech.maven.publish.JavadocJar
import com.vanniktech.maven.publish.KotlinJvm
import com.vanniktech.maven.publish.MavenPublishBaseExtension
Expand All @@ -10,15 +11,20 @@ import org.gradle.api.publish.PublishingExtension
import org.gradle.api.publish.maven.MavenPublication
import org.gradle.api.publish.tasks.GenerateModuleMetadata
import org.gradle.api.tasks.bundling.Jar
import org.jetbrains.kotlin.gradle.internal.KaptTask
import javax.inject.Inject

open class PublishConventionPlugin : Plugin<Project> {
override fun apply(target: Project) {
target.extensions.create("publish", PublishExtension::class.java)

// if (target.rootProject.name != "anvil") return

target.plugins.apply("com.vanniktech.maven.publish.base")
target.plugins.apply("org.jetbrains.dokka")

target.extensions.create("publish", PublishExtension::class.java)
target.tasks.named("dokkaHtml")
.mustRunAfter(target.tasks.withType(KaptTask::class.java))

val mavenPublishing = target.extensions
.getByType(MavenPublishBaseExtension::class.java)
Expand All @@ -29,8 +35,14 @@ open class PublishConventionPlugin : Plugin<Project> {
mavenPublishing.pomFromGradleProperties()
mavenPublishing.signAllPublications()

target.plugins.withId("org.jetbrains.kotlin.jvm") {
val javadocJar = if (target.isInMainBuild) {
JavadocJar.Dokka("dokkaHtml")
} else {
// skip Dokka if this is just publishing for integration tests
JavadocJar.None()
}

target.plugins.withId("org.jetbrains.kotlin.jvm") {
when {
target.plugins.hasPlugin(pluginPublishId) -> {
// Gradle's 'plugin-publish' plugin creates its own publication. We only apply this plugin
Expand All @@ -41,11 +53,26 @@ open class PublishConventionPlugin : Plugin<Project> {
configurePublication(
target,
mavenPublishing,
KotlinJvm(javadocJar = JavadocJar.Dokka("dokkaHtml"), sourcesJar = true),
KotlinJvm(javadocJar = javadocJar, sourcesJar = true),
)
}
}
}

// We publish all artifacts to `anvil/build/m2` for the plugin integration tests.
target.gradlePublishingExtension.repositories { repositories ->
repositories.maven {
it.name = "buildM2"
it.setUrl(target.rootProject.layout.buildDirectory.dir("m2"))
}
}
// No one wants to type all that
target.tasks.register("publishToBuildM2") {
it.group = "Publishing"
it.description = "Delegates to the publishAllPublicationsToBuildM2Repository task " +
"on projects where publishing is enabled."
it.dependsOn("publishAllPublicationsToBuildM2Repository")
}
}

@Suppress("UnstableApiUsage")
Expand All @@ -64,19 +91,23 @@ open class PublishConventionPlugin : Plugin<Project> {
}
}

private val Project.isInMainBuild: Boolean
get() = rootProject.name == "anvil"
private val Project.gradlePublishingExtension: PublishingExtension
get() = extensions.getByType(PublishingExtension::class.java)

open class PublishExtension @Inject constructor(
private val target: Project,
private val target: Project
) {
fun configurePom(args: Map<String, Any>) {
// if (target.rootProject.name != "anvil") return

val artifactId = args.getValue("artifactId") as String
val pomName = args.getValue("pomName") as String
val pomDescription = args.getValue("pomDescription") as String

target.extensions
.getByType(PublishingExtension::class.java)
target.gradlePublishingExtension
.publications.withType(MavenPublication::class.java)
.matching { !it.name.endsWith("PluginMarkerMaven") }
.configureEach { publication ->

// Gradle plugin publications have their own artifactID convention,
Expand Down
16 changes: 15 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@ import org.gradle.api.internal.project.DefaultProject
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

buildscript {
dependencies {
classpath 'com.squareup.anvil:gradle-plugin'
}
}

plugins {
alias(libs.plugins.agp.application) apply false
alias(libs.plugins.agp.library) apply false
Expand All @@ -14,7 +20,6 @@ plugins {
alias(libs.plugins.ktlint) apply false
alias(libs.plugins.mavenPublishBase) apply false
id 'com.squareup.anvil.root'
id 'com.squareup.anvil' apply false
}

allprojects {
Expand All @@ -36,6 +41,15 @@ println "Versions: " + [
"Full test run": ext.fullTestRun,
]

// This task is registered in all projects in order to simplify publishing before the
// `:gradle-plugin` integration tests.
// Since the plugin doesn't actually directly depend upon the other projects, it doesn't force the
// other projects to be configured. This task is a simple hook to force that configuration in the
// integration test workflow.
tasks.register("publishToBuildM2") {
it.group = 'Publishing'
}

boolean configureOnDemandEnabled = getProperty("org.gradle.configureondemand", "false").toBoolean()

subprojects {
Expand Down
5 changes: 0 additions & 5 deletions compiler/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,6 @@ dependencies {
testImplementation libs.truth
}

// Fixes:
// Reason: Task ':compiler:dokkaHtml' uses this output of task ':compiler:kaptKotlin'
// without declaring an explicit or implicit dependency.
tasks.named("dokkaHtml") { mustRunAfter("kaptKotlin") }

tasks.withType(KotlinCompile).configureEach {
compilerOptions {
// The flag is needed because we extend an interface that uses @JvmDefault and the Kotlin
Expand Down
60 changes: 60 additions & 0 deletions gradle-plugin-build-logic/build.gradle
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
id 'java-base'
alias(libs.plugins.kotlin.android) apply false
alias(libs.plugins.kotlin.dokka) apply false
alias(libs.plugins.kotlin.jvm) apply false
alias(libs.plugins.kotlin.kapt) apply false
alias(libs.plugins.kotlin.multiplatform) apply false
}

java {
Expand All @@ -19,3 +27,55 @@ Properties mainBuildProperties = new Properties().tap { props ->
mainBuildProperties.each { key, value ->
ext[key.toString()] = value
}

boolean isCi = (System.getenv('CI') ?: 'false').toBoolean()

ext {
ci = isCi
fullTestRun = libs.versions.config.fullTestRun.get().toBoolean()
warningsAsErrors = isCi
}

subprojects {

tasks.withType(Test).configureEach {
testLogging {
events 'passed', 'failed', 'skipped', 'standardOut', 'standardError'
exceptionFormat 'FULL'
showCauses true
showExceptions true
showStackTraces true
showStandardStreams true
}
}

pluginManager.withPlugin("java") {
// Use JDK 11 but target Java 8 for maximum compatibility.
java {
toolchain {
languageVersion.set(JavaLanguageVersion.of(11))
}
}

tasks.withType(JavaCompile).configureEach {
options.release.set(8)
}
}

tasks.withType(KotlinCompile).configureEach {
compilerOptions {
jvmTarget.set(JvmTarget.JVM_1_8)

allWarningsAsErrors.set(warningsAsErrors)
freeCompilerArgs.add("-opt-in=kotlin.RequiresOptIn")

boolean optInExperimental = project.name != "annotations"
&& project.name != "annotations-optional"
&& project.name != "scopes"
&& project.name != "dagger-factories-only"
if (project.path != ':gradle-plugin' && optInExperimental) {
freeCompilerArgs.add("-opt-in=com.squareup.anvil.annotations.ExperimentalAnvilApi")
}
}
}
}
15 changes: 14 additions & 1 deletion gradle-plugin-build-logic/settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,17 @@ dependencyResolutionManagement {
}

include ':gradle-plugin'
project(':gradle-plugin').projectDir = new File('../gradle-plugin')
project(':gradle-plugin').projectDir = file('../gradle-plugin')
include ':annotations'
project(':annotations').projectDir = file('../annotations')
include ':annotations-optional'
project(':annotations-optional').projectDir = file('../annotations-optional')
include ':compiler'
project(':compiler').projectDir = file('../compiler')
include ':compiler-api'
project(':compiler-api').projectDir = file('../compiler-api')
include ':compiler-utils'
project(':compiler-utils').projectDir = file('../compiler-utils')

// TODO delete me
includeBuild '../../kase'
Loading

0 comments on commit 12283a0

Please sign in to comment.