mirror of
				https://github.com/gradle/gradle-build-action.git
				synced 2025-11-04 09:58:56 +08:00 
			
		
		
		
	Avoid saving config-cache from Gradle < 8.6
Earlier versions of Gradle didn't support the `GRADLE_ENCRYPTION_KEY` for the configuration-cache, and so are either not useful to save, or are actually unsafe due to unencrypted secrets. We use semver to compare the Gradle version used to produce the config-cache entry with the minimum Gradle version required.
This commit is contained in:
		@@ -3,13 +3,14 @@ import fs from 'fs'
 | 
			
		||||
import crypto from 'crypto'
 | 
			
		||||
import * as core from '@actions/core'
 | 
			
		||||
import * as glob from '@actions/glob'
 | 
			
		||||
import * as semver from 'semver'
 | 
			
		||||
 | 
			
		||||
import * as params from './input-params'
 | 
			
		||||
 | 
			
		||||
import {META_FILE_DIR} from './cache-base'
 | 
			
		||||
import {CacheEntryListener, CacheListener} from './cache-reporting'
 | 
			
		||||
import {cacheDebug, getCacheKeyPrefix, hashFileNames, restoreCache, saveCache, tryDelete} from './cache-utils'
 | 
			
		||||
import {loadBuildResults} from './build-results'
 | 
			
		||||
import {BuildResult, loadBuildResults} from './build-results'
 | 
			
		||||
 | 
			
		||||
const SKIP_RESTORE_VAR = 'GRADLE_BUILD_ACTION_SKIP_RESTORE'
 | 
			
		||||
 | 
			
		||||
@@ -47,6 +48,7 @@ class ExtractedCacheEntryDefinition {
 | 
			
		||||
    pattern: string
 | 
			
		||||
    bundle: boolean
 | 
			
		||||
    uniqueFileNames = true
 | 
			
		||||
    notCacheableReason: string | undefined
 | 
			
		||||
 | 
			
		||||
    constructor(artifactType: string, pattern: string, bundle: boolean) {
 | 
			
		||||
        this.artifactType = artifactType
 | 
			
		||||
@@ -54,10 +56,24 @@ class ExtractedCacheEntryDefinition {
 | 
			
		||||
        this.bundle = bundle
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Indicate that the file names matching the cache entry pattern are NOT sufficient to uniquely identify the contents.
 | 
			
		||||
     * If the file names are sufficient, then we use a hash of the file names to identify the entry.
 | 
			
		||||
     * With non-unique-file-names, we hash the file contents to identify the cache entry.
 | 
			
		||||
     */
 | 
			
		||||
    withNonUniqueFileNames(): ExtractedCacheEntryDefinition {
 | 
			
		||||
        this.uniqueFileNames = false
 | 
			
		||||
        return this
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Specify that the cache entry, should not be saved for some reason, even though the contents exist.
 | 
			
		||||
     * This is used to prevent configuration-cache entries being cached when they were generated by Gradle < 8.6,
 | 
			
		||||
     */
 | 
			
		||||
    notCacheableBecause(reason: string): ExtractedCacheEntryDefinition {
 | 
			
		||||
        this.notCacheableReason = reason
 | 
			
		||||
        return this
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -143,6 +159,11 @@ abstract class AbstractEntryExtractor {
 | 
			
		||||
            const artifactType = cacheEntryDefinition.artifactType
 | 
			
		||||
            const pattern = cacheEntryDefinition.pattern
 | 
			
		||||
 | 
			
		||||
            if (cacheEntryDefinition.notCacheableReason) {
 | 
			
		||||
                listener.entry(pattern).markNotSaved(cacheEntryDefinition.notCacheableReason)
 | 
			
		||||
                continue
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Find all matching files for this cache entry definition
 | 
			
		||||
            const globber = await glob.create(pattern, {
 | 
			
		||||
                implicitDescendants: false
 | 
			
		||||
@@ -402,25 +423,51 @@ export class ConfigurationCacheEntryExtractor extends AbstractEntryExtractor {
 | 
			
		||||
     * Extract cache entries for the configuration cache in each project.
 | 
			
		||||
     */
 | 
			
		||||
    protected getExtractedCacheEntryDefinitions(): ExtractedCacheEntryDefinition[] {
 | 
			
		||||
        return this.getConfigCacheDirs().map(configCachePath => {
 | 
			
		||||
            return new ExtractedCacheEntryDefinition(
 | 
			
		||||
        // Group BuildResult by existing configCacheDir
 | 
			
		||||
        const groupedResults = this.getConfigCacheDirectoriesWithAssociatedBuildResults()
 | 
			
		||||
 | 
			
		||||
        return Object.entries(groupedResults).map(([configCachePath, pathResults]) => {
 | 
			
		||||
            // Create a entry definition for each unique configuration cache directory
 | 
			
		||||
            const definition = new ExtractedCacheEntryDefinition(
 | 
			
		||||
                'configuration-cache',
 | 
			
		||||
                configCachePath,
 | 
			
		||||
                true
 | 
			
		||||
            ).withNonUniqueFileNames()
 | 
			
		||||
 | 
			
		||||
            // If any associated build result used Gradle < 8.6, then mark it as not cacheable
 | 
			
		||||
            if (
 | 
			
		||||
                pathResults.find(result => {
 | 
			
		||||
                    const gradleVersion = semver.coerce(result.gradleVersion)
 | 
			
		||||
                    return gradleVersion && semver.lt(gradleVersion, '8.6.0')
 | 
			
		||||
                })
 | 
			
		||||
            ) {
 | 
			
		||||
                core.info(
 | 
			
		||||
                    `Not saving config-cache data for ${configCachePath}. Configuration cache data is only saved for Gradle 8.6+`
 | 
			
		||||
                )
 | 
			
		||||
                definition.notCacheableBecause('Configuration cache data only saved for Gradle 8.6+')
 | 
			
		||||
            }
 | 
			
		||||
            return definition
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * For every Gradle invocation, we record the project root directory.
 | 
			
		||||
     * This method returns any configuraton-cache directories found in any of these project roots.
 | 
			
		||||
     */
 | 
			
		||||
    private getConfigCacheDirs(): string[] {
 | 
			
		||||
        const buildResults = loadBuildResults()
 | 
			
		||||
        const configCacheDirs = buildResults
 | 
			
		||||
            .map(x => path.resolve(x.rootProjectDir, '.gradle/configuration-cache'))
 | 
			
		||||
            .filter(x => fs.existsSync(x))
 | 
			
		||||
    private getConfigCacheDirectoriesWithAssociatedBuildResults(): Record<string, BuildResult[]> {
 | 
			
		||||
        return loadBuildResults().reduce(
 | 
			
		||||
            (acc, buildResult) => {
 | 
			
		||||
                // For each build result, find the config-cache dir
 | 
			
		||||
                const configCachePath = path.resolve(buildResult.rootProjectDir, '.gradle/configuration-cache')
 | 
			
		||||
                // Ignore case where config-cache dir doesn't exist
 | 
			
		||||
                if (!fs.existsSync(configCachePath)) {
 | 
			
		||||
                    return acc
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
        return [...new Set(configCacheDirs)] // Remove duplicates
 | 
			
		||||
                // Group by unique config cache directories and collect associated build results
 | 
			
		||||
                if (!acc[configCachePath]) {
 | 
			
		||||
                    acc[configCachePath] = []
 | 
			
		||||
                }
 | 
			
		||||
                acc[configCachePath].push(buildResult)
 | 
			
		||||
                return acc
 | 
			
		||||
            },
 | 
			
		||||
            {} as Record<string, BuildResult[]>
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user