-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add bare-bones dependency caching functions
- Loading branch information
Michael B. Gale
committed
Oct 29, 2024
1 parent
51d90f4
commit 2b7af49
Showing
3 changed files
with
271 additions
and
0 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,145 @@ | ||
| import * as os from "os"; | ||
| import { join } from "path"; | ||
|
|
||
| import * as actionsCache from "@actions/cache"; | ||
| import * as glob from "@actions/glob"; | ||
|
|
||
| import { getTotalCacheSize } from "./caching-utils"; | ||
| import { Config } from "./config-utils"; | ||
| import { Language } from "./languages"; | ||
| import { Logger } from "./logging"; | ||
| import { getRequiredEnvParam } from "./util"; | ||
|
|
||
| interface CacheConfig { | ||
| paths: string[]; | ||
| hash: string[]; | ||
| } | ||
|
|
||
| const CODEQL_DEPENDENCY_CACHE_PREFIX = "codeql-dependencies"; | ||
| const CODEQL_DEPENDENCY_CACHE_VERSION = 1; | ||
|
|
||
| const CODEQL_DEFAULT_CACHE_CONFIG: { [language: string]: CacheConfig } = { | ||
| java: { | ||
| paths: [ | ||
| // Maven | ||
| join(os.homedir(), ".m2", "repository"), | ||
| // Gradle | ||
| join(os.homedir(), ".gradle", "caches"), | ||
| ], | ||
| hash: [ | ||
| // Maven | ||
| "**/pom.xml", | ||
| // Gradle | ||
| "**/*.gradle*", | ||
| "**/gradle-wrapper.properties", | ||
| "buildSrc/**/Versions.kt", | ||
| "buildSrc/**/Dependencies.kt", | ||
| "gradle/*.versions.toml", | ||
| "**/versions.properties", | ||
| ], | ||
| }, | ||
| }; | ||
|
|
||
| /** | ||
| * Attempts to restore dependency caches for the languages being analyzed. | ||
| * | ||
| * @param languages The languages being analyzed. | ||
| * @param logger A logger to record some informational messages to. | ||
| * @returns A list of languages for which dependency caches were restored. | ||
| */ | ||
| export async function downloadDependencyCaches( | ||
| languages: Language[], | ||
| logger: Logger, | ||
| ): Promise<Language[]> { | ||
| const restoredCaches: Language[] = []; | ||
|
|
||
| for (const language of languages) { | ||
| const cacheConfig = CODEQL_DEFAULT_CACHE_CONFIG[language]; | ||
|
|
||
| if (cacheConfig === undefined) { | ||
| logger.info( | ||
| `Skipping download of dependency cache for ${language} as we have no caching configuration for it.`, | ||
| ); | ||
| continue; | ||
| } | ||
|
|
||
| const primaryKey = await cacheKey(language, cacheConfig); | ||
| const restoreKeys: string[] = [await cachePrefix(language)]; | ||
|
|
||
| logger.info( | ||
| `Downloading cache for ${language} with key ${primaryKey} and restore keys ${restoreKeys.join( | ||
| ", ", | ||
| )}`, | ||
| ); | ||
|
|
||
| const hitKey = await actionsCache.restoreCache( | ||
| cacheConfig.paths, | ||
| primaryKey, | ||
| restoreKeys, | ||
| ); | ||
|
|
||
| if (hitKey !== undefined) { | ||
| logger.info(`Cache hit on key ${hitKey} for ${language}.`); | ||
| restoredCaches.push(language); | ||
| } | ||
| } | ||
|
|
||
| return restoredCaches; | ||
| } | ||
|
|
||
| /** | ||
| * Attempts to store caches for the languages that were analyzed. | ||
| * | ||
| * @param config The configuration for this workflow. | ||
| * @param logger A logger to record some informational messages to. | ||
| */ | ||
| export async function uploadDependencyCaches(config: Config, logger: Logger) { | ||
| for (const language of config.languages) { | ||
| const cacheConfig = CODEQL_DEFAULT_CACHE_CONFIG[language]; | ||
|
|
||
| if (cacheConfig === undefined) { | ||
| logger.info( | ||
| `Skipping upload of dependency cache for ${language} as we have no caching configuration for it.`, | ||
| ); | ||
| continue; | ||
| } | ||
|
|
||
| const globber = await glob.create(cacheConfig.hash.join("\n")); | ||
| const size = await getTotalCacheSize(await globber.glob(), logger); | ||
|
|
||
| const key = await cacheKey(language, cacheConfig); | ||
|
|
||
| logger.info( | ||
| `Uploading cache of size ${size} for ${language} with key ${key}`, | ||
| ); | ||
|
|
||
| await actionsCache.saveCache(cacheConfig.paths, key); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Computes a cache key for the specified language. | ||
| * | ||
| * @param language The language being analyzed. | ||
| * @param cacheConfig The cache configuration for the language. | ||
| * @returns A cache key capturing information about the project(s) being analyzed in the specified language. | ||
| */ | ||
| async function cacheKey( | ||
| language: Language, | ||
| cacheConfig: CacheConfig, | ||
| ): Promise<string> { | ||
| const hash = await glob.hashFiles(cacheConfig.hash.join("\n")); | ||
| return `${await cachePrefix(language)}${hash}`; | ||
| } | ||
|
|
||
| /** | ||
| * Constructs a prefix for the cache key, comprised of a CodeQL-specific prefix, a version number that | ||
| * can be changed to invalidate old caches, the runner's operating system, and the specified language name. | ||
| * | ||
| * @param language The language being analyzed. | ||
| * @returns The prefix that identifies what a cache is for. | ||
| */ | ||
| async function cachePrefix(language: Language): Promise<string> { | ||
| const runnerOs = getRequiredEnvParam("RUNNER_OS"); | ||
| return `${CODEQL_DEPENDENCY_CACHE_PREFIX}-${CODEQL_DEPENDENCY_CACHE_VERSION}-${runnerOs}-${language}-`; | ||
| } |