Skip to content

Commit 90c1c5c

Browse files
danysantiagoDagger Team
authored andcommitted
Consolidate Dagger Gradle build convention plugin into one.
Using a single plugin but different project types allows for better integration between the plugin configurations under one convention plugin. RELNOTES=N/A PiperOrigin-RevId: 752412990
1 parent 5885a1e commit 90c1c5c

13 files changed

Lines changed: 325 additions & 322 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ eclipsebin
1010
bin
1111
gen
1212
build
13+
buildOut
1314
out
1415
lib
1516

buildSrc/build.gradle.kts

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,21 +17,9 @@ dependencies {
1717

1818
gradlePlugin {
1919
plugins {
20-
register("kotlinJvm") {
21-
id = libs.plugins.dagger.kotlinJvm.get().pluginId
22-
implementationClass = "dagger.gradle.build.KotlinJvmConventionPlugin"
23-
}
24-
}
25-
plugins {
26-
register("publish") {
27-
id = libs.plugins.dagger.publish.get().pluginId
28-
implementationClass = "dagger.gradle.build.PublishConventionPlugin"
29-
}
30-
}
31-
plugins {
32-
register("shadow") {
33-
id = libs.plugins.dagger.shadow.get().pluginId
34-
implementationClass = "dagger.gradle.build.ShadowConventionPlugin"
20+
register("build") {
21+
id = libs.plugins.daggerBuild.get().pluginId
22+
implementationClass = "dagger.gradle.build.DaggerConventionPlugin"
3523
}
3624
}
3725
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
* Copyright (C) 2025 The Dagger Authors.
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+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package dagger.gradle.build
18+
19+
/**
20+
* Extension for [DaggerConventionPlugin] that's responsible for holding configuration options.
21+
*/
22+
abstract class DaggerBuildExtension {
23+
/** The type of project */
24+
var type: ProjectType = ProjectType.LIBRARY
25+
26+
/** Whether the project artifacts are published or not */
27+
var isPublished = false
28+
}
29+
30+
enum class ProjectType {
31+
LIBRARY,
32+
PROCESSOR,
33+
TEST
34+
}
35+
36+
/**
37+
* Extension for [DaggerConventionPlugin] created when the shadow plugin is applied.
38+
*
39+
* Relocation rules can be specified vis this extension:
40+
* ```
41+
* shading {
42+
* relocate("com.google.auto.common", "dagger.spi.internal.shaded.auto.common")
43+
* }
44+
* ```
45+
*/
46+
abstract class ShadeExtension {
47+
internal val rules = mutableMapOf<String, String>()
48+
49+
fun relocate(fromPackage: String, toPackage: String) {
50+
check(!rules.containsKey(fromPackage)) { "Duplicate shading rule declared for $fromPackage" }
51+
rules[fromPackage] = toPackage
52+
}
53+
}
Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
/*
2+
* Copyright (C) 2025 The Dagger Authors.
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+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package dagger.gradle.build
18+
19+
import com.github.jengelman.gradle.plugins.shadow.ShadowPlugin
20+
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
21+
import com.vanniktech.maven.publish.MavenPublishBaseExtension
22+
import com.vanniktech.maven.publish.SonatypeHost
23+
import org.gradle.api.JavaVersion
24+
import org.gradle.api.Plugin
25+
import org.gradle.api.Project
26+
import org.gradle.api.plugins.JavaPluginExtension
27+
import org.gradle.api.tasks.TaskProvider
28+
import org.gradle.jvm.tasks.Jar
29+
import org.gradle.jvm.toolchain.JavaLanguageVersion
30+
import org.gradle.kotlin.dsl.create
31+
import org.gradle.kotlin.dsl.withType
32+
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
33+
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension
34+
import org.jetbrains.kotlin.gradle.dsl.KotlinProjectExtension
35+
import org.jetbrains.kotlin.gradle.dsl.KotlinVersion
36+
import org.jetbrains.kotlin.gradle.plugin.KotlinBasePluginWrapper
37+
38+
/**
39+
* A plugin to configure the Gradle projects. All projects should apply this plugin which will configure the project
40+
* based on other projects plugins applied, such as the Kotlin JVM plugin (`libs.plugins.kotlinJvm`) or the shadow
41+
* plugin (`libs.plugins.shadow`).
42+
*
43+
* This plugin can be applied using:
44+
* ```
45+
* plugins {
46+
* alias(libs.plugins.daggerBuild)
47+
* }
48+
* ```
49+
*
50+
* Source sets for the project are configured by this plugin and should have the following
51+
* convention:
52+
* ```
53+
* <project>
54+
* main
55+
* java - Library sources
56+
* resources - Library resources
57+
* test
58+
* javatests - Unit test sources
59+
* resources - Unit test resources
60+
* ```
61+
*/
62+
class DaggerConventionPlugin : Plugin<Project> {
63+
override fun apply(project: Project) {
64+
val daggerExtension = project.extensions.create<DaggerBuildExtension>("daggerBuild")
65+
val shadeExtension = project.extensions.create<ShadeExtension>("shading")
66+
67+
// Perform different configuration action based on the plugins applied to the project
68+
project.plugins.configureEach {
69+
when (this) {
70+
is KotlinBasePluginWrapper ->
71+
configureWithKotlinPlugin(project)
72+
is ShadowPlugin ->
73+
configureWithShadowPlugin(project, shadeExtension)
74+
}
75+
}
76+
configurePublish(project, daggerExtension)
77+
}
78+
79+
private fun configureWithKotlinPlugin(project: Project) {
80+
configureSourceSets(project)
81+
configureKotlinJvmTarget(project)
82+
}
83+
84+
private fun configureSourceSets(project: Project) {
85+
val kotlinExtension =
86+
project.extensions.findByType(KotlinProjectExtension::class.java)
87+
?: error("Unable to find Kotlin Project Extension")
88+
val javaExtension =
89+
project.extensions.findByType(JavaPluginExtension::class.java)
90+
?: error("Unable to find Java Project Extension")
91+
listOf("main", "test").forEach { name ->
92+
val rootSrcDir =
93+
when (name) {
94+
"main" -> "java"
95+
"test" -> "javatests"
96+
else -> error("Unknown source set named '$name'.")
97+
}
98+
kotlinExtension.sourceSets.named(name).configure {
99+
kotlin.srcDirs("$name/$rootSrcDir")
100+
resources.srcDirs("$name/resources")
101+
}
102+
javaExtension.sourceSets.named(name).configure { java.srcDirs("$name/$rootSrcDir") }
103+
}
104+
}
105+
106+
private fun configureKotlinJvmTarget(project: Project) {
107+
val kotlinProject = project.extensions.getByName("kotlin") as KotlinJvmProjectExtension
108+
kotlinProject.jvmToolchain {
109+
languageVersion.set(JavaLanguageVersion.of(project.getVersionByName("jdk")))
110+
}
111+
kotlinProject.compilerOptions.apply {
112+
languageVersion.set(KotlinVersion.fromVersion(project.getVersionByName("kotlinTarget")))
113+
apiVersion.set(KotlinVersion.fromVersion(project.getVersionByName("kotlinTarget")))
114+
jvmTarget.set(JvmTarget.fromTarget(project.getVersionByName("jvmTarget")))
115+
}
116+
val javaProject = project.extensions.getByName("java") as JavaPluginExtension
117+
javaProject.sourceCompatibility = JavaVersion.toVersion(project.getVersionByName("jvmTarget"))
118+
javaProject.targetCompatibility = JavaVersion.toVersion(project.getVersionByName("jvmTarget"))
119+
}
120+
121+
private fun configureWithShadowPlugin(project: Project, shadeExtension: ShadeExtension) {
122+
// Configuration for shaded dependencies
123+
val shadedConfiguration =
124+
project.configurations.create("shaded") {
125+
isCanBeConsumed = false
126+
isCanBeResolved = true
127+
isTransitive = false // Do not include transitive dependencies of shaded deps
128+
}
129+
130+
// Shaded dependencies are compile only dependencies
131+
project.configurations.named("compileOnly").configure { extendsFrom(shadedConfiguration) }
132+
133+
val shadowTask =
134+
project.tasks.withType<ShadowJar>().named("shadowJar") {
135+
// Use no classifier, the shaded jar is the one to be published.
136+
archiveClassifier.set("")
137+
// Set the 'shaded' configuration as the dependencies configuration to shade
138+
configurations = listOf(shadedConfiguration)
139+
// Enable service files merging
140+
mergeServiceFiles()
141+
// Enable package relocation (necessary for project that only relocate but have no
142+
// shaded deps)
143+
isEnableRelocation = true
144+
145+
shadeExtension.rules.forEach { (from, to) -> relocate(from, to) }
146+
}
147+
148+
// Change the default jar task classifier to avoid conflicting with the shaded one.
149+
project.tasks.withType<Jar>().named("jar").configure { archiveClassifier.set("before-shade") }
150+
151+
configureOutgoingArtifacts(project, shadowTask)
152+
}
153+
154+
/**
155+
* Configure Gradle consumers (that use Gradle publishing metadata) of the project to use the
156+
* shaded jar.
157+
*
158+
* This is necessary so that the publishing Gradle module metadata references the shaded jar. See
159+
* https://github.com/GradleUp/shadow/issues/847
160+
*/
161+
private fun configureOutgoingArtifacts(project: Project, task: TaskProvider<ShadowJar>) {
162+
project.configurations.configureEach {
163+
if (name == "apiElements" || name == "runtimeElements") {
164+
outgoing.artifacts.clear()
165+
outgoing.artifact(task)
166+
}
167+
}
168+
}
169+
170+
private fun configurePublish(project: Project, daggerExtension: DaggerBuildExtension) {
171+
if (!daggerExtension.isPublished) {
172+
return
173+
}
174+
project.pluginManager.apply(project.getPluginIdByName("publish"))
175+
project.plugins.withId(project.getPluginIdByName("publish")) {
176+
val publishExtension =
177+
project.extensions.getByName("mavenPublishing") as MavenPublishBaseExtension
178+
publishExtension.apply {
179+
coordinates(
180+
groupId = "com.google.dagger",
181+
artifactId = project.name,
182+
version = project.findProperty("PUBLISH_VERSION").toString(),
183+
)
184+
publishToMavenCentral(SonatypeHost.CENTRAL_PORTAL)
185+
pom {
186+
name.set(project.name.asPomName())
187+
description.set("A fast dependency injector for Android and Java.")
188+
url.set("https://github.com/google/dagger")
189+
scm {
190+
url.set("https://github.com/google/dagger/")
191+
connection.set("scm:git:git://github.com/google/dagger.git")
192+
}
193+
issueManagement {
194+
system.set("GitHub Issues")
195+
url.set("https://github.com/google/dagger/issues")
196+
}
197+
licenses {
198+
license {
199+
name.set("The Apache Software License, Version 2.0")
200+
url.set("https://www.apache.org/licenses/LICENSE-2.0.txt")
201+
}
202+
}
203+
organization {
204+
name.set("Google, Inc.")
205+
url.set("https://www.google.com")
206+
}
207+
}
208+
}
209+
}
210+
}
211+
212+
/**
213+
* Converts the Gradle project name to a more appropriate name for the POM file.
214+
*
215+
* For example: 'dagger-compiler' to 'Dagger Compiler'
216+
*/
217+
private fun String.asPomName(): String {
218+
val parts = split("-").map { first().uppercaseChar() + drop(1) }
219+
return parts.joinToString(separator = " ")
220+
}
221+
}

0 commit comments

Comments
 (0)