|
6 | 6 | # |
7 | 7 | # If no arguments provided, it will try to detect from GitHub Actions environment |
8 | 8 | # Output: Space-separated list of changed challenge paths (module/challenge format) |
| 9 | +# |
| 10 | +# This script also detects when base templates change and includes all challenges |
| 11 | +# that depend on those templates |
9 | 12 |
|
10 | 13 | set -e |
11 | 14 |
|
|
58 | 61 | HEAD_SHA="HEAD" |
59 | 62 | fi |
60 | 63 |
|
61 | | -# Get list of changed files |
62 | | -CHANGED_FILES=$(git diff --name-only "$BASE_SHA" "$HEAD_SHA") |
| 64 | +# Find all challenges that use (extend/include) a template |
| 65 | +find_dependent_challenges() { |
| 66 | + local template="$1" |
| 67 | + local name=$(basename "$template") |
| 68 | + local rel_path=${template#*/} # Remove module prefix |
| 69 | + |
| 70 | + # Find all .j2 files in challenge dirs that reference this template |
| 71 | + find . -name "*.j2" -path "*/challenge/*" 2>/dev/null | \ |
| 72 | + xargs grep -lE "{%-? *(extends|include).*[\"'](.*/)?(${name}|${rel_path})[\"']" 2>/dev/null | \ |
| 73 | + sed 's|^\./||' | cut -d'/' -f1-2 | sort -u || true |
| 74 | +} |
| 75 | + |
| 76 | +# Recursively find all templates that depend on a given template |
| 77 | +find_child_templates() { |
| 78 | + local template="$1" |
| 79 | + local module=${template%%/*} |
| 80 | + local seen=() |
| 81 | + local queue=("$template") |
| 82 | + |
| 83 | + while [ ${#queue[@]} -gt 0 ]; do |
| 84 | + local current="${queue[0]}" |
| 85 | + queue=("${queue[@]:1}") # Remove first element |
| 86 | + |
| 87 | + # Skip if already seen |
| 88 | + [[ " ${seen[@]} " =~ " ${current} " ]] && continue |
| 89 | + seen+=("$current") |
| 90 | + |
| 91 | + local name=$(basename "$current") |
| 92 | + local rel_path=${current#*/} |
| 93 | + |
| 94 | + # Find templates that reference this one |
| 95 | + local children=$( |
| 96 | + grep -rE "{%-? *(extends|include).*[\"'](.*/)?(${name}|${rel_path})[\"']" \ |
| 97 | + --include="*.j2" "$module" 2>/dev/null | cut -d':' -f1 | sort -u || true |
| 98 | + ) |
| 99 | + |
| 100 | + # Add children to queue |
| 101 | + for child in $children; do |
| 102 | + [[ " ${seen[@]} " =~ " ${child} " ]] || queue+=("$child") |
| 103 | + done |
| 104 | + done |
| 105 | + |
| 106 | + printf '%s\n' "${seen[@]}" |
| 107 | +} |
| 108 | + |
| 109 | +DIRECT_CHALLENGES=$(git diff --name-only "$BASE_SHA" "$HEAD_SHA" | grep -E '^[^/]+/[^/]+/' | cut -d'/' -f1-2 | sort -u || true) |
| 110 | +CHANGED_BASE_TEMPLATES=$(git diff --name-only "$BASE_SHA" "$HEAD_SHA" | grep -E '^[^/]+/base_templates/.*\.j2$' || true) |
63 | 111 |
|
64 | | -# Extract unique challenge paths (module/challenge format) |
65 | | -CHALLENGES=$(echo "$CHANGED_FILES" | grep -E '^[^/]+/[^/]+/' | cut -d'/' -f1-2 | sort -u) |
| 112 | +declare -A AFFECTED_CHALLENGES_SET |
66 | 113 |
|
67 | | -# Filter out non-challenge directories (like base_templates, legacy, etc.) |
68 | | -for CHALLENGE in $CHALLENGES; do |
69 | | - if [[ -d "$CHALLENGE/challenge" || -d "$CHALLENGE/tests_public" || -d "$CHALLENGE/tests_private" ]]; then |
70 | | - echo "$CHALLENGE" |
| 114 | +# Add directly changed challenges that exist |
| 115 | +for challenge in $DIRECT_CHALLENGES; do |
| 116 | + if [[ -d "$challenge/challenge" || -d "$challenge/tests_public" || -d "$challenge/tests_private" ]]; then |
| 117 | + AFFECTED_CHALLENGES_SET["$challenge"]=1 |
71 | 118 | fi |
72 | 119 | done |
| 120 | + |
| 121 | +# Process base template changes |
| 122 | +for template in $CHANGED_BASE_TEMPLATES; do |
| 123 | + # Find all templates that depend on this one (including itself) |
| 124 | + for dependent_template in $(find_child_templates "$template"); do |
| 125 | + # Find all challenges using this template |
| 126 | + for challenge in $(find_dependent_challenges "$dependent_template"); do |
| 127 | + AFFECTED_CHALLENGES_SET["$challenge"]=1 |
| 128 | + done |
| 129 | + done |
| 130 | +done |
| 131 | + |
| 132 | +[ ${#AFFECTED_CHALLENGES_SET[@]} -eq 0 ] || printf '%s\n' "${!AFFECTED_CHALLENGES_SET[@]}" | sort |
0 commit comments