-
Notifications
You must be signed in to change notification settings - Fork 0
/
get_changes.sh
105 lines (81 loc) · 3.42 KB
/
get_changes.sh
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
#!/usr/bin/env bash
# The following command makes this bash script slightly more safe. It does the following things:
# If any command fails the whole script will exit.
# If any variable is not set it is treated as an error, and the script immediately exits.
# Disable filename expansion (globbing) upon seeing *, ?, etc..
# If any part of a pipeline fails the whole pipeline fails.
set -euf -o pipefail
# INPUT HANDLING
# The following sections attempt to prevent script injection from inputs, but it is up
# to the user to provide safe values.
# This should work - is there a good reason to use it instead of cat? (cat is not builtin)
# IFS='' read -r -d '' test <<"EOF" || true
# $ {{ inputs.filters }}
# EOF
# Escape inputs
# shellcheck disable=SC2153
base=$BASE
# shellcheck disable=SC2153
commit=$COMMIT
# shellcheck disable=SC2153
filters=$FILTERS
# shellcheck disable=SC2153
fetch_depth=$FETCH_DEPTH
# Commit hashes / branch names can only have the following characters
branch_name_commit_characters="[:alnum:]/\_\-.=><@"
# Remove disallowed characters
base="$(tr -cd -- "$branch_name_commit_characters" <<< "$base")"
commit="$(tr -cd -- "$branch_name_commit_characters" <<< "$commit")"
# Limit the characters that one can send through inputs.filters.
regex_symbols=".+?[]<>()|^$\{}\`/"
filter_characters="[:alnum:][:space:]:*"
allowed_characters="$regex_symbols$filter_characters"
# Remove disallowed characters
filters="$(tr -cd -- "$allowed_characters" <<< "$filters")"
# Read filters into array
readarray -t filter_array -- <<< "$filters"
# INPUT DONE
# Set default 'has_any_changes' value
result="$(jq -n '{has_any_changes: "false"}')"
git fetch -q --depth="$fetch_depth"
while [ -z "$( git merge-base "$base" "$commit" )" ]; do
git fetch -q --deepen=100 "$base" "$commit";
done
# Retrieving diff
diff=$(git diff --name-only "$base".."$commit")
changes=()
for row in "${filter_array[@]}"; do
# xargs echo removes leading and trailing whitespaces
row_trimmed=$(echo "$row" | xargs -- echo)
# Check if the row is empty or not.
if (( ${#row_trimmed} )); then
# If there is a row, split it into two parts on ':'
IFS=":" read -r filter_key filter_regex <<< "$row"
# filter keys can only be alphanumerical
key="$(tr -cd -- "[:alnum:]" <<< "$filter_key")"
# Remove surrounding whitespace from regex if present
regex_trimmed=$(echo "$filter_regex" | xargs -- echo)
# Skip this row if key or regex is empty
if (( !${#key} || !${#regex_trimmed} )); then
continue
fi
# The '|| true' suffix suppresses 'set -e' for this line. Otherwise we would exit the script
# if grep didn't find any results.
results=$(echo "$diff" | grep -E "$regex_trimmed" --) || true
readarray -t result_array <<< "$results"
results_json=$(jq -ncR '[inputs]' <<< "$results")
if (( ${#result_array} )); then
# If there are matches we write the values.
result=$(echo "$result" | jq '.has_any_changes |= "true"')
result=$(echo "$result" | jq ".${key} |= \"true\"")
result=$(echo "$result" | jq ".${key}_files |= $results_json")
result=$(echo "$result" | jq ".${key}_count |= ${#result_array[@]}")
changes+=("$key")
fi
fi
done
# Save list of filter keys that had matches.
# shellcheck disable=SC2034
changes_json=$(jq -cnR '$ARGS.positional' --args -- "${changes[@]}")
result=$(echo "$result" | jq ".changes |= $changes_json")
echo "result=$(echo "$result" | jq -c)" >> "$GITHUB_OUTPUT"