Skip to content

Commit 7abc8a2

Browse files
committed
Converty query to graphql
1 parent b272f9a commit 7abc8a2

File tree

1 file changed

+125
-56
lines changed

1 file changed

+125
-56
lines changed

plugins/src/main/java/com/google/firebase/gradle/plugins/report/UnitTestReport.kt

Lines changed: 125 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -15,43 +15,59 @@
1515
*/
1616
package com.google.firebase.gradle.plugins.report
1717

18-
import kotlinx.serialization.json.Json
19-
import kotlinx.serialization.json.JsonArray
20-
import kotlinx.serialization.json.JsonElement
21-
import kotlinx.serialization.json.JsonObject
2218
import java.io.FileWriter
2319
import java.io.IOException
2420
import java.net.URI
2521
import java.net.http.HttpClient
2622
import java.net.http.HttpRequest
2723
import java.net.http.HttpResponse
2824
import java.time.Duration
29-
import java.util.regex.Matcher
3025
import java.util.regex.Pattern
31-
import org.gradle.internal.Pair
3226
import java.util.stream.Stream
33-
import kotlin.streams.toList
27+
import kotlinx.serialization.json.Json
28+
import kotlinx.serialization.json.JsonArray
29+
import kotlinx.serialization.json.JsonElement
30+
import kotlinx.serialization.json.JsonObject
31+
import kotlinx.serialization.json.JsonPrimitive
32+
import kotlinx.serialization.json.int
33+
import kotlinx.serialization.json.jsonArray
34+
import kotlinx.serialization.json.jsonObject
35+
import kotlinx.serialization.json.jsonPrimitive
36+
import org.gradle.internal.Pair
3437

3538
@SuppressWarnings("NewApi")
3639
class UnitTestReport(private val apiToken: String) {
3740
private val client: HttpClient =
3841
HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(10)).build()
3942

