Skip to content
36 changes: 22 additions & 14 deletions .github/workflows/make-bom.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ jobs:
uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3
with:
python-version: '3.10'

- uses: actions/[email protected]

- name: Set up JDK 17
uses: actions/[email protected]
with:
Expand All @@ -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/[email protected]
with:
name: bom
path: build/bom/
retention-days: 15

- name: Upload release notes
uses: actions/[email protected]
with:
name: bom_release_notes
path: build/bomReleaseNotes.md
retention-days: 15

- name: Upload recipe version update
uses: actions/[email protected]
with:
name: artifacts
path: ./logs/artifacts/
retention-days: 5
name: recipe_version
path: build/recipeVersionUpdate.txt
retention-days: 15
Original file line number Diff line number Diff line change
Expand Up @@ -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(".", "-")}}"

Expand All @@ -71,8 +71,9 @@ abstract class GenerateBomReleaseNotesTask : DefaultTask() {
| Firebase Android SDKs mapped to this {{bom}} version
| </p>
| <p>
| Libraries that were versioned with this release are in highlighted rows.<br>
| 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.
| <br>Refer to a library's release notes (on this page) for details about its
| changes.
| </p>
| <table>
| <thead>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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) ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,43 @@ infix fun <T> List<T>.diff(other: List<T>): List<Pair<T?, T?>> {
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 <T, R> List<T>.pairBy(other: List<T>, mapper: (T) -> R): List<Pair<T?, T?>> {
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.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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())
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down Expand Up @@ -140,9 +142,16 @@ abstract class PublishingPlugin : Plugin<Project> {
destinationDirectory.set(project.layout.buildDirectory)
}

project.tasks.register<Zip>(BUILD_BOM_ZIP_TASK) {
from(generateBom, generateBomReleaseNotes, generateTutorialBundle)
archiveFileName.set("bom.zip")
val buildBomZip =
project.tasks.register<Zip>(BUILD_BOM_ZIP_TASK) {
from(generateBom)
archiveFileName.set("bom.zip")
destinationDirectory.set(project.layout.buildDirectory)
}

project.tasks.register<Zip>(BUILD_BOM_BUNDLE_ZIP_TASK) {
from(buildBomZip, generateBomReleaseNotes, generateTutorialBundle)
archiveFileName.set("bomBundle.zip")
destinationDirectory.set(project.layout.projectDirectory)
}

Expand Down Expand Up @@ -757,6 +766,7 @@ abstract class PublishingPlugin : Plugin<Project> {
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"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<LicenseElement>? = null,
@XmlChildrenName("license") val licenses: List<LicenseElement>? = null,
@XmlElement val scm: SourceControlManagement? = null,
@XmlElement val dependencyManagement: DependencyManagementElement? = null,
@XmlChildrenName("dependency") val dependencies: List<ArtifactDependency>? = null,
Expand All @@ -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.
*
Expand All @@ -201,6 +211,6 @@ data class PomElement(
* @see fromFile
*/
fun fromElement(element: Element): PomElement =
XML.decodeFromReader(xmlStreaming.newReader(element))
xml.decodeFromReader(xmlStreaming.newReader(element))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,9 @@ class GenerateBomReleaseNotesTests : FunSpec() {
Firebase Android SDKs mapped to this {{bom}} version
</p>
<p>
Libraries that were versioned with this release are in highlighted rows.<br>
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.
<br>Refer to a library's release notes (on this page) for details about its
changes.
</p>
<table>
<thead>
Expand All @@ -92,6 +93,65 @@ class GenerateBomReleaseNotesTests : FunSpec() {
.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 %}

<section class="expandable">
<p class="showalways">
Firebase Android SDKs mapped to this {{bom}} version
</p>
<p>
Libraries that were versioned with this release are in highlighted rows.
<br>Refer to a library's release notes (on this page) for details about its
changes.
</p>
<table>
<thead>
<th>Artifact name</th>
<th>Version mapped<br>to previous {{bom}} v1.0.0</th>
<th>Version mapped<br>to this {{bom}} v1.0.0</th>
</thead>
<tbody>
<tr>
<td>com.google.firebase:firebase-auth</td>
<td>10.0.0</td>
<td>10.0.0</td>
</tr>
<tr>
<td>com.google.firebase:firebase-firestore</td>
<td>10.0.0</td>
<td>10.0.0</td>
</tr>
</tbody>
</table>
</section>
"""
.trimIndent()
}

@Test
fun `correctly formats changed dependencies`() {
val oldDependencies =
Expand Down Expand Up @@ -147,8 +207,9 @@ class GenerateBomReleaseNotesTests : FunSpec() {
Firebase Android SDKs mapped to this {{bom}} version
</p>
<p>
Libraries that were versioned with this release are in highlighted rows.<br>
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.
<br>Refer to a library's release notes (on this page) for details about its
changes.
</p>
<table>
<thead>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -243,11 +243,11 @@ class GenerateBomTests : FunSpec() {
<version>1.0.1</version>
<packaging>pom</packaging>
<licenses>
<licenses>
<license>
<name>The Apache Software License, Version 2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
<distribution>repo</distribution>
</licenses>
</license>
</licenses>
<dependencyManagement>
<dependencies>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,16 @@ class ModuleVersionTests : FunSpec() {
ModuleVersion(1, 1, 1).apply { bump(PRE) shouldBe this }
}

@Test
fun `Bump resets the smaller version types`() {
val version = ModuleVersion(1, 1, 1, PreReleaseVersion(ALPHA, 2))

version.bump(PRE) shouldBe ModuleVersion(1, 1, 1, PreReleaseVersion(ALPHA, 3))
version.bump(PATCH) shouldBe ModuleVersion(1, 1, 2, PreReleaseVersion(ALPHA, 1))
version.bump(MINOR) shouldBe ModuleVersion(1, 2, 0, PreReleaseVersion(ALPHA, 1))
version.bump(MAJOR) shouldBe ModuleVersion(2, 0, 0, PreReleaseVersion(ALPHA, 1))
}

@Test
fun `Bump correctly chooses the smallest by default`() {
ModuleVersion(1, 1, 1).bump().patch shouldBe 2
Expand Down
Loading