Skip to content

Commit 29f5bab

Browse files
committed
Fix races in pre-commit checks and improve error handling
1 parent 4ca29ca commit 29f5bab

File tree

2 files changed

+95
-36
lines changed

2 files changed

+95
-36
lines changed

.githooks/pre-commit

Lines changed: 94 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -127,77 +127,135 @@ function regenerate_public_rbac_multi_cluster() {
127127
}
128128

129129
function update_licenses() {
130-
echo 'regenerating licenses'
131-
time scripts/evergreen/update_licenses.sh 2>&1 | prepend "update_licenses"
132-
git add LICENSE-THIRD-PARTY
130+
if [[ "${MDB_UPDATE_LICENSES:-""}" == "true" ]]; then
131+
echo 'regenerating licenses'
132+
time scripts/evergreen/update_licenses.sh 2>&1 | prepend "update_licenses"
133+
git add LICENSE-THIRD-PARTY
134+
fi
133135
}
134136

135137
function check_erroneous_kubebuilder_annotations() {
136138
# Makes sure there are not erroneous kubebuilder annotations that can
137139
# end up in CRDs as descriptions.
138140
if grep "// kubebuilder" ./* -r --exclude-dir=vendor --include=\*.go; then
139-
echo "Found an erroneous kubebuilder annotation"
141+
echo -e "${RED}Found an erroneous kubebuilder annotation${NO_COLOR}"
140142
exit 1
141143
fi
142144
}
143145

144146
function check_incorrect_makefile_variable_brackets() {
145147
if find . -name "Makefile" | grep -v vendor | xargs grep "\${"; then
146-
echo 'ERROR: Makefiles should NEVER contain curly brackets variables'
148+
echo -e "${RED}ERROR: Makefiles should NEVER contain curly brackets variables${NO_COLOR}"
147149
exit 1
148150
fi
149151
}
150152

153+
function validate_snippets() {
154+
echo scripts/code_snippets/validate_snippets.py
155+
}
156+
157+
# Helper function to capture background job PID with job name
158+
capture_bg_job() {
159+
local job_name="$1"
160+
local job_pid=$!
161+
bg_job_pids+=("${job_pid}")
162+
bg_job_pids_with_names+=("${job_pid}:${job_name}")
163+
echo "Started ${job_name} with PID: ${job_pid}"
164+
}
165+
166+
get_job_name() {
167+
local search_pid="$1"
168+
local match
169+
match=$(printf '%s\n' "${bg_job_pids_with_names[@]}" | grep "^${search_pid}:")
170+
echo "${match#*:}" # Remove everything up to and including the colon
171+
}
172+
151173
function pre_commit() {
152-
if [[ "${MDB_UPDATE_LICENSES:-""}" == "true" ]]; then
153-
( (time update_licenses) 2>&1 | prepend "update_licenses" ) &
154-
fi
155-
( (time scripts/evergreen/lint_code.sh) 2>&1 | prepend "lint_code.sh" ) &
156-
( (time start_shellcheck) 2>&1 | prepend "shellcheck" ) &
174+
# Array to store background job PIDs
175+
# IMPORTANT: ensure each task is executed in it's own subshell following the pattern:
176+
# time new_check 2>&1 | prepend "new_check" &
177+
# capture_bg_job "new_check"
178+
179+
# those bg_job_ vars are global and capture_bg_job is appending to them on each call
180+
bg_job_pids=()
181+
bg_job_pids_with_names=()
182+
183+
{
184+
# Update release.json first in case there is a newer version
185+
time update_release_json
186+
# We need to generate the values files first
187+
time update_values_yaml_files
188+
# The values files are used for generating the standalone yaml
189+
time generate_standalone_yaml
190+
} 2>&1 | prepend "update_jobs" &
191+
capture_bg_job "update_jobs"
192+
193+
time update_licenses 2>&1 | prepend "update_licenses" &
194+
capture_bg_job "update_licenses"
195+
196+
time scripts/evergreen/lint_code.sh 2>&1 | prepend "lint_code.sh" &
197+
capture_bg_job "lint_code.sh"
157198

158-
# Update release.json first in case there is a newer version
159-
(time update_release_json) 2>&1 | prepend "update_release_json"
160-
# We need to generate the values files first
161-
(time update_values_yaml_files) 2>&1 | prepend "update_values_yaml_files"
162-
# The values files are used for generating the standalone yaml
163-
(time generate_standalone_yaml) 2>&1 | prepend "generate_standalone_yaml"
199+
time start_shellcheck 2>&1 | prepend "shellcheck" &
200+
capture_bg_job "shellcheck"
164201

165-
( (time regenerate_public_rbac_multi_cluster) 2>&1 | prepend "regenerate_public_rbac_multi_cluster" ) &
202+
time validate_snippets 2>&1 | prepend "validate_snippets" &
203+
capture_bg_job "validate_snippets"
204+
205+
time regenerate_public_rbac_multi_cluster 2>&1 | prepend "regenerate_public_rbac_multi_cluster" &
206+
capture_bg_job "regenerate_public_rbac_multi_cluster"
166207

167208
# Run black and isort on python files that have changed
168-
( (time python_formatting) 2>&1 | prepend "python_formatting") &
209+
time python_formatting 2>&1 | prepend "python_formatting" &
210+
capture_bg_job "python_formatting"
211+
212+
time check_erroneous_kubebuilder_annotations 2>&1 | prepend "check_erroneous_kubebuilder_annotations" &
213+
capture_bg_job "check_erroneous_kubebuilder_annotations"
214+
215+
# add any other checks above
169216

170-
( (time check_erroneous_kubebuilder_annotations) 2>&1 | prepend "check_erroneous_kubebuilder_annotations" ) &
217+
# Wait for all background jobs and check their exit codes
218+
failures=()
219+
for pid in "${bg_job_pids[@]}"; do
220+
wait "${pid}" || {
221+
job_name=$(get_job_name "${pid}")
222+
failures+=(" ${RED}${job_name} (PID ${pid})${NO_COLOR}")
223+
}
224+
done
171225

172-
wait
226+
if [[ ${#failures[@]} -gt 0 ]]; then
227+
echo -e "${RED}Some checks have failed:${NO_COLOR}"
228+
for failure in "${failures[@]}"; do
229+
echo -e "$failure"
230+
done
231+
echo -e "${RED}To see the details look for the job's logs by it's prefixed name (e.g. \"shellcheck:\").${NO_COLOR}"
232+
exit 1
233+
fi
234+
235+
echo -e "${GREEN}pre-commit: All checks passed!${NO_COLOR}"
173236
}
174237

175238
# Function to run shellcheck on a single file
176239
run_shellcheck() {
177240
local file="$1"
178241
echo "Running shellcheck on $file"
179242
if ! shellcheck --color=always -x "$file" -e SC2154 -e SC1091 -e SC1090 -e SC2148 -o require-variable-braces -P "scripts"; then
180-
echo "shellcheck failed on $file"
243+
echo -e "${RED}shellcheck failed on $file${NO_COLOR}"
181244
exit 1
182245
fi
183246
}
247+
# Export function so it's available in subshells
248+
export -f run_shellcheck
184249

185250
start_shellcheck() {
186-
files_1=$(find scripts -type f -name "*.sh")
187-
files_2=$(find scripts/dev/contexts -type f | grep -v private-context)
188-
files_3=$(find scripts/funcs -type f)
189-
files_4=$(find public/architectures -type f -name "*.sh")
190-
files=$(echo -e "$files_1\n$files_2\n$files_3\n$files_4")
191-
# Process each file in parallel
192-
for file in $files; do
193-
run_shellcheck "$file" &
194-
done
195-
196-
# Wait for all background jobs
197-
for job in $(jobs -p); do
198-
wait "$job" || exit 1
199-
done
200-
251+
# shellcheck disable=SC2016
252+
{
253+
find scripts -type f -name "*.sh"
254+
find scripts/dev/contexts -type f | grep -v private-context
255+
find scripts/funcs -type f
256+
find public/architectures -type f -name "*.sh"
257+
find docs/ -type f -name "*.sh"
258+
} | xargs -I {} -P 20 bash -c 'run_shellcheck "$1"' _ {}
201259
}
202260

203261
cmd=${1:-"pre-commit"}

scripts/funcs/printing

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,5 @@ prepend() {
2020
}
2121

2222
export RED='\033[0;31m'
23+
export GREEN='\033[0;32m'
2324
export NO_COLOR='\033[0m'

0 commit comments

Comments
 (0)