diff --git a/.github/workflows/unit-test-report.yml b/.github/workflows/unit-test-report.yml new file mode 100644 index 00000000000..9a8a5e92745 --- /dev/null +++ b/.github/workflows/unit-test-report.yml @@ -0,0 +1,35 @@ +name: Generate Test Report + +on: + schedule: + - cron: 51 8 * * * # Runs automatically once a day + workflow_dispatch: # Allow triggering the workflow manually + +permissions: + contents: read + issues: write + +jobs: + report: + name: "Generate Test Report" + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + submodules: true + + - name: Set up JDK 17 + uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4.7.0 + with: + java-version: 17 + distribution: temurin + cache: gradle + + - name: Generate Test Report + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: ./gradlew generateTestReport + + - name: Update tracking issue + run: gh issue edit 7421 --body-file test-report.md diff --git a/build.gradle.kts b/build.gradle.kts index dab824bdf4b..022bd0e5d4b 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -23,6 +23,7 @@ plugins { alias(libs.plugins.errorprone) alias(libs.plugins.crashlytics) apply false id("PublishingPlugin") + id("test-report") id("firebase-ci") id("smoke-tests") alias(libs.plugins.google.services) diff --git a/plugins/build.gradle.kts b/plugins/build.gradle.kts index 7472538256f..3a29db37b3d 100644 --- a/plugins/build.gradle.kts +++ b/plugins/build.gradle.kts @@ -114,6 +114,10 @@ gradlePlugin { id = "copy-google-services" implementationClass = "com.google.firebase.gradle.plugins.CopyGoogleServicesPlugin" } + register("testReportPlugin") { + id = "test-report" + implementationClass = "com.google.firebase.gradle.plugins.report.TestReportPlugin" + } } } diff --git a/plugins/src/main/java/com/google/firebase/gradle/plugins/report/TestReportGenerator.kt b/plugins/src/main/java/com/google/firebase/gradle/plugins/report/TestReportGenerator.kt index 76dd5bda100..db733be838a 100644 --- a/plugins/src/main/java/com/google/firebase/gradle/plugins/report/TestReportGenerator.kt +++ b/plugins/src/main/java/com/google/firebase/gradle/plugins/report/TestReportGenerator.kt @@ -39,7 +39,7 @@ import org.slf4j.LoggerFactory class TestReportGenerator(private val apiToken: String) { private val LOG: Logger = LoggerFactory.getLogger("firebase-test-report") - fun createReport(commitCount: Int) { + fun createReport(outputFile: File, commitCount: Int) { val response: JsonObject = request( URI.create("https://api.github.com/graphql"), @@ -75,10 +75,10 @@ class TestReportGenerator(private val apiToken: String) { ?.int ?: throw RuntimeException("Couldn't find PR number for commit $obj"), ) } - outputReport(commits) + outputReport(outputFile, commits) } - private fun outputReport(commits: List) { + private fun outputReport(outputFile: File, commits: List) { val reports = commits.flatMap { commit -> parseTestReports(commit.sha) } val output = StringBuilder() output.append("### Unit Tests\n\n") @@ -99,7 +99,7 @@ class TestReportGenerator(private val apiToken: String) { output.append("\n") try { - File("test-report.md").writeText(output.toString()) + outputFile.writeText(output.toString()) } catch (e: Exception) { throw RuntimeException("Error writing report file", e) } diff --git a/plugins/src/main/java/com/google/firebase/gradle/plugins/report/TestReportPlugin.kt b/plugins/src/main/java/com/google/firebase/gradle/plugins/report/TestReportPlugin.kt new file mode 100644 index 00000000000..d6c45f819f6 --- /dev/null +++ b/plugins/src/main/java/com/google/firebase/gradle/plugins/report/TestReportPlugin.kt @@ -0,0 +1,31 @@ +/* + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.firebase.gradle.plugins.report + +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.kotlin.dsl.register + +class TestReportPlugin : Plugin { + override fun apply(project: Project) { + project.tasks.register("generateTestReport") { + outputFile.set(project.file("test-report.md")) + commitCount.set(8 as Integer) + apiToken.set(System.getenv("GH_TOKEN")) + } + } +} diff --git a/plugins/src/main/java/com/google/firebase/gradle/plugins/report/TestReportTask.kt b/plugins/src/main/java/com/google/firebase/gradle/plugins/report/TestReportTask.kt new file mode 100644 index 00000000000..55bf062b270 --- /dev/null +++ b/plugins/src/main/java/com/google/firebase/gradle/plugins/report/TestReportTask.kt @@ -0,0 +1,46 @@ +/* + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.firebase.gradle.plugins.report + +import org.gradle.api.DefaultTask +import org.gradle.api.file.RegularFileProperty +import org.gradle.api.provider.Property +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.OutputFile +import org.gradle.api.tasks.TaskAction + +/** + * Creates a markdown unit test report file based on recent runs of GitHub Actions. Task simply + * aggregates live test data and does not rely on the current state of the repository. + * + * @property outputFile The file path to output the markdown test report to. + * @property commitCount The number of remote commits to aggregate test results from. + * @property apiToken The GitHub API token with adequate permissions to read test result data and + * execute GraphQL queries. + */ +abstract class TestReportTask : DefaultTask() { + @get:OutputFile abstract val outputFile: RegularFileProperty + + @get:Input abstract val commitCount: Property + + @get:Input abstract val apiToken: Property + + @TaskAction + fun make() { + TestReportGenerator(apiToken.get()) + .createReport(outputFile.asFile.get(), commitCount.get().toInt()) + } +}