Skip to content

Commit

Permalink
feat: hash length configuration
Browse files Browse the repository at this point in the history
Add hash-length configuration option which controls the length of the
hash components.

Fixes #97
  • Loading branch information
stevenh committed May 17, 2023
1 parent 68377a4 commit 613631f
Show file tree
Hide file tree
Showing 6 changed files with 91 additions and 7 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
@@ -1,8 +1,9 @@
# Changelog

## 2.3.1
## 2.4.0

- Fix cache key stability.
- Add `hash-length` option, which provides control over the length of hash components.

## 2.3.0

Expand Down
5 changes: 5 additions & 0 deletions README.md
Expand Up @@ -65,6 +65,11 @@ sensible defaults.
# Useful for jobs where the matrix is additive e.g. additional Cargo features.
# default: "true"
save-if: ""

# The length of the hash components used to identify the cache.
# If `0`, the full hash is used."
# default: "0"
hash-length: ""
```

Further examples are available in the [.github/workflows](./.github/workflows/) directory.
Expand Down
4 changes: 4 additions & 0 deletions action.yml
Expand Up @@ -36,6 +36,10 @@ inputs:
description: "Determiners whether the cache should be saved. If `false`, the cache is only restored."
required: false
default: "true"
hash-length:
description: "The length of the hash components used to identify the cache. If `0`, the full hash is used."
required: false
default: "0"
outputs:
cache-hit:
description: "A boolean value that indicates an exact match was found."
Expand Down
28 changes: 26 additions & 2 deletions dist/restore/index.js
Expand Up @@ -60064,6 +60064,15 @@ class CacheConfig {
.map((w) => new Workspace(w.root, w.target));
return self;
}
let hashLenInput = lib_core.getInput("hash-length");
let hashLen = 0;
if (hashLenInput) {
hashLen = parseInt(hashLenInput, 10);
if (isNaN(hashLen)) {
lib_core.error(`Invalid hash-length: "${hashLenInput}" ignoring`);
hashLen = 0;
}
}
// Construct key prefix:
// This uses either the `shared-key` input,
// or the `key` input combined with the `job` key.
Expand Down Expand Up @@ -60111,7 +60120,7 @@ class CacheConfig {
}
}
self.keyEnvs = keyEnvs;
key += `-${hasher.digest("hex")}`;
key += `-${digest(hasher, hashLen)}`;
self.restoreKey = key;
// Construct the lockfiles portion of the key:
// This considers all the files found via globbing for various manifests
Expand Down Expand Up @@ -60140,7 +60149,7 @@ class CacheConfig {
hasher.update(chunk);
}
}
let lockHash = hasher.digest("hex");
let lockHash = digest(hasher, hashLen);
self.keyFiles = keyFiles;
key += `-${lockHash}`;
self.cacheKey = key;
Expand Down Expand Up @@ -60203,6 +60212,21 @@ class CacheConfig {
function isCacheUpToDate() {
return core.getState(STATE_CONFIG) === "";
}
/**
* Returns a hex digest of the given hasher.
* If `length` is `0`, the full digest is returned.
* Otherwise, the digest is truncated to the given length.
*
* @param hasher The hasher to digest.
* @param length The length of the digest.
* @returns The hex digest.
*/
function digest(hasher, length) {
if (length == 0) {
return hasher.digest("hex");
}
return hasher.digest("hex").substring(0, length);
}
async function getRustVersion() {
const stdout = await getCmdOutput("rustc", ["-vV"]);
let splits = stdout
Expand Down
28 changes: 26 additions & 2 deletions dist/save/index.js
Expand Up @@ -60064,6 +60064,15 @@ class CacheConfig {
.map((w) => new Workspace(w.root, w.target));
return self;
}
let hashLenInput = core.getInput("hash-length");
let hashLen = 0;
if (hashLenInput) {
hashLen = parseInt(hashLenInput, 10);
if (isNaN(hashLen)) {
core.error(`Invalid hash-length: "${hashLenInput}" ignoring`);
hashLen = 0;
}
}
// Construct key prefix:
// This uses either the `shared-key` input,
// or the `key` input combined with the `job` key.
Expand Down Expand Up @@ -60111,7 +60120,7 @@ class CacheConfig {
}
}
self.keyEnvs = keyEnvs;
key += `-${hasher.digest("hex")}`;
key += `-${digest(hasher, hashLen)}`;
self.restoreKey = key;
// Construct the lockfiles portion of the key:
// This considers all the files found via globbing for various manifests
Expand Down Expand Up @@ -60140,7 +60149,7 @@ class CacheConfig {
hasher.update(chunk);
}
}
let lockHash = hasher.digest("hex");
let lockHash = digest(hasher, hashLen);
self.keyFiles = keyFiles;
key += `-${lockHash}`;
self.cacheKey = key;
Expand Down Expand Up @@ -60203,6 +60212,21 @@ class CacheConfig {
function isCacheUpToDate() {
return core.getState(STATE_CONFIG) === "";
}
/**
* Returns a hex digest of the given hasher.
* If `length` is `0`, the full digest is returned.
* Otherwise, the digest is truncated to the given length.
*
* @param hasher The hasher to digest.
* @param length The length of the digest.
* @returns The hex digest.
*/
function digest(hasher, length) {
if (length == 0) {
return hasher.digest("hex");
}
return hasher.digest("hex").substring(0, length);
}
async function getRustVersion() {
const stdout = await getCmdOutput("rustc", ["-vV"]);
let splits = stdout
Expand Down
30 changes: 28 additions & 2 deletions src/config.ts
Expand Up @@ -56,6 +56,16 @@ export class CacheConfig {
return self;
}

let hashLenInput = core.getInput("hash-length");
let hashLen = 0;
if (hashLenInput) {
hashLen = parseInt(hashLenInput, 10);
if (isNaN(hashLen)) {
core.error(`Invalid hash-length: "${hashLenInput}" ignoring`);
hashLen = 0;
}
}

// Construct key prefix:
// This uses either the `shared-key` input,
// or the `key` input combined with the `job` key.
Expand Down Expand Up @@ -114,7 +124,7 @@ export class CacheConfig {

self.keyEnvs = keyEnvs;

key += `-${hasher.digest("hex")}`;
key += `-${digest(hasher, hashLen)}`;

self.restoreKey = key;

Expand Down Expand Up @@ -153,7 +163,7 @@ export class CacheConfig {
hasher.update(chunk);
}
}
let lockHash = hasher.digest("hex");
let lockHash = digest(hasher, hashLen);

self.keyFiles = keyFiles;

Expand Down Expand Up @@ -226,6 +236,22 @@ export function isCacheUpToDate(): boolean {
return core.getState(STATE_CONFIG) === "";
}

/**
* Returns a hex digest of the given hasher.
* If `length` is `0`, the full digest is returned.
* Otherwise, the digest is truncated to the given length.
*
* @param hasher The hasher to digest.
* @param length The length of the digest.
* @returns The hex digest.
*/
function digest(hasher: crypto.Hash, length: number): string {
if (length == 0) {
return hasher.digest("hex");
}
return hasher.digest("hex").substring(0, length);
}

interface RustVersion {
host: string;
release: string;
Expand Down

0 comments on commit 613631f

Please sign in to comment.