Skip to content

Commit 8c1a630

Browse files
committed
code cleanup, GithubClient.kt created
1 parent b4bc34a commit 8c1a630

File tree

2 files changed

+122
-63
lines changed

2 files changed

+122
-63
lines changed
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
/*
2+
* Copyright 2025 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.firebase.dataconnect.gradle.ci
18+
19+
import com.google.firebase.dataconnect.gradle.plugin.nextAlphanumericString
20+
import java.io.ByteArrayInputStream
21+
import java.io.ByteArrayOutputStream
22+
import java.io.File
23+
import java.net.URL
24+
import kotlin.random.Random
25+
import kotlinx.serialization.ExperimentalSerializationApi
26+
import kotlinx.serialization.Serializable
27+
import kotlinx.serialization.json.Json
28+
import kotlinx.serialization.json.decodeFromStream
29+
import org.gradle.api.logging.Logger
30+
import org.gradle.process.ExecOperations
31+
32+
/** Wrapper around the "gh" GitHub client application, for interacting with GitHub. */
33+
class GithubClient(
34+
val execOperations: ExecOperations,
35+
val tempDirectory: File,
36+
val githubRepository: String,
37+
val logger: Logger
38+
) {
39+
40+
fun fetchIssueInfo(issueNumber: Int): IssueInfo {
41+
logger.info("Fetching information from GitHub about issue #{}", issueNumber)
42+
43+
val stdoutBytes =
44+
runGithubClient(
45+
listOf(
46+
"issue",
47+
"view",
48+
issueNumber.toString(),
49+
"--json",
50+
"title,body",
51+
)
52+
)
53+
54+
val jsonParser = Json { ignoreUnknownKeys = true }
55+
@OptIn(ExperimentalSerializationApi::class)
56+
val issueInfo = jsonParser.decodeFromStream<IssueInfo>(ByteArrayInputStream(stdoutBytes))
57+
58+
logger.info("Fetched information from GitHub about issue #{}: {}", issueNumber, issueInfo)
59+
return issueInfo
60+
}
61+
62+
@Serializable data class IssueInfo(val title: String, val body: String)
63+
64+
/**
65+
* Posts a comment onto a GitHub issue or pull request.
66+
*
67+
* @param issueNumber the issue or pull request number on which to comment.
68+
* @param messageLines the lines of text of the comment to post.
69+
* @return the URL of the newly-created comment that was posted by this method call.
70+
*/
71+
fun postComment(issueNumber: Int, messageLines: Iterable<String>): URL {
72+
val tempFile = File(tempDirectory, Random.nextAlphanumericString(30))
73+
if (!tempDirectory.exists() && !tempDirectory.mkdirs()) {
74+
logger.warn(
75+
"WARNING: unable to create directory: {} [warning code kxd2j66gzm]",
76+
tempDirectory.absolutePath
77+
)
78+
}
79+
tempFile.writeText(messageLines.joinToString("\n"))
80+
81+
val stdoutBytes =
82+
try {
83+
runGithubClient(
84+
listOf(
85+
"issue",
86+
"comment",
87+
issueNumber.toString(),
88+
"--body-file",
89+
tempFile.absolutePath,
90+
)
91+
)
92+
} finally {
93+
tempFile.delete()
94+
}
95+
96+
return URL(String(stdoutBytes).trim())
97+
}
98+
99+
private fun runGithubClient(args: Iterable<String> = emptyList()): ByteArray {
100+
val byteArrayOutputStream = ByteArrayOutputStream()
101+
execOperations.exec { execSpec ->
102+
execSpec.standardOutput = byteArrayOutputStream
103+
execSpec.executable("gh")
104+
args.forEach { execSpec.args(it) }
105+
execSpec.args("-R")
106+
execSpec.args(githubRepository)
107+
logger.info("Running command: {}", execSpec.commandLine.joinToString(" "))
108+
}
109+
return byteArrayOutputStream.toByteArray()
110+
}
111+
}

firebase-dataconnect/gradleplugin/plugin/src/main/kotlin/com/google/firebase/dataconnect/gradle/ci/PostCommentForJobResults.kt

Lines changed: 11 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,8 @@
1616

1717
package com.google.firebase.dataconnect.gradle.ci
1818

19-
import com.google.firebase.dataconnect.gradle.plugin.nextAlphanumericString
20-
import java.io.ByteArrayInputStream
2119
import java.io.File
22-
import kotlin.random.Random
23-
import kotlinx.serialization.ExperimentalSerializationApi
24-
import kotlinx.serialization.Serializable
25-
import kotlinx.serialization.json.Json
26-
import kotlinx.serialization.json.decodeFromStream
2720
import org.gradle.api.logging.Logger
28-
import org.gradle.internal.impldep.org.apache.commons.io.output.ByteArrayOutputStream
2921
import org.gradle.process.ExecOperations
3022

