Replace actions/cache@v5 with local implementation, simplify key inputs
- Remove actions/cache@v5 dependency, implement cache API calls directly using curl, tar, and zstd against Gitea's /_apis/artifactcache/ API - Drop 'key' input, add required 'key-prefix' and 'key-file' inputs - Cache key is generated as key-prefix-<sha256-of-key-file> - Update README with revised inputs and Rust-only examples
This commit is contained in:
+218
-21
@@ -5,13 +5,12 @@ inputs:
|
||||
description: 'A list of files, directories, or wildcard patterns to cache. Defaults to ~/.cache/'
|
||||
required: false
|
||||
default: '~/.cache/'
|
||||
key:
|
||||
description: 'An explicit key for a cache entry. Defaults to runner.os-cache-{hash}'
|
||||
required: false
|
||||
key-prefix:
|
||||
description: 'Prefix for the cache key, combined with key-file hash'
|
||||
required: true
|
||||
key-file:
|
||||
description: 'The file to hash for generating the cache key. Used if key is not provided.'
|
||||
required: false
|
||||
default: ''
|
||||
description: 'The file to hash for generating the cache key'
|
||||
required: true
|
||||
restore-keys:
|
||||
description: 'An ordered list of prefix-matched keys for restoring stale cache'
|
||||
required: false
|
||||
@@ -20,29 +19,227 @@ outputs:
|
||||
cache-hit:
|
||||
description: 'A boolean value to indicate an exact match was found for the key'
|
||||
value: ${{ steps.restore-cache.outputs.cache-hit }}
|
||||
cache-primary-key:
|
||||
description: 'The primary key used for cache lookup'
|
||||
value: ${{ steps.restore-cache.outputs.cache-primary-key }}
|
||||
cache-matched-key:
|
||||
description: 'The key of the cache entry that was restored'
|
||||
value: ${{ steps.restore-cache.outputs.cache-matched-key }}
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Generate cache key
|
||||
id: gen-key
|
||||
if: inputs.key == ''
|
||||
shell: bash
|
||||
run: |
|
||||
if [ -n "${{ inputs.key-file }}" ]; then
|
||||
KEY_HASH=$(sha256sum "${{ inputs.key-file }}" | awk '{print $1}')
|
||||
else
|
||||
KEY_HASH=$(find . -type f \( -name "*.csproj" -o -name "*.sln" -o -name "package.json" -o -name "package-lock.json" -o -name "yarn.lock" -o -name "pnpm-lock.yaml" -o -name "Cargo.lock" -o -name "requirements.txt" -o -name "Pipfile.lock" -o -name "go.mod" -o -name "go.sum" -o -name "pom.xml" -o -name "build.gradle*" -o -name "Gemfile.lock" -o -name "composer.lock" \) -exec sha256sum {} + 2>/dev/null | sha256sum | awk '{print $1}')
|
||||
if [ "$KEY_HASH" = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" ]; then
|
||||
KEY_HASH=$(find . -type f -not -path './.git/*' -not -path './.cache/*' | sort | xargs sha256sum 2>/dev/null | sha256sum | awk '{print $1}')
|
||||
fi
|
||||
fi
|
||||
echo "cache-key=${{ runner.os }}-cache-${KEY_HASH}" >> $GITHUB_OUTPUT
|
||||
KEY_HASH=$(sha256sum "${{ inputs.key-file }}" | awk '{print $1}')
|
||||
echo "cache-key=${{ inputs.key-prefix }}-${KEY_HASH}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Restore cache
|
||||
id: restore-cache
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ${{ inputs.path }}
|
||||
key: ${{ inputs.key != '' && inputs.key || steps.gen-key.outputs.cache-key }}
|
||||
restore-keys: ${{ inputs.restore-keys != '' && inputs.restore-keys || format('{0}-cache-', runner.os) }}
|
||||
shell: bash
|
||||
env:
|
||||
CACHE_KEY: ${{ steps.gen-key.outputs.cache-key }}
|
||||
RESTORE_KEYS: ${{ inputs.restore-keys }}
|
||||
CACHE_PATH: ${{ inputs.path }}
|
||||
run: |
|
||||
CACHE_URL="${ACTIONS_CACHE_URL:-${ACTIONS_RUNTIME_URL:-}}"
|
||||
TOKEN="${ACTIONS_RUNTIME_TOKEN:-}"
|
||||
|
||||
if [ -z "$CACHE_URL" ] || [ -z "$TOKEN" ]; then
|
||||
echo "::warning::Cache environment variables not set. Skipping cache restore."
|
||||
echo "cache-hit=false" >> $GITHUB_OUTPUT
|
||||
echo "cache-primary-key=${CACHE_KEY}" >> $GITHUB_OUTPUT
|
||||
echo "cache-matched-key=" >> $GITHUB_OUTPUT
|
||||
exit 0
|
||||
fi
|
||||
|
||||
CACHE_URL="${CACHE_URL%/}/"
|
||||
API_BASE="${CACHE_URL}_apis/artifactcache/"
|
||||
|
||||
EXPANDED_PATH=$(eval echo "$CACHE_PATH")
|
||||
PATHS_HASH=$(echo "$EXPANDED_PATH" | sha256sum | awk '{print $1}')
|
||||
CACHE_VERSION="zstd-${PATHS_HASH}"
|
||||
|
||||
PRIMARY_KEY="${CACHE_KEY}"
|
||||
|
||||
KEYS="$PRIMARY_KEY"
|
||||
if [ -n "$RESTORE_KEYS" ]; then
|
||||
while IFS= read -r rk; do
|
||||
if [ -n "$rk" ]; then
|
||||
KEYS="${KEYS},${rk}"
|
||||
fi
|
||||
done <<< "$RESTORE_KEYS"
|
||||
fi
|
||||
|
||||
ENCODED_KEYS=$(echo "$KEYS" | sed 's/,/%2C/g')
|
||||
|
||||
echo "Looking up cache with keys: ${KEYS}"
|
||||
|
||||
HTTP_CODE=$(mktemp)
|
||||
CACHE_ENTRY=$(mktemp)
|
||||
curl -sL -w "%{http_code}" -o "$CACHE_ENTRY" \
|
||||
-H "Authorization: Bearer ${TOKEN}" \
|
||||
"${API_BASE}cache?keys=${ENCODED_KEYS}&version=${CACHE_VERSION}" \
|
||||
2>/dev/null > "$HTTP_CODE" || true
|
||||
|
||||
STATUS=$(cat "$HTTP_CODE")
|
||||
rm -f "$HTTP_CODE"
|
||||
|
||||
if [ "$STATUS" = "204" ] || [ "$STATUS" = "404" ] || [ ! -s "$CACHE_ENTRY" ]; then
|
||||
echo "Cache not found for keys: ${KEYS}"
|
||||
rm -f "$CACHE_ENTRY"
|
||||
echo "cache-hit=false" >> $GITHUB_OUTPUT
|
||||
echo "cache-primary-key=${PRIMARY_KEY}" >> $GITHUB_OUTPUT
|
||||
echo "cache-matched-key=" >> $GITHUB_OUTPUT
|
||||
exit 0
|
||||
fi
|
||||
|
||||
ARCHIVE_LOCATION=$(grep -o '"archiveLocation":"[^"]*"' "$CACHE_ENTRY" | head -1 | cut -d'"' -f4)
|
||||
MATCHED_KEY=$(grep -o '"cacheKey":"[^"]*"' "$CACHE_ENTRY" | head -1 | cut -d'"' -f4)
|
||||
rm -f "$CACHE_ENTRY"
|
||||
|
||||
if [ -z "$ARCHIVE_LOCATION" ]; then
|
||||
echo "Cache not found (no archive location)"
|
||||
echo "cache-hit=false" >> $GITHUB_OUTPUT
|
||||
echo "cache-primary-key=${PRIMARY_KEY}" >> $GITHUB_OUTPUT
|
||||
echo "cache-matched-key=" >> $GITHUB_OUTPUT
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "Cache found with key: ${MATCHED_KEY}"
|
||||
|
||||
EXACT_HIT="false"
|
||||
if [ "$PRIMARY_KEY" = "$MATCHED_KEY" ]; then
|
||||
EXACT_HIT="true"
|
||||
fi
|
||||
|
||||
TMPDIR=$(mktemp -d)
|
||||
ARCHIVE_PATH="${TMPDIR}/cache.tar.zst"
|
||||
|
||||
echo "Downloading cache archive..."
|
||||
curl -sL -o "$ARCHIVE_PATH" "$ARCHIVE_LOCATION"
|
||||
|
||||
echo "Extracting cache..."
|
||||
mkdir -p "$EXPANDED_PATH"
|
||||
|
||||
if command -v zstd &>/dev/null; then
|
||||
tar -I zstd -xf "$ARCHIVE_PATH" -C "/" 2>/dev/null || true
|
||||
else
|
||||
tar -xf "$ARCHIVE_PATH" -C "/" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
rm -rf "$TMPDIR"
|
||||
|
||||
echo "cache-hit=${EXACT_HIT}" >> $GITHUB_OUTPUT
|
||||
echo "cache-primary-key=${PRIMARY_KEY}" >> $GITHUB_OUTPUT
|
||||
echo "cache-matched-key=${MATCHED_KEY}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Save cache
|
||||
if: always()
|
||||
shell: bash
|
||||
env:
|
||||
CACHE_KEY: ${{ steps.gen-key.outputs.cache-key }}
|
||||
CACHE_PATH: ${{ inputs.path }}
|
||||
CACHE_HIT: ${{ steps.restore-cache.outputs.cache-hit }}
|
||||
run: |
|
||||
CACHE_URL="${ACTIONS_CACHE_URL:-${ACTIONS_RUNTIME_URL:-}}"
|
||||
TOKEN="${ACTIONS_RUNTIME_TOKEN:-}"
|
||||
|
||||
if [ -z "$CACHE_URL" ] || [ -z "$TOKEN" ]; then
|
||||
echo "::warning::Cache environment variables not set. Skipping cache save."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
CACHE_URL="${CACHE_URL%/}/"
|
||||
API_BASE="${CACHE_URL}_apis/artifactcache/"
|
||||
|
||||
EXPANDED_PATH=$(eval echo "$CACHE_PATH")
|
||||
PATHS_HASH=$(echo "$EXPANDED_PATH" | sha256sum | awk '{print $1}')
|
||||
CACHE_VERSION="zstd-${PATHS_HASH}"
|
||||
|
||||
PRIMARY_KEY="${CACHE_KEY}"
|
||||
|
||||
if [ "$CACHE_HIT" = "true" ]; then
|
||||
echo "Cache hit on primary key, skipping save."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "Checking if cache directory has content..."
|
||||
if [ ! -d "$EXPANDED_PATH" ] || [ -z "$(ls -A "$EXPANDED_PATH" 2>/dev/null)" ]; then
|
||||
echo "Cache directory is empty, skipping save."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
TMPDIR=$(mktemp -d)
|
||||
REL_PATH="$(echo "$EXPANDED_PATH" | sed 's|^/||')"
|
||||
|
||||
ARCHIVE_PATH="${TMPDIR}/cache.tar.zst"
|
||||
COMPRESS_METHOD="zstd"
|
||||
|
||||
if command -v zstd &>/dev/null; then
|
||||
tar -I zstd -cf "$ARCHIVE_PATH" -C "/" "$REL_PATH" 2>/dev/null || COMPRESS_METHOD="none"
|
||||
else
|
||||
COMPRESS_METHOD="none"
|
||||
fi
|
||||
|
||||
if [ "$COMPRESS_METHOD" = "none" ]; then
|
||||
echo "zstd not available, trying gzip..."
|
||||
ARCHIVE_PATH="${TMPDIR}/cache.tar.gz"
|
||||
tar -czf "$ARCHIVE_PATH" -C "/" "$REL_PATH" 2>/dev/null || {
|
||||
echo "Failed to create archive"
|
||||
rm -rf "$TMPDIR"
|
||||
exit 0
|
||||
}
|
||||
fi
|
||||
|
||||
ARCHIVE_SIZE=$(stat -c%s "$ARCHIVE_PATH" 2>/dev/null || stat -f%z "$ARCHIVE_PATH" 2>/dev/null || echo "0")
|
||||
|
||||
echo "Reserving cache with key: ${PRIMARY_KEY} (size: ${ARCHIVE_SIZE} bytes)"
|
||||
|
||||
RESERVE_RESPONSE=$(mktemp)
|
||||
curl -sL -o "$RESERVE_RESPONSE" -w "%{http_code}" \
|
||||
-X POST \
|
||||
-H "Authorization: Bearer ${TOKEN}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"key\":\"${PRIMARY_KEY}\",\"version\":\"${CACHE_VERSION}\",\"cacheSize\":${ARCHIVE_SIZE}}" \
|
||||
"${API_BASE}caches" 2>/dev/null > /dev/null || echo "000"
|
||||
|
||||
CACHE_ID=$(grep -o '"cacheId":[0-9]*' "$RESERVE_RESPONSE" | head -1 | cut -d':' -f2)
|
||||
rm -f "$RESERVE_RESPONSE"
|
||||
|
||||
if [ -z "$CACHE_ID" ]; then
|
||||
echo "No cache ID returned, cache may already exist or reservation failed"
|
||||
rm -rf "$TMPDIR"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "Uploading cache (ID: ${CACHE_ID})..."
|
||||
UPLOAD_STATUS=$(curl -sL -o /dev/null -w "%{http_code}" \
|
||||
-X PATCH \
|
||||
-H "Authorization: Bearer ${TOKEN}" \
|
||||
-H "Content-Type: application/octet-stream" \
|
||||
--data-binary "@${ARCHIVE_PATH}" \
|
||||
"${API_BASE}caches/${CACHE_ID}" 2>/dev/null || echo "000")
|
||||
|
||||
if [ "$UPLOAD_STATUS" != "200" ]; then
|
||||
echo "Upload failed with status: ${UPLOAD_STATUS}"
|
||||
rm -rf "$TMPDIR"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "Committing cache..."
|
||||
COMMIT_STATUS=$(curl -sL -o /dev/null -w "%{http_code}" \
|
||||
-X POST \
|
||||
-H "Authorization: Bearer ${TOKEN}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"size\":${ARCHIVE_SIZE}}" \
|
||||
"${API_BASE}caches/${CACHE_ID}" 2>/dev/null || echo "000")
|
||||
|
||||
rm -rf "$TMPDIR"
|
||||
|
||||
if [ "$COMMIT_STATUS" = "200" ]; then
|
||||
echo "Cache saved successfully"
|
||||
else
|
||||
echo "Commit failed with status: ${COMMIT_STATUS}"
|
||||
fi
|
||||
|
||||
Reference in New Issue
Block a user