Skip to content

Restructure library group logic in buildSrc #5297

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Sep 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,11 @@ ext {
protobufJavaUtilVersion = libs.versions.protobufjavautil.get()
}

apply plugin: com.google.firebase.gradle.plugins.PublishingPlugin

apply plugin: com.google.firebase.gradle.plugins.ci.ContinuousIntegrationPlugin
apply plugin: com.google.firebase.gradle.plugins.ci.SmokeTestsPlugin

apply plugin: com.google.firebase.gradle.plugins.PublishingPlugin

firebaseContinuousIntegration {
ignorePaths = [
/.*\.gitignore$/,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
import java.util.Collections;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import javax.inject.Inject;
import org.gradle.api.Action;
import org.gradle.api.Project;
Expand Down Expand Up @@ -50,8 +49,7 @@ public class FirebaseLibraryExtension {
public Property<String> groupId;
public Property<String> artifactId;

private String libraryGroupName;
private LibraryGroupRegistrar libraryGroupRegistrar;
String libraryGroupName;

private Action<MavenPom> customizePomAction =
pom -> {
Expand Down Expand Up @@ -86,8 +84,7 @@ public FirebaseLibraryExtension(Project project, LibraryType type) {
groupId.set(new DefaultProvider<>(() -> project.getGroup().toString()));
}
this.staticAnalysis = initializeStaticAnalysis(project);
this.libraryGroupRegistrar = LibraryGroupRegistrar.getInstance();
libraryGroupName = "";
libraryGroupName = this.artifactId.get();
}

private FirebaseStaticAnalysis initializeStaticAnalysis(Project project) {
Expand Down Expand Up @@ -115,18 +112,6 @@ public void testLab(Action<FirebaseTestLabExtension> action) {
*/
public void libraryGroup(String libraryGroupName) {
this.libraryGroupName = libraryGroupName;
libraryGroupRegistrar.registerLibrary(libraryGroupName, this);
}

public Set<Project> getProjectsToRelease() {
return getLibrariesToRelease().stream().map(l -> l.project).collect(Collectors.toSet());
}

public Set<FirebaseLibraryExtension> getLibrariesToRelease() {
return ImmutableSet.<FirebaseLibraryExtension>builder()
.addAll(libraryGroupRegistrar.getLibrariesForGroup(libraryGroupName))
.add(this)
.build();
}

/** Provides a hook to customize pom generation. */
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Copyright 2023 Google LLC
//
// 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.google.firebase.gradle.plugins

import org.gradle.api.GradleException
import org.gradle.api.Project

/**
* Returns a map of library group names to the list of libraries that belong to that group.
*
* Libraries, aka projects with `FirebaseLibraryExtension`, always belong to a library group. See
* [FirebaseLibraryExtension] to know more about library group names.
*/
fun computeLibraryGroups(project: Project): Map<String, List<FirebaseLibraryExtension>> {
if (project != project.rootProject) {
throw GradleException(
"Error trying to generate library groups from non root project. " +
"Computing library groups for non root projects can generate incomplete views."
)
}
val libraryGroups =
project.subprojects.mapNotNull { it.firebaseLibraryOrNull }.groupBy { it.libraryGroupName }

return libraryGroups
}

fun fixLibraryGroupVersions(libraryGroups: Map<String, List<FirebaseLibraryExtension>>) {
for ((name, libraryGroup) in libraryGroups) {
val maxVersion =
libraryGroup.mapNotNull { it.moduleVersion }.maxOrNull()?.toString() ?: continue
for (firebaseExtension in libraryGroup) {
if (ModuleVersion.fromStringOrNull(firebaseExtension.project.version.toString()) == null) {
firebaseExtension.project.version = maxVersion.toString()
}
}
}
}

/**
* Returns the list of libraries that should be transitively included in a release but are not.
*
* Based on [librariesToRelease], this function will find and return all libraries that belongs to
* the same library group of a releasing library and are not included.
*/
fun computeMissingLibrariesToRelease(
librariesToRelease: List<FirebaseLibraryExtension>,
libraryGroups: Map<String, List<FirebaseLibraryExtension>>
): List<FirebaseLibraryExtension> =
expandWithLibraryGroup(librariesToRelease, libraryGroups) - librariesToRelease

/** Returns a list that includes [libraries] and all their library group members. */
fun expandWithLibraryGroup(
libraries: List<FirebaseLibraryExtension>,
libraryGroups: Map<String, List<FirebaseLibraryExtension>>
) =
libraries
.flatMap { libraryGroups.getOrDefault(it.libraryGroupName, emptyList()) }
.distinctBy { it.artifactId.get() }

val FirebaseLibraryExtension.moduleVersion: ModuleVersion?
get() = ModuleVersion.fromStringOrNull(version)
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,13 @@ import org.gradle.kotlin.dsl.register
* each releasing library.
*/
abstract class PublishingPlugin : Plugin<Project> {

override fun apply(project: Project) {
project.gradle.projectsEvaluated {
val allFirebaseLibraries = project.subprojects.mapNotNull { it.firebaseLibraryOrNull }
val releaseMetadata = computeReleaseMetadata(project, allFirebaseLibraries)
val libraryGroups = computeLibraryGroups(project)
fixLibraryGroupVersions(libraryGroups)
val releaseMetadata = computeReleaseMetadata(project, allFirebaseLibraries, libraryGroups)

val releasingFirebaseLibraries = releaseMetadata?.releasingLibraries.orEmpty()
val releasingProjects = releasingFirebaseLibraries.map { it.project }
Expand All @@ -81,7 +84,11 @@ abstract class PublishingPlugin : Plugin<Project> {
val validateProjectsToPublish =
registerValidateProjectsToPublishTask(project, releasingFirebaseLibraries)
val validateLibraryGroupsToPublish =
registerValidateLibraryGroupsToPublishTask(project, releasingFirebaseLibraries)
registerValidateLibraryGroupsToPublishTask(
project,
releasingFirebaseLibraries,
libraryGroups
)
val publishReleasingLibrariesToBuildDir =
registerPublishReleasingLibrariesToBuildDirTask(project, releasingProjects)
val generateKotlindocsForRelease =
Expand All @@ -93,11 +100,12 @@ abstract class PublishingPlugin : Plugin<Project> {
releaseMetadata?.name.orEmpty()
)

registerGenerateReleaseConfigFilesTask(project)
registerGenerateReleaseConfigFilesTask(project, libraryGroups)
registerPublishReleasingLibrariesToMavenLocalTask(project, releasingProjects)
registerSemverCheckForReleaseTask(project, releasingProjects)
registerPublishAllToBuildDir(project, allFirebaseLibraries)
registerPostReleasePlugin(releasingProjects)
registerLibraryGroupsTaks(project, libraryGroups)

val buildMavenZip =
project.tasks.register<Zip>(BUILD_MAVEN_ZIP_TASK) {
Expand Down Expand Up @@ -147,6 +155,19 @@ abstract class PublishingPlugin : Plugin<Project> {
}
}

protected fun registerLibraryGroupsTaks(
project: Project,
libraryGroups: Map<String, List<FirebaseLibraryExtension>>
) {
project.tasks.register("libraryGroups") {
for (libraryGroup in libraryGroups) {
println(
"${libraryGroup.key} -> ${libraryGroup.value.joinToString(" | ") { it.artifactName }}"
)
}
}
}

/**
* Figures out the [ReleaseMetadata] for with this release.
*
Expand Down Expand Up @@ -181,33 +202,40 @@ abstract class PublishingPlugin : Plugin<Project> {
*/
private fun computeReleaseMetadata(
project: Project,
allFirebaseLibraries: List<FirebaseLibraryExtension>
allFirebaseLibraries: List<FirebaseLibraryExtension>,
libraryGroups: Map<String, List<FirebaseLibraryExtension>>
): ReleaseMetadata? =
releaseMetadataFromProperties(project, allFirebaseLibraries)
?: releaseMetadataFromReleaseConfig(project, allFirebaseLibraries)
releaseMetadataFromProperties(project, allFirebaseLibraries, libraryGroups)
?: releaseMetadataFromReleaseConfig(project, allFirebaseLibraries, libraryGroups)

private fun releaseMetadataFromProperties(
project: Project,
allFirebaseLibraries: List<FirebaseLibraryExtension>
allFirebaseLibraries: List<FirebaseLibraryExtension>,
libraryGroups: Map<String, List<FirebaseLibraryExtension>>
): ReleaseMetadata? {
val projectsToPublish = project.provideProperty<String>("projectsToPublish").orNull
val releaseName = project.provideProperty<String>("releaseName").orNull ?: "NO_NAME"

if (projectsToPublish == null) return null

val projectNames = projectsToPublish.split(",")
val librariesToRelease =

val libraryGroupsToRelease =
allFirebaseLibraries
.filter { it.artifactId.get() in projectNames }
.flatMap { it.librariesToRelease }
.map { it.libraryGroupName }
val librariesToRelease =
libraryGroups
.filterKeys { it in libraryGroupsToRelease }
.flatMap { it.value }
.distinctBy { it.artifactId.get() }

return ReleaseMetadata(librariesToRelease, releaseName)
}

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

val missingLibrariesToRelease =
computeMissingLibrariesToRelease(librariesToRelease, libraryGroups)
if (missingLibrariesToRelease.isNotEmpty()) {
throw GradleException(
"Invalid release configuration. " +
"It's should include the following libraries due to library groups: \n" +
"${missingLibrariesToRelease.joinToString("\n"){ it.artifactName }}"
)
}

ReleaseMetadata(librariesToRelease, releaseConfig.name)
}
}
Expand Down Expand Up @@ -301,16 +339,18 @@ abstract class PublishingPlugin : Plugin<Project> {
*/
private fun registerValidateLibraryGroupsToPublishTask(
project: Project,
releasinglibraries: List<FirebaseLibraryExtension>
librariesToRelease: List<FirebaseLibraryExtension>,
libraryGroups: Map<String, List<FirebaseLibraryExtension>>
) =
project.tasks.register(VALIDATE_LIBRARY_GROUPS_TO_PUBLISH_TASK) {
doLast {
val libraryGroupProjects = releasinglibraries.flatMap { it.librariesToRelease }
val missingProjects = libraryGroupProjects - releasinglibraries
if (missingProjects.isNotEmpty()) {
val missingLibrariesToRelease =
computeMissingLibrariesToRelease(librariesToRelease, libraryGroups)
if (missingLibrariesToRelease.isNotEmpty()) {
throw GradleException(
"Some libraries in library groups are not in the release: " +
missingProjects.map { it.mavenName }.joinToString("\n")
"Invalid release configuration. " +
"It's should include the following libraries due to library groups: \n" +
"${missingLibrariesToRelease.joinToString("\n")}"
)
}
}
Expand Down Expand Up @@ -400,7 +440,10 @@ abstract class PublishingPlugin : Plugin<Project> {
*
* @see [ReleaseGenerator]
*/
private fun registerGenerateReleaseConfigFilesTask(project: Project) =
private fun registerGenerateReleaseConfigFilesTask(
project: Project,
libraryGroups: Map<String, List<FirebaseLibraryExtension>>
) =
project.tasks.register<ReleaseGenerator>(RELEASE_GENEATOR_TASK) {
currentRelease.convention(project.provideProperty("currentRelease"))
pastRelease.convention(project.provideProperty("pastRelease"))
Expand All @@ -412,6 +455,7 @@ abstract class PublishingPlugin : Plugin<Project> {
releaseReportJsonFile.convention(
project.layout.projectDirectory.file(RELEASE_REPORT_JSON_FILE)
)
this.libraryGroups = libraryGroups
}

/**
Expand Down
Loading