From fa61956921061aa8a18b89ab6a442b1c50645804 Mon Sep 17 00:00:00 2001 From: Dominik Nakamura Date: Thu, 7 Oct 2021 11:35:31 +0900 Subject: [PATCH] Include env vars in the generated cache key --- README.md | 4 ++++ action.yml | 3 +++ src/common.ts | 44 +++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 50 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ccb16f8..a3f3cd6 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,10 @@ An optional key that is added to the automatic cache key. : `sharedKey` An additional key that is stable over multiple jobs. +: `envVars` +A space-separated list of regular expressions that define additional environment variable filters. +These are added to an additional cache key that's generated from environment variable contents. + : `working-directory` The working directory the action operates in, is case the cargo project is not located in the repo root. diff --git a/action.yml b/action.yml index d20981c..ee9362d 100644 --- a/action.yml +++ b/action.yml @@ -8,6 +8,9 @@ inputs: sharedKey: description: "An additional cache key that is stable over multiple jobs" required: false + envVars: + description: "Additional environment variables to include in the cache key, separeted by spaces" + required: false working-directory: description: "The working directory this action should operate in" required: false diff --git a/src/common.ts b/src/common.ts index 668734b..2eaaa8e 100644 --- a/src/common.ts +++ b/src/common.ts @@ -71,6 +71,9 @@ export async function getCacheConfig(): Promise { } } + const extraEnvKeys = core.getInput("envVars").split(/\s+/); + + key += `${getEnvKey(extraEnvKeys)}-`; key += await getRustKey(); return { @@ -105,6 +108,45 @@ export async function getCargoBins(): Promise> { } } +/** + * Create a key hash, generated from environment variables. + * + * The available environment variables are filtered by a set of defaults that are common for Rust + * projects and should apply to almost all runs, as they modify the Rustc compiler's, Clippy's and + * other tools' behavior. + * + * @param extraKeys additional user-provided keys that are added to the default list. These are + * treated as regular expressions ({@link RegExp}), and will each be surrounded by a `^` and `$`, + * to make sure they are matched against the whole env var name. + * @returns An SHA-1 hash over all the environment variable values, whose names were not filtered + * out. The hash is returned as hex-string, **reduced to half its length**. + */ +function getEnvKey(extraKeys: string[]): string { + const hasher = crypto.createHash("sha1"); + const defaultValidKeys = [ + /^CARGO_.+$/, + /^CC_.+$/, + /^CXX_.+$/, + /^RUSTC_.+$/, + /^RUSTC$/, + /^RUSTDOC$/, + /^RUSTDOCFLAGS$/, + /^RUSTFLAGS$/, + /^RUSTFMT$/, + ]; + + // Combine default key filters with user-provided ones. + const keyFilter = defaultValidKeys.concat(extraKeys.map((key) => new RegExp(`^${key}$`))); + + for (const [key, value] of Object.entries(process.env)) { + if (keyFilter.some((re) => re.test(key)) && value) { + hasher.update(`${key}=${value}`); + } + } + + return hasher.digest("hex").slice(0, 20); +} + async function getRustKey(): Promise { const rustc = await getRustVersion(); return `${rustc.release}-${rustc.host}-${rustc["commit-hash"].slice(0, 12)}`; @@ -261,5 +303,5 @@ export async function rm(parent: string, dirent: fs.Dirent) { } else if (dirent.isDirectory()) { await io.rmRF(fileName); } - } catch {} + } catch { } }