Skip to content

Commit 59847de

Browse files
committed
BUILD-10699: Adds fallback-to-default-branch option for auto setting restore-keys to default branch
1 parent 52e7096 commit 59847de

File tree

3 files changed

+105
-45
lines changed

3 files changed

+105
-45
lines changed

README.md

Lines changed: 42 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -65,14 +65,15 @@ Bundled output goes to `credential-setup/dist/` and `credential-guard/dist/`. Th
6565
|------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------|----------|---------|
6666
| `path` | Files, directories, and wildcard patterns to cache | Yes | |
6767
| `key` | Explicit key for restoring and saving cache | Yes | |
68-
| `restore-keys` | Ordered list of prefix-matched keys for fallback | No | |
69-
| `fallback-branch` | Optional maintenance branch for fallback restore keys (pattern: `branch-*`, S3 backend only). If not set, the repository default branch is used. | No | |
70-
| `environment` | Environment to use (dev or prod, S3 backend only) | No | `prod` |
71-
| `upload-chunk-size` | Chunk size for large file uploads (bytes) | No | |
72-
| `enableCrossOsArchive` | Enable cross-OS cache compatibility | No | `false` |
73-
| `fail-on-cache-miss` | Fail workflow if cache entry not found | No | `false` |
74-
| `lookup-only` | Only check cache existence without downloading | No | `false` |
75-
| `backend` | Force specific backend: `github` or `s3`. Takes priority over `CACHE_BACKEND` env var and auto-detection. | No | |
68+
| `restore-keys` | Ordered list of prefix-matched keys for fallback | No | |
69+
| `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` |
70+
| `fallback-branch` | Optional maintenance branch for fallback restore keys (pattern: `branch-*`, S3 backend only). If not set, the repository default branch is used. | No | |
71+
| `environment` | Environment to use (dev or prod, S3 backend only) | No | `prod` |
72+
| `upload-chunk-size` | Chunk size for large file uploads (bytes) | No | |
73+
| `enableCrossOsArchive` | Enable cross-OS cache compatibility | No | `false` |
74+
| `fail-on-cache-miss` | Fail workflow if cache entry not found | No | `false` |
75+
| `lookup-only` | Only check cache existence without downloading | No | `false` |
76+
| `backend` | Force specific backend: `github` or `s3`. Takes priority over `CACHE_BACKEND` env var and auto-detection. | No | |
7677

7778
## Backend Selection
7879

@@ -114,20 +115,17 @@ A GitHub Action that provides branch-specific caching on AWS S3 with intelligent
114115

115116
### How Restore Keys Work
116117

117-
**Important**: This action's restore key behavior differs from the standard GitHub cache action.
118-
To enable fallback to default branch caches, you **must** use the `restore-keys` property.
119-
120118
#### Cache Key Resolution Order
121119

122-
When you provide `restore-keys`, the action searches for cache entries in this order:
120+
The action searches for cache entries in this order:
123121

124122
1. **Primary key**: `${BRANCH_NAME}/${key}`
125-
2. **Branch-specific restore keys**: `${BRANCH_NAME}/${restore-key}` (for each restore key)
126-
3. **Default branch fallbacks**:
127-
- `refs/heads/${DEFAULT_BRANCH}/${restore-key}` (for each restore key, where `DEFAULT_BRANCH` is dynamically obtained from the
128-
repository)
123+
2. **Branch-specific restore keys**: `${BRANCH_NAME}/${restore-key}` (for each restore key provided)
124+
3. **Default branch fallbacks** (when `fallback-to-default-branch: true`, the default):
125+
- If `restore-keys` are provided: `refs/heads/${DEFAULT_BRANCH}/${restore-key}` for each restore key
126+
- If no `restore-keys` are provided: `refs/heads/${DEFAULT_BRANCH}/${key}` (exact-match fallback)
129127

130-
#### Example
128+
#### Example — with restore-keys
131129

