Compare commits

..

1 Commits

Author SHA1 Message Date
dependabot[bot] 7704e13a8f Bump gradle/actions in the github-actions group across 1 directory
Bumps the github-actions group with 1 update in the / directory: [gradle/actions](https://github.com/gradle/actions).


Updates `gradle/actions` from 6.1.0 to 6.1.1
- [Release notes](https://github.com/gradle/actions/releases)
- [Commits](https://github.com/gradle/actions/compare/50e97c2cd7a37755bbfafc9c5b7cafaece252f6e...5e2ebd065dc2488b7a6ad670704656cbbe1e8f60)

---
updated-dependencies:
- dependency-name: gradle/actions
  dependency-version: 6.1.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-11 23:04:59 +00:00
25 changed files with 674 additions and 1100 deletions
+1 -1
View File
@@ -26,7 +26,7 @@ jobs:
cache-dependency-path: sources/package-lock.json cache-dependency-path: sources/package-lock.json
- name: Setup Gradle - name: Setup Gradle
# Use a released version to avoid breakages # Use a released version to avoid breakages
uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0 uses: gradle/actions/setup-gradle@5e2ebd065dc2488b7a6ad670704656cbbe1e8f60 # v6.1.1
env: env:
ALLOWED_GRADLE_WRAPPER_CHECKSUMS: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 # Invalid wrapper jar used for testing ALLOWED_GRADLE_WRAPPER_CHECKSUMS: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 # Invalid wrapper jar used for testing
with: with:
+1 -1
View File
@@ -43,7 +43,7 @@ jobs:
- name: Setup Gradle - name: Setup Gradle
if: steps.changes.outputs.any_changed == 'true' || github.event_name != 'pull_request' if: steps.changes.outputs.any_changed == 'true' || github.event_name != 'pull_request'
# Use a released version to avoid breakages # Use a released version to avoid breakages
uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0 uses: gradle/actions/setup-gradle@5e2ebd065dc2488b7a6ad670704656cbbe1e8f60 # v6.1.1
env: env:
ALLOWED_GRADLE_WRAPPER_CHECKSUMS: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 # Invalid wrapper jar used for testing ALLOWED_GRADLE_WRAPPER_CHECKSUMS: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 # Invalid wrapper jar used for testing
- name: Run integration tests - name: Run integration tests
+1 -1
View File
@@ -12,6 +12,6 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- uses: gradle/actions/wrapper-validation@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0 - uses: gradle/actions/wrapper-validation@5e2ebd065dc2488b7a6ad670704656cbbe1e8f60 # v6.1.1
with: with:
allow-checksums: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 allow-checksums: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
+131 -117
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+127 -149
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+130 -116
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+173 -195
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+13 -75
View File
@@ -4,9 +4,7 @@ import * as glob from '@actions/glob'
import * as path from 'path' import * as path from 'path'
import {BuildResult} from './build-results' import {BuildResult} from './build-results'
import {CacheEntryReport, CacheOptions, CacheReport, CacheService} from './cache-service' import {CacheOptions, CacheService} from './cache-service'
const ENTRY_NAME = 'Gradle User Home'
const PRIMARY_KEY_STATE = 'BASIC_CACHE_PRIMARY_KEY' const PRIMARY_KEY_STATE = 'BASIC_CACHE_PRIMARY_KEY'
const RESTORED_KEY_STATE = 'BASIC_CACHE_RESTORED_KEY' const RESTORED_KEY_STATE = 'BASIC_CACHE_RESTORED_KEY'
@@ -42,39 +40,21 @@ export class BasicCacheService implements CacheService {
} }
} }
async save(gradleUserHome: string, _buildResults: BuildResult[], cacheOptions: CacheOptions): Promise<CacheReport> { async save(gradleUserHome: string, _buildResults: BuildResult[], cacheOptions: CacheOptions): Promise<string> {
if (cacheOptions.readOnly) {
const restoredKey = core.getState(RESTORED_KEY_STATE)
if (restoredKey) {
return `Basic caching was read-only. Restored from cache key \`${restoredKey}\`.`
}
return 'Basic caching was read-only. No cache entry was found to restore.'
}
const primaryKey = core.getState(PRIMARY_KEY_STATE) const primaryKey = core.getState(PRIMARY_KEY_STATE)
const restoredKey = core.getState(RESTORED_KEY_STATE) const restoredKey = core.getState(RESTORED_KEY_STATE)
if (cacheOptions.readOnly) {
return {
status: 'read-only',
entries: [
entryReport({
primaryKey,
restoredKey,
restoredOutcome: restoredKey
? '(Entry restored: exact match found)'
: '(Entry not restored: no match found)',
savedOutcome: '(Entry not saved: cache is read-only)'
})
]
}
}
if (restoredKey === primaryKey) { if (restoredKey === primaryKey) {
core.info(`Basic caching restored entry with key \`${primaryKey}\`. Save was skipped.`) core.info(`Basic caching restored entry with key \`${primaryKey}\`. Save was skipped.`)
return { return `Basic caching restored entry with key \`${primaryKey}\`. Save was skipped.`
status: 'enabled',
entries: [
entryReport({
primaryKey,
restoredKey,
restoredOutcome: '(Entry restored: exact match found)',
savedOutcome: '(Entry not saved: entry with key already exists)'
})
]
}
} }
const cachePaths = getCachePaths(gradleUserHome) const cachePaths = getCachePaths(gradleUserHome)
@@ -82,56 +62,14 @@ export class BasicCacheService implements CacheService {
try { try {
await cache.saveCache(cachePaths, primaryKey) await cache.saveCache(cachePaths, primaryKey)
core.info(`Basic caching saved entry with key: ${primaryKey}`) core.info(`Basic caching saved entry with key: ${primaryKey}`)
return { return `Basic caching saved entry with key \`${primaryKey}\`.`
status: 'enabled',
entries: [
entryReport({
primaryKey,
restoredKey,
savedKey: primaryKey,
restoredOutcome: restoredKey
? '(Entry restored: exact match found)'
: '(Entry not restored: no match found)',
savedOutcome: '(Entry saved)'
})
]
}
} catch (error) { } catch (error) {
core.warning(`Basic caching failed to save entry with key \`${primaryKey}\`: ${error}`) core.warning(`Basic caching failed to save entry with key \`${primaryKey}\`: ${error}`)
return { return `Basic caching save failed: ${error}`
status: 'enabled',
entries: [
entryReport({
primaryKey,
restoredKey,
restoredOutcome: restoredKey
? '(Entry restored: exact match found)'
: '(Entry not restored: no match found)',
savedOutcome: `(Entry not saved: ${error})`
})
]
}
} }
} }
} }
function entryReport(opts: {
primaryKey: string
restoredKey?: string
savedKey?: string
restoredOutcome: string
savedOutcome: string
}): CacheEntryReport {
return {
entryName: ENTRY_NAME,
requestedKey: opts.primaryKey || undefined,
restoredKey: opts.restoredKey || undefined,
restoredOutcome: opts.restoredOutcome,
savedKey: opts.savedKey || undefined,
savedOutcome: opts.savedOutcome
}
}
function getCachePaths(gradleUserHome: string): string[] { function getCachePaths(gradleUserHome: string): string[] {
return [path.join(gradleUserHome, 'caches'), path.join(gradleUserHome, 'wrapper')] return [path.join(gradleUserHome, 'caches'), path.join(gradleUserHome, 'wrapper')]
} }
+48 -21
View File
@@ -5,24 +5,57 @@ import {pathToFileURL} from 'url'
import {CacheConfig, CacheProvider} from './configuration' import {CacheConfig, CacheProvider} from './configuration'
import {BasicCacheService} from './cache-service-basic' import {BasicCacheService} from './cache-service-basic'
import {BuildResult} from './build-results' import {BuildResult} from './build-results'
import {CacheOptions, CacheReport, CacheService} from './cache-service' import {CacheOptions, CacheService} from './cache-service'
import {ProviderNote} from './caching-report'
const NOOP_CACHING_REPORT = `
[Cache was disabled](https://github.com/gradle/actions/blob/main/docs/setup-gradle.md#disabling-caching). Gradle User Home was not restored from or saved to the cache.
`
const ENHANCED_CACHE_MESSAGE = `Enhanced Caching: This build is using the proprietary 'gradle-actions-caching' provider for optimized caching support. See https://github.com/gradle/actions/blob/main/DISTRIBUTION.md for terms of use and opt-out instructions.` const ENHANCED_CACHE_MESSAGE = `Enhanced Caching: This build is using the proprietary 'gradle-actions-caching' provider for optimized caching support. See https://github.com/gradle/actions/blob/main/DISTRIBUTION.md for terms of use and opt-out instructions.`
const BASIC_CACHE_MESSAGE = `Basic Caching: This build uses the basic open-source caching provider. For faster builds and advanced features, consider switching to the Enhanced Caching provider. See https://github.com/gradle/actions/blob/main/DISTRIBUTION.md for details.` const ENHANCED_CACHE_SUMMARY = `
> [!NOTE]
> ### ⚡️ Enhanced Caching enabled
> This build provides optimized caching support via the proprietary **gradle-actions-caching** provider.
> See [DISTRIBUTION.md](https://github.com/gradle/actions/blob/main/DISTRIBUTION.md) for terms of use and opt-out instructions.
`
const BASIC_CACHE_MESSAGE = `Basic Caching: This build uses the open-source caching provider for reliable, path-based caching of Gradle dependencies. Upgrade available: for faster builds and advanced features, consider switching to the Enhanced Caching provider. See https://github.com/gradle/actions/blob/main/DISTRIBUTION.md for details.`
const BASIC_CACHE_SUMMARY = `
> [!NOTE]
> ### 🛡️ Basic Caching enabled
> This build uses the open-source caching provider for reliable, path-based caching of Gradle dependencies.
>
> **Upgrade Available:** For faster builds and advanced features, consider switching to the **Enhanced Caching** provider.
> See [DISTRIBUTION.md](https://github.com/gradle/actions/blob/main/DISTRIBUTION.md) for details.`
class NoOpCacheService implements CacheService { class NoOpCacheService implements CacheService {
async restore(_gradleUserHome: string, _cacheOptions: CacheOptions): Promise<void> { async restore(_gradleUserHome: string, _cacheOptions: CacheOptions): Promise<void> {
return return
} }
async save( async save(_gradleUserHome: string, _buildResults: BuildResult[], _cacheOptions: CacheOptions): Promise<string> {
_gradleUserHome: string, return NOOP_CACHING_REPORT
_buildResults: BuildResult[], }
_cacheOptions: CacheOptions }
): Promise<CacheReport> {
return {status: 'disabled', entries: []} class LicenseWarningCacheService implements CacheService {
private delegate: CacheService
private summary: string
constructor(delegate: CacheService, summary: string) {
this.delegate = delegate
this.summary = summary
}
async restore(gradleUserHome: string, cacheOptions: CacheOptions): Promise<void> {
await this.delegate.restore(gradleUserHome, cacheOptions)
}
async save(gradleUserHome: string, buildResults: BuildResult[], cacheOptions: CacheOptions): Promise<string> {
const cachingReport = await this.delegate.save(gradleUserHome, buildResults, cacheOptions)
return `${cachingReport}\n${this.summary}`
} }
} }
@@ -34,22 +67,16 @@ export async function getCacheService(cacheConfig: CacheConfig): Promise<CacheSe
if (cacheConfig.getCacheProvider() === CacheProvider.Basic) { if (cacheConfig.getCacheProvider() === CacheProvider.Basic) {
logCacheMessage(BASIC_CACHE_MESSAGE) logCacheMessage(BASIC_CACHE_MESSAGE)
return new BasicCacheService() return new LicenseWarningCacheService(new BasicCacheService(), BASIC_CACHE_SUMMARY)
} }
logCacheMessage(ENHANCED_CACHE_MESSAGE) logCacheMessage(ENHANCED_CACHE_MESSAGE)
return loadVendoredCacheService() const cacheService = await loadVendoredCacheService()
} if (cacheConfig.isCacheLicenseAccepted()) {
return cacheService
/**
* Identifies the caching provider for the Job Summary. Returns `undefined` when
* caching is disabled, since no provider is engaged in that case.
*/
export function getProviderNote(cacheConfig: CacheConfig): ProviderNote | undefined {
if (cacheConfig.isCacheDisabled()) {
return undefined
} }
return cacheConfig.getCacheProvider() === CacheProvider.Basic ? {kind: 'basic'} : {kind: 'enhanced'}
return new LicenseWarningCacheService(cacheService, ENHANCED_CACHE_SUMMARY)
} }
export async function loadVendoredCacheService(): Promise<CacheService> { export async function loadVendoredCacheService(): Promise<CacheService> {
+1 -39
View File
@@ -12,45 +12,7 @@ export interface CacheOptions {
excludes: string[] excludes: string[]
} }
export type CacheStatus =
| 'enabled'
| 'read-only'
| 'write-only'
| 'disabled'
| 'disabled-existing-home'
| 'not-available'
export type CacheCleanupStatus =
| 'enabled'
| 'disabled-param'
| 'disabled-failure'
| 'disabled-config-cache-hit'
| 'disabled-readonly'
export interface CacheEntryReport {
entryName: string
requestedKey?: string
restoredKey?: string
restoredSize?: number
restoredTime?: number
restoredOutcome: string
savedKey?: string
savedSize?: number
savedTime?: number
savedOutcome: string
}
/**
* Structured result of a cache save operation. Rendering this into a human-readable
* Job Summary is handled centrally by `caching-report.ts`.
*/
export interface CacheReport {
status: CacheStatus
cleanup?: CacheCleanupStatus
entries: CacheEntryReport[]
}
export interface CacheService { export interface CacheService {
restore(gradleUserHome: string, cacheOptions: CacheOptions): Promise<void> restore(gradleUserHome: string, cacheOptions: CacheOptions): Promise<void>
save(gradleUserHome: string, buildResults: BuildResult[], cacheOptions: CacheOptions): Promise<CacheReport> save(gradleUserHome: string, buildResults: BuildResult[], cacheOptions: CacheOptions): Promise<string>
} }
-168
View File
@@ -1,168 +0,0 @@
import {CacheCleanupStatus, CacheEntryReport, CacheReport, CacheStatus} from './cache-service'
const DOCS = 'https://github.com/gradle/actions/blob/main/docs/setup-gradle.md'
const DISTRIBUTION = 'https://github.com/gradle/actions/blob/main/DISTRIBUTION.md'
/**
* Identifies the caching provider in use, so the report can attribute the cache
* and surface the relevant terms-of-use / upgrade information.
*/
export interface ProviderNote {
kind: 'enhanced' | 'basic'
}
const STATUS_COPY: Record<CacheStatus, string> = {
enabled: `[Cache was enabled](${DOCS}#caching-build-state-between-jobs) — Gradle User Home was restored from the cache and saved for use by subsequent jobs.`,
'read-only': `[Cache was read-only](${DOCS}#using-the-cache-read-only) — by default, the action only writes to the cache for jobs running on the default branch.`,
'write-only': `[Cache was write-only](${DOCS}#using-the-cache-write-only) — Gradle User Home was not restored from the cache.`,
disabled: `[Caching was disabled](${DOCS}#disabling-caching) — Gradle User Home was not restored from or saved to the cache.`,
'disabled-existing-home': `⚠️ [Caching was skipped](${DOCS}#overwriting-an-existing-gradle-user-home) — a pre-existing Gradle User Home was found, so the cache was not restored or saved.`,
'not-available': `Caching is not available — the GitHub Actions cache service could not be reached, so Gradle User Home was not restored or saved.`
}
const CLEANUP_COPY: Record<CacheCleanupStatus, string> = {
enabled: `[Cache cleanup](${DOCS}#configuring-cache-cleanup) purged stale files from Gradle User Home before saving.`,
'disabled-param': `[Cache cleanup](${DOCS}#configuring-cache-cleanup) was disabled via action parameter.`,
'disabled-failure': `[Cache cleanup](${DOCS}#configuring-cache-cleanup) was skipped due to a build failure. Use \`cache-cleanup: always\` to override.`,
'disabled-config-cache-hit': `[Cache cleanup](${DOCS}#configuring-cache-cleanup) was skipped due to configuration-cache reuse.`,
'disabled-readonly': `[Cache cleanup](${DOCS}#configuring-cache-cleanup) is always disabled when the cache is read-only.`
}
/**
* Renders a cache report into the unified Job Summary markdown, with a consistent
* skeleton across every variant: a section heading, a status line, an integrated
* provider note, and (when there are entries) an expandable details section.
*/
export function renderCachingReport(report: CacheReport, providerNote?: ProviderNote): string {
if (!isActive(report.status)) {
// Disabled / skipped / unavailable: a compact heading + status line, no expandable section.
return `${renderHeading(report.status, providerNote)}\n\n${STATUS_COPY[report.status]}\n`
}
const sections = [
renderHeading(report.status, providerNote),
renderProviderNote(providerNote),
// Status and cleanup messages live inside the details expando; if there are no entries
// to expand, fall back to showing the status line directly.
report.entries.length > 0 ? renderDetails(report) : STATUS_COPY[report.status]
]
return `${sections.filter(section => section !== undefined && section !== '').join('\n\n')}\n`
}
function isActive(status: CacheStatus): boolean {
return status === 'enabled' || status === 'read-only' || status === 'write-only'
}
function renderHeading(status: CacheStatus, providerNote?: ProviderNote): string {
if (!isActive(status)) {
const label =
status === 'disabled-existing-home' ? 'Skipped' : status === 'not-available' ? 'Unavailable' : 'Disabled'
return `<h4>Gradle State Caching - ${label}</h4>`
}
const icon = providerNote?.kind === 'basic' ? '🛡️' : '⚡'
const provider = providerNote?.kind === 'basic' ? 'Basic' : 'Enhanced'
const suffix = status === 'read-only' ? ' (read-only)' : status === 'write-only' ? ' (write-only)' : ''
return `<h4>Gradle State Caching - ${icon} ${provider}${suffix}</h4>`
}
function renderCleanupLine(cleanup?: CacheCleanupStatus): string | undefined {
return cleanup ? CLEANUP_COPY[cleanup] : undefined
}
function renderProviderNote(providerNote?: ProviderNote): string | undefined {
if (!providerNote) {
return undefined
}
if (providerNote.kind === 'enhanced') {
return `**[Enhanced Caching](${DOCS}#enhanced-caching)** uses the proprietary \`gradle-actions-caching\` provider. See [DISTRIBUTION.md](${DISTRIBUTION}) for terms of use and opt-out instructions.`
}
return `**[Basic Caching](${DOCS}#basic-caching)** uses the basic open-source caching provider. For faster builds and advanced features, consider the **[Enhanced Caching](${DOCS}#enhanced-caching)** provider.`
}
function renderDetails(report: CacheReport): string {
const entries = report.entries
const restored = entries.filter(entry => entry.restoredKey).length
const saved = entries.filter(entry => entry.savedKey).length
const summary = hasMetrics(entries)
? `Entries: ${restored} restored (${getSize(entries, e => e.restoredSize)}Mb), ${saved} saved (${getSize(entries, e => e.savedSize)}Mb) - Expand for more details`
: `Entries: ${restored} restored, ${saved} saved - Expand for more details`
const cleanup = report.status === 'enabled' ? renderCleanupLine(report.cleanup) : undefined
const table = renderEntryTable(report.entries)
const pre = `<pre>\n${renderEntryDetails(report.entries)}</pre>`
const body = [STATUS_COPY[report.status], cleanup, table, pre].filter(Boolean).join('\n\n')
return `<details>
<summary>${summary}</summary>
${body}
</details>`
}
function hasMetrics(entries: CacheEntryReport[]): boolean {
return entries.some(entry => entry.restoredSize || entry.restoredTime || entry.savedSize || entry.savedTime)
}
function renderEntryTable(entries: CacheEntryReport[]): string {
if (!hasMetrics(entries)) {
return ''
}
return `<table>
<tr><td></td><th>Count</th><th>Total Size (Mb)</th><th>Total Time (ms)</th></tr>
<tr><td>Entries Restored</td>
<td>${getCount(entries, e => e.restoredSize)}</td>
<td>${getSize(entries, e => e.restoredSize)}</td>
<td>${getTime(entries, e => e.restoredTime)}</td>
</tr>
<tr><td>Entries Saved</td>
<td>${getCount(entries, e => e.savedSize)}</td>
<td>${getSize(entries, e => e.savedSize)}</td>
<td>${getTime(entries, e => e.savedTime)}</td>
</tr>
</table>`
}
function renderEntryDetails(entries: CacheEntryReport[]): string {
return entries
.map(
entry => `Entry: ${entry.entryName}
Requested Key : ${entry.requestedKey ?? ''}
Restored Key : ${entry.restoredKey ?? ''}
Size: ${formatSize(entry.restoredSize)}
Time: ${formatTime(entry.restoredTime)}
${entry.restoredOutcome}
Saved Key : ${entry.savedKey ?? ''}
Size: ${formatSize(entry.savedSize)}
Time: ${formatTime(entry.savedTime)}
${entry.savedOutcome}
`
)
.join('---\n')
}
function getCount(entries: CacheEntryReport[], predicate: (value: CacheEntryReport) => number | undefined): number {
return entries.filter(e => predicate(e)).length
}
function getSize(entries: CacheEntryReport[], predicate: (value: CacheEntryReport) => number | undefined): number {
const bytes = entries.map(e => predicate(e) ?? 0).reduce((p, v) => p + v, 0)
return Math.round(bytes / (1024 * 1024))
}
function getTime(entries: CacheEntryReport[], predicate: (value: CacheEntryReport) => number | undefined): number {
return entries.map(e => predicate(e) ?? 0).reduce((p, v) => p + v, 0)
}
function formatSize(bytes: number | undefined): string {
if (bytes === undefined || bytes === 0) {
return ''
}
return `${Math.round(bytes / (1024 * 1024))} MB (${bytes} B)`
}
function formatTime(ms: number | undefined): string {
if (ms === undefined || ms === 0) {
return ''
}
return `${ms} ms`
}
+5
View File
@@ -167,6 +167,11 @@ export class CacheConfig {
return core.getMultilineInput('gradle-home-cache-excludes') return core.getMultilineInput('gradle-home-cache-excludes')
} }
isCacheLicenseAccepted(): boolean {
const dvConfig = new DevelocityConfig()
return dvConfig.getDevelocityAccessKey() !== '' || dvConfig.hasTermsOfUseAgreement()
}
getCacheProvider(): CacheProvider { getCacheProvider(): CacheProvider {
const val = core.getInput('cache-provider') const val = core.getInput('cache-provider')
switch (val.toLowerCase().trim()) { switch (val.toLowerCase().trim()) {
+1 -5
View File
@@ -2,15 +2,12 @@ import * as core from '@actions/core'
import * as github from '@actions/github' import * as github from '@actions/github'
import {BuildResult} from './build-results' import {BuildResult} from './build-results'
import {CacheReport} from './cache-service'
import {ProviderNote, renderCachingReport} from './caching-report'
import {DependencyGraphConfig, getActionId, getGithubToken, getJobMatrix, SummaryConfig} from './configuration' import {DependencyGraphConfig, getActionId, getGithubToken, getJobMatrix, SummaryConfig} from './configuration'
import {Deprecation, getDeprecations, getErrors} from './deprecation-collector' import {Deprecation, getDeprecations, getErrors} from './deprecation-collector'
export async function generateJobSummary( export async function generateJobSummary(
buildResults: BuildResult[], buildResults: BuildResult[],
cacheReport: CacheReport, cachingReport: string,
providerNote: ProviderNote | undefined,
config: SummaryConfig config: SummaryConfig
): Promise<void> { ): Promise<void> {
const errors = renderErrors() const errors = renderErrors()
@@ -21,7 +18,6 @@ export async function generateJobSummary(
} }
const summaryTable = renderSummaryTable(buildResults) const summaryTable = renderSummaryTable(buildResults)
const cachingReport = renderCachingReport(cacheReport, providerNote)
const hasFailure = anyFailed(buildResults) const hasFailure = anyFailed(buildResults)
if (config.shouldGenerateJobSummary(hasFailure)) { if (config.shouldGenerateJobSummary(hasFailure)) {
core.info('Generating Job Summary') core.info('Generating Job Summary')
+3 -3
View File
@@ -7,7 +7,7 @@ import * as jobSummary from './job-summary'
import * as buildScan from './develocity/build-scan' import * as buildScan from './develocity/build-scan'
import {loadBuildResults, markBuildResultsProcessed} from './build-results' import {loadBuildResults, markBuildResultsProcessed} from './build-results'
import {getCacheService, getProviderNote} from './cache-service-loader' import {getCacheService} from './cache-service-loader'
import {CacheOptions} from './cache-service' import {CacheOptions} from './cache-service'
import { import {
DevelocityConfig, DevelocityConfig,
@@ -65,8 +65,8 @@ export async function complete(cacheConfig: CacheConfig, summaryConfig: SummaryC
const gradleUserHome = core.getState(GRADLE_USER_HOME) const gradleUserHome = core.getState(GRADLE_USER_HOME)
const cacheService = await getCacheService(cacheConfig) const cacheService = await getCacheService(cacheConfig)
const cacheReport = await cacheService.save(gradleUserHome, buildResults, cacheOptionsFrom(cacheConfig)) const cachingReport = await cacheService.save(gradleUserHome, buildResults, cacheOptionsFrom(cacheConfig))
await jobSummary.generateJobSummary(buildResults, cacheReport, getProviderNote(cacheConfig), summaryConfig) await jobSummary.generateJobSummary(buildResults, cachingReport, summaryConfig)
markBuildResultsProcessed() markBuildResultsProcessed()
+7 -11
View File
@@ -138,8 +138,8 @@ describe('BasicCacheService', () => {
}) })
expect(mockSaveCache).not.toHaveBeenCalled() expect(mockSaveCache).not.toHaveBeenCalled()
expect(report.status).toBe('read-only') expect(report).toContain('read-only')
expect(report.entries[0].restoredKey).toBe(PRIMARY_KEY) expect(report).toContain(PRIMARY_KEY)
}) })
it('reports readOnly with no restore when cache was missed', async () => { it('reports readOnly with no restore when cache was missed', async () => {
@@ -156,9 +156,8 @@ describe('BasicCacheService', () => {
}) })
expect(mockSaveCache).not.toHaveBeenCalled() expect(mockSaveCache).not.toHaveBeenCalled()
expect(report.status).toBe('read-only') expect(report).toContain('read-only')
expect(report.entries[0].restoredKey).toBeUndefined() expect(report).toContain('No cache entry')
expect(report.entries[0].restoredOutcome).toContain('not restored')
}) })
it('skips save when restored key equals primary key', async () => { it('skips save when restored key equals primary key', async () => {
@@ -180,8 +179,7 @@ describe('BasicCacheService', () => {
}) })
expect(mockSaveCache).not.toHaveBeenCalled() expect(mockSaveCache).not.toHaveBeenCalled()
expect(report.status).toBe('enabled') expect(report).toContain('Save was skipped')
expect(report.entries[0].savedOutcome).toContain('already exists')
}) })
it('saves cache and returns report on success', async () => { it('saves cache and returns report on success', async () => {
@@ -206,9 +204,7 @@ describe('BasicCacheService', () => {
['/home/.gradle/caches', '/home/.gradle/wrapper'], ['/home/.gradle/caches', '/home/.gradle/wrapper'],
PRIMARY_KEY PRIMARY_KEY
) )
expect(report.status).toBe('enabled') expect(report).toContain('saved entry with key')
expect(report.entries[0].savedKey).toBe(PRIMARY_KEY)
expect(report.entries[0].savedOutcome).toBe('(Entry saved)')
}) })
it('warns on save failure instead of throwing', async () => { it('warns on save failure instead of throwing', async () => {
@@ -232,7 +228,7 @@ describe('BasicCacheService', () => {
expect(mockWarning).toHaveBeenCalledWith( expect(mockWarning).toHaveBeenCalledWith(
expect.stringContaining('failed to save') expect.stringContaining('failed to save')
) )
expect(report.entries[0].savedOutcome).toContain('not saved') expect(report).toContain('failed')
}) })
}) })
}) })
+10 -39
View File
@@ -12,7 +12,8 @@ describe('getCacheService selection logic', () => {
const {getCacheService} = await import('../../src/cache-service-loader') const {getCacheService} = await import('../../src/cache-service-loader')
const mockConfig = { const mockConfig = {
isCacheDisabled: () => true, isCacheDisabled: () => true,
getCacheProvider: () => CacheProvider.Enhanced getCacheProvider: () => CacheProvider.Enhanced,
isCacheLicenseAccepted: () => true
} as unknown as CacheConfig } as unknown as CacheConfig
const service = await getCacheService(mockConfig) const service = await getCacheService(mockConfig)
@@ -27,53 +28,23 @@ describe('getCacheService selection logic', () => {
excludes: [] excludes: []
}) })
// NoOpCacheService reports a disabled cache with no entries // NoOpCacheService returns a specific report mentioning cache was disabled
expect(report.status).toBe('disabled') expect(report).toContain('Cache was disabled')
expect(report.entries).toHaveLength(0)
}) })
it('returns a BasicCacheService when cache-provider is basic', async () => { it('wraps BasicCacheService with LicenseWarningCacheService when cache-provider is basic', async () => {
const {getCacheService} = await import('../../src/cache-service-loader') const {getCacheService} = await import('../../src/cache-service-loader')
const mockConfig = { const mockConfig = {
isCacheDisabled: () => false, isCacheDisabled: () => false,
getCacheProvider: () => CacheProvider.Basic getCacheProvider: () => CacheProvider.Basic,
isCacheLicenseAccepted: () => false
} as unknown as CacheConfig } as unknown as CacheConfig
const service = await getCacheService(mockConfig) const service = await getCacheService(mockConfig)
// The service should not be a bare BasicCacheService — it should be wrapped
// with LicenseWarningCacheService that appends the basic caching summary
const {BasicCacheService} = await import('../../src/cache-service-basic') const {BasicCacheService} = await import('../../src/cache-service-basic')
expect(service).toBeInstanceOf(BasicCacheService) expect(service).not.toBeInstanceOf(BasicCacheService)
})
describe('getProviderNote', () => {
it('returns undefined when cache is disabled', async () => {
const {getProviderNote} = await import('../../src/cache-service-loader')
const mockConfig = {
isCacheDisabled: () => true,
getCacheProvider: () => CacheProvider.Enhanced
} as unknown as CacheConfig
expect(getProviderNote(mockConfig)).toBeUndefined()
})
it('returns basic note for the basic provider', async () => {
const {getProviderNote} = await import('../../src/cache-service-loader')
const mockConfig = {
isCacheDisabled: () => false,
getCacheProvider: () => CacheProvider.Basic
} as unknown as CacheConfig
expect(getProviderNote(mockConfig)).toEqual({kind: 'basic'})
})
it('returns enhanced note for the enhanced provider', async () => {
const {getProviderNote} = await import('../../src/cache-service-loader')
const mockConfig = {
isCacheDisabled: () => false,
getCacheProvider: () => CacheProvider.Enhanced
} as unknown as CacheConfig
expect(getProviderNote(mockConfig)).toEqual({kind: 'enhanced'})
})
}) })
}) })
-110
View File
@@ -1,110 +0,0 @@
import {describe, expect, it} from '@jest/globals'
import {CacheReport} from '../../src/cache-service'
import {renderCachingReport} from '../../src/caching-report'
const ENHANCED = {kind: 'enhanced'} as const
const BASIC = {kind: 'basic'} as const
function entry(overrides: Partial<CacheReport['entries'][number]> = {}): CacheReport['entries'][number] {
return {
entryName: 'Gradle User Home',
requestedKey: 'gradle-home-v1|key',
restoredKey: 'gradle-home-v1|key',
restoredSize: 535792,
restoredTime: 253,
restoredOutcome: '(Entry restored: exact match found)',
savedKey: 'gradle-home-v1|key',
savedSize: 528509,
savedTime: 257,
savedOutcome: '(Entry saved)',
...overrides
}
}
describe('renderCachingReport', () => {
it('renders an enhanced read-only report with heading, note and details', () => {
const report: CacheReport = {status: 'read-only', cleanup: 'disabled-readonly', entries: [entry()]}
const md = renderCachingReport(report, ENHANCED)
expect(md).toContain('<h4>Gradle State Caching - ⚡ Enhanced (read-only)</h4>')
expect(md).toContain('[Enhanced Caching]')
expect(md).toContain('`gradle-actions-caching`')
expect(md).toContain('DISTRIBUTION.md')
expect(md).toContain('<details>')
expect(md).toContain('<summary>Entries: 1 restored (1Mb), 1 saved (1Mb) - Expand for more details</summary>')
// status message moves inside the details expando
expect(md).toContain('Cache was read-only')
// read-only does not render the cleanup line
expect(md).not.toContain('Cache cleanup')
})
it('renders an enhanced enabled report with status and cleanup inside the details', () => {
const report: CacheReport = {status: 'enabled', cleanup: 'enabled', entries: [entry()]}
const md = renderCachingReport(report, ENHANCED)
expect(md).toContain('<h4>Gradle State Caching - ⚡ Enhanced</h4>')
// status and cleanup messages are within the expando, after the summary
const detailsBody = md.slice(md.indexOf('</summary>'))
expect(detailsBody).toContain('Cache was enabled')
expect(detailsBody).toContain('Cache cleanup')
expect(md).toContain('<table>')
expect(md).toContain('Entries Restored')
})
it('renders a basic report with the upgrade note and no metrics table', () => {
const report: CacheReport = {
status: 'read-only',
entries: [
entry({
restoredSize: undefined,
restoredTime: undefined,
savedKey: undefined,
savedSize: undefined,
savedTime: undefined,
savedOutcome: '(Entry not saved: cache is read-only)'
})
]
}
const md = renderCachingReport(report, BASIC)
expect(md).toContain('<h4>Gradle State Caching - 🛡️ Basic (read-only)</h4>')
expect(md).toContain('[Basic Caching]')
expect(md).toContain('[Enhanced Caching]')
// DISTRIBUTION.md is only referenced for the enhanced provider
expect(md).not.toContain('DISTRIBUTION.md')
// No size/time data, so the metrics table is omitted but the entry list remains
expect(md).not.toContain('<table>')
expect(md).toContain('<pre>')
expect(md).toContain('<summary>Entries: 1 restored, 0 saved - Expand for more details</summary>')
})
it('renders a compact disabled report with no note and no details', () => {
const report: CacheReport = {status: 'disabled', entries: []}
const md = renderCachingReport(report, undefined)
expect(md).toContain('<h4>Gradle State Caching - Disabled</h4>')
expect(md).toContain('Caching was disabled')
expect(md).not.toContain('<details>')
expect(md).not.toContain('DISTRIBUTION.md')
})
it('renders a compact skipped report for a pre-existing Gradle User Home', () => {
const report: CacheReport = {status: 'disabled-existing-home', entries: []}
const md = renderCachingReport(report, ENHANCED)
expect(md).toContain('<h4>Gradle State Caching - Skipped</h4>')
expect(md).toContain('pre-existing Gradle User Home')
expect(md).not.toContain('<details>')
// no provider note for non-active states
expect(md).not.toContain('DISTRIBUTION.md')
})
it('renders an unavailable report compactly', () => {
const report: CacheReport = {status: 'not-available', entries: []}
const md = renderCachingReport(report, ENHANCED)
expect(md).toContain('<h4>Gradle State Caching - Unavailable</h4>')
expect(md).not.toContain('<details>')
})
})
+1 -28
View File
@@ -11,23 +11,6 @@ export declare interface BuildResult {
get buildScanFailed(): boolean; get buildScanFailed(): boolean;
} }
/** @public */
export declare type CacheCleanupStatus = 'enabled' | 'disabled-param' | 'disabled-failure' | 'disabled-config-cache-hit' | 'disabled-readonly';
/** @public */
export declare interface CacheEntryReport {
entryName: string;
requestedKey?: string;
restoredKey?: string;
restoredSize?: number;
restoredTime?: number;
restoredOutcome: string;
savedKey?: string;
savedSize?: number;
savedTime?: number;
savedOutcome: string;
}
/** @public */ /** @public */
export declare interface CacheOptions { export declare interface CacheOptions {
disabled: boolean; disabled: boolean;
@@ -41,20 +24,10 @@ export declare interface CacheOptions {
excludes: string[]; excludes: string[];
} }
/** @public */
export declare interface CacheReport {
status: CacheStatus;
cleanup?: CacheCleanupStatus;
entries: CacheEntryReport[];
}
/** @public */
export declare type CacheStatus = 'enabled' | 'read-only' | 'write-only' | 'disabled' | 'disabled-existing-home' | 'not-available';
/** @public */ /** @public */
export declare function restore(gradleUserHome: string, cacheOptions: CacheOptions): Promise<void>; export declare function restore(gradleUserHome: string, cacheOptions: CacheOptions): Promise<void>;
/** @public */ /** @public */
export declare function save(gradleUserHome: string, buildResults: BuildResult[], cacheOptions: CacheOptions): Promise<CacheReport>; export declare function save(gradleUserHome: string, buildResults: BuildResult[], cacheOptions: CacheOptions): Promise<string>;
export { } export { }
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "gradle-actions-caching", "name": "gradle-actions-caching",
"version": "0.7.0", "version": "0.6.0",
"type": "module", "type": "module",
"main": "./index.js", "main": "./index.js",
"types": "./index.d.ts", "types": "./index.d.ts",