Skip to content

Commit c796ced

Browse files
authored
Merge branch 'master' into ep/build-src-fix
2 parents dc552ac + c5f612a commit c796ced

File tree

63 files changed

+1674
-314
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+1674
-314
lines changed

.github/workflows/build-release-artifacts.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616

1717
- name: Perform gradle build
1818
run: |
19-
./gradlew firebasePublish -PprojectsToPublish=firebase-firestore -PpublishMode=RELEASE -PincludeFireEscapeArtifacts=true
19+
./gradlew firebasePublish -PpublishConfigFilePath=release.cfg -PpublishMode=RELEASE -PincludeFireEscapeArtifacts=true
2020
- name: Upload generated artifacts
2121
uses: actions/upload-artifact@v2
2222
with:

.github/workflows/ci_tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ jobs:
122122
FTL_RESULTS_DIR: ${{ github.event_name == 'pull_request' && format('pr-logs/pull/{0}/{1}/{2}/{3}_{4}/artifacts/', github.repository, github.event.pull_request.number, github.job, github.run_id, github.run_attempt) || format('logs/{0}/{1}_{2}/artifacts/', github.workflow, github.run_id, github.run_attempt)}}
123123
FIREBASE_APP_CHECK_DEBUG_SECRET: ${{ secrets.FIREBASE_APP_CHECK_DEBUG_SECRET }}
124124
run: |
125-
./gradlew ${{matrix.module}}:deviceCheck withErrorProne -PuseProdBackendForTests=true
125+
./gradlew ${{matrix.module}}:deviceCheck withErrorProne -PtargetBackend="prod"
126126
127127
publish-test-results:
128128
name: "Publish Tests Results"

.github/workflows/create_releases.yml

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ on:
77
description: 'Release name'
88
required: true
99
type: string
10+
past-name:
11+
description: 'Past release name'
12+
required: true
13+
type: string
1014

1115
jobs:
1216
create-branches:
@@ -18,32 +22,24 @@ jobs:
1822
uses: peterjgrainger/action-create-branch@c2800a3a9edbba2218da6861fa46496cf8f3195a
1923
with:
2024
branch: 'releases/${{ inputs.name }}'
21-
- name: Create release branch
22-
uses: peterjgrainger/action-create-branch@c2800a3a9edbba2218da6861fa46496cf8f3195a
23-
with:
24-
branch: 'releases/${{ inputs.name }}.release'
2525

2626
create-pull-request:
2727
runs-on: ubuntu-latest
2828
steps:
2929
- uses: actions/checkout@v3
30+
with:
31+
fetch-depth: 0
3032

3133
- name: Create release configuration template
3234
run: |
33-
git config user.name 'Create Release GA'
34-
git config user.email '[email protected]'
35-
echo "[release]" > release.cfg
36-
echo "name = ${{ inputs.name }}" >> release.cfg
37-
echo "mode = RELEASE" >> release.cfg
38-
echo "" >> release.cfg
39-
echo "[modules]" >> release.cfg
40-
echo "" >> release.cfg
41-
git add release.cfg
42-
git commit -a -m 'Create release config'
35+
./gradlew generateReleaseConfig -PcurrentRelease=${{ inputs.name }} -PpastRelease=${{ inputs.past-name }} -PprintOutput=true
4336
4437
- name: Create Pull Request
4538
uses: peter-evans/create-pull-request@v4
4639
with:
4740
base: 'releases/${{ inputs.name }}'
4841
branch: 'releases/${{ inputs.name }}.release'
42+
add-paths: release.cfg
4943
title: '${{ inputs.name}} release'
44+
body: 'Auto-generated PR for release ${{ inputs.name}}'
45+
commit-message: 'Create release config for ${{ inputs.name }}'

.github/workflows/diff-javadoc.yml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ jobs:
3131
echo "run=$(cat modules.json | sed "s/[]\"[]//g" | sed "s/,/\n/g" | xargs printf -- "%s:kotlinDoc ")" >> $GITHUB_OUTPUT
3232
3333
- name: Build
34-
run: ./gradlew ${{ steps.changed-modules.outputs.run }}
34+
# Certain SDKs won't export docs, make a blank folder to diff if that's the case
35+
run: mkdir build && ./gradlew ${{ steps.changed-modules.outputs.run }}
3536

3637
- name: Move original docs
3738
run: mv build ~/diff/modified
@@ -41,7 +42,8 @@ jobs:
4142
ref: ${{ github.base_ref }}
4243

4344
- name: Build
44-
run: ./gradlew ${{ steps.changed-modules.outputs.run }}
45+
# Certain SDKs won't export docs, make a blank folder to diff if that's the case
46+
run: mkdir build && ./gradlew ${{ steps.changed-modules.outputs.run }}
4547

