Moved cache-related code into subpackage

This commit is contained in:
daz 2024-04-08 13:29:58 -06:00
parent ecf84edd45
commit 528fe78d31
No known key found for this signature in database
14 changed files with 131 additions and 137 deletions

View File

@ -0,0 +1,97 @@
import * as github from '@actions/github'
import {CacheConfig, getJobMatrix} from '../input-params'
import {hashStrings} from './cache-utils'
const CACHE_PROTOCOL_VERSION = 'v9-'
const CACHE_KEY_PREFIX_VAR = 'GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX'
const CACHE_KEY_OS_VAR = 'GRADLE_BUILD_ACTION_CACHE_KEY_ENVIRONMENT'
const CACHE_KEY_JOB_VAR = 'GRADLE_BUILD_ACTION_CACHE_KEY_JOB'
const CACHE_KEY_JOB_INSTANCE_VAR = 'GRADLE_BUILD_ACTION_CACHE_KEY_JOB_INSTANCE'
const CACHE_KEY_JOB_EXECUTION_VAR = 'GRADLE_BUILD_ACTION_CACHE_KEY_JOB_EXECUTION'
/**
* Represents a key used to restore a cache entry.
* The Github Actions cache will first try for an exact match on the key.
* If that fails, it will try for a prefix match on any of the restoreKeys.
*/
export class CacheKey {
key: string
restoreKeys: string[]
constructor(key: string, restoreKeys: string[]) {
this.key = key
this.restoreKeys = restoreKeys
}
}
/**
* Generates a cache key specific to the current job execution.
* The key is constructed from the following inputs (with some user overrides):
* - The cache protocol version
* - The name of the cache
* - The runner operating system
* - The name of the workflow and Job being executed
* - The matrix values for the Job being executed (job context)
* - The SHA of the commit being executed
*
* Caches are restored by trying to match the these key prefixes in order:
* - The full key with SHA
* - A previous key for this Job + matrix
* - Any previous key for this Job (any matrix)
* - Any previous key for this cache on the current OS
*/
export function generateCacheKey(cacheName: string, config: CacheConfig): CacheKey {
const cacheKeyBase = `${getCacheKeyPrefix()}${CACHE_PROTOCOL_VERSION}${cacheName}`
// At the most general level, share caches for all executions on the same OS
const cacheKeyForEnvironment = `${cacheKeyBase}|${getCacheKeyEnvironment()}`
// Then prefer caches that run job with the same ID
const cacheKeyForJob = `${cacheKeyForEnvironment}|${getCacheKeyJob()}`
// Prefer (even more) jobs that run this job in the same workflow with the same context (matrix)
const cacheKeyForJobContext = `${cacheKeyForJob}[${getCacheKeyJobInstance()}]`
// Exact match on Git SHA
const cacheKey = `${cacheKeyForJobContext}-${getCacheKeyJobExecution()}`
if (config.isCacheStrictMatch()) {
return new CacheKey(cacheKey, [cacheKeyForJobContext])
}
return new CacheKey(cacheKey, [cacheKeyForJobContext, cacheKeyForJob, cacheKeyForEnvironment])
}
export function getCacheKeyPrefix(): string {
// Prefix can be used to force change all cache keys (defaults to cache protocol version)
return process.env[CACHE_KEY_PREFIX_VAR] || ''
}
function getCacheKeyEnvironment(): string {
const runnerOs = process.env['RUNNER_OS'] || ''
return process.env[CACHE_KEY_OS_VAR] || runnerOs
}
function getCacheKeyJob(): string {
return process.env[CACHE_KEY_JOB_VAR] || github.context.job
}
function getCacheKeyJobInstance(): string {
const override = process.env[CACHE_KEY_JOB_INSTANCE_VAR]
if (override) {
return override
}
// By default, we hash the workflow name and the full `matrix` data for the run, to uniquely identify this job invocation
// The only way we can obtain the `matrix` data is via the `workflow-job-context` parameter in action.yml.
const workflowName = github.context.workflow
const workflowJobContext = getJobMatrix()
return hashStrings([workflowName, workflowJobContext])
}
function getCacheKeyJobExecution(): string {
// Used to associate a cache key with a particular execution (default is bound to the git commit sha)
return process.env[CACHE_KEY_JOB_EXECUTION_VAR] || github.context.sha
}

View File