132130
```yaml
133131
- uses: SonarSource/gh-action_cache@v1
@@ -140,12 +138,36 @@ When you provide `restore-keys`, the action searches for cache entries in this o
140138
For a feature branch `feature/new-ui`, this will search for:
141139

142140
1. `feature/new-ui/node-linux-abc123...` (exact match)
143-
2. `feature/new-ui/node-linux` (branch-specific partial match)
144-
3. `refs/heads/main/node-linux` (default branch fallback, assuming `main` is the repository's default branch)
141+
2. `feature/new-ui/node-linux-` (branch-specific partial match)
142+
3. `refs/heads/main/node-linux-` (default branch fallback, assuming `main` is the repository's default branch)
143+
144+
#### Example — without restore-keys
145+
146+
```yaml
147+
- uses: SonarSource/gh-action_cache@v1
148+
with:
149+
path: ~/.npm
150+
key: node-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}
151+
```
152+
153+
For a feature branch `feature/new-ui`, this will search for:
154+
155+
1. `feature/new-ui/node-linux-abc123...` (exact match)
156+
2. `refs/heads/main/node-linux-abc123...` (exact-match fallback on default branch)
157+
158+
To disable the automatic default branch fallback:
159+
160+
```yaml
161+
- uses: SonarSource/gh-action_cache@v1
162+
with:
163+
path: ~/.npm
164+
key: node-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}
165+
fallback-to-default-branch: false
166+
```
145167

146168
#### Key Differences from Standard Cache Action
147169

148-
- **Fallback requires restore-keys**: Without `restore-keys`, the action only looks for branch-specific cache entries
170+
- **Automatic default branch fallback**: By default, feature branches fall back to the default branch cache when no branch-specific entry exists
149171
- **Dynamic default branch detection**: The action detects your default branch using the GitHub API and uses it for fallback
150172
- **Branch isolation**: Each branch maintains its own cache namespace, preventing cross-branch cache pollution
151173

action.yml

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,15 @@ inputs:
2626
description: Environment to use ('dev' or 'prod', 's3' backend only).
2727
default: prod
2828
fallback-branch:
29-
description: Optional maintenance branch for fallback restore keys (pattern 'branch-*', 's3' backend only). If not set, the repository
30-
default branch is used.
29+
description: >
30+
Explicit fallback branch for restore keys (pattern 'branch-*', 's3' backend only).
31+
Always honoured when set, regardless of 'fallback-to-default-branch'.
32+
If not set, the repository default branch is used when 'fallback-to-default-branch' is true.
33+
fallback-to-default-branch:
34+
description: >
35+
When enabled, automatically adds a fallback restore key pointing to the default branch cache.
36+
Only applies to the S3 backend.
37+
default: 'true'
3138
backend:
3239
description: >
3340
Force cache backend ('github' or 's3'). If not set, falls back to the CACHE_BACKEND environment variable if defined,
@@ -109,6 +116,7 @@ runs:
109116
INPUT_KEY: ${{ inputs.key }}
110117
INPUT_RESTORE_KEYS: ${{ inputs.restore-keys }}
111118
INPUT_FALLBACK_BRANCH: ${{ inputs.fallback-branch }}
119+
INPUT_FALLBACK_TO_DEFAULT_BRANCH: ${{ inputs.fallback-to-default-branch }}
112120
GITHUB_TOKEN: ${{ github.token }}
113121
GITHUB_REPOSITORY: ${{ github.repository }}
114122
run: $ACTION_PATH_CACHE/scripts/prepare-keys.sh

scripts/prepare-keys.sh

Lines changed: 53 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,39 @@ set -euo pipefail
1111
# Optional environment variables:
1212
# - INPUT_RESTORE_KEYS: Multi-line list of restore key prefixes
1313
# - INPUT_FALLBACK_BRANCH: Maintenance branch for fallback restore keys (pattern: branch-*)
14+
# - INPUT_FALLBACK_TO_DEFAULT_BRANCH: When 'true', add fallback restore key on the default branch (default: true)
1415
# - GITHUB_HEAD_REF: Branch name for PR events
1516
# - GITHUB_REF: Branch ref for push events
1617
# - GITHUB_TOKEN: GitHub token for API authentication
1718
# - GITHUB_REPOSITORY: Repository in owner/repo format
19+
# This script prepares cache keys with branch-specific paths and fallback logic (for the S3 backend only).
20+
#
21+
# Required inputs (must be explicitly provided):
22+
# - INPUT_KEY: The primary cache key
23+
#
24+
# GitHub Actions auto-provided:
25+
# - GITHUB_OUTPUT: File path for GitHub Actions output
26+
# - GITHUB_HEAD_REF: Branch name for PR events
27+
# - GITHUB_REF: Branch ref for push events
28+
# - GITHUB_TOKEN: GitHub token for API authentication
29+
#
30+
# Optional user customization:
31+
# - INPUT_RESTORE_KEYS: Multi-line list of restore key prefixes
32+
# - INPUT_FALLBACK_BRANCH: Maintenance branch for fallback restore keys (pattern: branch-*)
33+
# - INPUT_FALLBACK_TO_DEFAULT_BRANCH: Whether to add fallback restore key on the default branch (default: true)
34+
35+
: "${INPUT_KEY:?}" "${GITHUB_OUTPUT:?}" "${GITHUB_REF:?}" "${GITHUB_TOKEN:?}" "${GITHUB_REPOSITORY:?}"
36+
: "${INPUT_RESTORE_KEYS:=}" "${INPUT_FALLBACK_BRANCH:=}" "${INPUT_FALLBACK_TO_DEFAULT_BRANCH:=true}"
1837

1938
# Use GITHUB_HEAD_REF for PR events, GITHUB_REF for push events
2039
BRANCH_NAME="${GITHUB_HEAD_REF:-$GITHUB_REF}"
2140
BRANCH_KEY="${BRANCH_NAME}/${INPUT_KEY}"
2241
echo "branch-key=${BRANCH_KEY}" >> "$GITHUB_OUTPUT"
2342

24-
# Process restore keys: keep branch-specific keys and add fallback to default branch
25-
if [[ -n "${INPUT_RESTORE_KEYS:-}" ]]; then
26-
RESTORE_KEYS=""
27-
# First, add branch-specific restore keys
43+
RESTORE_KEYS=""
44+
45+
# Process restore keys: add branch-specific keys
46+
if [[ -n $INPUT_RESTORE_KEYS ]]; then
2847
while IFS= read -r line; do
2948
if [ -n "$line" ]; then
3049
if [ -n "$RESTORE_KEYS" ]; then
@@ -34,36 +53,47 @@ if [[ -n "${INPUT_RESTORE_KEYS:-}" ]]; then
3453
fi
3554
fi
3655
done <<< "$INPUT_RESTORE_KEYS"
56+
fi
3757

38-
FALLBACK_BRANCH_INPUT="${INPUT_FALLBACK_BRANCH:-}"
39-
40-
if [[ -n "$FALLBACK_BRANCH_INPUT" ]]; then
41-
FALLBACK_BRANCH="${FALLBACK_BRANCH_INPUT#refs/heads/}"
42-
else
43-
# Query GitHub API to get the default branch
44-
FALLBACK_BRANCH=$(curl -s -H "Authorization: token ${GITHUB_TOKEN}" \
45-
"https://api.github.com/repos/${GITHUB_REPOSITORY}" | \
46-
jq -r '.default_branch')
47-
fi
58+
# Determine the fallback branch
59+
if [[ -n "$INPUT_FALLBACK_BRANCH" ]]; then
60+
# Explicit fallback-branch is always honoured, regardless of fallback-to-default-branch
61+
FALLBACK_BRANCH="${INPUT_FALLBACK_BRANCH#refs/heads/}"
62+
elif [[ $INPUT_FALLBACK_TO_DEFAULT_BRANCH == "true" ]]; then
63+
# Query GitHub API to get the default branch
64+
FALLBACK_BRANCH=$(curl -s -H "Authorization: token ${GITHUB_TOKEN}" \
65+
"https://api.github.com/repos/${GITHUB_REPOSITORY}" | \
66+
jq -r '.default_branch')
67+
fi
4868

49-
if [[ -n "$FALLBACK_BRANCH" && "$FALLBACK_BRANCH" != "null" ]]; then
69+
if [[ -n "${FALLBACK_BRANCH:-}" && "$FALLBACK_BRANCH" != "null" ]]; then
70+
# Skip fallback if we're already on the fallback branch
71+
CURRENT_BRANCH="${BRANCH_NAME#refs/heads/}"
72+
if [[ "$CURRENT_BRANCH" != "$FALLBACK_BRANCH" ]]; then
5073
case "$FALLBACK_BRANCH" in
5174
main|master|branch-*)
52-
# Add fallback branch restore keys
53-
while IFS= read -r line; do
54-
if [[ -n "$line" ]]; then
55-
RESTORE_KEYS="${RESTORE_KEYS}"$'\n'"refs/heads/${FALLBACK_BRANCH}/${line}"
56-
fi
57-
done <<< "$INPUT_RESTORE_KEYS"
75+
if [[ -n $INPUT_RESTORE_KEYS ]]; then
76+
# Add fallback branch restore keys for each user-provided restore key
77+
while IFS= read -r line; do
78+
if [[ -n "$line" ]]; then
79+
RESTORE_KEYS="${RESTORE_KEYS}"$'\n'"refs/heads/${FALLBACK_BRANCH}/${line}"
80+
fi
81+
done <<< "$INPUT_RESTORE_KEYS"
82+
else
83+
# No restore keys provided: add exact-match fallback using the primary key
84+
RESTORE_KEYS="refs/heads/${FALLBACK_BRANCH}/${INPUT_KEY}"
85+
fi
5886
;;
5987
*)
6088
echo "::warning::Fallback branch '$FALLBACK_BRANCH' is not supported for cache fallback. Supported branches: main, master, branch-*"
6189
;;
6290
esac
63-
else
64-
echo "::warning::Unable to determine fallback branch; skipping fallback restore keys."
6591
fi
92+
elif [[ -n "$INPUT_FALLBACK_BRANCH" || $INPUT_FALLBACK_TO_DEFAULT_BRANCH == "true" ]]; then
93+
echo "::warning::Unable to determine fallback branch; skipping fallback restore keys."
94+
fi
6695

96+
if [[ -n "$RESTORE_KEYS" ]]; then
6797
{
6898
echo "branch-restore-keys<<EOF"
6999
echo "$RESTORE_KEYS"

0 commit comments

Comments
 (0)