4043
fun createReport(commitCount: Int) {
41-
val response = request("commits?per_page=$commitCount", JsonArray::class.java)
44+
val response =
45+
request(
46+
URI.create("https://api.github.com/graphql"),
47+
JsonObject::class.java,
48+
generateGraphQLQuery(commitCount),
49+
)
4250
val commits =
43-
response
51+
response["data"]!!
52+
.jsonObject["repository"]!!
53+
.jsonObject["ref"]!!
54+
.jsonObject["target"]!!
55+
.jsonObject["history"]!!
56+
.jsonObject["nodes"]!!
57+
.jsonArray
4458
.stream()
4559
.limit(commitCount.toLong())
4660
.map { el: JsonElement ->
4761
val obj = el as JsonObject
48-
var pr = -1
49-
val matcher: Matcher =
50-
PR_NUMBER_MATCHER.matcher((obj["commit"] as JsonObject)["message"].toString())
51-
if (matcher.find()) {
52-
pr = matcher.group(1).toInt()
53-
}
54-
ReportCommit(obj["sha"].toString(), pr)
62+
ReportCommit(
63+
obj["oid"]!!.jsonPrimitive.content,
64+
obj["associatedPullRequests"]!!
65+
.jsonObject["nodes"]!!
66+
.jsonArray[0]
67+
.jsonObject["number"]!!
68+
.jsonPrimitive
69+
.int,
70+
)
5571
}
5672
.toList()
5773
outputReport(commits)
@@ -174,9 +190,9 @@ class UnitTestReport(private val apiToken: String) {
174190
val runs = request("actions/runs?head_sha=" + commit)
175191
for (el in runs["workflow_runs"] as JsonArray) {
176192
val run = el as JsonObject
177-
val name = run["name"].toString()
193+
val name = run["name"]!!.jsonPrimitive.content
178194
if (name == "CI Tests") {
179-
return parseCITests(run["id"].toString(), commit)
195+
return parseCITests(run["id"]!!.jsonPrimitive.content, commit)
180196
}
181197
}
182198
return listOf()
@@ -187,7 +203,7 @@ class UnitTestReport(private val apiToken: String) {
187203
val jobs = request("actions/runs/" + id + "/jobs")
188204
for (el in jobs["jobs"] as JsonArray) {
189205
val job = el as JsonObject
190-
val jid = job["name"].toString()
206+
val jid = job["name"]!!.jsonPrimitive.content
191207
if (jid.startsWith("Unit Tests (:")) {
192208
reports.add(parseJob(TestReport.Type.UNIT_TEST, job, commit))
193209
} else if (jid.startsWith("Instrumentation Tests (:")) {
@@ -199,24 +215,61 @@ class UnitTestReport(private val apiToken: String) {
199215

200216
private fun parseJob(type: TestReport.Type, job: JsonObject, commit: String): TestReport {
201217
var name =
202-
job["name"]
203-
.toString()
218+
job["name"]!!
219+
.jsonPrimitive
220+
.content
204221
.split("\\(:".toRegex())
205222
.dropLastWhile { it.isEmpty() }
206223
.toTypedArray()[1]
207224
name = name.substring(0, name.length - 1) // Remove trailing ")"
208225
var status = TestReport.Status.OTHER
209-
if (job["status"].toString() == "completed") {
210-
if (job["conclusion"].toString() == "success") {
226+
if (job["status"]!!.jsonPrimitive.content == "completed") {
227+
if (job["conclusion"]!!.jsonPrimitive.content == "success") {
211228
status = TestReport.Status.SUCCESS
212229
} else {
213230
status = TestReport.Status.FAILURE
214231
}
215232
}
216-
val url = job["html_url"].toString()
233+
val url = job["html_url"]!!.jsonPrimitive.content
217234
return TestReport(name, type, status, commit, url)
218235
}
219236

237+
private fun generateGraphQLQuery(commitCount: Int): JsonObject {
238+
return JsonObject(
239+
mapOf(
240+
Pair(
241+
"query",
242+
JsonPrimitive(
243+
"""
244+
query {
245+
repository(owner: "firebase", name: "firebase-android-sdk") {
246+
ref(qualifiedName: "refs/heads/main") {
247+
target {
248+
... on Commit {
249+
history(first: ${commitCount}) {
250+
nodes {
251+
messageHeadline
252+
oid
253+
associatedPullRequests(first: 1) {
254+
nodes {
255+
number
256+
title
257+
}
258+
}
259+
}
260+
}
261+
}
262+
}
263+
}
264+
}
265+
}
266+
"""
267+
),
268+
)
269+
)
270+
)
271+
}
272+
220273
private fun request(path: String): JsonObject {
221274
return request(path, JsonObject::class.java)
222275
}
@@ -228,10 +281,15 @@ class UnitTestReport(private val apiToken: String) {
228281
/**
229282
* Abstracts away paginated calling. Naively joins pages together by merging root level arrays.
230283
*/
231-
private fun <T> request(uri: URI, clazz: Class<T>): T {
284+
private fun <T> request(uri: URI, clazz: Class<T>, payload: JsonObject? = null): T {
285+
val builder = HttpRequest.newBuilder()
286+
if (payload == null) {
287+
builder.GET()
288+
} else {
289+
builder.POST(HttpRequest.BodyPublishers.ofString(payload.toString()))
290+
}
232291
val request =
233-
HttpRequest.newBuilder()
234-
.GET()
292+
builder
235293
.uri(uri)
236294
.header("Authorization", "Bearer $apiToken")
237295
.header("X-GitHub-Api-Version", "2022-11-28")
@@ -243,39 +301,50 @@ class UnitTestReport(private val apiToken: String) {
243301
System.err.println(response)
244302
System.err.println(body)
245303
}
246-
val json = when (clazz) {
247-
JsonObject::class.java -> Json.decodeFromString<JsonObject>(body)
248-
JsonArray::class.java -> Json.decodeFromString<JsonArray>(body)
249-
else -> throw IllegalArgumentException()
250-
}
304+
val json =
305+
when (clazz) {
306+
JsonObject::class.java -> Json.decodeFromString<JsonObject>(body)
307+
JsonArray::class.java -> Json.decodeFromString<JsonArray>(body)
308+
else -> throw IllegalArgumentException()
309+
}
251310
if (json is JsonObject) {
252311
// Retrieve and merge objects from other pages, if present
253-
return response.headers().firstValue("Link").map { link: String ->
254-
val parts = link.split(",".toRegex()).dropLastWhile { it.isEmpty() }
255-
for (part in parts) {
256-
if (part.endsWith("rel=\"next\"")) {
257-
// <foo>; rel="next" -> foo
258-
val url =
259-
part
260-
.split(">;".toRegex())
261-
.dropLastWhile { it.isEmpty() }
262-
.toTypedArray()[0]
263-
.split("<".toRegex())
264-
.dropLastWhile { it.isEmpty() }
265-
.toTypedArray()[1]
266-
val p = request<JsonObject>(URI.create(url), JsonObject::class.java)
267-
return@map JsonObject(json.keys.associateWith {
268-
key: String ->
269-
270-
if (json[key] is JsonArray && p.containsKey(key) && p[key] is JsonArray) {
271-
JsonArray(Stream.concat((json[key] as JsonArray).stream(), (p[key] as JsonArray).stream()).toList())
272-
}
273-
json[key]!!
274-
})
312+
return response
313+
.headers()
314+
.firstValue("Link")
315+
.map { link: String ->
316+
val parts = link.split(",".toRegex()).dropLastWhile { it.isEmpty() }
317+
for (part in parts) {
318+
if (part.endsWith("rel=\"next\"")) {
319+
// <foo>; rel="next" -> foo
320+
val url =
321+
part
322+
.split(">;".toRegex())
323+
.dropLastWhile { it.isEmpty() }
324+
.toTypedArray()[0]
325+
.split("<".toRegex())
326+
.dropLastWhile { it.isEmpty() }
327+
.toTypedArray()[1]
328+
val p = request<JsonObject>(URI.create(url), JsonObject::class.java)
329+
return@map JsonObject(
330+
json.keys.associateWith { key: String ->
331+
if (json[key] is JsonArray && p.containsKey(key) && p[key] is JsonArray) {
332+
return@associateWith JsonArray(
333+
Stream.concat(
334+
(json[key] as JsonArray).stream(),
335+
(p[key] as JsonArray).stream(),
336+
)
337+
.toList()
338+
)
339+
}
340+
return@associateWith json[key]!!
341+
}
342+
)
343+
}
275344
}
345+
return@map json
276346
}
277-
return@map json
278-
}.orElse(json) as T
347+
.orElse(json) as T
279348
}
280349
return json as T
281350
} catch (e: IOException) {

0 commit comments

Comments
 (0)