diff --git a/dist/post_run/index.js b/dist/post_run/index.js index 5d93c81..863fc4c 100644 --- a/dist/post_run/index.js +++ b/dist/post_run/index.js @@ -10681,6 +10681,66 @@ function createTar(archiveFolder, sourceDirectories, compressionMethod) { exports.createTar = createTar; //# sourceMappingURL=tar.js.map +/***/ }), + +/***/ 443: +/***/ (function(__unusedmodule, exports, __webpack_require__) { + +"use strict"; + +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; + result["default"] = mod; + return result; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const core = __importStar(__webpack_require__(470)); +const constants_1 = __webpack_require__(694); +function isExactKeyMatch(key, cacheKey) { + return !!(cacheKey && + cacheKey.localeCompare(key, undefined, { + sensitivity: "accent", + }) === 0); +} +exports.isExactKeyMatch = isExactKeyMatch; +function setCacheState(state) { + core.saveState(constants_1.State.CacheMatchedKey, state); +} +exports.setCacheState = setCacheState; +function setCacheHitOutput(isCacheHit) { + core.setOutput(constants_1.Outputs.CacheHit, isCacheHit.toString()); +} +exports.setCacheHitOutput = setCacheHitOutput; +function setOutputAndState(key, cacheKey) { + setCacheHitOutput(isExactKeyMatch(key, cacheKey)); + // Store the matched cache key if it exists + cacheKey && setCacheState(cacheKey); +} +exports.setOutputAndState = setOutputAndState; +function getCacheState() { + const cacheKey = core.getState(constants_1.State.CacheMatchedKey); + if (cacheKey) { + core.debug(`Cache state/key: ${cacheKey}`); + return cacheKey; + } + return undefined; +} +exports.getCacheState = getCacheState; +function logWarning(message) { + const warningPrefix = "[warning]"; + core.info(`${warningPrefix}${message}`); +} +exports.logWarning = logWarning; +// Cache token authorized for all events that are tied to a ref +// See GitHub Context https://help.github.com/actions/automating-your-workflow-with-github-actions/contexts-and-expression-syntax-for-github-actions#github-context +function isValidEvent() { + return constants_1.RefKey in process.env && Boolean(process.env[constants_1.RefKey]); +} +exports.isValidEvent = isValidEvent; + + /***/ }), /***/ 446: @@ -29620,6 +29680,38 @@ class Deprecation extends Error { exports.Deprecation = Deprecation; +/***/ }), + +/***/ 694: +/***/ (function(__unusedmodule, exports) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +var Inputs; +(function (Inputs) { + Inputs["Key"] = "key"; + Inputs["Path"] = "path"; + Inputs["RestoreKeys"] = "restore-keys"; +})(Inputs = exports.Inputs || (exports.Inputs = {})); +var Outputs; +(function (Outputs) { + Outputs["CacheHit"] = "cache-hit"; +})(Outputs = exports.Outputs || (exports.Outputs = {})); +var State; +(function (State) { + State["CachePrimaryKey"] = "CACHE_KEY"; + State["CacheMatchedKey"] = "CACHE_RESULT"; +})(State = exports.State || (exports.State = {})); +var Events; +(function (Events) { + Events["Key"] = "GITHUB_EVENT_NAME"; + Events["Push"] = "push"; + Events["PullRequest"] = "pull_request"; +})(Events = exports.Events || (exports.Events = {})); +exports.RefKey = "GITHUB_REF"; + + /***/ }), /***/ 696: @@ -29727,6 +29819,8 @@ const cache = __importStar(__webpack_require__(638)); const core = __importStar(__webpack_require__(470)); const crypto = __importStar(__webpack_require__(417)); const fs = __importStar(__webpack_require__(747)); +const constants_1 = __webpack_require__(694); +const utils = __importStar(__webpack_require__(443)); function checksumFile(hashName, path) { return new Promise((resolve, reject) => { const hash = crypto.createHash(hashName); @@ -29770,24 +29864,40 @@ function buildCacheKeys() { } function restoreCache() { return __awaiter(this, void 0, void 0, function* () { + if (!utils.isValidEvent()) { + utils.logWarning(`Event Validation Error: The event type ${process.env[constants_1.Events.Key]} is not supported because it's not tied to a branch or tag ref.`); + return; + } const startedAt = Date.now(); const keys = yield buildCacheKeys(); const primaryKey = keys.pop(); const restoreKeys = keys.reverse(); // Tell golangci-lint to use our cache directory. process.env.GOLANGCI_LINT_CACHE = getLintCacheDir(); - if (primaryKey !== undefined) { - try { - yield cache.restoreCache(getCacheDirs(), primaryKey, restoreKeys); - core.info(`Restored cache for golangci-lint from key '${primaryKey}' in ${Date.now() - startedAt}ms`); + if (!primaryKey) { + utils.logWarning(`Invalid primary key`); + return; + } + core.saveState(constants_1.State.CachePrimaryKey, primaryKey); + try { + const cacheKey = yield cache.restoreCache(getCacheDirs(), primaryKey, restoreKeys); + if (!cacheKey) { + core.info(`Cache not found for input keys: ${[primaryKey, ...restoreKeys].join(", ")}`); + return; } - catch (error) { - if (error.name === cache.ValidationError.name) { - throw error; - } - else { - core.warning(error.message); - } + // Store the matched cache key + utils.setCacheState(cacheKey); + const isExactKeyMatch = utils.isExactKeyMatch(primaryKey, cacheKey); + utils.setCacheHitOutput(isExactKeyMatch); + core.info(`Cache restored from key: ${cacheKey}`); + core.info(`Restored cache for golangci-lint from key '${primaryKey}' in ${Date.now() - startedAt}ms`); + } + catch (error) { + if (error.name === cache.ValidationError.name) { + throw error; + } + else { + core.warning(error.message); } } }); @@ -29795,25 +29905,36 @@ function restoreCache() { exports.restoreCache = restoreCache; function saveCache() { return __awaiter(this, void 0, void 0, function* () { + // Validate inputs, this can cause task failure + if (!utils.isValidEvent()) { + utils.logWarning(`Event Validation Error: The event type ${process.env[constants_1.Events.Key]} is not supported because it's not tied to a branch or tag ref.`); + return; + } const startedAt = Date.now(); const cacheDirs = getCacheDirs(); - const keys = yield buildCacheKeys(); - const primaryKey = keys.pop(); - if (primaryKey !== undefined) { - try { - yield cache.saveCache(cacheDirs, primaryKey); - core.info(`Saved cache for golangci-lint from paths '${cacheDirs.join(`, `)}' in ${Date.now() - startedAt}ms`); + const primaryKey = core.getState(constants_1.State.CachePrimaryKey); + if (!primaryKey) { + utils.logWarning(`Error retrieving key from state.`); + return; + } + const state = utils.getCacheState(); + if (utils.isExactKeyMatch(primaryKey, state)) { + core.info(`Cache hit occurred on the primary key ${primaryKey}, not saving cache.`); + return; + } + try { + yield cache.saveCache(cacheDirs, primaryKey); + core.info(`Saved cache for golangci-lint from paths '${cacheDirs.join(`, `)}' in ${Date.now() - startedAt}ms`); + } + catch (error) { + if (error.name === cache.ValidationError.name) { + throw error; } - catch (error) { - if (error.name === cache.ValidationError.name) { - throw error; - } - else if (error.name === cache.ReserveCacheError.name) { - core.info(error.message); - } - else { - core.info(`[warning] ${error.message}`); - } + else if (error.name === cache.ReserveCacheError.name) { + core.info(error.message); + } + else { + core.info(`[warning] ${error.message}`); } } }); diff --git a/dist/run/index.js b/dist/run/index.js index 4e58182..8f26585 100644 --- a/dist/run/index.js +++ b/dist/run/index.js @@ -10693,6 +10693,66 @@ function createTar(archiveFolder, sourceDirectories, compressionMethod) { exports.createTar = createTar; //# sourceMappingURL=tar.js.map +/***/ }), + +/***/ 443: +/***/ (function(__unusedmodule, exports, __webpack_require__) { + +"use strict"; + +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; + result["default"] = mod; + return result; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const core = __importStar(__webpack_require__(470)); +const constants_1 = __webpack_require__(694); +function isExactKeyMatch(key, cacheKey) { + return !!(cacheKey && + cacheKey.localeCompare(key, undefined, { + sensitivity: "accent", + }) === 0); +} +exports.isExactKeyMatch = isExactKeyMatch; +function setCacheState(state) { + core.saveState(constants_1.State.CacheMatchedKey, state); +} +exports.setCacheState = setCacheState; +function setCacheHitOutput(isCacheHit) { + core.setOutput(constants_1.Outputs.CacheHit, isCacheHit.toString()); +} +exports.setCacheHitOutput = setCacheHitOutput; +function setOutputAndState(key, cacheKey) { + setCacheHitOutput(isExactKeyMatch(key, cacheKey)); + // Store the matched cache key if it exists + cacheKey && setCacheState(cacheKey); +} +exports.setOutputAndState = setOutputAndState; +function getCacheState() { + const cacheKey = core.getState(constants_1.State.CacheMatchedKey); + if (cacheKey) { + core.debug(`Cache state/key: ${cacheKey}`); + return cacheKey; + } + return undefined; +} +exports.getCacheState = getCacheState; +function logWarning(message) { + const warningPrefix = "[warning]"; + core.info(`${warningPrefix}${message}`); +} +exports.logWarning = logWarning; +// Cache token authorized for all events that are tied to a ref +// See GitHub Context https://help.github.com/actions/automating-your-workflow-with-github-actions/contexts-and-expression-syntax-for-github-actions#github-context +function isValidEvent() { + return constants_1.RefKey in process.env && Boolean(process.env[constants_1.RefKey]); +} +exports.isValidEvent = isValidEvent; + + /***/ }), /***/ 446: @@ -29632,6 +29692,38 @@ class Deprecation extends Error { exports.Deprecation = Deprecation; +/***/ }), + +/***/ 694: +/***/ (function(__unusedmodule, exports) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +var Inputs; +(function (Inputs) { + Inputs["Key"] = "key"; + Inputs["Path"] = "path"; + Inputs["RestoreKeys"] = "restore-keys"; +})(Inputs = exports.Inputs || (exports.Inputs = {})); +var Outputs; +(function (Outputs) { + Outputs["CacheHit"] = "cache-hit"; +})(Outputs = exports.Outputs || (exports.Outputs = {})); +var State; +(function (State) { + State["CachePrimaryKey"] = "CACHE_KEY"; + State["CacheMatchedKey"] = "CACHE_RESULT"; +})(State = exports.State || (exports.State = {})); +var Events; +(function (Events) { + Events["Key"] = "GITHUB_EVENT_NAME"; + Events["Push"] = "push"; + Events["PullRequest"] = "pull_request"; +})(Events = exports.Events || (exports.Events = {})); +exports.RefKey = "GITHUB_REF"; + + /***/ }), /***/ 696: @@ -29739,6 +29831,8 @@ const cache = __importStar(__webpack_require__(638)); const core = __importStar(__webpack_require__(470)); const crypto = __importStar(__webpack_require__(417)); const fs = __importStar(__webpack_require__(747)); +const constants_1 = __webpack_require__(694); +const utils = __importStar(__webpack_require__(443)); function checksumFile(hashName, path) { return new Promise((resolve, reject) => { const hash = crypto.createHash(hashName); @@ -29782,24 +29876,40 @@ function buildCacheKeys() { } function restoreCache() { return __awaiter(this, void 0, void 0, function* () { + if (!utils.isValidEvent()) { + utils.logWarning(`Event Validation Error: The event type ${process.env[constants_1.Events.Key]} is not supported because it's not tied to a branch or tag ref.`); + return; + } const startedAt = Date.now(); const keys = yield buildCacheKeys(); const primaryKey = keys.pop(); const restoreKeys = keys.reverse(); // Tell golangci-lint to use our cache directory. process.env.GOLANGCI_LINT_CACHE = getLintCacheDir(); - if (primaryKey !== undefined) { - try { - yield cache.restoreCache(getCacheDirs(), primaryKey, restoreKeys); - core.info(`Restored cache for golangci-lint from key '${primaryKey}' in ${Date.now() - startedAt}ms`); + if (!primaryKey) { + utils.logWarning(`Invalid primary key`); + return; + } + core.saveState(constants_1.State.CachePrimaryKey, primaryKey); + try { + const cacheKey = yield cache.restoreCache(getCacheDirs(), primaryKey, restoreKeys); + if (!cacheKey) { + core.info(`Cache not found for input keys: ${[primaryKey, ...restoreKeys].join(", ")}`); + return; } - catch (error) { - if (error.name === cache.ValidationError.name) { - throw error; - } - else { - core.warning(error.message); - } + // Store the matched cache key + utils.setCacheState(cacheKey); + const isExactKeyMatch = utils.isExactKeyMatch(primaryKey, cacheKey); + utils.setCacheHitOutput(isExactKeyMatch); + core.info(`Cache restored from key: ${cacheKey}`); + core.info(`Restored cache for golangci-lint from key '${primaryKey}' in ${Date.now() - startedAt}ms`); + } + catch (error) { + if (error.name === cache.ValidationError.name) { + throw error; + } + else { + core.warning(error.message); } } }); @@ -29807,25 +29917,36 @@ function restoreCache() { exports.restoreCache = restoreCache; function saveCache() { return __awaiter(this, void 0, void 0, function* () { + // Validate inputs, this can cause task failure + if (!utils.isValidEvent()) { + utils.logWarning(`Event Validation Error: The event type ${process.env[constants_1.Events.Key]} is not supported because it's not tied to a branch or tag ref.`); + return; + } const startedAt = Date.now(); const cacheDirs = getCacheDirs(); - const keys = yield buildCacheKeys(); - const primaryKey = keys.pop(); - if (primaryKey !== undefined) { - try { - yield cache.saveCache(cacheDirs, primaryKey); - core.info(`Saved cache for golangci-lint from paths '${cacheDirs.join(`, `)}' in ${Date.now() - startedAt}ms`); + const primaryKey = core.getState(constants_1.State.CachePrimaryKey); + if (!primaryKey) { + utils.logWarning(`Error retrieving key from state.`); + return; + } + const state = utils.getCacheState(); + if (utils.isExactKeyMatch(primaryKey, state)) { + core.info(`Cache hit occurred on the primary key ${primaryKey}, not saving cache.`); + return; + } + try { + yield cache.saveCache(cacheDirs, primaryKey); + core.info(`Saved cache for golangci-lint from paths '${cacheDirs.join(`, `)}' in ${Date.now() - startedAt}ms`); + } + catch (error) { + if (error.name === cache.ValidationError.name) { + throw error; } - catch (error) { - if (error.name === cache.ValidationError.name) { - throw error; - } - else if (error.name === cache.ReserveCacheError.name) { - core.info(error.message); - } - else { - core.info(`[warning] ${error.message}`); - } + else if (error.name === cache.ReserveCacheError.name) { + core.info(error.message); + } + else { + core.info(`[warning] ${error.message}`); } } }); diff --git a/src/cache.ts b/src/cache.ts index a9be9e9..0a694b1 100644 --- a/src/cache.ts +++ b/src/cache.ts @@ -3,6 +3,9 @@ import * as core from "@actions/core" import * as crypto from "crypto" import * as fs from "fs" +import { Events, State } from "./constants" +import * as utils from "./utils/actionUtils" + function checksumFile(hashName: string, path: string): Promise { return new Promise((resolve, reject) => { const hash = crypto.createHash(hashName) @@ -51,6 +54,13 @@ async function buildCacheKeys(): Promise { } export async function restoreCache(): Promise { + if (!utils.isValidEvent()) { + utils.logWarning( + `Event Validation Error: The event type ${process.env[Events.Key]} is not supported because it's not tied to a branch or tag ref.` + ) + return + } + const startedAt = Date.now() const keys = await buildCacheKeys() @@ -59,39 +69,68 @@ export async function restoreCache(): Promise { // Tell golangci-lint to use our cache directory. process.env.GOLANGCI_LINT_CACHE = getLintCacheDir() - if (primaryKey !== undefined) { - try { - await cache.restoreCache(getCacheDirs(), primaryKey, restoreKeys) - core.info(`Restored cache for golangci-lint from key '${primaryKey}' in ${Date.now() - startedAt}ms`) - } catch (error) { - if (error.name === cache.ValidationError.name) { - throw error - } else { - core.warning(error.message) - } + + if (!primaryKey) { + utils.logWarning(`Invalid primary key`) + return + } + core.saveState(State.CachePrimaryKey, primaryKey) + try { + const cacheKey = await cache.restoreCache(getCacheDirs(), primaryKey, restoreKeys) + if (!cacheKey) { + core.info(`Cache not found for input keys: ${[primaryKey, ...restoreKeys].join(", ")}`) + return + } + // Store the matched cache key + utils.setCacheState(cacheKey) + const isExactKeyMatch = utils.isExactKeyMatch(primaryKey, cacheKey) + utils.setCacheHitOutput(isExactKeyMatch) + core.info(`Cache restored from key: ${cacheKey}`) + core.info(`Restored cache for golangci-lint from key '${primaryKey}' in ${Date.now() - startedAt}ms`) + } catch (error) { + if (error.name === cache.ValidationError.name) { + throw error + } else { + core.warning(error.message) } } } export async function saveCache(): Promise { + // Validate inputs, this can cause task failure + if (!utils.isValidEvent()) { + utils.logWarning( + `Event Validation Error: The event type ${process.env[Events.Key]} is not supported because it's not tied to a branch or tag ref.` + ) + return + } + const startedAt = Date.now() const cacheDirs = getCacheDirs() - const keys = await buildCacheKeys() - const primaryKey = keys.pop() + const primaryKey = core.getState(State.CachePrimaryKey) + if (!primaryKey) { + utils.logWarning(`Error retrieving key from state.`) + return + } - if (primaryKey !== undefined) { - try { - await cache.saveCache(cacheDirs, primaryKey) - core.info(`Saved cache for golangci-lint from paths '${cacheDirs.join(`, `)}' in ${Date.now() - startedAt}ms`) - } catch (error) { - if (error.name === cache.ValidationError.name) { - throw error - } else if (error.name === cache.ReserveCacheError.name) { - core.info(error.message) - } else { - core.info(`[warning] ${error.message}`) - } + const state = utils.getCacheState() + + if (utils.isExactKeyMatch(primaryKey, state)) { + core.info(`Cache hit occurred on the primary key ${primaryKey}, not saving cache.`) + return + } + + try { + await cache.saveCache(cacheDirs, primaryKey) + core.info(`Saved cache for golangci-lint from paths '${cacheDirs.join(`, `)}' in ${Date.now() - startedAt}ms`) + } catch (error) { + if (error.name === cache.ValidationError.name) { + throw error + } else if (error.name === cache.ReserveCacheError.name) { + core.info(error.message) + } else { + core.info(`[warning] ${error.message}`) } } } diff --git a/src/constants.ts b/src/constants.ts new file mode 100644 index 0000000..b2f3e57 --- /dev/null +++ b/src/constants.ts @@ -0,0 +1,22 @@ +export enum Inputs { + Key = "key", + Path = "path", + RestoreKeys = "restore-keys", +} + +export enum Outputs { + CacheHit = "cache-hit", +} + +export enum State { + CachePrimaryKey = "CACHE_KEY", + CacheMatchedKey = "CACHE_RESULT", +} + +export enum Events { + Key = "GITHUB_EVENT_NAME", + Push = "push", + PullRequest = "pull_request", +} + +export const RefKey = "GITHUB_REF" diff --git a/src/utils/actionUtils.ts b/src/utils/actionUtils.ts new file mode 100644 index 0000000..bd01a2a --- /dev/null +++ b/src/utils/actionUtils.ts @@ -0,0 +1,47 @@ +import * as core from "@actions/core" + +import { Outputs, RefKey, State } from "../constants" + +export function isExactKeyMatch(key: string, cacheKey?: string): boolean { + return !!( + cacheKey && + cacheKey.localeCompare(key, undefined, { + sensitivity: "accent", + }) === 0 + ) +} + +export function setCacheState(state: string): void { + core.saveState(State.CacheMatchedKey, state) +} + +export function setCacheHitOutput(isCacheHit: boolean): void { + core.setOutput(Outputs.CacheHit, isCacheHit.toString()) +} + +export function setOutputAndState(key: string, cacheKey?: string): void { + setCacheHitOutput(isExactKeyMatch(key, cacheKey)) + // Store the matched cache key if it exists + cacheKey && setCacheState(cacheKey) +} + +export function getCacheState(): string | undefined { + const cacheKey = core.getState(State.CacheMatchedKey) + if (cacheKey) { + core.debug(`Cache state/key: ${cacheKey}`) + return cacheKey + } + + return undefined +} + +export function logWarning(message: string): void { + const warningPrefix = "[warning]" + core.info(`${warningPrefix}${message}`) +} + +// Cache token authorized for all events that are tied to a ref +// See GitHub Context https://help.github.com/actions/automating-your-workflow-with-github-actions/contexts-and-expression-syntax-for-github-actions#github-context +export function isValidEvent(): boolean { + return RefKey in process.env && Boolean(process.env[RefKey]) +}