Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/test-action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -85,19 +85,19 @@ jobs:
- uses: jdx/mise-action@c37c93293d6b742fc901e1406b8f764f6fb19dac # v2.4.4
with:
version: 2025.7.12
- name: Cache Go modules with multiple restore keys
- name: Cache Go modules with fallback branch
id: cache-go
uses: ./
with:
path: |
~/go/pkg/mod
~/.cache/go-build
key: go-${{ runner.os }}-${{ hashFiles('**/go.sum') }}
key: go-${{ runner.os }}-${{ github.run_id }}
restore-keys: |
go-${{ runner.os }}-${{ hashFiles('**/go.mod') }}
go-${{ runner.os }}-
fail-on-cache-miss: false
fallback-branch: refs/heads/branch-2
fallback-to-default-branch: 'true'
environment: dev
backend: s3
- name: Check Go cache hit result
Expand Down
23 changes: 13 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ npm run build:guard-main # build credential-guard main only
npm run build:guard-post # build credential-guard post only
```

Bundled output goes to `credential-setup/dist/` and `credential-guard/dist/`. These must be committed since GitHub Actions runs them directly.
Bundled output goes to `credential-setup/dist/` and `credential-guard/dist/`.
These must be committed since GitHub Actions runs them directly.

## Usage

Expand All @@ -66,7 +67,7 @@ Bundled output goes to `credential-setup/dist/` and `credential-guard/dist/`. Th
| `path` | Files, directories, and wildcard patterns to cache | Yes | |
| `key` | Explicit key for restoring and saving cache | Yes | |
| `restore-keys` | Ordered list of prefix-matched keys for fallback | No | |
| `fallback-to-default-branch` | Automatically add a fallback restore key pointing to the default branch cache (S3 backend only). Disable if you want strict branch isolation. | No | `true` |
| `fallback-to-default-branch` | Automatically add a fallback restore key pointing to the default branch cache (S3 backend only). Disable if you want strict branch isolation. | No | `false` |
| `fallback-branch` | Optional maintenance branch for fallback restore keys (pattern: `branch-*`, S3 backend only). If not set, the repository default branch is used. | No | |
| `environment` | Environment to use (dev or prod, S3 backend only) | No | `prod` |
| `upload-chunk-size` | Chunk size for large file uploads (bytes) | No | |
Expand Down Expand Up @@ -119,11 +120,11 @@ A GitHub Action that provides branch-specific caching on AWS S3 with intelligent

The action searches for cache entries in this order:

1. **Primary key**: `${BRANCH_NAME}/${key}`
2. **Branch-specific restore keys**: `${BRANCH_NAME}/${restore-key}` (for each restore key provided)
3. **Default branch fallbacks** (when `fallback-to-default-branch: true`, the default):
- If `restore-keys` are provided: `refs/heads/${DEFAULT_BRANCH}/${restore-key}` for each restore key
- If no `restore-keys` are provided: `refs/heads/${DEFAULT_BRANCH}/${key}` (exact-match fallback)
1. **Primary key**: `${BRANCH_NAME}/${key}` (exact match)
2. **Default branch exact-match fallback** (when `fallback-to-default-branch: true`): `refs/heads/${DEFAULT_BRANCH}/${key}`
3. **Branch-specific restore keys** (if `restore-keys` provided): `${BRANCH_NAME}/${restore-key}` for each restore key (prefix match)
4. **Default branch restore key fallbacks** (if `restore-keys` provided):
`refs/heads/${DEFAULT_BRANCH}/${restore-key}` for each restore key (prefix match, lowest priority)

#### Example — with restore-keys

Expand All @@ -138,8 +139,9 @@ The action searches for cache entries in this order:
For a feature branch `feature/new-ui`, this will search for:

1. `feature/new-ui/node-linux-abc123...` (exact match)
2. `feature/new-ui/node-linux-` (branch-specific partial match)
3. `refs/heads/main/node-linux-` (default branch fallback, assuming `main` is the repository's default branch)
2. `refs/heads/main/node-linux-abc123...` (default branch fallback, exact match)
3. `feature/new-ui/node-linux-` (branch-specific prefix match)
4. `refs/heads/main/node-linux-` (default branch fallback, prefix match)

#### Example — without restore-keys

Expand Down Expand Up @@ -167,7 +169,8 @@ To disable the automatic default branch fallback:

#### Key Differences from Standard Cache Action

- **Automatic default branch fallback**: By default, feature branches fall back to the default branch cache when no branch-specific entry exists
- **Automatic default branch fallback**: By default, feature branches fall back to the default branch cache
when no branch-specific entry exists
- **Dynamic default branch detection**: The action detects your default branch using the GitHub API and uses it for fallback
- **Branch isolation**: Each branch maintains its own cache namespace, preventing cross-branch cache pollution

Expand Down
61 changes: 36 additions & 25 deletions scripts/prepare-keys.sh
Original file line number Diff line number Diff line change
Expand Up @@ -42,19 +42,6 @@ echo "branch-key=${BRANCH_KEY}" >> "$GITHUB_OUTPUT"

RESTORE_KEYS=""

# Process restore keys: add branch-specific keys
if [[ -n $INPUT_RESTORE_KEYS ]]; then
while IFS= read -r line; do
if [ -n "$line" ]; then
if [ -n "$RESTORE_KEYS" ]; then
RESTORE_KEYS="${RESTORE_KEYS}"$'\n'"${BRANCH_NAME}/${line}"
else
RESTORE_KEYS="${BRANCH_NAME}/${line}"
fi
fi
done <<< "$INPUT_RESTORE_KEYS"
fi

# Determine the fallback branch
if [[ -n "$INPUT_FALLBACK_BRANCH" ]]; then
# Explicit fallback-branch is always honoured, regardless of fallback-to-default-branch
Expand All @@ -66,23 +53,21 @@ elif [[ $INPUT_FALLBACK_TO_DEFAULT_BRANCH == "true" ]]; then
jq -r '.default_branch')
fi

# Build restore keys in priority order:
# 1. Fallback branch exact match (primary key re-scoped to fallback branch)
# 2. Branch-specific prefix matches (user's restore-keys scoped to current branch)
# 3. Fallback branch prefix matches (user's restore-keys re-scoped to fallback branch)

FALLBACK_EXACT_KEY=""
FALLBACK_ACTIVE=false

if [[ -n "${FALLBACK_BRANCH:-}" && "$FALLBACK_BRANCH" != "null" ]]; then
# Skip fallback if we're already on the fallback branch
CURRENT_BRANCH="${BRANCH_NAME#refs/heads/}"
if [[ "$CURRENT_BRANCH" != "$FALLBACK_BRANCH" ]]; then
case "$FALLBACK_BRANCH" in
main|master|branch-*)
if [[ -n $INPUT_RESTORE_KEYS ]]; then
# Add fallback branch restore keys for each user-provided restore key
while IFS= read -r line; do
if [[ -n "$line" ]]; then
RESTORE_KEYS="${RESTORE_KEYS}"$'\n'"refs/heads/${FALLBACK_BRANCH}/${line}"
fi
done <<< "$INPUT_RESTORE_KEYS"
else
# No restore keys provided: add exact-match fallback using the primary key
RESTORE_KEYS="refs/heads/${FALLBACK_BRANCH}/${INPUT_KEY}"
fi
FALLBACK_ACTIVE=true
FALLBACK_EXACT_KEY="refs/heads/${FALLBACK_BRANCH}/${INPUT_KEY}"
;;
*)
echo "::warning::Fallback branch '$FALLBACK_BRANCH' is not supported for cache fallback. Supported branches: main, master, branch-*"
Expand All @@ -93,6 +78,32 @@ elif [[ -n "$INPUT_FALLBACK_BRANCH" || $INPUT_FALLBACK_TO_DEFAULT_BRANCH == "tru
echo "::warning::Unable to determine fallback branch; skipping fallback restore keys."
fi

# Add fallback exact-match key first (highest priority restore key)
if [[ -n "$FALLBACK_EXACT_KEY" ]]; then
RESTORE_KEYS="$FALLBACK_EXACT_KEY"
fi

# Helper: append a prefixed restore key for each user-provided restore-key line
append_restore_keys() {
local prefix="$1"
while IFS= read -r line; do
if [[ -n "$line" ]]; then
RESTORE_KEYS="${RESTORE_KEYS:+${RESTORE_KEYS}$'\n'}${prefix}/${line}"
fi
done <<< "$INPUT_RESTORE_KEYS"
return 0
}

# Add branch-specific restore keys (prefix match)
if [[ -n $INPUT_RESTORE_KEYS ]]; then
append_restore_keys "$BRANCH_NAME"
fi

# Add fallback branch restore keys (prefix match, lowest priority)
if [[ $FALLBACK_ACTIVE == true && -n $INPUT_RESTORE_KEYS ]]; then
append_restore_keys "refs/heads/${FALLBACK_BRANCH}"
fi

if [[ -n "$RESTORE_KEYS" ]]; then
{
echo "branch-restore-keys<<EOF"
Expand Down
Loading