mirror of
https://github.com/ivuorinen/actions.git
synced 2026-03-10 08:57:20 +00:00
refactor: remove common-cache action
Delete common-cache action and all associated test files. All actions now use native actions/cache@v4.3.0 instead of the wrapper. Deleted: - common-cache/action.yml - common-cache/README.md - common-cache/rules.yml - common-cache/CustomValidator.py - _tests/unit/common-cache/validation.spec.sh - _tests/integration/workflows/common-cache-test.yml - validate-inputs/tests/test_common-cache_custom.py Action count: 28 → 27
This commit is contained in:
@@ -1,471 +0,0 @@
|
|||||||
---
|
|
||||||
name: Integration Test - Common Cache
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
push:
|
|
||||||
paths:
|
|
||||||
- 'common-cache/**'
|
|
||||||
- '_tests/integration/workflows/common-cache-test.yml'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
test-common-cache-key-generation:
|
|
||||||
name: Test Cache Key Generation
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Test basic key generation
|
|
||||||
run: |
|
|
||||||
RUNNER_OS="Linux"
|
|
||||||
CACHE_TYPE="npm"
|
|
||||||
KEY_PREFIX=""
|
|
||||||
|
|
||||||
cache_key="$RUNNER_OS"
|
|
||||||
[ -n "$CACHE_TYPE" ] && cache_key="${cache_key}-${CACHE_TYPE}"
|
|
||||||
|
|
||||||
expected="Linux-npm"
|
|
||||||
if [[ "$cache_key" != "$expected" ]]; then
|
|
||||||
echo "❌ ERROR: Expected '$expected', got '$cache_key'"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
echo "✓ Basic cache key generation works"
|
|
||||||
|
|
||||||
- name: Test key with prefix
|
|
||||||
run: |
|
|
||||||
RUNNER_OS="Linux"
|
|
||||||
CACHE_TYPE="npm"
|
|
||||||
KEY_PREFIX="node-20"
|
|
||||||
|
|
||||||
cache_key="$RUNNER_OS"
|
|
||||||
[ -n "$KEY_PREFIX" ] && cache_key="${cache_key}-${KEY_PREFIX}"
|
|
||||||
[ -n "$CACHE_TYPE" ] && cache_key="${cache_key}-${CACHE_TYPE}"
|
|
||||||
|
|
||||||
expected="Linux-node-20-npm"
|
|
||||||
if [[ "$cache_key" != "$expected" ]]; then
|
|
||||||
echo "❌ ERROR: Expected '$expected', got '$cache_key'"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
echo "✓ Cache key with prefix works"
|
|
||||||
|
|
||||||
- name: Test OS-specific keys
|
|
||||||
run: |
|
|
||||||
for os in "Linux" "macOS" "Windows"; do
|
|
||||||
CACHE_TYPE="test"
|
|
||||||
cache_key="$os-$CACHE_TYPE"
|
|
||||||
if [[ ! "$cache_key" =~ ^(Linux|macOS|Windows)-test$ ]]; then
|
|
||||||
echo "❌ ERROR: Invalid key for OS $os: $cache_key"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
echo "✓ OS-specific key for $os: $cache_key"
|
|
||||||
done
|
|
||||||
|
|
||||||
test-common-cache-file-hashing:
|
|
||||||
name: Test File Hashing
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Create test files
|
|
||||||
run: |
|
|
||||||
mkdir -p test-cache
|
|
||||||
cd test-cache
|
|
||||||
echo "content1" > file1.txt
|
|
||||||
echo "content2" > file2.txt
|
|
||||||
echo "content3" > file3.txt
|
|
||||||
|
|
||||||
- name: Test single file hash
|
|
||||||
run: |
|
|
||||||
cd test-cache
|
|
||||||
file_hash=$(cat file1.txt | sha256sum | cut -d' ' -f1)
|
|
||||||
|
|
||||||
if [[ ! "$file_hash" =~ ^[a-f0-9]{64}$ ]]; then
|
|
||||||
echo "❌ ERROR: Invalid hash format: $file_hash"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
echo "✓ Single file hash: $file_hash"
|
|
||||||
|
|
||||||
- name: Test multiple file hash
|
|
||||||
run: |
|
|
||||||
cd test-cache
|
|
||||||
multi_hash=$(cat file1.txt file2.txt file3.txt | sha256sum | cut -d' ' -f1)
|
|
||||||
|
|
||||||
if [[ ! "$multi_hash" =~ ^[a-f0-9]{64}$ ]]; then
|
|
||||||
echo "❌ ERROR: Invalid hash format: $multi_hash"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
echo "✓ Multiple file hash: $multi_hash"
|
|
||||||
|
|
||||||
- name: Test hash changes with content
|
|
||||||
run: |
|
|
||||||
cd test-cache
|
|
||||||
|
|
||||||
# Get initial hash
|
|
||||||
hash1=$(cat file1.txt | sha256sum | cut -d' ' -f1)
|
|
||||||
|
|
||||||
# Modify file
|
|
||||||
echo "modified" > file1.txt
|
|
||||||
|
|
||||||
# Get new hash
|
|
||||||
hash2=$(cat file1.txt | sha256sum | cut -d' ' -f1)
|
|
||||||
|
|
||||||
if [[ "$hash1" == "$hash2" ]]; then
|
|
||||||
echo "❌ ERROR: Hash should change when content changes"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
echo "✓ Hash changes with content modification"
|
|
||||||
|
|
||||||
- name: Test comma-separated file list processing
|
|
||||||
run: |
|
|
||||||
cd test-cache
|
|
||||||
|
|
||||||
KEY_FILES="file1.txt,file2.txt,file3.txt"
|
|
||||||
IFS=',' read -ra FILES <<< "$KEY_FILES"
|
|
||||||
|
|
||||||
existing_files=()
|
|
||||||
for file in "${FILES[@]}"; do
|
|
||||||
file=$(echo "$file" | xargs)
|
|
||||||
if [ -f "$file" ]; then
|
|
||||||
existing_files+=("$file")
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ ${#existing_files[@]} -ne 3 ]; then
|
|
||||||
echo "❌ ERROR: Should find 3 files, found ${#existing_files[@]}"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "✓ Comma-separated file list processing works"
|
|
||||||
|
|
||||||
- name: Test missing file handling
|
|
||||||
run: |
|
|
||||||
cd test-cache
|
|
||||||
|
|
||||||
KEY_FILES="file1.txt,missing.txt,file2.txt"
|
|
||||||
IFS=',' read -ra FILES <<< "$KEY_FILES"
|
|
||||||
|
|
||||||
existing_files=()
|
|
||||||
for file in "${FILES[@]}"; do
|
|
||||||
file=$(echo "$file" | xargs)
|
|
||||||
if [ -f "$file" ]; then
|
|
||||||
existing_files+=("$file")
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ ${#existing_files[@]} -ne 2 ]; then
|
|
||||||
echo "❌ ERROR: Should find 2 files, found ${#existing_files[@]}"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "✓ Missing files correctly skipped"
|
|
||||||
|
|
||||||
test-common-cache-env-vars:
|
|
||||||
name: Test Environment Variables
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Test single env var inclusion
|
|
||||||
run: |
|
|
||||||
export NODE_VERSION="20.9.0"
|
|
||||||
ENV_VARS="NODE_VERSION"
|
|
||||||
|
|
||||||
IFS=',' read -ra VARS <<< "$ENV_VARS"
|
|
||||||
env_hash=""
|
|
||||||
for var in "${VARS[@]}"; do
|
|
||||||
if [ -n "${!var}" ]; then
|
|
||||||
env_hash="${env_hash}-${var}-${!var}"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
expected="-NODE_VERSION-20.9.0"
|
|
||||||
if [[ "$env_hash" != "$expected" ]]; then
|
|
||||||
echo "❌ ERROR: Expected '$expected', got '$env_hash'"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
echo "✓ Single env var inclusion works"
|
|
||||||
|
|
||||||
- name: Test multiple env vars
|
|
||||||
run: |
|
|
||||||
export NODE_VERSION="20.9.0"
|
|
||||||
export PACKAGE_MANAGER="npm"
|
|
||||||
ENV_VARS="NODE_VERSION,PACKAGE_MANAGER"
|
|
||||||
|
|
||||||
IFS=',' read -ra VARS <<< "$ENV_VARS"
|
|
||||||
env_hash=""
|
|
||||||
for var in "${VARS[@]}"; do
|
|
||||||
if [ -n "${!var}" ]; then
|
|
||||||
env_hash="${env_hash}-${var}-${!var}"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
expected="-NODE_VERSION-20.9.0-PACKAGE_MANAGER-npm"
|
|
||||||
if [[ "$env_hash" != "$expected" ]]; then
|
|
||||||
echo "❌ ERROR: Expected '$expected', got '$env_hash'"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
echo "✓ Multiple env vars inclusion works"
|
|
||||||
|
|
||||||
- name: Test undefined env var skipping
|
|
||||||
run: |
|
|
||||||
export NODE_VERSION="20.9.0"
|
|
||||||
ENV_VARS="NODE_VERSION,UNDEFINED_VAR"
|
|
||||||
|
|
||||||
IFS=',' read -ra VARS <<< "$ENV_VARS"
|
|
||||||
env_hash=""
|
|
||||||
for var in "${VARS[@]}"; do
|
|
||||||
if [ -n "${!var}" ]; then
|
|
||||||
env_hash="${env_hash}-${var}-${!var}"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
# Should only include NODE_VERSION
|
|
||||||
expected="-NODE_VERSION-20.9.0"
|
|
||||||
if [[ "$env_hash" != "$expected" ]]; then
|
|
||||||
echo "❌ ERROR: Expected '$expected', got '$env_hash'"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
echo "✓ Undefined env vars correctly skipped"
|
|
||||||
|
|
||||||
test-common-cache-path-processing:
|
|
||||||
name: Test Path Processing
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Test single path
|
|
||||||
run: |
|
|
||||||
CACHE_PATHS="~/.npm"
|
|
||||||
IFS=',' read -ra PATHS <<< "$CACHE_PATHS"
|
|
||||||
|
|
||||||
if [ ${#PATHS[@]} -ne 1 ]; then
|
|
||||||
echo "❌ ERROR: Should have 1 path, got ${#PATHS[@]}"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
echo "✓ Single path processing works"
|
|
||||||
|
|
||||||
- name: Test multiple paths
|
|
||||||
run: |
|
|
||||||
CACHE_PATHS="~/.npm,~/.yarn/cache,node_modules"
|
|
||||||
IFS=',' read -ra PATHS <<< "$CACHE_PATHS"
|
|
||||||
|
|
||||||
if [ ${#PATHS[@]} -ne 3 ]; then
|
|
||||||
echo "❌ ERROR: Should have 3 paths, got ${#PATHS[@]}"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
echo "✓ Multiple paths processing works"
|
|
||||||
|
|
||||||
- name: Test path with spaces (trimming)
|
|
||||||
run: |
|
|
||||||
CACHE_PATHS=" ~/.npm , ~/.yarn/cache , node_modules "
|
|
||||||
IFS=',' read -ra PATHS <<< "$CACHE_PATHS"
|
|
||||||
|
|
||||||
trimmed_paths=()
|
|
||||||
for path in "${PATHS[@]}"; do
|
|
||||||
trimmed=$(echo "$path" | xargs)
|
|
||||||
trimmed_paths+=("$trimmed")
|
|
||||||
done
|
|
||||||
|
|
||||||
# Check first path is trimmed
|
|
||||||
if [[ "${trimmed_paths[0]}" != "~/.npm" ]]; then
|
|
||||||
echo "❌ ERROR: Path not trimmed: '${trimmed_paths[0]}'"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
echo "✓ Path trimming works"
|
|
||||||
|
|
||||||
test-common-cache-complete-key-generation:
|
|
||||||
name: Test Complete Key Generation
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Create test files
|
|
||||||
run: |
|
|
||||||
mkdir -p test-complete
|
|
||||||
cd test-complete
|
|
||||||
echo "package-lock content" > package-lock.json
|
|
||||||
|
|
||||||
- name: Test complete cache key with all components
|
|
||||||
run: |
|
|
||||||
cd test-complete
|
|
||||||
|
|
||||||
RUNNER_OS="Linux"
|
|
||||||
CACHE_TYPE="npm"
|
|
||||||
KEY_PREFIX="node-20"
|
|
||||||
|
|
||||||
# Generate file hash
|
|
||||||
files_hash=$(cat package-lock.json | sha256sum | cut -d' ' -f1)
|
|
||||||
|
|
||||||
# Generate env hash
|
|
||||||
export NODE_VERSION="20.9.0"
|
|
||||||
env_hash="-NODE_VERSION-20.9.0"
|
|
||||||
|
|
||||||
# Generate final key
|
|
||||||
cache_key="$RUNNER_OS"
|
|
||||||
[ -n "$KEY_PREFIX" ] && cache_key="${cache_key}-${KEY_PREFIX}"
|
|
||||||
[ -n "$CACHE_TYPE" ] && cache_key="${cache_key}-${CACHE_TYPE}"
|
|
||||||
[ -n "$files_hash" ] && cache_key="${cache_key}-${files_hash}"
|
|
||||||
[ -n "$env_hash" ] && cache_key="${cache_key}${env_hash}"
|
|
||||||
|
|
||||||
echo "Generated cache key: $cache_key"
|
|
||||||
|
|
||||||
# Verify structure
|
|
||||||
if [[ ! "$cache_key" =~ ^Linux-node-20-npm-[a-f0-9]{64}-NODE_VERSION-20\.9\.0$ ]]; then
|
|
||||||
echo "❌ ERROR: Invalid cache key structure: $cache_key"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
echo "✓ Complete cache key generation works"
|
|
||||||
|
|
||||||
test-common-cache-restore-keys:
|
|
||||||
name: Test Restore Keys
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Test single restore key
|
|
||||||
run: |
|
|
||||||
RESTORE_KEYS="Linux-npm-"
|
|
||||||
|
|
||||||
if [[ -z "$RESTORE_KEYS" ]]; then
|
|
||||||
echo "❌ ERROR: Restore keys should not be empty"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
echo "✓ Single restore key: $RESTORE_KEYS"
|
|
||||||
|
|
||||||
- name: Test multiple restore keys
|
|
||||||
run: |
|
|
||||||
RESTORE_KEYS="Linux-node-20-npm-,Linux-node-npm-,Linux-npm-"
|
|
||||||
|
|
||||||
IFS=',' read -ra KEYS <<< "$RESTORE_KEYS"
|
|
||||||
if [ ${#KEYS[@]} -ne 3 ]; then
|
|
||||||
echo "❌ ERROR: Should have 3 restore keys, got ${#KEYS[@]}"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
echo "✓ Multiple restore keys work"
|
|
||||||
|
|
||||||
test-common-cache-type-specific-scenarios:
|
|
||||||
name: Test Type-Specific Scenarios
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Test NPM cache key
|
|
||||||
run: |
|
|
||||||
TYPE="npm"
|
|
||||||
FILES="package-lock.json"
|
|
||||||
PATHS="~/.npm,node_modules"
|
|
||||||
|
|
||||||
echo "✓ NPM cache configuration valid"
|
|
||||||
echo " Type: $TYPE"
|
|
||||||
echo " Key files: $FILES"
|
|
||||||
echo " Paths: $PATHS"
|
|
||||||
|
|
||||||
- name: Test Composer cache key
|
|
||||||
run: |
|
|
||||||
TYPE="composer"
|
|
||||||
FILES="composer.lock"
|
|
||||||
PATHS="~/.composer/cache,vendor"
|
|
||||||
|
|
||||||
echo "✓ Composer cache configuration valid"
|
|
||||||
echo " Type: $TYPE"
|
|
||||||
echo " Key files: $FILES"
|
|
||||||
echo " Paths: $PATHS"
|
|
||||||
|
|
||||||
- name: Test Go cache key
|
|
||||||
run: |
|
|
||||||
TYPE="go"
|
|
||||||
FILES="go.sum"
|
|
||||||
PATHS="~/go/pkg/mod,~/.cache/go-build"
|
|
||||||
|
|
||||||
echo "✓ Go cache configuration valid"
|
|
||||||
echo " Type: $TYPE"
|
|
||||||
echo " Key files: $FILES"
|
|
||||||
echo " Paths: $PATHS"
|
|
||||||
|
|
||||||
- name: Test Pip cache key
|
|
||||||
run: |
|
|
||||||
TYPE="pip"
|
|
||||||
FILES="requirements.txt"
|
|
||||||
PATHS="~/.cache/pip"
|
|
||||||
|
|
||||||
echo "✓ Pip cache configuration valid"
|
|
||||||
echo " Type: $TYPE"
|
|
||||||
echo " Key files: $FILES"
|
|
||||||
echo " Paths: $PATHS"
|
|
||||||
|
|
||||||
test-common-cache-edge-cases:
|
|
||||||
name: Test Edge Cases
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Test empty prefix
|
|
||||||
run: |
|
|
||||||
KEY_PREFIX=""
|
|
||||||
cache_key="Linux"
|
|
||||||
[ -n "$KEY_PREFIX" ] && cache_key="${cache_key}-${KEY_PREFIX}"
|
|
||||||
|
|
||||||
if [[ "$cache_key" != "Linux" ]]; then
|
|
||||||
echo "❌ ERROR: Empty prefix should not modify key"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
echo "✓ Empty prefix handling works"
|
|
||||||
|
|
||||||
- name: Test no key files
|
|
||||||
run: |
|
|
||||||
KEY_FILES=""
|
|
||||||
files_hash=""
|
|
||||||
|
|
||||||
if [ -n "$KEY_FILES" ]; then
|
|
||||||
echo "❌ ERROR: Should detect empty key files"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
echo "✓ No key files handling works"
|
|
||||||
|
|
||||||
- name: Test no env vars
|
|
||||||
run: |
|
|
||||||
ENV_VARS=""
|
|
||||||
env_hash=""
|
|
||||||
|
|
||||||
if [ -n "$ENV_VARS" ]; then
|
|
||||||
echo "❌ ERROR: Should detect empty env vars"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
echo "✓ No env vars handling works"
|
|
||||||
|
|
||||||
integration-test-summary:
|
|
||||||
name: Integration Test Summary
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs:
|
|
||||||
- test-common-cache-key-generation
|
|
||||||
- test-common-cache-file-hashing
|
|
||||||
- test-common-cache-env-vars
|
|
||||||
- test-common-cache-path-processing
|
|
||||||
- test-common-cache-complete-key-generation
|
|
||||||
- test-common-cache-restore-keys
|
|
||||||
- test-common-cache-type-specific-scenarios
|
|
||||||
- test-common-cache-edge-cases
|
|
||||||
steps:
|
|
||||||
- name: Summary
|
|
||||||
run: |
|
|
||||||
echo "=========================================="
|
|
||||||
echo "Common Cache Integration Tests - PASSED"
|
|
||||||
echo "=========================================="
|
|
||||||
echo ""
|
|
||||||
echo "✓ Cache key generation tests"
|
|
||||||
echo "✓ File hashing tests"
|
|
||||||
echo "✓ Environment variable tests"
|
|
||||||
echo "✓ Path processing tests"
|
|
||||||
echo "✓ Complete key generation tests"
|
|
||||||
echo "✓ Restore keys tests"
|
|
||||||
echo "✓ Type-specific scenario tests"
|
|
||||||
echo "✓ Edge case tests"
|
|
||||||
echo ""
|
|
||||||
echo "All common-cache integration tests completed successfully!"
|
|
||||||
@@ -1,168 +0,0 @@
|
|||||||
#!/usr/bin/env shellspec
|
|
||||||
# Unit tests for common-cache action validation and logic
|
|
||||||
|
|
||||||
# Framework is automatically loaded via spec_helper.sh
|
|
||||||
|
|
||||||
Describe "common-cache action"
|
|
||||||
ACTION_DIR="common-cache"
|
|
||||||
ACTION_FILE="$ACTION_DIR/action.yml"
|
|
||||||
|
|
||||||
Context "when validating cache type input"
|
|
||||||
It "accepts npm cache type"
|
|
||||||
When call validate_input_python "common-cache" "type" "npm"
|
|
||||||
The status should be success
|
|
||||||
End
|
|
||||||
It "accepts composer cache type"
|
|
||||||
When call validate_input_python "common-cache" "type" "composer"
|
|
||||||
The status should be success
|
|
||||||
End
|
|
||||||
It "accepts go cache type"
|
|
||||||
When call validate_input_python "common-cache" "type" "go"
|
|
||||||
The status should be success
|
|
||||||
End
|
|
||||||
It "accepts pip cache type"
|
|
||||||
When call validate_input_python "common-cache" "type" "pip"
|
|
||||||
The status should be success
|
|
||||||
End
|
|
||||||
It "accepts maven cache type"
|
|
||||||
When call validate_input_python "common-cache" "type" "maven"
|
|
||||||
The status should be success
|
|
||||||
End
|
|
||||||
It "accepts gradle cache type"
|
|
||||||
When call validate_input_python "common-cache" "type" "gradle"
|
|
||||||
The status should be success
|
|
||||||
End
|
|
||||||
It "rejects empty cache type"
|
|
||||||
When call validate_input_python "common-cache" "type" ""
|
|
||||||
The status should be failure
|
|
||||||
End
|
|
||||||
It "rejects invalid cache type"
|
|
||||||
Pending "TODO: Implement enum validation for cache type"
|
|
||||||
When call validate_input_python "common-cache" "type" "invalid-type"
|
|
||||||
The status should be failure
|
|
||||||
End
|
|
||||||
End
|
|
||||||
|
|
||||||
Context "when validating paths input"
|
|
||||||
It "accepts single path"
|
|
||||||
When call validate_input_python "common-cache" "paths" "node_modules"
|
|
||||||
The status should be success
|
|
||||||
End
|
|
||||||
It "accepts multiple paths"
|
|
||||||
When call validate_input_python "common-cache" "paths" "node_modules,dist,build"
|
|
||||||
The status should be success
|
|
||||||
End
|
|
||||||
It "rejects empty paths"
|
|
||||||
When call validate_input_python "common-cache" "paths" ""
|
|
||||||
The status should be failure
|
|
||||||
End
|
|
||||||
It "rejects path traversal"
|
|
||||||
When call validate_input_python "common-cache" "paths" "../../../etc/passwd"
|
|
||||||
The status should be failure
|
|
||||||
End
|
|
||||||
It "rejects command injection in paths"
|
|
||||||
When call validate_input_python "common-cache" "paths" "node_modules;rm -rf /"
|
|
||||||
The status should be failure
|
|
||||||
End
|
|
||||||
End
|
|
||||||
|
|
||||||
Context "when validating key-prefix input"
|
|
||||||
It "accepts valid key prefix"
|
|
||||||
When call validate_input_python "common-cache" "key-prefix" "v2-build"
|
|
||||||
The status should be success
|
|
||||||
End
|
|
||||||
It "rejects command injection in key-prefix"
|
|
||||||
When call validate_input_python "common-cache" "key-prefix" "v2&&malicious"
|
|
||||||
The status should be failure
|
|
||||||
End
|
|
||||||
End
|
|
||||||
|
|
||||||
Context "when validating key-files input"
|
|
||||||
It "accepts single key file"
|
|
||||||
When call validate_input_python "common-cache" "key-files" "package.json"
|
|
||||||
The status should be success
|
|
||||||
End
|
|
||||||
It "accepts multiple key files"
|
|
||||||
When call validate_input_python "common-cache" "key-files" "package.json,package-lock.json,yarn.lock"
|
|
||||||
The status should be success
|
|
||||||
End
|
|
||||||
It "rejects path traversal in key-files"
|
|
||||||
When call validate_input_python "common-cache" "key-files" "../../../sensitive.json"
|
|
||||||
The status should be failure
|
|
||||||
End
|
|
||||||
End
|
|
||||||
|
|
||||||
Context "when validating restore-keys input"
|
|
||||||
It "accepts valid restore keys format"
|
|
||||||
When call validate_input_python "common-cache" "restore-keys" "Linux-npm-,Linux-"
|
|
||||||
The status should be success
|
|
||||||
End
|
|
||||||
It "rejects malicious restore keys"
|
|
||||||
When call validate_input_python "common-cache" "restore-keys" "Linux-npm-;rm -rf /"
|
|
||||||
The status should be failure
|
|
||||||
End
|
|
||||||
End
|
|
||||||
|
|
||||||
Context "when checking action.yml structure"
|
|
||||||
It "has valid YAML syntax"
|
|
||||||
When call validate_action_yml_quiet "$ACTION_FILE"
|
|
||||||
The status should be success
|
|
||||||
End
|
|
||||||
|
|
||||||
It "has correct action name"
|
|
||||||
name=$(get_action_name "$ACTION_FILE")
|
|
||||||
When call echo "$name"
|
|
||||||
The output should equal "Common Cache"
|
|
||||||
End
|
|
||||||
|
|
||||||
It "defines required inputs"
|
|
||||||
inputs=$(get_action_inputs "$ACTION_FILE")
|
|
||||||
When call echo "$inputs"
|
|
||||||
The output should include "type"
|
|
||||||
The output should include "paths"
|
|
||||||
End
|
|
||||||
|
|
||||||
It "defines optional inputs"
|
|
||||||
inputs=$(get_action_inputs "$ACTION_FILE")
|
|
||||||
When call echo "$inputs"
|
|
||||||
The output should include "key-prefix"
|
|
||||||
The output should include "key-files"
|
|
||||||
The output should include "restore-keys"
|
|
||||||
The output should include "env-vars"
|
|
||||||
End
|
|
||||||
|
|
||||||
It "defines expected outputs"
|
|
||||||
outputs=$(get_action_outputs "$ACTION_FILE")
|
|
||||||
When call echo "$outputs"
|
|
||||||
The output should include "cache-hit"
|
|
||||||
The output should include "cache-key"
|
|
||||||
The output should include "cache-paths"
|
|
||||||
End
|
|
||||||
End
|
|
||||||
|
|
||||||
Context "when validating security"
|
|
||||||
It "rejects injection in all input types"
|
|
||||||
When call validate_input_python "common-cache" "type" "npm;malicious"
|
|
||||||
The status should be failure
|
|
||||||
End
|
|
||||||
|
|
||||||
It "validates environment variable names safely"
|
|
||||||
When call validate_input_python "common-cache" "env-vars" "NODE_ENV,CI"
|
|
||||||
The status should be success
|
|
||||||
End
|
|
||||||
|
|
||||||
It "rejects injection in environment variables"
|
|
||||||
When call validate_input_python "common-cache" "env-vars" "NODE_ENV;rm -rf /"
|
|
||||||
The status should be failure
|
|
||||||
End
|
|
||||||
End
|
|
||||||
|
|
||||||
Context "when testing outputs"
|
|
||||||
It "produces all expected outputs consistently"
|
|
||||||
When call test_action_outputs "$ACTION_DIR" "type" "npm" "paths" "node_modules"
|
|
||||||
The status should be success
|
|
||||||
The stderr should include "Testing action outputs for: common-cache"
|
|
||||||
The stderr should include "Output test passed for: common-cache"
|
|
||||||
End
|
|
||||||
End
|
|
||||||
End
|
|
||||||
@@ -1,244 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
"""Custom validator for common-cache action.
|
|
||||||
|
|
||||||
This validator handles caching-specific validation including:
|
|
||||||
- Cache types (npm, composer, go, pip, maven, gradle)
|
|
||||||
- Cache paths (comma-separated list)
|
|
||||||
- Cache keys and restore keys
|
|
||||||
- Path validation with special handling for multiple paths
|
|
||||||
"""
|
|
||||||
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
from pathlib import Path
|
|
||||||
import sys
|
|
||||||
|
|
||||||
# Add validate-inputs directory to path to import validators
|
|
||||||
validate_inputs_path = Path(__file__).parent.parent / "validate-inputs"
|
|
||||||
sys.path.insert(0, str(validate_inputs_path))
|
|
||||||
|
|
||||||
from validators.base import BaseValidator
|
|
||||||
from validators.file import FileValidator
|
|
||||||
|
|
||||||
|
|
||||||
class CustomValidator(BaseValidator):
|
|
||||||
"""Custom validator for common-cache action.
|
|
||||||
|
|
||||||
Provides validation for cache configuration.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, action_type: str = "common-cache") -> None:
|
|
||||||
"""Initialize the common-cache validator."""
|
|
||||||
super().__init__(action_type)
|
|
||||||
self.file_validator = FileValidator(action_type)
|
|
||||||
|
|
||||||
def validate_inputs(self, inputs: dict[str, str]) -> bool:
|
|
||||||
"""Validate common-cache specific inputs.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
inputs: Dictionary of input names to values
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
True if all validations pass, False otherwise
|
|
||||||
"""
|
|
||||||
valid = True
|
|
||||||
|
|
||||||
# Validate type (required)
|
|
||||||
if "type" in inputs:
|
|
||||||
valid &= self.validate_cache_type(inputs["type"])
|
|
||||||
else:
|
|
||||||
# Type is required
|
|
||||||
self.add_error("Cache type is required")
|
|
||||||
valid = False
|
|
||||||
|
|
||||||
# Validate paths (required)
|
|
||||||
if "paths" in inputs:
|
|
||||||
valid &= self.validate_cache_paths(inputs["paths"])
|
|
||||||
else:
|
|
||||||
# Paths is required
|
|
||||||
self.add_error("Cache paths are required")
|
|
||||||
valid = False
|
|
||||||
|
|
||||||
# Validate key-prefix (optional)
|
|
||||||
if inputs.get("key-prefix"):
|
|
||||||
valid &= self.validate_key_prefix(inputs["key-prefix"])
|
|
||||||
|
|
||||||
# Validate key-files (optional)
|
|
||||||
if inputs.get("key-files"):
|
|
||||||
valid &= self.validate_key_files(inputs["key-files"])
|
|
||||||
|
|
||||||
# Validate restore-keys (optional)
|
|
||||||
if inputs.get("restore-keys"):
|
|
||||||
valid &= self.validate_restore_keys(inputs["restore-keys"])
|
|
||||||
|
|
||||||
# Validate env-vars (optional)
|
|
||||||
if inputs.get("env-vars"):
|
|
||||||
valid &= self.validate_env_vars(inputs["env-vars"])
|
|
||||||
|
|
||||||
return valid
|
|
||||||
|
|
||||||
def get_required_inputs(self) -> list[str]:
|
|
||||||
"""Get list of required inputs for common-cache.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
List of required input names
|
|
||||||
"""
|
|
||||||
return ["type", "paths"]
|
|
||||||
|
|
||||||
def get_validation_rules(self) -> dict:
|
|
||||||
"""Get validation rules for common-cache.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Dictionary of validation rules
|
|
||||||
"""
|
|
||||||
return {
|
|
||||||
"type": "Cache type (npm, composer, go, pip, maven, gradle)",
|
|
||||||
"paths": "Comma-separated list of paths to cache",
|
|
||||||
"key-prefix": "Optional prefix for cache key",
|
|
||||||
"key-files": "Files to include in cache key hash",
|
|
||||||
"restore-keys": "Fallback cache keys to try",
|
|
||||||
}
|
|
||||||
|
|
||||||
def validate_cache_type(self, cache_type: str) -> bool:
|
|
||||||
"""Validate cache type.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
cache_type: Type of cache
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
True if valid, False otherwise
|
|
||||||
"""
|
|
||||||
# Check for empty
|
|
||||||
if not cache_type or not cache_type.strip():
|
|
||||||
self.add_error("Cache type cannot be empty")
|
|
||||||
return False
|
|
||||||
|
|
||||||
# Allow GitHub Actions expressions
|
|
||||||
if self.is_github_expression(cache_type):
|
|
||||||
return True
|
|
||||||
|
|
||||||
# Note: The test says "accepts invalid cache type (no validation in action)"
|
|
||||||
# This suggests we should accept any value, not just the supported ones
|
|
||||||
# So we'll just validate for security issues, not restrict to specific types
|
|
||||||
|
|
||||||
# Check for command injection using base validator
|
|
||||||
return self.validate_security_patterns(cache_type, "cache type")
|
|
||||||
|
|
||||||
def validate_cache_paths(self, paths: str) -> bool:
|
|
||||||
"""Validate cache paths (comma-separated).
|
|
||||||
|
|
||||||
Args:
|
|
||||||
paths: Comma-separated paths
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
True if valid, False otherwise
|
|
||||||
"""
|
|
||||||
# Check for empty
|
|
||||||
if not paths or not paths.strip():
|
|
||||||
self.add_error("Cache paths cannot be empty")
|
|
||||||
return False
|
|
||||||
|
|
||||||
# Allow GitHub Actions expressions
|
|
||||||
if self.is_github_expression(paths):
|
|
||||||
return True
|
|
||||||
|
|
||||||
# Split paths and validate each
|
|
||||||
path_list = [p.strip() for p in paths.split(",")]
|
|
||||||
|
|
||||||
for path in path_list:
|
|
||||||
if not path:
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Use FileValidator for path validation
|
|
||||||
result = self.file_validator.validate_file_path(path, "paths")
|
|
||||||
# Propagate errors from file validator
|
|
||||||
for error in self.file_validator.errors:
|
|
||||||
if error not in self.errors:
|
|
||||||
self.add_error(error)
|
|
||||||
self.file_validator.clear_errors()
|
|
||||||
|
|
||||||
if not result:
|
|
||||||
return False
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
def validate_key_prefix(self, key_prefix: str) -> bool:
|
|
||||||
"""Validate cache key prefix.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
key_prefix: Key prefix
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
True if valid, False otherwise
|
|
||||||
"""
|
|
||||||
# Allow GitHub Actions expressions
|
|
||||||
if self.is_github_expression(key_prefix):
|
|
||||||
return True
|
|
||||||
|
|
||||||
# Check for command injection using base validator
|
|
||||||
return self.validate_security_patterns(key_prefix, "key-prefix")
|
|
||||||
|
|
||||||
def validate_key_files(self, key_files: str) -> bool:
|
|
||||||
"""Validate key files (comma-separated).
|
|
||||||
|
|
||||||
Args:
|
|
||||||
key_files: Comma-separated file paths
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
True if valid, False otherwise
|
|
||||||
"""
|
|
||||||
# Allow GitHub Actions expressions
|
|
||||||
if self.is_github_expression(key_files):
|
|
||||||
return True
|
|
||||||
|
|
||||||
# Split files and validate each
|
|
||||||
file_list = [f.strip() for f in key_files.split(",")]
|
|
||||||
|
|
||||||
for file_path in file_list:
|
|
||||||
if not file_path:
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Use FileValidator for path validation
|
|
||||||
result = self.file_validator.validate_file_path(file_path, "key-files")
|
|
||||||
# Propagate errors from file validator
|
|
||||||
for error in self.file_validator.errors:
|
|
||||||
if error not in self.errors:
|
|
||||||
self.add_error(error)
|
|
||||||
self.file_validator.clear_errors()
|
|
||||||
|
|
||||||
if not result:
|
|
||||||
return False
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
def validate_restore_keys(self, restore_keys: str) -> bool:
|
|
||||||
"""Validate restore keys.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
restore_keys: Restore keys specification
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
True if valid, False otherwise
|
|
||||||
"""
|
|
||||||
# Allow GitHub Actions expressions
|
|
||||||
if self.is_github_expression(restore_keys):
|
|
||||||
return True
|
|
||||||
|
|
||||||
# Check for command injection using base validator
|
|
||||||
return self.validate_security_patterns(restore_keys, "restore-keys")
|
|
||||||
|
|
||||||
def validate_env_vars(self, env_vars: str) -> bool:
|
|
||||||
"""Validate environment variables.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
env_vars: Environment variables specification
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
True if valid, False otherwise
|
|
||||||
"""
|
|
||||||
# Allow GitHub Actions expressions
|
|
||||||
if self.is_github_expression(env_vars):
|
|
||||||
return True
|
|
||||||
|
|
||||||
# Check for command injection using base validator
|
|
||||||
return self.validate_security_patterns(env_vars, "env-vars")
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
# ivuorinen/actions/common-cache
|
|
||||||
|
|
||||||
## Common Cache
|
|
||||||
|
|
||||||
### Description
|
|
||||||
|
|
||||||
Standardized caching strategy for all actions
|
|
||||||
|
|
||||||
### Inputs
|
|
||||||
|
|
||||||
| name | description | required | default |
|
|
||||||
|----------------|------------------------------------------------------|----------|---------|
|
|
||||||
| `type` | <p>Type of cache (npm, composer, go, pip, etc.)</p> | `true` | `""` |
|
|
||||||
| `paths` | <p>Paths to cache (comma-separated)</p> | `true` | `""` |
|
|
||||||
| `key-prefix` | <p>Custom prefix for cache key</p> | `false` | `""` |
|
|
||||||
| `key-files` | <p>Files to hash for cache key (comma-separated)</p> | `false` | `""` |
|
|
||||||
| `restore-keys` | <p>Fallback keys for cache restoration</p> | `false` | `""` |
|
|
||||||
| `env-vars` | <p>Environment variables to include in cache key</p> | `false` | `""` |
|
|
||||||
|
|
||||||
### Outputs
|
|
||||||
|
|
||||||
| name | description |
|
|
||||||
|---------------|-----------------------------|
|
|
||||||
| `cache-hit` | <p>Cache hit indicator</p> |
|
|
||||||
| `cache-key` | <p>Generated cache key</p> |
|
|
||||||
| `cache-paths` | <p>Resolved cache paths</p> |
|
|
||||||
|
|
||||||
### Runs
|
|
||||||
|
|
||||||
This action is a `composite` action.
|
|
||||||
|
|
||||||
### Usage
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
- uses: ivuorinen/actions/common-cache@main
|
|
||||||
with:
|
|
||||||
type:
|
|
||||||
# Type of cache (npm, composer, go, pip, etc.)
|
|
||||||
#
|
|
||||||
# Required: true
|
|
||||||
# Default: ""
|
|
||||||
|
|
||||||
paths:
|
|
||||||
# Paths to cache (comma-separated)
|
|
||||||
#
|
|
||||||
# Required: true
|
|
||||||
# Default: ""
|
|
||||||
|
|
||||||
key-prefix:
|
|
||||||
# Custom prefix for cache key
|
|
||||||
#
|
|
||||||
# Required: false
|
|
||||||
# Default: ""
|
|
||||||
|
|
||||||
key-files:
|
|
||||||
# Files to hash for cache key (comma-separated)
|
|
||||||
#
|
|
||||||
# Required: false
|
|
||||||
# Default: ""
|
|
||||||
|
|
||||||
restore-keys:
|
|
||||||
# Fallback keys for cache restoration
|
|
||||||
#
|
|
||||||
# Required: false
|
|
||||||
# Default: ""
|
|
||||||
|
|
||||||
env-vars:
|
|
||||||
# Environment variables to include in cache key
|
|
||||||
#
|
|
||||||
# Required: false
|
|
||||||
# Default: ""
|
|
||||||
```
|
|
||||||
@@ -1,122 +0,0 @@
|
|||||||
# yaml-language-server: $schema=https://json.schemastore.org/github-action.json
|
|
||||||
# permissions:
|
|
||||||
# - contents: read # Required for reading cache contents
|
|
||||||
---
|
|
||||||
name: Common Cache
|
|
||||||
description: 'Standardized caching strategy for all actions'
|
|
||||||
author: 'Ismo Vuorinen'
|
|
||||||
|
|
||||||
branding:
|
|
||||||
icon: database
|
|
||||||
color: gray-dark
|
|
||||||
|
|
||||||
inputs:
|
|
||||||
type:
|
|
||||||
description: 'Type of cache (npm, composer, go, pip, etc.)'
|
|
||||||
required: true
|
|
||||||
paths:
|
|
||||||
description: 'Paths to cache (comma-separated)'
|
|
||||||
required: true
|
|
||||||
key-prefix:
|
|
||||||
description: 'Custom prefix for cache key'
|
|
||||||
required: false
|
|
||||||
default: ''
|
|
||||||
key-files:
|
|
||||||
description: 'Files to hash for cache key (comma-separated)'
|
|
||||||
required: false
|
|
||||||
default: ''
|
|
||||||
restore-keys:
|
|
||||||
description: 'Fallback keys for cache restoration'
|
|
||||||
required: false
|
|
||||||
default: ''
|
|
||||||
env-vars:
|
|
||||||
description: 'Environment variables to include in cache key'
|
|
||||||
required: false
|
|
||||||
default: ''
|
|
||||||
|
|
||||||
outputs:
|
|
||||||
cache-hit:
|
|
||||||
description: 'Cache hit indicator'
|
|
||||||
value: ${{ steps.cache.outputs.cache-hit }}
|
|
||||||
cache-key:
|
|
||||||
description: 'Generated cache key'
|
|
||||||
value: ${{ steps.prepare.outputs.cache-key }}
|
|
||||||
cache-paths:
|
|
||||||
description: 'Resolved cache paths'
|
|
||||||
value: ${{ steps.prepare.outputs.cache-paths }}
|
|
||||||
|
|
||||||
runs:
|
|
||||||
using: composite
|
|
||||||
steps:
|
|
||||||
- id: prepare
|
|
||||||
shell: bash
|
|
||||||
env:
|
|
||||||
RUNNER_OS: ${{ runner.os }}
|
|
||||||
CACHE_TYPE: ${{ inputs.type }}
|
|
||||||
KEY_PREFIX: ${{ inputs.key-prefix }}
|
|
||||||
KEY_FILES: ${{ inputs.key-files }}
|
|
||||||
ENV_VARS: ${{ inputs.env-vars }}
|
|
||||||
CACHE_PATHS: ${{ inputs.paths }}
|
|
||||||
run: |
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
# Generate standardized cache key components
|
|
||||||
os_key="$RUNNER_OS"
|
|
||||||
type_key="$CACHE_TYPE"
|
|
||||||
prefix_key="$KEY_PREFIX"
|
|
||||||
|
|
||||||
# Process file hashes
|
|
||||||
# Note: For simple glob patterns, hashFiles() function could be used directly
|
|
||||||
# in the cache key. This manual approach is used to support comma-separated
|
|
||||||
# file lists with complex cache key construction.
|
|
||||||
files_hash=""
|
|
||||||
if [ -n "$KEY_FILES" ]; then
|
|
||||||
IFS=',' read -ra FILES <<< "$KEY_FILES"
|
|
||||||
existing_files=()
|
|
||||||
for file in "${FILES[@]}"; do
|
|
||||||
# Trim whitespace
|
|
||||||
file=$(echo "$file" | xargs)
|
|
||||||
if [ -f "$file" ]; then
|
|
||||||
existing_files+=("$file")
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
# Hash all files together for better performance
|
|
||||||
if [ ${#existing_files[@]} -gt 0 ]; then
|
|
||||||
files_hash=$(cat "${existing_files[@]}" | sha256sum | cut -d' ' -f1)
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Process environment variables
|
|
||||||
env_hash=""
|
|
||||||
if [ -n "$ENV_VARS" ]; then
|
|
||||||
IFS=',' read -ra VARS <<< "$ENV_VARS"
|
|
||||||
for var in "${VARS[@]}"; do
|
|
||||||
if [ -n "${!var}" ]; then
|
|
||||||
env_hash="${env_hash}-${var}-${!var}"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Generate final cache key
|
|
||||||
cache_key="${os_key}"
|
|
||||||
[ -n "$prefix_key" ] && cache_key="${cache_key}-${prefix_key}"
|
|
||||||
[ -n "$type_key" ] && cache_key="${cache_key}-${type_key}"
|
|
||||||
[ -n "$files_hash" ] && cache_key="${cache_key}-${files_hash}"
|
|
||||||
[ -n "$env_hash" ] && cache_key="${cache_key}-${env_hash}"
|
|
||||||
|
|
||||||
echo "cache-key=${cache_key}" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
# Process cache paths
|
|
||||||
IFS=',' read -ra PATHS <<< "$CACHE_PATHS"
|
|
||||||
cache_paths=""
|
|
||||||
for path in "${PATHS[@]}"; do
|
|
||||||
cache_paths="${cache_paths}${path}\n"
|
|
||||||
done
|
|
||||||
echo "cache-paths=${cache_paths}" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
- id: cache
|
|
||||||
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
|
|
||||||
with:
|
|
||||||
path: ${{ steps.prepare.outputs.cache-paths }}
|
|
||||||
key: ${{ steps.prepare.outputs.cache-key }}
|
|
||||||
restore-keys: ${{ inputs.restore-keys }}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
---
|
|
||||||
# Validation rules for common-cache action
|
|
||||||
# Generated by update-validators.py v1.0.0 - DO NOT EDIT MANUALLY
|
|
||||||
# Schema version: 1.0
|
|
||||||
# Coverage: 50% (3/6 inputs)
|
|
||||||
#
|
|
||||||
# This file defines validation rules for the common-cache GitHub Action.
|
|
||||||
# Rules are automatically applied by validate-inputs action when this
|
|
||||||
# action is used.
|
|
||||||
#
|
|
||||||
|
|
||||||
schema_version: '1.0'
|
|
||||||
action: common-cache
|
|
||||||
description: Standardized caching strategy for all actions
|
|
||||||
generator_version: 1.0.0
|
|
||||||
required_inputs:
|
|
||||||
- paths
|
|
||||||
- type
|
|
||||||
optional_inputs:
|
|
||||||
- env-vars
|
|
||||||
- key-files
|
|
||||||
- key-prefix
|
|
||||||
- restore-keys
|
|
||||||
conventions:
|
|
||||||
key-files: file_path
|
|
||||||
key-prefix: prefix
|
|
||||||
paths: file_path
|
|
||||||
overrides: {}
|
|
||||||
statistics:
|
|
||||||
total_inputs: 6
|
|
||||||
validated_inputs: 3
|
|
||||||
skipped_inputs: 0
|
|
||||||
coverage_percentage: 50
|
|
||||||
validation_coverage: 50
|
|
||||||
auto_detected: true
|
|
||||||
manual_review_required: true
|
|
||||||
quality_indicators:
|
|
||||||
has_required_inputs: true
|
|
||||||
has_token_validation: false
|
|
||||||
has_version_validation: false
|
|
||||||
has_file_validation: true
|
|
||||||
has_security_validation: false
|
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
"""Tests for common-cache custom validator.
|
|
||||||
|
|
||||||
Generated by generate-tests.py - Do not edit manually.
|
|
||||||
"""
|
|
||||||
# pylint: disable=invalid-name # Test file name matches action name
|
|
||||||
|
|
||||||
import sys
|
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
# Add action directory to path to import custom validator
|
|
||||||
action_path = Path(__file__).parent.parent.parent / "common-cache"
|
|
||||||
sys.path.insert(0, str(action_path))
|
|
||||||
|
|
||||||
# pylint: disable=wrong-import-position
|
|
||||||
from CustomValidator import CustomValidator
|
|
||||||
|
|
||||||
|
|
||||||
class TestCustomCommonCacheValidator:
|
|
||||||
"""Test cases for common-cache custom validator."""
|
|
||||||
|
|
||||||
def setup_method(self):
|
|
||||||
"""Set up test fixtures."""
|
|
||||||
self.validator = CustomValidator("common-cache")
|
|
||||||
|
|
||||||
def teardown_method(self):
|
|
||||||
"""Clean up after tests."""
|
|
||||||
self.validator.clear_errors()
|
|
||||||
|
|
||||||
def test_validate_inputs_valid(self):
|
|
||||||
"""Test validation with valid inputs."""
|
|
||||||
# TODO: Add specific valid inputs for common-cache
|
|
||||||
inputs = {}
|
|
||||||
result = self.validator.validate_inputs(inputs)
|
|
||||||
# Adjust assertion based on required inputs
|
|
||||||
assert isinstance(result, bool)
|
|
||||||
|
|
||||||
def test_validate_inputs_invalid(self):
|
|
||||||
"""Test validation with invalid inputs."""
|
|
||||||
# TODO: Add specific invalid inputs for common-cache
|
|
||||||
inputs = {"invalid_key": "invalid_value"}
|
|
||||||
result = self.validator.validate_inputs(inputs)
|
|
||||||
# Custom validators may have specific validation rules
|
|
||||||
assert isinstance(result, bool)
|
|
||||||
|
|
||||||
def test_required_inputs(self):
|
|
||||||
"""Test required inputs detection."""
|
|
||||||
required = self.validator.get_required_inputs()
|
|
||||||
assert isinstance(required, list)
|
|
||||||
# TODO: Assert specific required inputs for common-cache
|
|
||||||
|
|
||||||
def test_validation_rules(self):
|
|
||||||
"""Test validation rules."""
|
|
||||||
rules = self.validator.get_validation_rules()
|
|
||||||
assert isinstance(rules, dict)
|
|
||||||
# TODO: Assert specific validation rules for common-cache
|
|
||||||
|
|
||||||
def test_github_expressions(self):
|
|
||||||
"""Test GitHub expression handling."""
|
|
||||||
inputs = {
|
|
||||||
"test_input": "${{ github.token }}",
|
|
||||||
}
|
|
||||||
result = self.validator.validate_inputs(inputs)
|
|
||||||
assert isinstance(result, bool)
|
|
||||||
# GitHub expressions should generally be accepted
|
|
||||||
|
|
||||||
def test_error_propagation(self):
|
|
||||||
"""Test error propagation from sub-validators."""
|
|
||||||
# Custom validators often use sub-validators
|
|
||||||
# Test that errors are properly propagated
|
|
||||||
inputs = {"test": "value"}
|
|
||||||
self.validator.validate_inputs(inputs)
|
|
||||||
# Check error handling
|
|
||||||
if self.validator.has_errors():
|
|
||||||
assert len(self.validator.errors) > 0
|
|
||||||
Reference in New Issue
Block a user