3123
class PostCommentForJobResults(
@@ -41,12 +33,16 @@ class PostCommentForJobResults(
4133
val githubRunNumber: String,
4234
val githubRunAttempt: String,
4335
val workDirectory: File,
44-
val execOperations: ExecOperations,
36+
execOperations: ExecOperations,
4537
val logger: Logger
4638
) {
4739

40+
private val githubClient = GithubClient(execOperations, workDirectory, githubRepository, logger)
41+
4842
fun run() {
49-
logger.info("jobResults={}", jobResults)
43+
logger.info("jobResults=[{}]{", jobResults.size)
44+
jobResults.forEach { logger.info(" {}: {}", it.jobId, it.result) }
45+
logger.info("}")
5046
logger.info("githubIssue={}", githubIssue)
5147
logger.info("githubRepository={}", githubRepository)
5248
logger.info("githubEventName={}", githubEventName)
@@ -64,32 +60,13 @@ class PostCommentForJobResults(
6460
val issueUrl = "$githubRepositoryHtmlUrl/issues/$githubIssue"
6561
logger.info("Posting the following comment to GitHub Issue {}:", issueUrl)
6662
messageLines.forEach { logger.info("> {}", it) }
67-
postCommentToGithubIssue(messageLines)
68-
}
69-
70-
private fun postCommentToGithubIssue(messageLines: List<String>) {
71-
val tempFile = File(workDirectory, Random.nextAlphanumericString(30))
72-
logger.info("Writing GitHub Issue comment into text file: {}", tempFile.absolutePath)
73-
workDirectory.mkdirs()
74-
tempFile.writeText(messageLines.joinToString("\n"))
75-
76-
execOperations.exec { execSpec ->
77-
execSpec.executable("gh")
78-
execSpec.args("issue")
79-
execSpec.args("comment")
80-
execSpec.args(githubIssue.toString())
81-
execSpec.args("--body-file")
82-
execSpec.args(tempFile.absolutePath)
83-
execSpec.args("-R")
84-
execSpec.args(githubRepository)
85-
logger.info("Running command: {}", execSpec.commandLine.joinToString(" "))
86-
}
63+
val commentUrl = githubClient.postComment(githubIssue, messageLines)
64+
logger.lifecycle("Comment posted successfully: {}", commentUrl)
8765
}
8866

8967
private fun calculateMessageLines(): List<String> = buildList {
90-
val prNumber: Int? = parseGithubPrNumberFromGithubRef()
91-
val prInfo: GitHubPrInfo? = if (prNumber === null) null else fetchGithubPrInfo(prNumber)
92-
if (prInfo !== null) {
68+
parseGithubPrNumberFromGithubRef()?.let { prNumber ->
69+
val prInfo = githubClient.fetchIssueInfo(prNumber)
9370
add("Posting from Pull Request $githubRepositoryHtmlUrl/pull/$prNumber (${prInfo.title})")
9471
}
9572

@@ -120,38 +97,9 @@ class PostCommentForJobResults(
12097
logger.info("Extracting PR number from githubRef: {}", githubRef)
12198
val prNumber: Int? =
12299
Regex("refs/pull/([0-9]+)/merge").matchEntire(githubRef)?.groupValues?.get(1)?.toInt()
123-
logger.info("Extracted PR number from githubRef: {}", githubRef)
100+
logger.info("Extracted PR number from githubRef {}: {}", githubRef, prNumber)
124101
return prNumber
125102
}
126103

127-
private fun fetchGithubPrInfo(prNumber: Int): GitHubPrInfo {
128-
logger.info("Fetching information from GitHub about PR #{}", prNumber)
129-
val byteArrayOutputStream = ByteArrayOutputStream()
130-
execOperations.exec { execSpec ->
131-
execSpec.standardOutput = byteArrayOutputStream
132-
execSpec.executable("gh")
133-
execSpec.args("issue")
134-
execSpec.args("view")
135-
execSpec.args(prNumber.toString())
136-
execSpec.args("--json")
137-
execSpec.args("title,body")
138-
execSpec.args("-R")
139-
execSpec.args(githubRepository)
140-
logger.info("Running command: {}", execSpec.commandLine.joinToString(" "))
141-
}
142-
143-
val jsonParser = Json { ignoreUnknownKeys = true }
144-
@OptIn(ExperimentalSerializationApi::class)
145-
val githubPrInfo =
146-
jsonParser.decodeFromStream<GitHubPrInfo>(
147-
ByteArrayInputStream(byteArrayOutputStream.toByteArray())
148-
)
149-
150-
logger.info("Fetched information from GitHub about PR #{}: {}", prNumber, githubPrInfo)
151-
return githubPrInfo
152-
}
153-
154104
data class JobResult(val jobId: String, val result: String)
155-
156-
@Serializable private data class GitHubPrInfo(val title: String, val body: String)
157105
}

0 commit comments

Comments
 (0)