@ -1,6 +1,5 @@
import * as core from '@actions/core'
import * as cache from '@actions/cache'
import * as github from '@actions/github'
import * as exec from '@actions/exec'
import * as crypto from 'crypto'
@ -8,15 +7,6 @@ import * as path from 'path'
import * as fs from 'fs'
import {CacheEntryListener} from './cache-reporting'
import {CacheConfig, getJobMatrix} from './input-params'
const CACHE_PROTOCOL_VERSION = 'v9-'
const CACHE_KEY_PREFIX_VAR = 'GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX'
const CACHE_KEY_OS_VAR = 'GRADLE_BUILD_ACTION_CACHE_KEY_ENVIRONMENT'
const CACHE_KEY_JOB_VAR = 'GRADLE_BUILD_ACTION_CACHE_KEY_JOB'
const CACHE_KEY_JOB_INSTANCE_VAR = 'GRADLE_BUILD_ACTION_CACHE_KEY_JOB_INSTANCE'
const CACHE_KEY_JOB_EXECUTION_VAR = 'GRADLE_BUILD_ACTION_CACHE_KEY_JOB_EXECUTION'
const SEGMENT_DOWNLOAD_TIMEOUT_VAR = 'SEGMENT_DOWNLOAD_TIMEOUT_MINS'
const SEGMENT_DOWNLOAD_TIMEOUT_DEFAULT = 10 * 60 * 1000 // 10 minutes
@ -28,91 +18,6 @@ export function isCacheDebuggingEnabled(): boolean {
return process.env['GRADLE_BUILD_ACTION_CACHE_DEBUG_ENABLED'] ? true : false
}
/**
* Represents a key used to restore a cache entry.
* The Github Actions cache will first try for an exact match on the key.
* If that fails, it will try for a prefix match on any of the restoreKeys.
*/
export class CacheKey {
key: string
restoreKeys: string[]
constructor(key: string, restoreKeys: string[]) {
this.key = key
this.restoreKeys = restoreKeys
}
}
/**
* Generates a cache key specific to the current job execution.
* The key is constructed from the following inputs (with some user overrides):
* - The cache protocol version
* - The name of the cache
* - The runner operating system
* - The name of the workflow and Job being executed
* - The matrix values for the Job being executed (job context)
* - The SHA of the commit being executed
*
* Caches are restored by trying to match the these key prefixes in order:
* - The full key with SHA
* - A previous key for this Job + matrix
* - Any previous key for this Job (any matrix)
* - Any previous key for this cache on the current OS
*/
export function generateCacheKey(cacheName: string, config: CacheConfig): CacheKey {
const cacheKeyBase = `${getCacheKeyPrefix()}${CACHE_PROTOCOL_VERSION}${cacheName}`
// At the most general level, share caches for all executions on the same OS
const cacheKeyForEnvironment = `${cacheKeyBase}|${getCacheKeyEnvironment()}`
// Then prefer caches that run job with the same ID
const cacheKeyForJob = `${cacheKeyForEnvironment}|${getCacheKeyJob()}`
// Prefer (even more) jobs that run this job in the same workflow with the same context (matrix)
const cacheKeyForJobContext = `${cacheKeyForJob}[${getCacheKeyJobInstance()}]`
// Exact match on Git SHA
const cacheKey = `${cacheKeyForJobContext}-${getCacheKeyJobExecution()}`
if (config.isCacheStrictMatch()) {
return new CacheKey(cacheKey, [cacheKeyForJobContext])
}
return new CacheKey(cacheKey, [cacheKeyForJobContext, cacheKeyForJob, cacheKeyForEnvironment])
}
export function getCacheKeyPrefix(): string {
// Prefix can be used to force change all cache keys (defaults to cache protocol version)
return process.env[CACHE_KEY_PREFIX_VAR] || ''
}
function getCacheKeyEnvironment(): string {
const runnerOs = process.env['RUNNER_OS'] || ''
return process.env[CACHE_KEY_OS_VAR] || runnerOs
}
function getCacheKeyJob(): string {
return process.env[CACHE_KEY_JOB_VAR] || github.context.job
}
function getCacheKeyJobInstance(): string {
const override = process.env[CACHE_KEY_JOB_INSTANCE_VAR]
if (override) {
return override
}
// By default, we hash the workflow name and the full `matrix` data for the run, to uniquely identify this job invocation
// The only way we can obtain the `matrix` data is via the `workflow-job-context` parameter in action.yml.
const workflowName = github.context.workflow
const workflowJobContext = getJobMatrix()
return hashStrings([workflowName, workflowJobContext])
}
function getCacheKeyJobExecution(): string {
// Used to associate a cache key with a particular execution (default is bound to the git commit sha)
return process.env[CACHE_KEY_JOB_EXECUTION_VAR] || github.context.sha
}
export function hashFileNames(fileNames: string[]): string {
return hashStrings(fileNames.map(x => x.replace(new RegExp(`\\${path.sep}`, 'g'), '/')))
}

