Skip to content

Commit 5150eda

Browse files
authored
Restructure library group logic in buildSrc (#5297)
Library groups are now compute at the plugin, rather than being a singleton class using registrars. This fixes the previous bug that caused duplicate entries to be generated for the release generator because the singleton class was kept alive by the gradle daemon. Additionally, it simplifies the verification of missing libraries due to library groups. Now, the build **will fail** if the release.json file does not include all the libraries in the library group.
1 parent c5a894c commit 5150eda

File tree

8 files changed

+155
-100
lines changed

8 files changed

+155
-100
lines changed

build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,11 @@ ext {
5858
protobufJavaUtilVersion = libs.versions.protobufjavautil.get()
5959
}
6060

61+
apply plugin: com.google.firebase.gradle.plugins.PublishingPlugin
62+
6163
apply plugin: com.google.firebase.gradle.plugins.ci.ContinuousIntegrationPlugin
6264
apply plugin: com.google.firebase.gradle.plugins.ci.SmokeTestsPlugin
6365

64-
apply plugin: com.google.firebase.gradle.plugins.PublishingPlugin
65-
6666
firebaseContinuousIntegration {
6767
ignorePaths = [
6868
/.*\.gitignore$/,

buildSrc/src/main/java/com/google/firebase/gradle/plugins/FirebaseLibraryExtension.java

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
import java.util.Collections;
2222
import java.util.Optional;
2323
import java.util.Set;
24-
import java.util.stream.Collectors;
2524
import javax.inject.Inject;
2625
import org.gradle.api.Action;
2726
import org.gradle.api.Project;
@@ -50,8 +49,7 @@ public class FirebaseLibraryExtension {
5049
public Property<String> groupId;
5150
public Property<String> artifactId;
5251

53-
private String libraryGroupName;
54-
private LibraryGroupRegistrar libraryGroupRegistrar;
52+
String libraryGroupName;
5553

5654
private Action<MavenPom> customizePomAction =
5755
pom -> {
@@ -86,8 +84,7 @@ public FirebaseLibraryExtension(Project project, LibraryType type) {
8684
groupId.set(new DefaultProvider<>(() -> project.getGroup().toString()));
8785
}
8886
this.staticAnalysis = initializeStaticAnalysis(project);
89-
this.libraryGroupRegistrar = LibraryGroupRegistrar.getInstance();
90-
libraryGroupName = "";
87+
libraryGroupName = this.artifactId.get();
9188
}
9289

9390
private FirebaseStaticAnalysis initializeStaticAnalysis(Project project) {
@@ -115,18 +112,6 @@ public void testLab(Action<FirebaseTestLabExtension> action) {
115112
*/
116113
public void libraryGroup(String libraryGroupName) {
117114
this.libraryGroupName = libraryGroupName;
118-
libraryGroupRegistrar.registerLibrary(libraryGroupName, this);
119-
}
120-
121-
public Set<Project> getProjectsToRelease() {
122-
return getLibrariesToRelease().stream().map(l -> l.project).collect(Collectors.toSet());
123-
}
124-
125-
public Set<FirebaseLibraryExtension> getLibrariesToRelease() {
126-
return ImmutableSet.<FirebaseLibraryExtension>builder()
127-
.addAll(libraryGroupRegistrar.getLibrariesForGroup(libraryGroupName))
128-
.add(this)
129-
.build();
130115
}
131116

132117
/** Provides a hook to customize pom generation. */

buildSrc/src/main/java/com/google/firebase/gradle/plugins/LibraryGroupRegistrar.kt

Lines changed: 0 additions & 46 deletions
This file was deleted.
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// Copyright 2023 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
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+
package com.google.firebase.gradle.plugins
15+
16+
import org.gradle.api.GradleException
17+
import org.gradle.api.Project
18+
19+
/**
20+
* Returns a map of library group names to the list of libraries that belong to that group.
21+
*
22+
* Libraries, aka projects with `FirebaseLibraryExtension`, always belong to a library group. See
23+
* [FirebaseLibraryExtension] to know more about library group names.
24+
*/
25+
fun computeLibraryGroups(project: Project): Map<String, List<FirebaseLibraryExtension>> {
26+
if (project != project.rootProject) {
27+
throw GradleException(
28+
"Error trying to generate library groups from non root project. " +
29+
"Computing library groups for non root projects can generate incomplete views."
30+
)
31+
}
32+
val libraryGroups =
33+
project.subprojects.mapNotNull { it.firebaseLibraryOrNull }.groupBy { it.libraryGroupName }
34+
35+
return libraryGroups
36+
}
37+
38+
fun fixLibraryGroupVersions(libraryGroups: Map<String, List<FirebaseLibraryExtension>>) {
39+
for ((name, libraryGroup) in libraryGroups) {
40+
val maxVersion =
41+
libraryGroup.mapNotNull { it.moduleVersion }.maxOrNull()?.toString() ?: continue
42+
for (firebaseExtension in libraryGroup) {
43+
if (ModuleVersion.fromStringOrNull(firebaseExtension.project.version.toString()) == null) {
44+
firebaseExtension.project.version = maxVersion.toString()
45+
}
46+
}
47+
}
48+
}
49+
50+
/**
51+
* Returns the list of libraries that should be transitively included in a release but are not.
52+
*
53+
* Based on [librariesToRelease], this function will find and return all libraries that belongs to
54+
* the same library group of a releasing library and are not included.
55+
*/
56+
fun computeMissingLibrariesToRelease(
57+
librariesToRelease: List<FirebaseLibraryExtension>,
58+
libraryGroups: Map<String, List<FirebaseLibraryExtension>>
59+
): List<FirebaseLibraryExtension> =
60+
expandWithLibraryGroup(librariesToRelease, libraryGroups) - librariesToRelease
61+
62+
/** Returns a list that includes [libraries] and all their library group members. */
63+
fun expandWithLibraryGroup(
64+
libraries: List<FirebaseLibraryExtension>,
65+
libraryGroups: Map<String, List<FirebaseLibraryExtension>>
66+
) =
67+
libraries
68+
.flatMap { libraryGroups.getOrDefault(it.libraryGroupName, emptyList()) }
69+
.distinctBy { it.artifactId.get() }
70+
71+
val FirebaseLibraryExtension.moduleVersion: ModuleVersion?
72+
get() = ModuleVersion.fromStringOrNull(version)

buildSrc/src/main/java/com/google/firebase/gradle/plugins/PublishingPlugin.kt

Lines changed: 62 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,13 @@ import org.gradle.kotlin.dsl.register
6666
* each releasing library.
6767
*/
6868
abstract class PublishingPlugin : Plugin<Project> {
69+
6970
override fun apply(project: Project) {
7071
project.gradle.projectsEvaluated {
7172
val allFirebaseLibraries = project.subprojects.mapNotNull { it.firebaseLibraryOrNull }
72-
val releaseMetadata = computeReleaseMetadata(project, allFirebaseLibraries)
73+
val libraryGroups = computeLibraryGroups(project)
74+
fixLibraryGroupVersions(libraryGroups)
75+
val releaseMetadata = computeReleaseMetadata(project, allFirebaseLibraries, libraryGroups)
7376

7477
val releasingFirebaseLibraries = releaseMetadata?.releasingLibraries.orEmpty()
7578
val releasingProjects = releasingFirebaseLibraries.map { it.project }
@@ -81,7 +84,11 @@ abstract class PublishingPlugin : Plugin<Project> {
8184
val validateProjectsToPublish =
8285
registerValidateProjectsToPublishTask(project, releasingFirebaseLibraries)
8386
val validateLibraryGroupsToPublish =
84-
registerValidateLibraryGroupsToPublishTask(project, releasingFirebaseLibraries)
87+
registerValidateLibraryGroupsToPublishTask(
88+
project,
89+
releasingFirebaseLibraries,
90+
libraryGroups
91+
)
8592
val publishReleasingLibrariesToBuildDir =
8693
registerPublishReleasingLibrariesToBuildDirTask(project, releasingProjects)
8794
val generateKotlindocsForRelease =
@@ -93,11 +100,12 @@ abstract class PublishingPlugin : Plugin<Project> {
93100
releaseMetadata?.name.orEmpty()
94101
)
95102

96-
registerGenerateReleaseConfigFilesTask(project)
103+
registerGenerateReleaseConfigFilesTask(project, libraryGroups)
97104
registerPublishReleasingLibrariesToMavenLocalTask(project, releasingProjects)
98105
registerSemverCheckForReleaseTask(project, releasingProjects)
99106
registerPublishAllToBuildDir(project, allFirebaseLibraries)
100107
registerPostReleasePlugin(releasingProjects)
108+
registerLibraryGroupsTaks(project, libraryGroups)
101109

102110
val buildMavenZip =
103111
project.tasks.register<Zip>(BUILD_MAVEN_ZIP_TASK) {
@@ -147,6 +155,19 @@ abstract class PublishingPlugin : Plugin<Project> {
147155
}
148156
}
149157

158+
protected fun registerLibraryGroupsTaks(
159+
project: Project,
160+
libraryGroups: Map<String, List<FirebaseLibraryExtension>>
161+
) {
162+
project.tasks.register("libraryGroups") {
163+
for (libraryGroup in libraryGroups) {
164+
println(
165+
"${libraryGroup.key} -> ${libraryGroup.value.joinToString(" | ") { it.artifactName }}"
166+
)
167+
}
168+
}
169+
}
170+
150171
/**
151172
* Figures out the [ReleaseMetadata] for with this release.
152173
*
@@ -181,33 +202,40 @@ abstract class PublishingPlugin : Plugin<Project> {
181202
*/
182203
private fun computeReleaseMetadata(
183204
project: Project,
184-
allFirebaseLibraries: List<FirebaseLibraryExtension>
205+
allFirebaseLibraries: List<FirebaseLibraryExtension>,
206+
libraryGroups: Map<String, List<FirebaseLibraryExtension>>
185207
): ReleaseMetadata? =
186-
releaseMetadataFromProperties(project, allFirebaseLibraries)
187-
?: releaseMetadataFromReleaseConfig(project, allFirebaseLibraries)
208+
releaseMetadataFromProperties(project, allFirebaseLibraries, libraryGroups)
209+
?: releaseMetadataFromReleaseConfig(project, allFirebaseLibraries, libraryGroups)
188210

189211
private fun releaseMetadataFromProperties(
190212
project: Project,
191-
allFirebaseLibraries: List<FirebaseLibraryExtension>
213+
allFirebaseLibraries: List<FirebaseLibraryExtension>,
214+
libraryGroups: Map<String, List<FirebaseLibraryExtension>>
192215
): ReleaseMetadata? {
193216
val projectsToPublish = project.provideProperty<String>("projectsToPublish").orNull
194217
val releaseName = project.provideProperty<String>("releaseName").orNull ?: "NO_NAME"
195218

196219
if (projectsToPublish == null) return null
197220

198221
val projectNames = projectsToPublish.split(",")
199-
val librariesToRelease =
222+
223+
val libraryGroupsToRelease =
200224
allFirebaseLibraries
201225
.filter { it.artifactId.get() in projectNames }
202-
.flatMap { it.librariesToRelease }
226+
.map { it.libraryGroupName }
227+
val librariesToRelease =
228+
libraryGroups
229+
.filterKeys { it in libraryGroupsToRelease }
230+
.flatMap { it.value }
203231
.distinctBy { it.artifactId.get() }
204-
205232
return ReleaseMetadata(librariesToRelease, releaseName)
206233
}
207234

208235
private fun releaseMetadataFromReleaseConfig(
209236
project: Project,
210-
allFirebaseLibraries: List<FirebaseLibraryExtension>
237+
allFirebaseLibraries: List<FirebaseLibraryExtension>,
238+
libraryGroups: Map<String, List<FirebaseLibraryExtension>>
211239
): ReleaseMetadata? {
212240
val releaseConfigFile =
213241
project.layout.projectDirectory.file(RELEASE_CONFIG_FILE).asFile.takeIf { it.exists() }
@@ -216,6 +244,16 @@ abstract class PublishingPlugin : Plugin<Project> {
216244
val releaseConfig = ReleaseConfig.fromFile(it)
217245
val librariesToRelease = allFirebaseLibraries.filter { it.path in releaseConfig.libraries }
218246

247+
val missingLibrariesToRelease =
248+
computeMissingLibrariesToRelease(librariesToRelease, libraryGroups)
249+
if (missingLibrariesToRelease.isNotEmpty()) {
250+
throw GradleException(
251+
"Invalid release configuration. " +
252+
"It's should include the following libraries due to library groups: \n" +
253+
"${missingLibrariesToRelease.joinToString("\n"){ it.artifactName }}"
254+
)
255+
}
256+
219257
ReleaseMetadata(librariesToRelease, releaseConfig.name)
220258
}
221259
}
@@ -301,16 +339,18 @@ abstract class PublishingPlugin : Plugin<Project> {
301339
*/
302340
private fun registerValidateLibraryGroupsToPublishTask(
303341
project: Project,
304-
releasinglibraries: List<FirebaseLibraryExtension>
342+
librariesToRelease: List<FirebaseLibraryExtension>,
343+
libraryGroups: Map<String, List<FirebaseLibraryExtension>>
305344
) =
306345
project.tasks.register(VALIDATE_LIBRARY_GROUPS_TO_PUBLISH_TASK) {
307346
doLast {
308-
val libraryGroupProjects = releasinglibraries.flatMap { it.librariesToRelease }
309-
val missingProjects = libraryGroupProjects - releasinglibraries
310-
if (missingProjects.isNotEmpty()) {
347+
val missingLibrariesToRelease =
348+
computeMissingLibrariesToRelease(librariesToRelease, libraryGroups)
349+
if (missingLibrariesToRelease.isNotEmpty()) {
311350
throw GradleException(
312-
"Some libraries in library groups are not in the release: " +
313-
missingProjects.map { it.mavenName }.joinToString("\n")
351+
"Invalid release configuration. " +
352+
"It's should include the following libraries due to library groups: \n" +
353+
"${missingLibrariesToRelease.joinToString("\n")}"
314354
)
315355
}
316356
}
@@ -400,7 +440,10 @@ abstract class PublishingPlugin : Plugin<Project> {
400440
*
401441
* @see [ReleaseGenerator]
402442
*/
403-
private fun registerGenerateReleaseConfigFilesTask(project: Project) =
443+
private fun registerGenerateReleaseConfigFilesTask(
444+
project: Project,
445+
libraryGroups: Map<String, List<FirebaseLibraryExtension>>
446+
) =
404447
project.tasks.register<ReleaseGenerator>(RELEASE_GENEATOR_TASK) {
405448
currentRelease.convention(project.provideProperty("currentRelease"))
406449
pastRelease.convention(project.provideProperty("pastRelease"))
@@ -412,6 +455,7 @@ abstract class PublishingPlugin : Plugin<Project> {
412455
releaseReportJsonFile.convention(
413456
project.layout.projectDirectory.file(RELEASE_REPORT_JSON_FILE)
414457
)
458+
this.libraryGroups = libraryGroups
415459
}
416460

417461
/**

0 commit comments

Comments
 (0)