Skip to content

Commit

Permalink
feat: add custom cache key and cache restore key input (#47)
Browse files Browse the repository at this point in the history
* refactor: add github job id in cache primary key

* feat: add cache-restore-key action input

* refactor: allow list of restore keys

* docs: update README

* fix: append prefix on restore keys

* refactor: rename variable for better readability

* refactor: abstract primary and restore key gets

* chore: run build for dist

* chore: reduce verbose comments

* refactor: default to prefix + github.sha on bad input
  • Loading branch information
penandlim authored Mar 1, 2024
1 parent 362aa1b commit 8f1998e
Show file tree
Hide file tree
Showing 8 changed files with 365 additions and 27 deletions.
38 changes: 34 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,12 @@ jobs:
### Inputs
| **Name** | **Required** | **Default** | **Description** | **Type** |
| --------- | ------------ | ----------- | ------------------------------------------------------------------------------------------------------------ | -------- |
| `cache` | No | `true` | Whether to cache RPC responses or not. | bool |
| `version` | No | `nightly` | Version to install, e.g. `nightly` or `1.0.0`. **Note:** Foundry only has nightly builds for the time being. | string |
| **Name** | **Required** | **Default** | **Description** | **Type** |
| -------------------- | ------------ | ------------------------------------- | ------------------------------------------------------------------------------------------------------------ | -------- |
| `cache` | No | `true` | Whether to cache RPC responses or not. | bool |
| `version` | No | `nightly` | Version to install, e.g. `nightly` or `1.0.0`. **Note:** Foundry only has nightly builds for the time being. | string |
| `cache-key` | No | `${{ github.job }}-${{ github.sha }}` | The cache key to use for caching. | string |
| `cache-restore-keys` | No | `[${{ github.job }}-]` | The cache keys to use for restoring the cache. | string[] |

### RPC Caching

Expand All @@ -58,6 +60,34 @@ the `cache` input to `false`, like this:
cache: false
```

### Custom Cache Keys

You have the ability to define custom cache keys by utilizing the `cache-key` and `cache-restore-keys` inputs. This
feature is particularly beneficial when you aim to tailor the cache-sharing strategy across multiple jobs. It is
important to ensure that the `cache-key` is unique for each execution to prevent conflicts and guarantee successful
cache saving.

For instance, if you wish to utilize a shared cache between two distinct jobs, the following configuration can be
applied:

```yml
- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1
with:
cache-key: custom-seed-test-${{ github.sha }}
cache-restore-keys: |-
custom-seed-test-
custom-seed-
---
- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1
with:
cache-key: custom-seed-coverage-${{ github.sha }}
cache-restore-keys: |-
custom-seed-coverage-
custom-seed-
```

#### Deleting Caches

You can delete caches via the GitHub Actions user interface. Just go to your repo's "Actions" page:
Expand Down
15 changes: 15 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,21 @@ inputs:
Caching is activated by default.
required: false
cache-key:
default: "${{ github.job }}-${{ github.sha }}"
description: |
A custom cache key to use.
This key is used to identify the cache. If not provided, a default key consisting of the job id and the commit hash is used.
required: false
cache-restore-keys:
default: |-
${{ github.job }}-
description: |
Custom cache restore keys to use.
This key is used to identify the cache to restore. If not provided, a default key consisting of the job id is used.
required: false
version:
default: "nightly"
description: |
Expand Down
125 changes: 118 additions & 7 deletions dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -86178,32 +86178,98 @@ const github = __nccwpck_require__(5438);
const fs = __nccwpck_require__(7147);
const os = __nccwpck_require__(2037);
const path = __nccwpck_require__(1017);
const { State } = __nccwpck_require__(4438);

// Define constants for cache paths and prefix
const HOME = os.homedir();
const PLATFORM = os.platform();
const CACHE_PATHS = [path.join(HOME, ".foundry/cache/rpc")];
const CACHE_PREFIX = `${PLATFORM}-foundry-chain-fork-`;

/**
* Constructs the primary key for the cache using a custom key input.
* @param {string} customKeyInput - The custom part of the key provided by the user.
* @returns {string} The complete primary key for the cache.
*/
function getPrimaryKey(customKeyInput) {
if (!customKeyInput) {
return `${CACHE_PREFIX}${github.context.sha}`;
}
return `${CACHE_PREFIX}${customKeyInput.trim()}`;
}

/**
* Constructs an array of restore keys based on user input and a default prefix.
* @param {string} customRestoreKeysInput - Newline-separated string of custom restore keys.
* @returns {string[]} An array of restore keys for the cache.
*/
function getRestoreKeys(customRestoreKeysInput) {
const defaultRestoreKeys = [CACHE_PREFIX];
if (!customRestoreKeysInput) {
return defaultRestoreKeys;
}
const restoreKeys = customRestoreKeysInput
.split(/[\r\n]/)
.map((input) => input.trim())
.filter((input) => input !== "")
.map((input) => `${CACHE_PREFIX}${input}`);
return [...restoreKeys, ...defaultRestoreKeys];
}

/**
* Restores the RPC cache using the provided keys.
*/
async function restoreRPCCache() {
const primaryKey = PLATFORM + "-foundry-chain-fork-" + github.context.sha;
const restoreKeys = [PLATFORM + "-foundry-chain-fork-"];
const cacheKey = await cache.restoreCache(CACHE_PATHS, primaryKey, restoreKeys);
if (!cacheKey) {
const customKeyInput = core.getInput("cache-key");
const primaryKey = getPrimaryKey(customKeyInput);
core.saveState(State.CachePrimaryKey, primaryKey);

const customRestoreKeysInput = core.getInput("cache-restore-keys");
const restoreKeys = getRestoreKeys(customRestoreKeysInput);
const matchedKey = await cache.restoreCache(CACHE_PATHS, primaryKey, restoreKeys);

if (!matchedKey) {
core.info("Cache not found");
return;
}
core.info(`Cache restored from key: ${cacheKey}`);

core.saveState(State.CacheMatchedKey, matchedKey);
core.info(`Cache restored from key: ${matchedKey}`);
}

/**
* Saves the RPC cache using the primary key saved in the state.
* If the cache was already saved with the primary key, it will not save it again.
*/
async function saveCache() {
const primaryKey = PLATFORM + "-foundry-chain-fork-" + github.context.sha;
const primaryKey = core.getState(State.CachePrimaryKey);
const matchedKey = core.getState(State.CacheMatchedKey);

// If the cache path does not exist, do not save the cache
if (!fs.existsSync(CACHE_PATHS[0])) {
core.info(`Cache path does not exist, not saving cache : ${CACHE_PATHS[0]}`);
core.info(`Cache path does not exist, not saving cache: ${CACHE_PATHS[0]}`);
return;
}

// If the primary key is not generated, do not save the cache
if (!primaryKey) {
core.info("Primary key was not generated. Please check the log messages above for more errors or information");
return;
}

// If the primary key and the matched key are the same, this means the cache was already saved
if (primaryKey === matchedKey) {
core.info(`Cache hit occurred on the primary key ${primaryKey}, not saving cache.`);
return;
}

const cacheId = await cache.saveCache(CACHE_PATHS, primaryKey);

// If the cacheId is -1, the saving failed with an error message log. No additional logging is needed.
if (cacheId === -1) {
return;
}

core.info(`Cache saved with the key: ${primaryKey}`);
}

Expand All @@ -86213,6 +86279,23 @@ module.exports = {
};


/***/ }),

/***/ 4438:
/***/ ((__unused_webpack_module, __webpack_exports__, __nccwpck_require__) => {

"use strict";
__nccwpck_require__.r(__webpack_exports__);
/* harmony export */ __nccwpck_require__.d(__webpack_exports__, {
/* harmony export */ "State": () => (/* binding */ State)
/* harmony export */ });
// Enum for the cache primary key and result key.
const State = {
CachePrimaryKey: "CACHE_KEY",
CacheMatchedKey: "CACHE_RESULT",
};


/***/ }),

/***/ 4351:
Expand Down Expand Up @@ -86610,6 +86693,34 @@ module.exports = JSON.parse('[[[0,44],"disallowed_STD3_valid"],[[45,46],"valid"]
/******/ }
/******/
/************************************************************************/
/******/ /* webpack/runtime/define property getters */
/******/ (() => {
/******/ // define getter functions for harmony exports
/******/ __nccwpck_require__.d = (exports, definition) => {
/******/ for(var key in definition) {
/******/ if(__nccwpck_require__.o(definition, key) && !__nccwpck_require__.o(exports, key)) {
/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
/******/ }
/******/ }
/******/ };
/******/ })();
/******/
/******/ /* webpack/runtime/hasOwnProperty shorthand */
/******/ (() => {
/******/ __nccwpck_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
/******/ })();
/******/
/******/ /* webpack/runtime/make namespace object */
/******/ (() => {
/******/ // define __esModule on exports
/******/ __nccwpck_require__.r = (exports) => {
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ }
/******/ Object.defineProperty(exports, '__esModule', { value: true });
/******/ };
/******/ })();
/******/
/******/ /* webpack/runtime/compat */
/******/
/******/ if (typeof __nccwpck_require__ !== 'undefined') __nccwpck_require__.ab = __dirname + "/";
Expand Down
2 changes: 1 addition & 1 deletion dist/index.js.map

Large diffs are not rendered by default.

Loading

0 comments on commit 8f1998e

Please sign in to comment.