From 86e82987ba0152ca7d7e8fedd3b4676b6295d7dc Mon Sep 17 00:00:00 2001 From: Daz DeBoer Date: Thu, 2 Jun 2022 12:57:35 -0600 Subject: [PATCH] Write job summary in post action - Save build results in file encoded as JSON - Read all build results in post action and render as table in job summary --- src/job-summary.ts | 59 +++++++++++++++++++ src/post.ts | 3 + .../build-result-capture.init.gradle | 26 ++++---- 3 files changed, 78 insertions(+), 10 deletions(-) create mode 100644 src/job-summary.ts diff --git a/src/job-summary.ts b/src/job-summary.ts new file mode 100644 index 0000000..314aace --- /dev/null +++ b/src/job-summary.ts @@ -0,0 +1,59 @@ +import * as core from '@actions/core' +import fs from 'fs' +import path from 'path' + +interface BuildResult { + get rootProject(): string + get requestedTasks(): string + get gradleVersion(): string + get buildFailed(): boolean + get buildScanUri(): string +} + +export function writeJobSummary(): void { + const buildResults = loadBuildResults() + if (buildResults.length === 0) { + core.debug('No Gradle build results found. Summary table will not be generated.') + } else { + writeSummaryTable(buildResults) + } +} + +function loadBuildResults(): BuildResult[] { + const buildResultsDir = path.resolve(process.env['RUNNER_TEMP']!, '.build-results') + if (!fs.existsSync(buildResultsDir)) { + return [] + } + + return fs.readdirSync(buildResultsDir).map(file => { + // Every file in the .build-results dir should be a BuildResults JSON + const filePath = path.join(buildResultsDir, file) + const content = fs.readFileSync(filePath, 'utf8') + return JSON.parse(content) as BuildResult + }) +} + +function writeSummaryTable(results: BuildResult[]): void { + core.summary.addRaw(`| Root Project | Tasks | Gradle Version | Outcome |\n| - | - | - | - |\n`) + for (const result of results) { + const tableRow = `| ${result.rootProject} \ + | ${result.requestedTasks} \ + | ${result.gradleVersion} \ + | ${renderOutcome(result)} \ + |\n` + core.summary.addRaw(tableRow) + } + core.summary.write() +} + +function renderOutcome(result: BuildResult): string { + if (result.buildScanUri) { + return `[![Gradle Build](https://img.shields.io/badge/Build%20Scan%E2%84%A2-${ + result.buildFailed ? 'FAILED-red' : 'SUCCESS-brightgreen' + }?logo=Gradle)](${result.buildScanUri})` + } + + return `![Gradle Build](https://img.shields.io/badge/${ + result.buildFailed ? 'FAILED-red' : 'SUCCESS-brightgreen' + }?logo=Gradle)` +} diff --git a/src/post.ts b/src/post.ts index d81a8ca..cebdeab 100644 --- a/src/post.ts +++ b/src/post.ts @@ -1,5 +1,6 @@ import * as core from '@actions/core' import * as setupGradle from './setup-gradle' +import {writeJobSummary} from './job-summary' // Catch and log any unhandled exceptions. These exceptions can leak out of the uploadChunk method in // @actions/toolkit when a failed upload closes the file descriptor causing any in-process reads to @@ -12,6 +13,8 @@ process.on('uncaughtException', e => handleFailure(e)) export async function run(): Promise { try { await setupGradle.complete() + + writeJobSummary() } catch (error) { handleFailure(error) } diff --git a/src/resources/build-result-capture.init.gradle b/src/resources/build-result-capture.init.gradle index 89904dd..fdb8997 100644 --- a/src/resources/build-result-capture.init.gradle +++ b/src/resources/build-result-capture.init.gradle @@ -33,17 +33,23 @@ def registerCallbacks(buildScanExtension, rootProjectName) { } buildScanPublished { buildScan -> - def gradleCommand = rootProjectName + " " + gradle.startParameter.taskNames.join(" ") + def buildResultsDir = new File(System.getenv("RUNNER_TEMP"), ".build-results") + buildResultsDir.mkdirs() + + def buildResultsFile = new File(buildResultsDir, System.getenv("GITHUB_ACTION") + System.currentTimeMillis() + ".json") + + def requestedTasks = gradle.startParameter.taskNames.join(" ") + def gradleVersion = GradleVersion.current().version + def buildScanUri = buildScan.buildScanUri.toASCIIString() + def buildResults = [ + rootProject: rootProjectName, + requestedTasks: requestedTasks, + gradleVersion: gradleVersion, + buildFailed: buildFailed, + buildScanUri: buildScanUri + ] + buildResultsFile << groovy.json.JsonOutput.toJson(buildResults) - // Write job summary to magic file defined by GitHub Actions. - def githubSummaryFile = new File(System.getenv("GITHUB_STEP_SUMMARY")) - if (buildFailed) { - githubSummaryFile << ":x: Gradle Build `${gradleCommand}` [![Gradle Enterprise Build Scan](https://img.shields.io/badge/Gradle%20Enterprise%20Build%20Scan%E2%84%A2-FAILED-red?logo=Gradle)](${buildScan.buildScanUri})" - } else { - githubSummaryFile << ":white_check_mark: Gradle Build `${gradleCommand}` [![Gradle Enterprise Build Scan](https://img.shields.io/badge/Gradle%20Enterprise%20Build%20Scan%E2%84%A2-SUCCESS-brightgreen?logo=Gradle)](${buildScan.buildScanUri})" - } - - // Send 'set-output' command directly to GitHub Actions via STDOUT. println("::set-output name=build-scan-url::${buildScan.buildScanUri}") } }