This repository was archived by the owner on Mar 12, 2026. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathaction.yaml
More file actions
186 lines (167 loc) · 7.03 KB
/
action.yaml
File metadata and controls
186 lines (167 loc) · 7.03 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
name: 'Get changed paths'
inputs:
filter_paths:
required: false
description: 'Optional. Newline-separated list of path prefixes to filter results (e.g., "components/mdz", "components/transaction")'
path_level:
required: false
description: 'Optional. Limits the path to the first N segments (e.g., 2 -> "components/transactions")'
get_app_name:
required: false
description: 'If true, outputs a matrix of objects with app name and working directory. Otherwise, outputs a list of changed directories.'
app_name_prefix:
required: false
description: 'Optional. If set and get_app_name is true, this prefix will be added to each app name.'
app_name_overrides:
required: false
description: 'Optional. Newline-separated list of explicit app name mappings in "path:name" format. Use "path:" for prefix-only (no suffix). Overrides default segment extraction for matched paths.'
normalize_to_filter:
required: false
default: 'false'
description: 'If true, uses the filter path as working_dir (e.g., components/app/cmd becomes components/app). Set to false to keep the actual trimmed directory path.'
outputs:
matrix:
description: 'JSON array of changed directories'
value: ${{ steps.dirs.outputs.matrix }}
runs:
using: "composite"
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Get changed files
id: changed
shell: bash
run: |
if [[ "${{ github.event_name }}" == "pull_request" || "${{ github.event_name }}" == "pull_request_target" ]]; then
# For PRs, diff between the base branch and current HEAD
FILES=$(git diff --name-only ${{ github.event.pull_request.base.sha }} HEAD)
elif [[ "${{ github.event.before }}" == "0000000000000000000000000000000000000000" ]] || [[ -z "${{ github.event.before }}" ]]; then
# For tags or when before is not available, compare with the previous commit
PREV_COMMIT=$(git rev-parse HEAD^)
if [[ $? -eq 0 ]]; then
FILES=$(git diff --name-only $PREV_COMMIT HEAD)
else
# Fallback for first commit
FILES=$(git ls-tree -r --name-only HEAD)
fi
else
# Normal case - diff between commits
FILES=$(git diff --name-only ${{ github.event.before }} ${{ github.sha }})
fi
printf "files<<EOF\n%s\nEOF\n" "$FILES" >> "$GITHUB_OUTPUT"
- name: Extract changed directories
id: dirs
shell: bash
run: |
FILES="${{ steps.changed.outputs.files }}"
FILTER_PATHS="${{ inputs.filter_paths || '' }}"
PATH_LEVEL="${{ inputs.path_level || '' }}"
GET_APP_NAME="${{ inputs.get_app_name || 'false' }}"
APP_NAME_PREFIX="${{ inputs.app_name_prefix || '' }}"
APP_NAME_OVERRIDES="${{ inputs.app_name_overrides || '' }}"
NORMALIZE_TO_FILTER="${{ inputs.normalize_to_filter || 'false' }}"
# Parse app_name_overrides into associative array
declare -A NAME_OVERRIDES
if [[ -n "$APP_NAME_OVERRIDES" ]]; then
echo "Parsing app name overrides..."
while IFS= read -r line; do
[[ -z "$line" ]] && continue
OVERRIDE_PATH="${line%%:*}"
OVERRIDE_NAME="${line#*:}"
NAME_OVERRIDES["$OVERRIDE_PATH"]="$OVERRIDE_NAME"
echo " Override: $OVERRIDE_PATH -> '${OVERRIDE_NAME:-<prefix-only>}'"
done <<< "$APP_NAME_OVERRIDES"
fi
if [[ -z "$FILES" ]]; then
echo "No files changed."
printf "matrix=[]\n" >> "$GITHUB_OUTPUT"
exit 0
fi
# Get directory for each file
DIRS=$(echo "$FILES" | xargs -n1 dirname)
# Trim to first N path segments if specified
if [[ -n "$PATH_LEVEL" ]]; then
echo "Trimming paths to first $PATH_LEVEL segments"
DIRS=$(echo "$DIRS" | cut -d'/' -f-"$PATH_LEVEL")
fi
# Filter paths if filter_paths is provided
if [[ -n "$FILTER_PATHS" ]]; then
echo "Filtering directories using list:"
echo "$FILTER_PATHS"
# Convert multi-line input into array
mapfile -t FILTER_ARRAY <<< "$FILTER_PATHS"
FILTERED=""
while read -r DIR; do
for FILTER in "${FILTER_ARRAY[@]}"; do
# Skip empty filters (from trailing newlines in YAML)
[[ -z "$FILTER" ]] && continue
if [[ "$DIR" == "$FILTER"* ]]; then
if [[ "$NORMALIZE_TO_FILTER" == "true" ]]; then
# Use filter path as working_dir (normalizes deeper paths to filter)
FILTERED+="$FILTER"$'\n'
else
# Keep actual DIR path (PATH_LEVEL already handles truncation)
FILTERED+="$DIR"$'\n'
fi
break
fi
done
done <<< "$DIRS"
# If nothing matched, exit
if [[ -z "$FILTERED" ]]; then
echo "No matching directories found after filtering."
printf "matrix=[]\n" >> "$GITHUB_OUTPUT"
exit 0
fi
DIRS="$FILTERED"
fi
# Deduplicate and remove empty lines
DIRS=$(echo "$DIRS" | grep -v '^$' | sort -u)
if [[ "$GET_APP_NAME" == "true" ]]; then
echo "Generating object matrix with app names"
MATRIX="["
FIRST=true
while read -r DIR; do
# Check if there's an explicit override for this path
if [[ -n "${NAME_OVERRIDES[$DIR]+set}" ]]; then
OVERRIDE_VALUE="${NAME_OVERRIDES[$DIR]}"
if [[ -z "$OVERRIDE_VALUE" ]]; then
# Empty override means use prefix only (no suffix)
APP_NAME="$APP_NAME_PREFIX"
echo " Using override for $DIR: prefix-only -> $APP_NAME"
else
# Use prefix + override value
if [[ -n "$APP_NAME_PREFIX" ]]; then
APP_NAME="${APP_NAME_PREFIX}-${OVERRIDE_VALUE}"
else
APP_NAME="$OVERRIDE_VALUE"
fi
echo " Using override for $DIR: $APP_NAME"
fi
else
# No override - extract app name from second path segment
EXTRACTED_NAME="$(echo "$DIR" | cut -d'/' -f2)"
# Apply prefix if set
if [[ -n "$APP_NAME_PREFIX" ]]; then
APP_NAME="${APP_NAME_PREFIX}-${EXTRACTED_NAME}"
else
APP_NAME="$EXTRACTED_NAME"
fi
fi
ENTRY="{\"name\":\"$APP_NAME\",\"working_dir\":\"$DIR\"}"
if $FIRST; then
MATRIX+="$ENTRY"
FIRST=false
else
MATRIX+=",$ENTRY"
fi
done <<< "$DIRS"
MATRIX+="]"
else
# Default: return just an array of paths
MATRIX=$(echo "$DIRS" | jq -Rc . | jq -sc .)
fi
echo "Changed directories matrix: $MATRIX"
printf "matrix=%s\n" "$MATRIX" >> "$GITHUB_OUTPUT"