View File

@ -1,9 +1,9 @@
import * as core from '@actions/core'
import {CacheListener} from './cache-reporting'
import {DaemonController} from './daemon-controller'
import {GradleStateCache} from './cache-base'
import {GradleUserHomeCache} from './gradle-user-home-cache'
import {CacheCleaner} from './cache-cleaner'
import {CacheConfig} from './input-params'
import {DaemonController} from '../daemon-controller'
import {CacheConfig} from '../input-params'
const CACHE_RESTORED_VAR = 'GRADLE_BUILD_ACTION_CACHE_RESTORED'
@ -20,7 +20,7 @@ export async function restore(
}
core.exportVariable(CACHE_RESTORED_VAR, true)
const gradleStateCache = new GradleStateCache(userHome, gradleUserHome, cacheConfig)
const gradleStateCache = new GradleUserHomeCache(userHome, gradleUserHome, cacheConfig)
if (cacheConfig.isCacheDisabled()) {
core.info('Cache is disabled: will not restore state from previous builds.')
@ -99,6 +99,6 @@ export async function save(
}
await core.group('Caching Gradle state', async () => {
return new GradleStateCache(userHome, gradleUserHome, cacheConfig).save(cacheListener)
return new GradleUserHomeCache(userHome, gradleUserHome, cacheConfig).save(cacheListener)
})
}

View File

@ -4,19 +4,13 @@ import * as core from '@actions/core'
import * as glob from '@actions/glob'
import * as semver from 'semver'
import {META_FILE_DIR} from './cache-base'
import {META_FILE_DIR} from './gradle-user-home-cache'
import {CacheEntryListener, CacheListener} from './cache-reporting'
import {
cacheDebug,
getCacheKeyPrefix,
hashFileNames,
isCacheDebuggingEnabled,
restoreCache,
saveCache,
tryDelete
} from './cache-utils'
import {BuildResult, loadBuildResults} from './build-results'
import {CacheConfig} from './input-params'
import {cacheDebug, hashFileNames, isCacheDebuggingEnabled, restoreCache, saveCache, tryDelete} from './cache-utils'
import {BuildResult, loadBuildResults} from '../build-results'
import {CacheConfig} from '../input-params'
import {getCacheKeyPrefix} from './cache-key'
const SKIP_RESTORE_VAR = 'GRADLE_BUILD_ACTION_SKIP_RESTORE'

View File

