diff --git a/.github/workflows/make-bom.yml b/.github/workflows/make-bom.yml index 0ad2ecf4add..0e7d63f5c96 100644 --- a/.github/workflows/make-bom.yml +++ b/.github/workflows/make-bom.yml @@ -11,7 +11,9 @@ jobs: uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 with: python-version: '3.10' + - uses: actions/checkout@v4.1.1 + - name: Set up JDK 17 uses: actions/setup-java@v4.1.0 with: @@ -21,19 +23,25 @@ jobs: - name: Build run: | - ./ci/run.sh \ - --artifact-target-dir=./logs/artifacts \ - --artifact-patterns=bom.zip \ - --artifact-patterns=bomReleaseNotes.md \ - --artifact-patterns=recipeVersionUpdate.txt \ - gradle \ - -- \ - --build-cache \ - buildBomZip - - - name: Upload generated artifacts + ./gradlew buildBomBundleZip + + - name: Upload bom + uses: actions/upload-artifact@v4.3.3 + with: + name: bom + path: build/bom/ + retention-days: 15 + + - name: Upload release notes + uses: actions/upload-artifact@v4.3.3 + with: + name: bom_release_notes + path: build/bomReleaseNotes.md + retention-days: 15 + + - name: Upload recipe version update uses: actions/upload-artifact@v4.3.3 with: - name: artifacts - path: ./logs/artifacts/ - retention-days: 5 + name: recipe_version + path: build/recipeVersionUpdate.txt + retention-days: 15 diff --git a/plugins/src/main/java/com/google/firebase/gradle/bomgenerator/GenerateBomReleaseNotesTask.kt b/plugins/src/main/java/com/google/firebase/gradle/bomgenerator/GenerateBomReleaseNotesTask.kt index 72fe51a8017..75bb991dd60 100644 --- a/plugins/src/main/java/com/google/firebase/gradle/bomgenerator/GenerateBomReleaseNotesTask.kt +++ b/plugins/src/main/java/com/google/firebase/gradle/bomgenerator/GenerateBomReleaseNotesTask.kt @@ -51,7 +51,7 @@ abstract class GenerateBomReleaseNotesTask : DefaultTask() { val previousDeps = previousBom.get().dependencyManagement?.dependencies.orEmpty() previousBomVersions.set(previousDeps.associate { it.fullArtifactName to it.version }) - val sortedDependencies = currentDeps.sortedBy { it.version } + val sortedDependencies = currentDeps.sortedBy { it.toString() } val headingId = "{: #bom_v${bom.version.replace(".", "-")}}" @@ -71,8 +71,9 @@ abstract class GenerateBomReleaseNotesTask : DefaultTask() { | Firebase Android SDKs mapped to this {{bom}} version |

|

- | Libraries that were versioned with this release are in highlighted rows.
- | Refer to a library's release notes (on this page) for details about its changes. + | Libraries that were versioned with this release are in highlighted rows. + |
Refer to a library's release notes (on this page) for details about its + | changes. |

| | diff --git a/plugins/src/main/java/com/google/firebase/gradle/bomgenerator/GenerateBomTask.kt b/plugins/src/main/java/com/google/firebase/gradle/bomgenerator/GenerateBomTask.kt index 8e5599a530a..9fb7fe35130 100644 --- a/plugins/src/main/java/com/google/firebase/gradle/bomgenerator/GenerateBomTask.kt +++ b/plugins/src/main/java/com/google/firebase/gradle/bomgenerator/GenerateBomTask.kt @@ -25,8 +25,8 @@ import com.google.firebase.gradle.plugins.datamodels.LicenseElement import com.google.firebase.gradle.plugins.datamodels.PomElement import com.google.firebase.gradle.plugins.datamodels.fullArtifactName import com.google.firebase.gradle.plugins.datamodels.moduleVersion -import com.google.firebase.gradle.plugins.diff import com.google.firebase.gradle.plugins.orEmpty +import com.google.firebase.gradle.plugins.pairBy import com.google.firebase.gradle.plugins.partitionNotNull import com.google.firebase.gradle.plugins.services.GMavenService import org.gradle.api.DefaultTask @@ -144,7 +144,7 @@ abstract class GenerateBomTask : DefaultTask() { val oldBomVersion = ModuleVersion.fromString(oldBom.artifactId, oldBom.version) val oldBomDependencies = oldBom.dependencyManagement?.dependencies.orEmpty() - val changedDependencies = oldBomDependencies.diff(releasingDependencies) + val changedDependencies = oldBomDependencies.pairBy(releasingDependencies) { it.artifactId } val versionBumps = changedDependencies.mapNotNull { (old, new) -> diff --git a/plugins/src/main/java/com/google/firebase/gradle/plugins/KotlinExtensions.kt b/plugins/src/main/java/com/google/firebase/gradle/plugins/KotlinExtensions.kt index 8b7634f4500..8f058603e3b 100644 --- a/plugins/src/main/java/com/google/firebase/gradle/plugins/KotlinExtensions.kt +++ b/plugins/src/main/java/com/google/firebase/gradle/plugins/KotlinExtensions.kt @@ -296,6 +296,43 @@ infix fun List.diff(other: List): List> { return firstList.zip(secondList).filter { it.first != it.second } } +/** + * Creates a list of pairs between two lists, matching according to the provided [mapper]. + * + * ```kotlin + * data class Person(name: String, age: Int) + * + * val firstList = listOf( + * Person("Mike", 5), + * Person("Rachel", 6) + * ) + * + * val secondList = listOf( + * Person("Michael", 4), + * Person("Mike", 1) + * ) + * + * val diffList = firstList.pairBy(secondList) { + * it.name + * } + * + * diffList shouldBeEqualTo listOf( + * Person("Mike", 5) to Person("Mike", 1) + * Person("Rachel", 6) to null + * null to Person("Mike", 1) + * ) + * ``` + */ +inline fun List.pairBy(other: List, mapper: (T) -> R): List> { + val firstMap = associateBy { mapper(it) } + val secondMap = other.associateBy { mapper(it) } + + val changedOrRemoved = firstMap.map { it.value to secondMap[it.key] } + val added = secondMap.filterKeys { it !in firstMap }.map { null to it.value } + + return changedOrRemoved + added +} + /** * Creates a list that is forced to certain size. * diff --git a/plugins/src/main/java/com/google/firebase/gradle/plugins/ModuleVersion.kt b/plugins/src/main/java/com/google/firebase/gradle/plugins/ModuleVersion.kt index c07b382aac6..3479c536699 100644 --- a/plugins/src/main/java/com/google/firebase/gradle/plugins/ModuleVersion.kt +++ b/plugins/src/main/java/com/google/firebase/gradle/plugins/ModuleVersion.kt @@ -269,9 +269,10 @@ data class ModuleVersion( .let { it ?: if (pre != null) VersionType.PRE else VersionType.PATCH } .let { when (it) { - VersionType.MAJOR -> copy(major = major + 1) - VersionType.MINOR -> copy(minor = minor + 1) - VersionType.PATCH -> copy(patch = patch + 1) + VersionType.MAJOR -> + copy(major = major + 1, minor = 0, patch = 0, pre = pre?.copy(build = 1)) + VersionType.MINOR -> copy(minor = minor + 1, patch = 0, pre = pre?.copy(build = 1)) + VersionType.PATCH -> copy(patch = patch + 1, pre = pre?.copy(build = 1)) VersionType.PRE -> copy(pre = pre?.bump()) } } diff --git a/plugins/src/main/java/com/google/firebase/gradle/plugins/PublishingPlugin.kt b/plugins/src/main/java/com/google/firebase/gradle/plugins/PublishingPlugin.kt index b698dc08ad8..82a2aaae858 100644 --- a/plugins/src/main/java/com/google/firebase/gradle/plugins/PublishingPlugin.kt +++ b/plugins/src/main/java/com/google/firebase/gradle/plugins/PublishingPlugin.kt @@ -61,6 +61,8 @@ import org.gradle.kotlin.dsl.register * outside of the standard [FIREBASE_PUBLISH_TASK] workflow (possibly at a later time in the release * cycle): * - [BUILD_BOM_ZIP_TASK] -> Creates a zip file of the contents of [GENERATE_BOM_TASK] + * [registerGenerateBomTask] + * - [BUILD_BOM_BUNDLE_ZIP_TASK] -> Creates a zip file of the contents of [BUILD_BOM_ZIP_TASK] * [registerGenerateBomTask], * [GENERATE_BOM_RELEASE_NOTES_TASK][registerGenerateBomReleaseNotesTask] and * [GENERATE_TUTORIAL_BUNDLE_TASK][registerGenerateTutorialBundleTask] @@ -140,9 +142,16 @@ abstract class PublishingPlugin : Plugin { destinationDirectory.set(project.layout.buildDirectory) } - project.tasks.register(BUILD_BOM_ZIP_TASK) { - from(generateBom, generateBomReleaseNotes, generateTutorialBundle) - archiveFileName.set("bom.zip") + val buildBomZip = + project.tasks.register(BUILD_BOM_ZIP_TASK) { + from(generateBom) + archiveFileName.set("bom.zip") + destinationDirectory.set(project.layout.buildDirectory) + } + + project.tasks.register(BUILD_BOM_BUNDLE_ZIP_TASK) { + from(buildBomZip, generateBomReleaseNotes, generateTutorialBundle) + archiveFileName.set("bomBundle.zip") destinationDirectory.set(project.layout.projectDirectory) } @@ -757,6 +766,7 @@ abstract class PublishingPlugin : Plugin { const val BUILD_KOTLINDOC_ZIP_TASK = "buildKotlindocZip" const val BUILD_RELEASE_NOTES_ZIP_TASK = "buildReleaseNotesZip" const val BUILD_BOM_ZIP_TASK = "buildBomZip" + const val BUILD_BOM_BUNDLE_ZIP_TASK = "buildBomBundleZip" const val FIREBASE_PUBLISH_TASK = "firebasePublish" const val PUBLISH_ALL_TO_BUILD_TASK = "publishAllToBuildDir" diff --git a/plugins/src/main/java/com/google/firebase/gradle/plugins/datamodels/PomElement.kt b/plugins/src/main/java/com/google/firebase/gradle/plugins/datamodels/PomElement.kt index e3fccfb66e9..dda8db2896d 100644 --- a/plugins/src/main/java/com/google/firebase/gradle/plugins/datamodels/PomElement.kt +++ b/plugins/src/main/java/com/google/firebase/gradle/plugins/datamodels/PomElement.kt @@ -158,7 +158,7 @@ data class PomElement( @XmlElement val artifactId: String, @XmlElement val version: String, @XmlElement val packaging: String? = null, - @XmlChildrenName("licenses") val licenses: List? = null, + @XmlChildrenName("license") val licenses: List? = null, @XmlElement val scm: SourceControlManagement? = null, @XmlElement val dependencyManagement: DependencyManagementElement? = null, @XmlChildrenName("dependency") val dependencies: List? = null, @@ -171,15 +171,25 @@ data class PomElement( * @see fromFile */ fun toFile(file: File): File { - val xmlWriter = XML { - indent = 2 - xmlDeclMode = XmlDeclMode.None - } - file.writeText(xmlWriter.encodeToString(this)) + file.writeText(toString()) return file } + /** + * Serializes this pom element into a valid XML element. + * + * @see toFile + */ + override fun toString(): String { + return xml.encodeToString(this) + } + companion object { + private val xml = XML { + indent = 2 + xmlDeclMode = XmlDeclMode.None + } + /** * Deserializes a [PomElement] from a `pom.xml` file. * @@ -201,6 +211,6 @@ data class PomElement( * @see fromFile */ fun fromElement(element: Element): PomElement = - XML.decodeFromReader(xmlStreaming.newReader(element)) + xml.decodeFromReader(xmlStreaming.newReader(element)) } } diff --git a/plugins/src/test/kotlin/com/google/firebase/gradle/plugins/GenerateBomReleaseNotesTests.kt b/plugins/src/test/kotlin/com/google/firebase/gradle/plugins/GenerateBomReleaseNotesTests.kt index 3d914df29d8..182d7d0ffb2 100644 --- a/plugins/src/test/kotlin/com/google/firebase/gradle/plugins/GenerateBomReleaseNotesTests.kt +++ b/plugins/src/test/kotlin/com/google/firebase/gradle/plugins/GenerateBomReleaseNotesTests.kt @@ -65,8 +65,68 @@ class GenerateBomReleaseNotesTests : FunSpec() { Firebase Android SDKs mapped to this {{bom}} version

- Libraries that were versioned with this release are in highlighted rows.
- Refer to a library's release notes (on this page) for details about its changes. + Libraries that were versioned with this release are in highlighted rows. +
Refer to a library's release notes (on this page) for details about its + changes. +

+
+ + + + + + + + + + + + + + + + + +
Artifact nameVersion mapped
to previous {{bom}} v1.0.0
Version mapped
to this {{bom}} v1.0.0
com.google.firebase:firebase-auth10.0.010.0.0
com.google.firebase:firebase-firestore10.0.010.0.0
+ + """ + .trimIndent() + } + + @Test + fun `sorts the entries alphabetically`() { + val dependencies = + listOf( + ArtifactDependency( + groupId = "com.google.firebase", + artifactId = "firebase-firestore", + version = "10.0.0", + ), + ArtifactDependency( + groupId = "com.google.firebase", + artifactId = "firebase-auth", + version = "10.0.0", + ), + ) + val bom = makeBom("1.0.0", dependencies) + val file = makeReleaseNotes(bom, bom) + + file.readText().trim() shouldBeText + """ + ### {{firebase_bom_long}} ({{bill_of_materials}}) version 1.0.0 {: #bom_v1-0-0} + {% comment %} + These library versions must be flat-typed, do not use variables. + The release note for this BoM version is a library-version snapshot. + {% endcomment %} + +