14
14
15
15
package com.google.firebase.gradle.plugins.publish
16
16
17
+ import com.google.firebase.gradle.plugins.ci.AffectedProjectFinder
17
18
import com.google.firebase.gradle.plugins.FirebaseLibraryExtension
18
19
import digital.wup.android_maven_publish.AndroidMavenPublishPlugin
19
20
import org.gradle.api.Plugin
20
21
import org.gradle.api.Project
22
+ import org.gradle.api.artifacts.ProjectDependency
21
23
import org.gradle.api.publish.maven.MavenPublication
22
24
import org.gradle.api.tasks.bundling.Jar
23
25
import org.gradle.api.tasks.bundling.Zip
26
+ import org.json.JSONArray
27
+ import org.json.JSONObject
24
28
25
29
/**
26
30
* Enables releasing of the SDKs.
@@ -64,6 +68,16 @@ import org.gradle.api.tasks.bundling.Zip
64
68
* -PpublishMode=(RELEASE|SNAPSHOT) \
65
69
* publishProjectsToMavenLocal
66
70
* </pre>
71
+ *
72
+ * <p ><strong >Build recently changed snapshots</strong>
73
+ *
74
+ * <pre >
75
+ * ./gradlew publishChangedToBuildDir # publishes changed projects to build/m2repository
76
+ * </pre>
77
+ *
78
+ * This option builds projects that have been changed by the latest git commit and all of their
79
+ * dependencies. They are published to the build directory. This workflow is intended for
80
+ * compatibility testing, where the changed projects need to be layered over a previous release.
67
81
*/
68
82
class PublishingPlugin implements Plugin<Project > {
69
83
@Override
@@ -83,9 +97,16 @@ class PublishingPlugin implements Plugin<Project> {
83
97
84
98
def publishAllToLocal = project. task(' publishAllToLocal' )
85
99
def publishAllToBuildDir = project. task(' publishAllToBuildDir' )
100
+ def publishChangedToBuildDir = project. task(' publishChangedToBuildDir' )
86
101
def firebasePublish = project. task(' firebasePublish' )
87
102
88
103
project. getGradle(). projectsEvaluated {
104
+ // These three variables are used for generating the JSON file that lists the artifacts
105
+ // affected by the latest commit. This is generally useful only on CI builds.
106
+ def changedProjects = getChangedProjects(project)
107
+ def changedArtifacts = new HashSet<String > ()
108
+ def allArtifacts = new HashSet<String > ()
109
+
89
110
project. subprojects { Project sub ->
90
111
if (! sub. plugins. hasPlugin(' firebase-library' )) {
91
112
return
@@ -121,11 +142,40 @@ class PublishingPlugin implements Plugin<Project> {
121
142
publisher. decorate(sub, it)
122
143
}
123
144
}
145
+
124
146
publishAllToLocal. dependsOn " $sub . path :publishMavenAarPublicationToMavenLocal"
125
147
publishAllToBuildDir. dependsOn " $sub . path :publishMavenAarPublicationToBuildDirRepository"
126
148
149
+ // Update the changed and all sets each time an artifact is published. This is
150
+ // used to build the JSON file of affected targets.
151
+ sub. tasks. getByName(" publishMavenAarPublicationToBuildDirRepository" ). doLast {
152
+ def artifact = " $sub . group :$sub . name :$sub . version -SNAPSHOT"
153
+ allArtifacts. add(artifact)
154
+
155
+ if (changedProjects. contains(sub)) {
156
+ changedArtifacts. add(artifact)
157
+ }
158
+ }
127
159
}
160
+
128
161
}
162
+
163
+ // Build the JSON file of affected targets after all artifacts have been published.
164
+ publishAllToBuildDir. doLast {
165
+ def changed = new JSONArray ()
166
+ changedArtifacts. each { changed. put(it) }
167
+
168
+ def all = new JSONArray ()
169
+ allArtifacts. each { all. put(it) }
170
+
171
+ def json = new JSONObject ()
172
+ json. put(" all" , all)
173
+ json. put(" changed" , changed)
174
+
175
+ def path = project. buildDir. toPath()
176
+ path. resolve(" m2repository/changed-artifacts.json" ). write(json. toString())
177
+ }
178
+
129
179
project. task(' publishProjectsToMavenLocal' ) {
130
180
projectsToPublish. each { projectToPublish ->
131
181
dependsOn getPublishTask(projectToPublish, ' MavenLocal' )
@@ -155,6 +205,31 @@ class PublishingPlugin implements Plugin<Project> {
155
205
}
156
206
}
157
207
208
+ private static Set<Project > getChangedProjects (Project p ) {
209
+ Set<Project > roots = new AffectedProjectFinder (p, []). find()
210
+ HashSet<Project > changed = new HashSet<> ()
211
+
212
+ getChangedProjectsLoop(roots, changed)
213
+ return changed
214
+ }
215
+
216
+ private static void getChangedProjectsLoop (Collection<Project > projects , Set<Project > changed ) {
217
+ for (Project p : projects) {
218
+ // Skip processing and recursion if this project has already been added to the set.
219
+ if (! changed. add(p)) {
220
+ continue ;
221
+ }
222
+
223
+ // Find all (head) dependencies to other projects in this respository.
224
+ def all = p. configurations. releaseRuntimeClasspath. allDependencies
225
+ def affected =
226
+ all. findAll { it instanceof ProjectDependency }. collect { it. getDependencyProject() }
227
+
228
+ // Recurse with the new dependencies.
229
+ getChangedProjectsLoop(affected, changed)
230
+ }
231
+ }
232
+
158
233
private static String getPublishTask (Project p , String repoName ) {
159
234
return " ${ p.path} :publishMavenAarPublicationTo$repoName "
160
235
}
0 commit comments