@ -4,29 +4,28 @@ import * as glob from '@actions/glob'
import path from 'path'
import fs from 'fs'
import {CacheConfig} from './input-params'
import {generateCacheKey} from './cache-key'
import {CacheListener} from './cache-reporting'
import {saveCache, restoreCache, cacheDebug, isCacheDebuggingEnabled, tryDelete, generateCacheKey} from './cache-utils'
import {GradleHomeEntryExtractor, ConfigurationCacheEntryExtractor} from './cache-extract-entries'
import {saveCache, restoreCache, cacheDebug, isCacheDebuggingEnabled, tryDelete} from './cache-utils'
import {GradleHomeEntryExtractor, ConfigurationCacheEntryExtractor} from './gradle-home-extry-extractor'
import {CacheConfig} from '../input-params'
const RESTORED_CACHE_KEY_KEY = 'restored-cache-key'
export const META_FILE_DIR = '.setup-gradle'
export class GradleStateCache {
private cacheConfig: CacheConfig
private cacheName: string
private cacheDescription: string
export class GradleUserHomeCache {
private readonly cacheName = 'gradle'
private readonly cacheDescription = 'Gradle User Home'
protected readonly userHome: string
protected readonly gradleUserHome: string
private readonly userHome: string
private readonly gradleUserHome: string
private readonly cacheConfig: CacheConfig
constructor(userHome: string, gradleUserHome: string, cacheConfig: CacheConfig) {
this.userHome = userHome
this.gradleUserHome = gradleUserHome
this.cacheConfig = cacheConfig
this.cacheName = 'gradle'
this.cacheDescription = 'Gradle User Home'
}
init(): void {

View File

@ -3,16 +3,14 @@ import * as github from '@actions/github'
import {RequestError} from '@octokit/request-error'
import {BuildResult} from './build-results'
import {CacheListener, generateCachingReport} from './cache-reporting'
import {SummaryConfig, getGithubToken} from './input-params'
export async function generateJobSummary(
buildResults: BuildResult[],
cacheListener: CacheListener,
cachingReport: string,
config: SummaryConfig
): Promise<void> {
const summaryTable = renderSummaryTable(buildResults)
const cachingReport = generateCachingReport(cacheListener)
const hasFailure = buildResults.some(result => result.buildFailed)
if (config.shouldGenerateJobSummary(hasFailure)) {

View File

@ -8,7 +8,7 @@ import * as toolCache from '@actions/tool-cache'
import * as gradlew from './gradlew'
import * as params from './input-params'
import {handleCacheFailure} from './cache-utils'
import {handleCacheFailure} from './caching/cache-utils'
import {CacheConfig} from './input-params'
const gradleVersionsBaseUrl = 'https://services.gradle.org/versions'

View File

@ -2,13 +2,13 @@ import * as core from '@actions/core'
import * as exec from '@actions/exec'
import * as path from 'path'
import * as os from 'os'
import * as caches from './caches'
import * as caches from './caching/caches'
import * as layout from './repository-layout'
import * as jobSummary from './job-summary'
import * as buildScan from './build-scan'
import {loadBuildResults} from './build-results'
import {CacheListener} from './cache-reporting'
import {CacheListener, generateCachingReport} from './caching/cache-reporting'
import {DaemonController} from './daemon-controller'
import {BuildScanConfig, CacheConfig, SummaryConfig} from './input-params'
@ -57,11 +57,12 @@ export async function complete(cacheConfig: CacheConfig, summaryConfig: SummaryC
const userHome = core.getState(USER_HOME)
const gradleUserHome = core.getState(GRADLE_USER_HOME)
const cacheListener: CacheListener = CacheListener.rehydrate(core.getState(CACHE_LISTENER))
const daemonController = new DaemonController(buildResults)
const daemonController = new DaemonController(buildResults)
await caches.save(userHome, gradleUserHome, cacheListener, daemonController, cacheConfig)
await jobSummary.generateJobSummary(buildResults, cacheListener, summaryConfig)
const cachingReport = generateCachingReport(cacheListener)
await jobSummary.generateJobSummary(buildResults, cachingReport, summaryConfig)
core.info('Completed post-action step')

View File

@ -1,7 +1,7 @@
import * as exec from '@actions/exec'
import fs from 'fs'
import path from 'path'
import {CacheCleaner} from '../../src/cache-cleaner'
import {CacheCleaner} from '../../src/caching/cache-cleaner'
jest.setTimeout(120000)

View File

@ -1,6 +1,6 @@
import * as path from 'path'
import * as fs from 'fs'
import {GradleStateCache} from "../../src/cache-base"
import {GradleUserHomeCache} from "../../src/caching/gradle-user-home-cache"
import {CacheConfig} from "../../src/input-params"
const testTmp = 'test/jest/tmp'
@ -12,7 +12,7 @@ describe("--info and --stacktrace", () => {
const emptyGradleHome = `${testTmp}/empty-gradle-home`
fs.mkdirSync(emptyGradleHome, {recursive: true})
const stateCache = new GradleStateCache("ignored", emptyGradleHome, new CacheConfig())
const stateCache = new GradleUserHomeCache("ignored", emptyGradleHome, new CacheConfig())
stateCache.configureInfoLogLevel()
expect(fs.readFileSync(path.resolve(emptyGradleHome, "gradle.properties"), 'utf-8'))
@ -25,7 +25,7 @@ describe("--info and --stacktrace", () => {
fs.mkdirSync(existingGradleHome, {recursive: true})
fs.writeFileSync(path.resolve(existingGradleHome, "gradle.properties"), "org.gradle.logging.level=debug\n")
const stateCache = new GradleStateCache("ignored", existingGradleHome, new CacheConfig())
const stateCache = new GradleUserHomeCache("ignored", existingGradleHome, new CacheConfig())
stateCache.configureInfoLogLevel()
expect(fs.readFileSync(path.resolve(existingGradleHome, "gradle.properties"), 'utf-8'))

View File

@ -1,4 +1,4 @@
import {CacheEntryListener, CacheListener} from '../../src/cache-reporting'
import {CacheEntryListener, CacheListener} from '../../src/caching/cache-reporting'
describe('caching report', () => {
describe('reports not fully restored', () => {

View File

@ -1,4 +1,4 @@
import * as cacheUtils from '../../src/cache-utils'
import * as cacheUtils from '../../src/caching/cache-utils'
describe('cacheUtils-utils', () => {
describe('can hash', () => {