Skip to content

Commit bd90132

Browse files
authored
Allow custom jacoco version (#16)
The version of the jacoco used to pre-instrument classes must match the version of jacoco used at runtime. Instead of having the coverage plugin depend on the jacoco runtime, we inject the jacoco dependency (with the right version) when we publish a plugin under test into the integration repository
1 parent 04afa16 commit bd90132

File tree

6 files changed

+118
-30
lines changed

6 files changed

+118
-30
lines changed

coverage-plugin/build.gradle.kts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,6 @@ gradlePlugin {
1818

1919
dependencies {
2020
implementation(gradleApi())
21-
implementation(libs.jacoco.agent) {
22-
artifact {
23-
classifier = "runtime"
24-
extension = "jar"
25-
}
26-
}
2721
implementation(projects.jacocoReflect)
2822

2923
testImplementation(projects.junit5)

integration-tests/build.gradle.kts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import com.gradle.publish.PublishPlugin
2+
import com.gradle.publish.PublishTask
13
import com.toasttab.gradle.testkit.shared.RepositoryDescriptor
24
import com.toasttab.gradle.testkit.shared.configureIntegrationPublishing
35
import com.toasttab.gradle.testkit.shared.publishOnlyIf
@@ -22,6 +24,10 @@ gradlePlugin {
2224
}
2325
}
2426

27+
jacoco {
28+
toolVersion = "0.8.12"
29+
}
30+
2531
tasks {
2632
test {
2733
systemProperty("version", "$version")
@@ -32,6 +38,10 @@ tasks {
3238
configureIntegrationPublishing("testRuntimeClasspath")
3339
publishOnlyIf { _, repo -> repo == RepositoryDescriptor.INTEGRATION }
3440

41+
tasks.withType<PublishTask> {
42+
enabled = false
43+
}
44+
3545
dependencies {
3646
implementation(gradleApi())
3747
testImplementation(libs.junit)

shared-build-logic/src/main/kotlin/com/toasttab/gradle/testkit/shared/Artifacts.kt

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,24 +15,12 @@
1515

1616
package com.toasttab.gradle.testkit.shared
1717

18-
import org.gradle.api.Project
19-
import org.gradle.api.artifacts.component.ModuleComponentIdentifier
20-
import org.gradle.api.artifacts.component.ProjectComponentIdentifier
21-
import org.gradle.api.artifacts.result.ArtifactResult
18+
import org.gradle.api.artifacts.Configuration
2219
import org.gradle.api.attributes.Attribute
23-
import org.gradle.api.plugins.JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME
2420

2521
private val ARTIFACT_TYPE_ATTRIBUTE = Attribute.of("artifactType", String::class.java)
2622

27-
fun Project.runtimeArtifacts() = configurations.getAt(RUNTIME_CLASSPATH_CONFIGURATION_NAME).incoming.artifactView {
23+
fun Configuration.artifacts() = incoming.artifactView {
2824
lenient(true)
2925
attributes.attribute(ARTIFACT_TYPE_ATTRIBUTE, "jar")
3026
}.artifacts
31-
32-
fun ArtifactResult.isProject() = id.componentIdentifier is ProjectComponentIdentifier
33-
34-
fun ArtifactResult.isExternalPluginDependency(): Boolean {
35-
val identifier = id.componentIdentifier
36-
37-
return identifier is ModuleComponentIdentifier && identifier.group != "org.jetbrains.kotlin"
38-
}

shared-build-logic/src/main/kotlin/com/toasttab/gradle/testkit/shared/IntegrationPublishing.kt

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,21 @@
1+
/*
2+
* Copyright (c) 2024 Toast Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
116
package com.toasttab.gradle.testkit.shared
217

318
import org.gradle.api.Project
4-
import org.gradle.api.artifacts.Configuration
519
import org.gradle.api.artifacts.component.ProjectComponentIdentifier
620
import org.gradle.api.attributes.Attribute
721
import org.gradle.api.publish.PublishingExtension
@@ -16,7 +30,6 @@ import org.gradle.kotlin.dsl.named
1630
import org.gradle.kotlin.dsl.register
1731
import org.gradle.kotlin.dsl.withType
1832
import org.gradle.plugin.devel.GradlePluginDevelopmentExtension
19-
import org.gradle.testing.jacoco.plugins.JacocoPlugin
2033

2134
sealed interface RepositoryDescriptor {
2235
object MavenLocal : RepositoryDescriptor
@@ -59,33 +72,33 @@ fun Project.configureIntegrationPublishing(
5972
val repo = integrationRepo
6073

6174
afterEvaluate {
62-
val jacocoAnt = project.configurations.findByName(JacocoPlugin.ANT_CONFIGURATION_NAME)
75+
val coverage = project.coverage()
6376

6477
configurations.getAt(configuration).incoming.artifactView {
6578
lenient(true)
6679
attributes.attribute(Attribute.of("artifactType", String::class.java), "jar")
6780
}.artifacts.map {
6881
it.id.componentIdentifier
6982
}.filterIsInstance<ProjectComponentIdentifier>().forEach {
70-
configureIntegrationPublishingForDependency(project(":${it.projectPath}"), repo, jacocoAnt)
83+
configureIntegrationPublishingForDependency(project(":${it.projectPath}"), repo, coverage)
7184
}
7285

73-
configureIntegrationPublishingForDependency(this, repo, jacocoAnt)
86+
configureIntegrationPublishingForDependency(this, repo, coverage)
7487
}
7588

7689
tasks.named("test") {
7790
dependsOn("publishIntegrationPublicationToIntegrationRepository")
7891
}
7992
}
8093

81-
private fun Project.configureIntegrationPublishingForDependency(project: Project, repo: Any, jacocoAnt: Configuration?) {
94+
private fun Project.configureIntegrationPublishingForDependency(project: Project, repo: Any, coverage: CoverageConfiguration) {
8295
project.pluginManager.apply("maven-publish")
8396

84-
if (jacocoAnt != null) {
97+
if (coverage is CoverageConfiguration.Jacoco) {
8598
project.tasks.register<InstrumentWithJacocoOfflineTask>("instrument") {
8699
dependsOn("jar")
87100

88-
classpath = jacocoAnt
101+
classpath = coverage.configuration
89102

90103
jar = project.tasks.named<Jar>("jar").flatMap { it.archiveFile }
91104

@@ -105,7 +118,16 @@ private fun Project.configureIntegrationPublishingForDependency(project: Project
105118
create<MavenPublication>(PublicationDescriptor.INTEGRATION_PUBLICATION_NAME) {
106119
from(project.components["java"])
107120

108-
if (jacocoAnt != null) {
121+
if (coverage is CoverageConfiguration.Jacoco) {
122+
pom {
123+
injectDependency(
124+
groupId = "org.jacoco",
125+
artifactId = "org.jacoco.agent",
126+
version = coverage.version,
127+
classifier = "runtime"
128+
)
129+
}
130+
109131
artifacts.clear()
110132

111133
artifact(project.layout.buildDirectory.file("instrumented/${project.name}-${project.version}.jar")) {
@@ -130,7 +152,7 @@ private fun Project.configureIntegrationPublishingForDependency(project: Project
130152
}
131153
}
132154

133-
if (jacocoAnt != null) {
155+
if (coverage is CoverageConfiguration.Jacoco) {
134156
project.tasks.named<GenerateModuleMetadata>("generateMetadataFileForIntegrationPublication") {
135157
enabled = false
136158
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* Copyright (c) 2024 Toast Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
package com.toasttab.gradle.testkit.shared
17+
18+
import org.gradle.api.Project
19+
import org.gradle.api.artifacts.Configuration
20+
import org.gradle.api.artifacts.component.ModuleComponentIdentifier
21+
import org.gradle.testing.jacoco.plugins.JacocoPlugin
22+
23+
sealed interface CoverageConfiguration {
24+
object None: CoverageConfiguration
25+
26+
class Jacoco(
27+
val configuration: Configuration
28+
): CoverageConfiguration {
29+
val version by lazy {
30+
configuration.artifacts().map { it.id.componentIdentifier }
31+
.filterIsInstance<ModuleComponentIdentifier>()
32+
.first { it.group == "org.jacoco" && it.module == "org.jacoco.ant" }
33+
.version
34+
}
35+
}
36+
}
37+
38+
fun Project.coverage() = configurations.findByName(JacocoPlugin.ANT_CONFIGURATION_NAME)?.let {
39+
CoverageConfiguration.Jacoco(it)
40+
} ?: CoverageConfiguration.None
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* Copyright (c) 2024 Toast Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
package com.toasttab.gradle.testkit.shared
17+
18+
import groovy.namespace.QName
19+
import groovy.util.Node
20+
import org.gradle.api.publish.maven.MavenPom
21+
22+
fun MavenPom.injectDependency(groupId: String, artifactId: String, version: String, classifier: String) {
23+
withXml {
24+
asNode().findOrCreateChild("dependencies").appendNode("dependency").apply {
25+
appendNode("groupId", groupId)
26+
appendNode("artifactId", artifactId)
27+
appendNode("version", version)
28+
appendNode("classifier", classifier)
29+
}
30+
}
31+
}
32+
33+
private fun Node.findChild(localName: String) = children().filterIsInstance<Node>().firstOrNull { (it.name() as QName).localPart == localName }
34+
private fun Node.findOrCreateChild(localName: String) = findChild(localName) ?: appendNode(localName)

0 commit comments

Comments
 (0)