mirror of
https://github.com/gradle/actions.git
synced 2025-08-18 23:01:27 +08:00
Make cache-keys more consistent (#131)
- All cache keys are now structured as `gradle-<cache-name>-<protocol-version>-<key>`. This ensures that extracted entries are prefixed and versioned consistently - Avoid using custom cache-key prefix for extracted entries. This should reduce the churn in integration tests that require some level of cache isolation. As a result of this change, cache entries written with previous versions of the action will not be used.
This commit is contained in:
commit
8ffe734df6
1868
dist/dependency-submission/main/index.js
vendored
1868
dist/dependency-submission/main/index.js
vendored
File diff suppressed because it is too large
Load Diff
2
dist/dependency-submission/main/index.js.map
vendored
2
dist/dependency-submission/main/index.js.map
vendored
File diff suppressed because one or more lines are too long
1369
dist/dependency-submission/post/index.js
vendored
1369
dist/dependency-submission/post/index.js
vendored
File diff suppressed because it is too large
Load Diff
2
dist/dependency-submission/post/index.js.map
vendored
2
dist/dependency-submission/post/index.js.map
vendored
File diff suppressed because one or more lines are too long
1870
dist/setup-gradle/main/index.js
vendored
1870
dist/setup-gradle/main/index.js
vendored
File diff suppressed because it is too large
Load Diff
2
dist/setup-gradle/main/index.js.map
vendored
2
dist/setup-gradle/main/index.js.map
vendored
File diff suppressed because one or more lines are too long
1378
dist/setup-gradle/post/index.js
vendored
1378
dist/setup-gradle/post/index.js
vendored
File diff suppressed because it is too large
Load Diff
2
dist/setup-gradle/post/index.js.map
vendored
2
dist/setup-gradle/post/index.js.map
vendored
File diff suppressed because one or more lines are too long
99
sources/src/caching/cache-key.ts
Normal file
99
sources/src/caching/cache-key.ts
Normal file
@ -0,0 +1,99 @@
|
||||
import * as github from '@actions/github'
|
||||
|
||||
import {CacheConfig, getJobMatrix} from '../input-params'
|
||||
import {hashStrings} from './cache-utils'
|
||||
|
||||
const CACHE_PROTOCOL_VERSION = 'v1'
|
||||
|
||||
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 key prefix: defaults to 'gradle-' but can be overridden by the user
|
||||
* - The cache protocol version
|
||||
* - 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 prefix = process.env[CACHE_KEY_PREFIX_VAR] || ''
|
||||
|
||||
const cacheKeyBase = `${prefix}${getCacheKeyBase(cacheName, CACHE_PROTOCOL_VERSION)}`
|
||||
|
||||
// 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 getCacheKeyBase(cacheName: string, cacheProtocolVersion: string): string {
|
||||
// Prefix can be used to force change all cache keys (defaults to cache protocol version)
|
||||
return `gradle-${cacheName}-${cacheProtocolVersion}`
|
||||
}
|
||||
|
||||
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
|
||||
}
|
@ -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'), '/')))
|
||||
}
|
@ -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)
|
||||
})
|
||||
}
|
@ -4,21 +4,16 @@ 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 {getCacheKeyBase} from './cache-key'
|
||||
|
||||
const SKIP_RESTORE_VAR = 'GRADLE_BUILD_ACTION_SKIP_RESTORE'
|
||||
const CACHE_PROTOCOL_VERSION = 'v1'
|
||||
|
||||
/**
|
||||
* Represents the result of attempting to load or store an extracted cache entry.
|
||||
@ -250,22 +245,20 @@ abstract class AbstractEntryExtractor {
|
||||
}
|
||||
|
||||
protected createCacheKeyFromFileNames(artifactType: string, files: string[]): string {
|
||||
const cacheKeyPrefix = getCacheKeyPrefix()
|
||||
const relativeFiles = files.map(x => path.relative(this.gradleUserHome, x))
|
||||
const key = hashFileNames(relativeFiles)
|
||||
|
||||
cacheDebug(`Generating cache key for ${artifactType} from file names: ${relativeFiles}`)
|
||||
|
||||
return `${cacheKeyPrefix}${artifactType}-${key}`
|
||||
return `${getCacheKeyBase(artifactType, CACHE_PROTOCOL_VERSION)}-${key}`
|
||||
}
|
||||
|
||||
protected async createCacheKeyFromFileContents(artifactType: string, pattern: string): Promise<string> {
|
||||
const cacheKeyPrefix = getCacheKeyPrefix()
|
||||
const key = await glob.hashFiles(pattern)
|
||||
|
||||
cacheDebug(`Generating cache key for ${artifactType} from files matching: ${pattern}`)
|
||||
|
||||
return `${cacheKeyPrefix}${artifactType}-${key}`
|
||||
return `${getCacheKeyBase(artifactType, CACHE_PROTOCOL_VERSION)}-${key}`
|
||||
}
|
||||
|
||||
// Run actions sequentially if debugging is enabled
|
@ -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 = 'home'
|
||||
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 {
|
@ -9,9 +9,8 @@ import type {PullRequestEvent} from '@octokit/webhooks-types'
|
||||
import * as path from 'path'
|
||||
import fs from 'fs'
|
||||
|
||||
import * as layout from './repository-layout'
|
||||
import {PostActionJobFailure} from './errors'
|
||||
import {DependencyGraphConfig, DependencyGraphOption, getGithubToken} from './input-params'
|
||||
import {DependencyGraphConfig, DependencyGraphOption, getGithubToken, getWorkspaceDirectory} from './input-params'
|
||||
|
||||
const DEPENDENCY_GRAPH_PREFIX = 'dependency-graph_'
|
||||
|
||||
@ -34,10 +33,10 @@ export async function setup(config: DependencyGraphConfig): Promise<void> {
|
||||
maybeExportVariable('GITHUB_DEPENDENCY_GRAPH_JOB_ID', github.context.runId)
|
||||
maybeExportVariable('GITHUB_DEPENDENCY_GRAPH_REF', github.context.ref)
|
||||
maybeExportVariable('GITHUB_DEPENDENCY_GRAPH_SHA', getShaFromContext())
|
||||
maybeExportVariable('GITHUB_DEPENDENCY_GRAPH_WORKSPACE', layout.workspaceDirectory())
|
||||
maybeExportVariable('GITHUB_DEPENDENCY_GRAPH_WORKSPACE', getWorkspaceDirectory())
|
||||
maybeExportVariable(
|
||||
'DEPENDENCY_GRAPH_REPORT_DIR',
|
||||
path.resolve(layout.workspaceDirectory(), 'dependency-graph-reports')
|
||||
path.resolve(getWorkspaceDirectory(), 'dependency-graph-reports')
|
||||
)
|
||||
|
||||
// To clear the dependency graph, we generate an empty graph by excluding all projects and configurations
|
||||
@ -74,7 +73,7 @@ export async function complete(config: DependencyGraphConfig): Promise<void> {
|
||||
}
|
||||
|
||||
async function findGeneratedDependencyGraphFiles(): Promise<string[]> {
|
||||
const workspaceDirectory = layout.workspaceDirectory()
|
||||
const workspaceDirectory = getWorkspaceDirectory()
|
||||
return await findDependencyGraphFiles(workspaceDirectory)
|
||||
}
|
||||
|
||||
@ -85,7 +84,7 @@ async function uploadDependencyGraphs(dependencyGraphFiles: string[], config: De
|
||||
return
|
||||
}
|
||||
|
||||
const workspaceDirectory = layout.workspaceDirectory()
|
||||
const workspaceDirectory = getWorkspaceDirectory()
|
||||
|
||||
const artifactClient = new DefaultArtifactClient()
|
||||
for (const dependencyGraphFile of dependencyGraphFiles) {
|
||||
@ -157,7 +156,7 @@ async function submitDependencyGraphFile(jsonFile: string): Promise<void> {
|
||||
}
|
||||
|
||||
async function downloadDependencyGraphs(): Promise<string[]> {
|
||||
const workspaceDirectory = layout.workspaceDirectory()
|
||||
const workspaceDirectory = getWorkspaceDirectory()
|
||||
|
||||
const findBy = github.context.payload.workflow_run
|
||||
? {
|
||||
@ -220,7 +219,7 @@ function getOctokit(): InstanceType<typeof GitHub> {
|
||||
}
|
||||
|
||||
function getRelativePathFromWorkspace(file: string): string {
|
||||
const workspaceDirectory = layout.workspaceDirectory()
|
||||
const workspaceDirectory = getWorkspaceDirectory()
|
||||
return path.relative(workspaceDirectory, file)
|
||||
}
|
||||
|
||||
|
@ -1,9 +1,7 @@
|
||||
import * as core from '@actions/core'
|
||||
|
||||
import * as setupGradle from '../setup-gradle'
|
||||
import * as execution from '../execution'
|
||||
import * as provisioner from '../provision'
|
||||
import * as layout from '../repository-layout'
|
||||
import * as gradle from '../execution/gradle'
|
||||
import * as dependencyGraph from '../dependency-graph'
|
||||
|
||||
import {parseArgsStringToArgv} from 'string-argv'
|
||||
@ -26,9 +24,6 @@ export async function run(): Promise<void> {
|
||||
return
|
||||
}
|
||||
|
||||
// Download and install Gradle if required
|
||||
const executable = await provisioner.provisionGradle()
|
||||
|
||||
// Only execute if arguments have been provided
|
||||
const additionalArgs = core.getInput('additional-arguments')
|
||||
const executionArgs = `
|
||||
@ -38,10 +33,8 @@ export async function run(): Promise<void> {
|
||||
:ForceDependencyResolutionPlugin_resolveAllDependencies
|
||||
${additionalArgs}
|
||||
`
|
||||
|
||||
const args: string[] = parseArgsStringToArgv(executionArgs)
|
||||
const buildRootDirectory = layout.buildRootDirectory()
|
||||
await execution.executeGradleBuild(executable, buildRootDirectory, args)
|
||||
await gradle.provisionAndMaybeExecute(args)
|
||||
|
||||
await dependencyGraph.complete(config)
|
||||
} catch (error) {
|
||||
|
@ -1,17 +0,0 @@
|
||||
import * as core from '@actions/core'
|
||||
import * as exec from '@actions/exec'
|
||||
import * as gradlew from './gradlew'
|
||||
|
||||
export async function executeGradleBuild(executable: string | undefined, root: string, args: string[]): Promise<void> {
|
||||
// Use the provided executable, or look for a Gradle wrapper script to run
|
||||
const toExecute = executable ?? gradlew.gradleWrapperScript(root)
|
||||
|
||||
const status: number = await exec.exec(toExecute, args, {
|
||||
cwd: root,
|
||||
ignoreReturnCode: true
|
||||
})
|
||||
|
||||
if (status !== 0) {
|
||||
core.setFailed(`Gradle build failed: see console output for details`)
|
||||
}
|
||||
}
|
42
sources/src/execution/gradle.ts
Normal file
42
sources/src/execution/gradle.ts
Normal file
@ -0,0 +1,42 @@
|
||||
import * as core from '@actions/core'
|
||||
import * as exec from '@actions/exec'
|
||||
import * as path from 'path'
|
||||
|
||||
import * as params from '../input-params'
|
||||
import * as provisioner from './provision'
|
||||
import * as gradlew from './gradlew'
|
||||
import {getWorkspaceDirectory} from '../input-params'
|
||||
|
||||
export async function provisionAndMaybeExecute(args: string[]): Promise<void> {
|
||||
// Download and install Gradle if required
|
||||
const executable = await provisioner.provisionGradle()
|
||||
|
||||
// Only execute if arguments have been provided
|
||||
if (args.length > 0) {
|
||||
await executeGradleBuild(executable, buildRootDirectory(), args)
|
||||
}
|
||||
}
|
||||
|
||||
async function executeGradleBuild(executable: string | undefined, root: string, args: string[]): Promise<void> {
|
||||
// Use the provided executable, or look for a Gradle wrapper script to run
|
||||
const toExecute = executable ?? gradlew.gradleWrapperScript(root)
|
||||
|
||||
const status: number = await exec.exec(toExecute, args, {
|
||||
cwd: root,
|
||||
ignoreReturnCode: true
|
||||
})
|
||||
|
||||
if (status !== 0) {
|
||||
core.setFailed(`Gradle build failed: see console output for details`)
|
||||
}
|
||||
}
|
||||
|
||||
function buildRootDirectory(): string {
|
||||
const baseDirectory = getWorkspaceDirectory()
|
||||
const buildRootDirectoryInput = params.getBuildRootDirectory()
|
||||
const resolvedBuildRootDirectory =
|
||||
buildRootDirectoryInput === ''
|
||||
? path.resolve(baseDirectory)
|
||||
: path.resolve(baseDirectory, buildRootDirectoryInput)
|
||||
return resolvedBuildRootDirectory
|
||||
}
|
@ -7,9 +7,9 @@ import * as cache from '@actions/cache'
|
||||
import * as toolCache from '@actions/tool-cache'
|
||||
|
||||
import * as gradlew from './gradlew'
|
||||
import * as params from './input-params'
|
||||
import {handleCacheFailure} from './cache-utils'
|
||||
import {CacheConfig} from './input-params'
|
||||
import * as params from '../input-params'
|
||||
import {handleCacheFailure} from '../caching/cache-utils'
|
||||
import {CacheConfig} from '../input-params'
|
||||
|
||||
const gradleVersionsBaseUrl = 'https://services.gradle.org/versions'
|
||||
|
@ -240,6 +240,10 @@ export function getGithubToken(): string {
|
||||
return core.getInput('github-token', {required: true})
|
||||
}
|
||||
|
||||
export function getWorkspaceDirectory(): string {
|
||||
return process.env[`GITHUB_WORKSPACE`] || ''
|
||||
}
|
||||
|
||||
export function parseNumericInput(paramName: string, paramValue: string, paramDefault: number): number {
|
||||
if (paramValue.length === 0) {
|
||||
return paramDefault
|
||||
|
@ -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)) {
|
||||
|
@ -1,16 +0,0 @@
|
||||
import * as params from './input-params'
|
||||
import * as path from 'path'
|
||||
|
||||
export function workspaceDirectory(): string {
|
||||
return process.env[`GITHUB_WORKSPACE`] || ''
|
||||
}
|
||||
|
||||
export function buildRootDirectory(): string {
|
||||
const baseDirectory = workspaceDirectory()
|
||||
const buildRootDirectoryInput = params.getBuildRootDirectory()
|
||||
const resolvedBuildRootDirectory =
|
||||
buildRootDirectoryInput === ''
|
||||
? path.resolve(baseDirectory)
|
||||
: path.resolve(baseDirectory, buildRootDirectoryInput)
|
||||
return resolvedBuildRootDirectory
|
||||
}
|
@ -2,15 +2,14 @@ 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 layout from './repository-layout'
|
||||
import * as caches from './caching/caches'
|
||||
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'
|
||||
import {BuildScanConfig, CacheConfig, SummaryConfig, getWorkspaceDirectory} from './input-params'
|
||||
|
||||
const GRADLE_SETUP_VAR = 'GRADLE_BUILD_ACTION_SETUP_COMPLETED'
|
||||
const USER_HOME = 'USER_HOME'
|
||||
@ -57,11 +56,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')
|
||||
|
||||
@ -71,7 +71,7 @@ export async function complete(cacheConfig: CacheConfig, summaryConfig: SummaryC
|
||||
async function determineGradleUserHome(): Promise<string> {
|
||||
const customGradleUserHome = process.env['GRADLE_USER_HOME']
|
||||
if (customGradleUserHome) {
|
||||
const rootDir = layout.workspaceDirectory()
|
||||
const rootDir = getWorkspaceDirectory()
|
||||
return path.resolve(rootDir, customGradleUserHome)
|
||||
}
|
||||
|
||||
|
@ -1,9 +1,7 @@
|
||||
import * as core from '@actions/core'
|
||||
|
||||
import * as setupGradle from '../setup-gradle'
|
||||
import * as execution from '../execution'
|
||||
import * as provisioner from '../provision'
|
||||
import * as layout from '../repository-layout'
|
||||
import * as gradle from '../execution/gradle'
|
||||
import * as dependencyGraph from '../dependency-graph'
|
||||
import {BuildScanConfig, CacheConfig, DependencyGraphConfig, getArguments} from '../input-params'
|
||||
|
||||
@ -18,15 +16,8 @@ export async function run(): Promise<void> {
|
||||
// Configure the dependency graph submission
|
||||
await dependencyGraph.setup(new DependencyGraphConfig())
|
||||
|
||||
// Download and install Gradle if required
|
||||
const executable = await provisioner.provisionGradle()
|
||||
|
||||
// Only execute if arguments have been provided
|
||||
const args: string[] = getArguments()
|
||||
if (args.length > 0) {
|
||||
const buildRootDirectory = layout.buildRootDirectory()
|
||||
await execution.executeGradleBuild(executable, buildRootDirectory, args)
|
||||
}
|
||||
await gradle.provisionAndMaybeExecute(args)
|
||||
} catch (error) {
|
||||
core.setFailed(String(error))
|
||||
if (error instanceof Error && error.stack) {
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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'))
|
||||
|
@ -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', () => {
|
||||
|
@ -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', () => {
|
||||
|
Loading…
x
Reference in New Issue
Block a user