4648
- name: Move modified docs
4749
run: mv build ~/diff/original
@@ -62,6 +64,7 @@ jobs:
6264
> diff.md
6365
6466
- name: Add comment
67+
continue-on-error: true
6568
uses: mshick/add-pr-comment@a65df5f64fc741e91c59b8359a4bc56e57aaf5b1
6669
with:
6770
message-path: diff.md

buildSrc/build.gradle.kts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ dependencies {
5858
implementation("org.eclipse.aether:aether-transport-http:1.0.0.v20140518")
5959
implementation("org.eclipse.aether:aether-transport-wagon:1.0.0.v20140518")
6060
implementation("org.apache.maven:maven-aether-provider:3.1.0")
61+
62+
implementation("org.eclipse.jgit:org.eclipse.jgit:6.3.0.202209071007-r")
6163

6264
implementation("com.google.code.gson:gson:2.8.9")
6365
implementation("com.android.tools.build:gradle:7.2.2")

buildSrc/src/main/java/com/google/firebase/gradle/MultiProjectReleasePlugin.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ public void apply(Project project) {
8080
task.getDestinationDirectory().set(project.getRootDir());
8181
});
8282

83+
project.getTasks().create("generateReleaseConfig", ReleaseGenerator.class);
84+
8385
project
8486
.getGradle()
8587
.projectsEvaluated(
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
// Copyright 2021 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
15+
16+
import java.io.File
17+
import org.eclipse.jgit.api.Git
18+
import org.eclipse.jgit.api.ListBranchCommand
19+
import org.eclipse.jgit.api.errors.GitAPIException
20+
import org.eclipse.jgit.lib.Constants
21+
import org.eclipse.jgit.lib.ObjectId
22+
import org.gradle.api.DefaultTask
23+
import org.gradle.api.tasks.TaskAction
24+
25+
data class FirebaseLibrary(val moduleNames: List<String>, val directories: List<String>)
26+
27+
open class ReleaseGenerator : DefaultTask() {
28+
@TaskAction
29+
@Throws(Exception::class)
30+
fun generateReleaseConfig() {
31+
val currentRelease = project.property("currentRelease").toString()
32+
val pastRelease = project.property("pastRelease").toString()
33+
val printReleaseConfig = project.property("printOutput").toString().toBoolean()
34+
val rootDir = project.rootDir
35+
val availableModules = parseSubProjects(rootDir)
36+
val firebaseLibraries = extractLibraries(availableModules, rootDir)
37+
38+
val repo = Git.open(rootDir)
39+
val headRef = repo.repository.resolve(Constants.HEAD)
40+
val branchRef = getObjectRefForBranchName(repo, pastRelease)
41+
42+
val changedLibraries = getChangedLibraries(repo, branchRef, headRef, firebaseLibraries)
43+
writeReleaseConfig(rootDir, changedLibraries, currentRelease)
44+
if (printReleaseConfig) {
45+
println(changedLibraries.joinToString(",", "LIBRARIES TO RELEASE: "))
46+
}
47+
}
48+
49+
private fun extractLibraries(
50+
availableModules: Set<String>,
51+
rootDir: File
52+
): List<FirebaseLibrary> {
53+
val nonKtxModules = availableModules.filter { !it.endsWith("ktx") }.toSet()
54+
return nonKtxModules
55+
.map { moduleName ->
56+
val ktxModuleName = "$moduleName:ktx"
57+
58+
val moduleNames = listOf(moduleName, ktxModuleName).filter { availableModules.contains(it) }
59+
val directories = moduleNames.map { it.replace(":", "/") }
60+
61+
FirebaseLibrary(moduleNames, directories)
62+
}
63+
.filter { firebaseLibrary ->
64+
firebaseLibrary.directories.first().let { File(rootDir, "$it/gradle.properties").exists() }
65+
}
66+
}
67+
68+
private fun parseSubProjects(rootDir: File) =
69+
File(rootDir, "subprojects.cfg")
70+
.readLines()
71+
.filterNot { it.startsWith("#") || it.isEmpty() }
72+
.toSet()
73+
74+
@Throws(GitAPIException::class)
75+
private fun getObjectRefForBranchName(repo: Git, branchName: String) =
76+
repo
77+
.branchList()
78+
.setListMode(ListBranchCommand.ListMode.REMOTE)
79+
.call()
80+
.firstOrNull { it.name == "refs/remotes/origin/$branchName" }
81+
?.objectId
82+
?: throw RuntimeException("Could not find branch named $branchName")
83+
84+
private fun getChangedLibraries(
85+
repo: Git,
86+
previousReleaseRef: ObjectId,
87+
currentReleaseRef: ObjectId,
88+
libraries: List<FirebaseLibrary>
89+
) =
90+
libraries
91+
.filter { library ->
92+
library.directories.any { checkDirChanges(repo, previousReleaseRef, currentReleaseRef, it) }
93+
}
94+
.flatMap { it.moduleNames }
95+
96+
private fun checkDirChanges(
97+
repo: Git,
98+
previousReleaseRef: ObjectId,
99+
currentReleaseRef: ObjectId,
100+
directory: String
101+
) =
102+
repo
103+
.log()
104+
.addPath("$directory/")
105+
.addRange(previousReleaseRef, currentReleaseRef)
106+
.setMaxCount(1)
107+
.call()
108+
.iterator()
109+
.hasNext()
110+
111+
private fun writeReleaseConfig(configPath: File, libraries: List<String>, releaseName: String) {
112+
File(configPath, "release.cfg")
113+
.writeText(
114+
"""
115+
[release]
116+
name = $releaseName
117+
mode = RELEASE
118+
119+
[modules]
120+
${libraries.joinToString("\n".padEnd(21, ' '))}
121+
"""
122+
.trimIndent()
123+
)
124+
}
125+
}

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

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,13 @@
1616

1717
import com.google.firebase.gradle.plugins.FirebaseLibraryExtension;
1818
import java.io.File;
19-
import java.util.Arrays;
19+
import java.io.IOException;
20+
import java.nio.file.Files;
21+
import java.nio.file.Path;
22+
import java.util.List;
2023
import java.util.Set;
2124
import java.util.stream.Collectors;
25+
import java.util.stream.Stream;
2226
import org.gradle.api.Plugin;
2327
import org.gradle.api.Project;
2428
import org.gradle.api.Task;
@@ -41,12 +45,33 @@
4145
* <p><strong>Prepare a release</strong>
4246
*
4347
* <pre>
48+
* ./gradlew -PpublishConfigFilePath=release.cfg
49+
* -PpublishMode=(RELEASE|SNAPSHOT) \
50+
* firebasePublish
51+
* </pre>
52+
*
53+
* <pre>
4454
* ./gradlew -PprojectsToPublish="firebase-inappmessaging,firebase-inappmessaging-display"\
4555
* -PpublishMode=(RELEASE|SNAPSHOT) \
4656
* firebasePublish
4757
* </pre>
4858
*
4959
* <ul>
60+
* <li>{@code publishConfigFilePath} is the path to the configuration file from which to read the
61+
* list of projects to release. The file format should be consistent with Python's
62+
* configparser, and the list of projects should be in a section called "modules". If both
63+
* this, and {@code projectsToPublish} are specified, this property takes precedence. <br>
64+
* <br>
65+
* Example config file content:
66+
* <pre>
67+
* [release]
68+
* name = M126
69+
* ...
70+
* [modules]
71+
* firebase-database
72+
* firebase-common
73+
* firebase-firestore
74+
* </pre>
5075
* <li>{@code projectsToPublish} is a list of projects to release separated by {@code
5176
* projectsToPublishSeparator}(default: ","), these projects will have their versions depend
5277
* on the {@code publishMode} parameter.
@@ -73,6 +98,7 @@ public PublishingPlugin() {}
7398
public void apply(Project project) {
7499
String projectNamesToPublish = getPropertyOr(project, "projectsToPublish", "");
75100
String projectsToPublishSeparator = getPropertyOr(project, "projectsToPublishSeparator", ",");
101+
String publishConfigFilePath = getPropertyOr(project, "publishConfigFilePath", "");
76102
Mode publishMode = Enum.valueOf(Mode.class, getPropertyOr(project, "publishMode", "SNAPSHOT"));
77103

78104
Task publishAllToLocal = project.task("publishAllToLocal");
@@ -83,8 +109,16 @@ public void apply(Project project) {
83109
.getGradle()
84110
.projectsEvaluated(
85111
gradle -> {
112+
List<String> projectsNames;
113+
if (!publishConfigFilePath.isEmpty()) {
114+
projectsNames = readReleaseConfigFile(publishConfigFilePath);
115+
} else {
116+
projectsNames =
117+
List.of(projectNamesToPublish.split(projectsToPublishSeparator, -1));
118+
}
119+
86120
Set<FirebaseLibraryExtension> projectsToPublish =
87-
Arrays.stream(projectNamesToPublish.split(projectsToPublishSeparator, -1))
121+
projectsNames.stream()
88122
.filter(name -> !name.isEmpty())
89123
.map(
90124
name ->
@@ -194,6 +228,19 @@ public void apply(Project project) {
194228
});
195229
}
196230

231+
private List<String> readReleaseConfigFile(String publishConfigurationFilePath) {
232+
try (Stream<String> stream = Files.lines(Path.of(publishConfigurationFilePath))) {
233+
return stream
234+
.dropWhile((line) -> !line.equals("[modules]"))
235+
// We need to skip the "[modules]" line since it's not dropped
236+
.skip(1)
237+
.collect(Collectors.toList());
238+
} catch (IOException e) {
239+
throw new IllegalArgumentException(
240+
"Error reading configuration file " + publishConfigurationFilePath, e);
241+
}
242+
}
243+
197244
private static String getPropertyOr(Project p, String property, String defaultValue) {
198245
Object value = p.findProperty(property);
199246
if (value != null) {

0 commit comments

Comments
 (0)