Improve layout and formatting of Job Summary

- Move entire caching summary into details section
- Use core.summary.addTable for all table creation
- Include cache status in clickable description
This commit is contained in:
Daz DeBoer 2022-06-04 09:36:41 -06:00
parent 9ab4abd18c
commit 4fa0803854
No known key found for this signature in database
GPG key ID: DD6B9F0B06683D5D
3 changed files with 58 additions and 70 deletions

View file

@ -8,11 +8,19 @@ export class CacheListener {
cacheEntries: CacheEntryListener[] = [] cacheEntries: CacheEntryListener[] = []
isCacheReadOnly = false isCacheReadOnly = false
isCacheWriteOnly = false isCacheWriteOnly = false
isCacheDisabled = false
get fullyRestored(): boolean { get fullyRestored(): boolean {
return this.cacheEntries.every(x => !x.wasRequestedButNotRestored()) return this.cacheEntries.every(x => !x.wasRequestedButNotRestored())
} }
get cacheStatus(): string {
if (this.isCacheDisabled) return 'disabled'
if (this.isCacheWriteOnly) return 'write-only'
if (this.isCacheReadOnly) return 'read-only'
return 'enabled'
}
entry(name: string): CacheEntryListener { entry(name: string): CacheEntryListener {
for (const entry of this.cacheEntries) { for (const entry of this.cacheEntries) {
if (entry.entryName === name) { if (entry.entryName === name) {
@ -97,13 +105,25 @@ export class CacheEntryListener {
} }
export function logCachingReport(listener: CacheListener): void { export function logCachingReport(listener: CacheListener): void {
if (listener.cacheEntries.length === 0) {
return
}
core.summary.addHeading('Gradle Home Caching Summary', 3)
const entries = listener.cacheEntries const entries = listener.cacheEntries
core.summary.addRaw(
`\n<details><summary><h4>Caching for gradle-build-action was ${listener.cacheStatus} - expand for details</h4></summary>\n`
)
core.summary.addTable([
[
{data: '', header: true},
{data: 'Count', header: true},
{data: 'Total Size (Mb)', header: true}
],
['Entries Restored', `${getCount(entries, e => e.restoredSize)}`, `${getSize(entries, e => e.restoredSize)}`],
['Entries Saved', `${getCount(entries, e => e.savedSize)}`, `${getSize(entries, e => e.savedSize)}`]
])
core.summary.addHeading('Cache Entry Details', 5)
const entryDetails = listener.cacheEntries
.map( .map(
entry => entry =>
`Entry: ${entry.entryName} `Entry: ${entry.entryName}
@ -114,43 +134,15 @@ export function logCachingReport(listener: CacheListener): void {
Saved Key : ${entry.savedKey ?? ''} Saved Key : ${entry.savedKey ?? ''}
Size: ${formatSize(entry.savedSize)} Size: ${formatSize(entry.savedSize)}
${getSavedMessage(entry, listener.isCacheReadOnly)} ${getSavedMessage(entry, listener.isCacheReadOnly)}
---` `
) )
.join('\n') .join('---\n')
core.summary.addRaw( core.summary.addRaw(`<pre>
` ${entryDetails}
| | Count | Size (Mb) | Size (B) |
| - | -: | -: | -: |
| Restored | ${getCount(listener.cacheEntries, e => e.restoredSize)} | ${getMegaBytes(
listener.cacheEntries,
e => e.restoredSize
)} | ${getBytes(listener.cacheEntries, e => e.restoredSize)} |
| Saved | ${getCount(listener.cacheEntries, e => e.savedSize)} | ${getMegaBytes(
listener.cacheEntries,
e => e.savedSize
)} | ${getBytes(listener.cacheEntries, e => e.savedSize)} |
`
)
if (listener.isCacheReadOnly) {
core.summary.addRaw('- **Cache is read-only**\n')
}
if (listener.isCacheWriteOnly) {
core.summary.addRaw('- **Cache is write-only**\n')
}
core.summary.addDetails(
'Cache Entry Details',
`
<pre>
${entries}
</pre> </pre>
</details>
` `)
)
} }
function getRestoredMessage(entry: CacheEntryListener, isCacheWriteOnly: boolean): string { function getRestoredMessage(entry: CacheEntryListener, isCacheWriteOnly: boolean): string {
@ -189,18 +181,11 @@ function getCount(
return cacheEntries.filter(e => predicate(e) !== undefined).length return cacheEntries.filter(e => predicate(e) !== undefined).length
} }
function getBytes( function getSize(
cacheEntries: CacheEntryListener[], cacheEntries: CacheEntryListener[],
predicate: (value: CacheEntryListener) => number | undefined predicate: (value: CacheEntryListener) => number | undefined
): number { ): number {
return cacheEntries.map(e => predicate(e) ?? 0).reduce((p, v) => p + v, 0) const bytes = cacheEntries.map(e => predicate(e) ?? 0).reduce((p, v) => p + v, 0)
}
function getMegaBytes(
cacheEntries: CacheEntryListener[],
predicate: (value: CacheEntryListener) => number | undefined
): number {
const bytes = getBytes(cacheEntries, predicate)
return Math.round(bytes / (1024 * 1024)) return Math.round(bytes / (1024 * 1024))
} }

View file

@ -19,6 +19,7 @@ export async function restore(gradleUserHome: string, cacheListener: CacheListen
core.info('Cache is disabled: will not restore state from previous builds.') core.info('Cache is disabled: will not restore state from previous builds.')
// Initialize the Gradle User Home even when caching is disabled. // Initialize the Gradle User Home even when caching is disabled.
gradleStateCache.init() gradleStateCache.init()
cacheListener.isCacheDisabled = true
return return
} }

View file

@ -12,17 +12,15 @@ interface BuildResult {
} }
export function writeJobSummary(cacheListener: CacheListener): void { export function writeJobSummary(cacheListener: CacheListener): void {
core.info('Writing job summary...') core.info('Writing job summary')
const buildResults = loadBuildResults() const buildResults = loadBuildResults()
if (buildResults.length === 0) { if (buildResults.length === 0) {
core.debug('No Gradle build results found. Summary table will not be generated.') core.debug('No Gradle build results found. Summary table will not be generated.')
} else { } else {
core.info('Writing summary table')
writeSummaryTable(buildResults) writeSummaryTable(buildResults)
} }
core.info('Writing cache report...')
logCachingReport(cacheListener) logCachingReport(cacheListener)
core.summary.write() core.summary.write()
@ -43,28 +41,32 @@ function loadBuildResults(): BuildResult[] {
} }
function writeSummaryTable(results: BuildResult[]): void { function writeSummaryTable(results: BuildResult[]): void {
core.summary.addRaw('\n')
core.summary.addHeading('Gradle Builds', 3) core.summary.addHeading('Gradle Builds', 3)
core.summary.addRaw('\n| Root Project | Tasks | Gradle Version | Outcome |\n| - | - | - | - |\n') core.summary.addTable([
for (const result of results) { [
const tableRow = `| ${result.rootProject} \ {data: 'Root Project', header: true},
| ${result.requestedTasks} \ {data: 'Tasks', header: true},
| ${result.gradleVersion} \ {data: 'Gradle Version', header: true},
| ${renderOutcome(result)} \ {data: 'Outcome', header: true}
|\n` ],
core.summary.addRaw(tableRow) ...results.map(result => [
} result.rootProject,
result.requestedTasks,
result.gradleVersion,
renderOutcome(result)
])
])
core.summary.addRaw('\n') core.summary.addRaw('\n')
} }
function renderOutcome(result: BuildResult): string { function renderOutcome(result: BuildResult): string {
if (result.buildScanUri) { const badgeUrl = result.buildFailed
return `[![Gradle Build](https://img.shields.io/badge/Build%20Scan%E2%84%A2-${ ? 'https://img.shields.io/badge/Build%20Scan%E2%84%A2-FAILED-red?logo=Gradle'
result.buildFailed ? 'FAILED-red' : 'SUCCESS-brightgreen' : 'https://img.shields.io/badge/Build%20Scan%E2%84%A2-SUCCESS-brightgreen?logo=Gradle'
}?logo=Gradle)](${result.buildScanUri})` const badgeHtml = `<img src="${badgeUrl}" alt="Gradle Build">`
}
return `![Gradle Build](https://img.shields.io/badge/${ if (result.buildScanUri) {
result.buildFailed ? 'FAILED-red' : 'SUCCESS-brightgreen' return `<a href="${result.buildScanUri}" rel="nofollow">${badgeHtml}</a>`
}?logo=Gradle)` }
return badgeHtml
} }