Skip to content

Commit 1dee560

Browse files
authored
Merge pull request #494 from casparvl/improve_error_on_unmerged_pr
Improve error reported by bot when using unmerged EasyBuild PR in easystack file
2 parents bc84aec + 8d6493e commit 1dee560

File tree

3 files changed

+127
-57
lines changed

3 files changed

+127
-57
lines changed

EESSI-install-software.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ else
237237
copy_build_log "${eb_last_log}" "${build_logs_dir}"
238238
fi
239239

240-
$TOPDIR/check_missing_installations.sh ${TOPDIR}/${easystack_file}
240+
$TOPDIR/check_missing_installations.sh ${TOPDIR}/${easystack_file} ${TOPDIR}/${pr_diff}
241241
else
242242
fatal_error "Easystack file ${easystack_file} not found!"
243243
fi

bot/check-build.sh

Lines changed: 92 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -98,15 +98,15 @@ job_dir=${PWD}
9898
job_out="slurm-${SLURM_JOB_ID}.out"
9999
[[ ${VERBOSE} -ne 0 ]] && echo ">> searching for job output file(s) matching '"${job_out}"'"
100100
if [[ -f ${job_out} ]]; then
101-
SLURM=1
101+
SLURM_OUTPUT_FOUND=1
102102
[[ ${VERBOSE} -ne 0 ]] && echo " found slurm output file '"${job_out}"'"
103103
else
104-
SLURM=0
104+
SLURM_OUTPUT_FOUND=0
105105
[[ ${VERBOSE} -ne 0 ]] && echo " Slurm output file '"${job_out}"' NOT found"
106106
fi
107107

108108
ERROR=-1
109-
if [[ ${SLURM} -eq 1 ]]; then
109+
if [[ ${SLURM_OUTPUT_FOUND} -eq 1 ]]; then
110110
GP_error='ERROR: '
111111
grep_out=$(grep -v "^>> searching for " ${job_dir}/${job_out} | grep "${GP_error}")
112112
[[ $? -eq 0 ]] && ERROR=1 || ERROR=0
@@ -116,7 +116,7 @@ if [[ ${SLURM} -eq 1 ]]; then
116116
fi
117117

118118
FAILED=-1
119-
if [[ ${SLURM} -eq 1 ]]; then
119+
if [[ ${SLURM_OUTPUT_FOUND} -eq 1 ]]; then
120120
GP_failed='FAILED: '
121121
grep_out=$(grep -v "^>> searching for " ${job_dir}/${job_out} | grep "${GP_failed}")
122122
[[ $? -eq 0 ]] && FAILED=1 || FAILED=0
@@ -126,7 +126,7 @@ if [[ ${SLURM} -eq 1 ]]; then
126126
fi
127127

128128
MISSING=-1
129-
if [[ ${SLURM} -eq 1 ]]; then
129+
if [[ ${SLURM_OUTPUT_FOUND} -eq 1 ]]; then
130130
GP_req_missing=' required modules missing:'
131131
grep_out=$(grep -v "^>> searching for " ${job_dir}/${job_out} | grep "${GP_req_missing}")
132132
[[ $? -eq 0 ]] && MISSING=1 || MISSING=0
@@ -136,7 +136,7 @@ if [[ ${SLURM} -eq 1 ]]; then
136136
fi
137137

138138
NO_MISSING=-1
139-
if [[ ${SLURM} -eq 1 ]]; then
139+
if [[ ${SLURM_OUTPUT_FOUND} -eq 1 ]]; then
140140
GP_no_missing='No missing installations'
141141
grep_out=$(grep -v "^>> searching for " ${job_dir}/${job_out} | grep "${GP_no_missing}")
142142
[[ $? -eq 0 ]] && NO_MISSING=1 || NO_MISSING=0
@@ -147,7 +147,7 @@ fi
147147

148148
TGZ=-1
149149
TARBALL=
150-
if [[ ${SLURM} -eq 1 ]]; then
150+
if [[ ${SLURM_OUTPUT_FOUND} -eq 1 ]]; then
151151
GP_tgz_created="\.tar\.gz created!"
152152
grep_out=$(grep -v "^>> searching for " ${job_dir}/${job_out} | grep "${GP_tgz_created}" | sort -u)
153153
if [[ $? -eq 0 ]]; then
@@ -169,9 +169,27 @@ fi
169169
[[ ${VERBOSE} -ne 0 ]] && echo " NO_MISSING.: $([[ $NO_MISSING -eq 1 ]] && echo 'yes' || echo 'no') (yes)"
170170
[[ ${VERBOSE} -ne 0 ]] && echo " TGZ_CREATED: $([[ $TGZ -eq 1 ]] && echo 'yes' || echo 'no') (yes)"
171171

172+
# Here, we try to do some additional analysis on the output file
173+
# to see if we can print a more clear 'reason' for the failure
174+
# For now, we only analyse unmerged EasyConfigs as potential cause, but we can easily add checks for other
175+
# specific scenarios below
176+
177+
# Check for the pattern being added here by check_missing_installations.sh to the output to
178+
# see if EasyConfigs might have been unmerged, and that's causing a failure
179+
UNMERGED_EASYCONFIG=-1
180+
if [[ ${SLURM_OUTPUT_FOUND} -eq 1 ]]; then
181+
gp_unmerged="are you sure all PRs referenced have been merged in EasyBuild"
182+
grep_unmerged=$(grep -v "^>> searching for " ${job_dir}/${job_out} | grep "${gp_unmerged}")
183+
[[ $? -eq 0 ]] && UNMERGED_EASYCONFIG=1 || UNMERGED_EASYCONFIG=0
184+
# have to be careful to not add searched for pattern into slurm out file
185+
[[ ${VERBOSE} -ne 0 ]] && echo ">> searching for '"${gp_unmerged}"'"
186+
[[ ${VERBOSE} -ne 0 ]] && echo "${grep_unmerged}"
187+
fi
188+
172189
job_result_file=_bot_job${SLURM_JOB_ID}.result
173190

174-
if [[ ${SLURM} -eq 1 ]] && \
191+
# Default reason:
192+
if [[ ${SLURM_OUTPUT_FOUND} -eq 1 ]] && \
175193
[[ ${ERROR} -eq 0 ]] && \
176194
[[ ${FAILED} -eq 0 ]] && \
177195
[[ ${MISSING} -eq 0 ]] && \
@@ -180,10 +198,17 @@ if [[ ${SLURM} -eq 1 ]] && \
180198
[[ ! -z ${TARBALL} ]]; then
181199
# SUCCESS
182200
status="SUCCESS"
201+
reason=""
183202
summary=":grin: SUCCESS"
203+
elif [[ ${UNMERGED_EASYCONFIG} -eq 1 ]]; then
204+
status="FAILURE"
205+
reason="EasyConfig not found during missing installation check. Are you sure all PRs referenced have been merged in EasyBuild?"
206+
summary=":cry: FAILURE"
184207
else
185208
# FAILURE
186209
status="FAILURE"
210+
# General failure, we don't know a more specific reason
211+
reason=""
187212
summary=":cry: FAILURE"
188213
fi
189214

@@ -253,14 +278,6 @@ fi
253278
# </details>
254279
###
255280

256-
# construct and write complete PR comment details: implements third alternative
257-
comment_template="<details>__SUMMARY_FMT__<dl>__DETAILS_FMT____ARTEFACTS_FMT__</dl></details>"
258-
comment_summary_fmt="<summary>__SUMMARY__ _(click triangle for details)_</summary>"
259-
comment_details_fmt="<dt>_Details_</dt><dd>__DETAILS_LIST__</dd>"
260-
comment_success_item_fmt=":white_check_mark: __ITEM__"
261-
comment_failure_item_fmt=":x: __ITEM__"
262-
comment_artefacts_fmt="<dt>_Artefacts_</dt><dd>__ARTEFACTS_LIST__</dd>"
263-
comment_artefact_details_fmt="<details>__ARTEFACT_SUMMARY____ARTEFACT_DETAILS__</details>"
264281

265282
function print_br_item() {
266283
format="${1}"
@@ -332,42 +349,65 @@ echo -n "comment_description = " >> ${job_result_file}
332349
# - __DETAILS_FMT__ -> variable $comment_details
333350
# - __ARTEFACTS_FMT__ -> variable $comment_artefacts
334351

352+
# construct and write complete PR comment details: implements third alternative
353+
comment_template="<details>__SUMMARY_FMT__<dl>__REASON_FMT____DETAILS_FMT____ARTEFACTS_FMT__</dl></details>"
354+
comment_success_item_fmt=":white_check_mark: __ITEM__"
355+
comment_failure_item_fmt=":x: __ITEM__"
356+
357+
# Initialize comment_description
358+
comment_description=${comment_template}
359+
360+
# Now, start replacing template items one by one
361+
# Replace the summary template (__SUMMARY_FMT__)
362+
comment_summary_fmt="<summary>__SUMMARY__ _(click triangle for details)_</summary>"
335363
comment_summary="${comment_summary_fmt/__SUMMARY__/${summary}}"
364+
comment_description=${comment_template/__SUMMARY_FMT__/${comment_summary}}
365+
366+
# Only add if there is a reason (e.g. no reason for successful runs)
367+
if [[ ! -z ${reason} ]]; then
368+
comment_reason_fmt="<dt>_Reason_</dt><dd>__REASONS__</dd>"
369+
reason_details="${comment_reason_fmt/__REASONS__/${reason}}"
370+
comment_description=${comment_description/__REASON_FMT__/${reason_details}}
371+
else
372+
comment_description=${comment_description/__REASON_FMT__/""}
373+
fi
336374

337-
# first construct comment_details_list, abbreviated CoDeList
375+
# Replace the details template (__DETAILS_FMT__)
376+
# first construct comment_details_list, abbreviated comment_details_list
338377
# then use it to set comment_details
339-
CoDeList=""
378+
comment_details_list=""
340379

341380
success_msg="job output file <code>${job_out}</code>"
342381
failure_msg="no job output file <code>${job_out}</code>"
343-
CoDeList=${CoDeList}$(add_detail ${SLURM} 1 "${success_msg}" "${failure_msg}")
382+
comment_details_list=${comment_details_list}$(add_detail ${SLURM_OUTPUT_FOUND} 1 "${success_msg}" "${failure_msg}")
344383

345384
success_msg="no message matching <code>${GP_error}</code>"
346385
failure_msg="found message matching <code>${GP_error}</code>"
347-
CoDeList=${CoDeList}$(add_detail ${ERROR} 0 "${success_msg}" "${failure_msg}")
386+
comment_details_list=${comment_details_list}$(add_detail ${ERROR} 0 "${success_msg}" "${failure_msg}")
348387

349388
success_msg="no message matching <code>${GP_failed}</code>"
350389
failure_msg="found message matching <code>${GP_failed}</code>"
351-
CoDeList=${CoDeList}$(add_detail ${FAILED} 0 "${success_msg}" "${failure_msg}")
390+
comment_details_list=${comment_details_list}$(add_detail ${FAILED} 0 "${success_msg}" "${failure_msg}")
352391

353392
success_msg="no message matching <code>${GP_req_missing}</code>"
354393
failure_msg="found message matching <code>${GP_req_missing}</code>"
355-
CoDeList=${CoDeList}$(add_detail ${MISSING} 0 "${success_msg}" "${failure_msg}")
394+
comment_details_list=${comment_details_list}$(add_detail ${MISSING} 0 "${success_msg}" "${failure_msg}")
356395

357396
success_msg="found message(s) matching <code>${GP_no_missing}</code>"
358397
failure_msg="no message matching <code>${GP_no_missing}</code>"
359-
CoDeList=${CoDeList}$(add_detail ${NO_MISSING} 1 "${success_msg}" "${failure_msg}")
398+
comment_details_list=${comment_details_list}$(add_detail ${NO_MISSING} 1 "${success_msg}" "${failure_msg}")
360399

361400
success_msg="found message matching <code>${GP_tgz_created}</code>"
362401
failure_msg="no message matching <code>${GP_tgz_created}</code>"
363-
CoDeList=${CoDeList}$(add_detail ${TGZ} 1 "${success_msg}" "${failure_msg}")
364-
365-
comment_details="${comment_details_fmt/__DETAILS_LIST__/${CoDeList}}"
366-
402+
comment_details_list=${comment_details_list}$(add_detail ${TGZ} 1 "${success_msg}" "${failure_msg}")
403+
# Now, do the actual replacement of __DETAILS_FMT__
404+
comment_details_fmt="<dt>_Details_</dt><dd>__DETAILS_LIST__</dd>"
405+
comment_details="${comment_details_fmt/__DETAILS_LIST__/${comment_details_list}}"
406+
comment_description=${comment_description/__DETAILS_FMT__/${comment_details}}
367407

368-
# first construct comment_artefacts_list, abbreviated CoArList
408+
# first construct comment_artefacts_list
369409
# then use it to set comment_artefacts
370-
CoArList=""
410+
comment_artifacts_list=""
371411

372412
# TARBALL should only contain a single tarball
373413
if [[ ! -z ${TARBALL} ]]; then
@@ -427,50 +467,49 @@ if [[ ! -z ${TARBALL} ]]; then
427467
software_pkgs=$(echo "${software_entries}" | sed -e "s@${prefix}/software/@@" | awk -F/ '{if (NR >= 2) {print $1 "/" $2}}' | sort -u)
428468

429469
artefact_summary="<summary>$(print_code_item '__ITEM__' ${TARBALL})</summary>"
430-
CoArList=""
431-
CoArList="${CoArList}$(print_br_item2 'size: __ITEM__ MiB (__ITEM2__ bytes)' ${size_mib} ${size})"
432-
CoArList="${CoArList}$(print_br_item 'entries: __ITEM__' ${entries})"
433-
CoArList="${CoArList}$(print_br_item 'modules under ___ITEM___' ${prefix}/modules/all)"
434-
CoArList="${CoArList}<pre>"
470+
comment_artifacts_list=""
471+
comment_artifacts_list="${comment_artifacts_list}$(print_br_item2 'size: __ITEM__ MiB (__ITEM2__ bytes)' ${size_mib} ${size})"
472+
comment_artifacts_list="${comment_artifacts_list}$(print_br_item 'entries: __ITEM__' ${entries})"
473+
comment_artifacts_list="${comment_artifacts_list}$(print_br_item 'modules under ___ITEM___' ${prefix}/modules/all)"
474+
comment_artifacts_list="${comment_artifacts_list}<pre>"
435475
if [[ ! -z ${modules} ]]; then
436476
while IFS= read -r mod ; do
437-
CoArList="${CoArList}$(print_br_item '<code>__ITEM__</code>' ${mod})"
477+
comment_artifacts_list="${comment_artifacts_list}$(print_br_item '<code>__ITEM__</code>' ${mod})"
438478
done <<< "${modules}"
439479
else
440-
CoArList="${CoArList}$(print_br_item '__ITEM__' 'no module files in tarball')"
480+
comment_artifacts_list="${comment_artifacts_list}$(print_br_item '__ITEM__' 'no module files in tarball')"
441481
fi
442-
CoArList="${CoArList}</pre>"
443-
CoArList="${CoArList}$(print_br_item 'software under ___ITEM___' ${prefix}/software)"
444-
CoArList="${CoArList}<pre>"
482+
comment_artifacts_list="${comment_artifacts_list}</pre>"
483+
comment_artifacts_list="${comment_artifacts_list}$(print_br_item 'software under ___ITEM___' ${prefix}/software)"
484+
comment_artifacts_list="${comment_artifacts_list}<pre>"
445485
if [[ ! -z ${software_pkgs} ]]; then
446486
while IFS= read -r sw_pkg ; do
447-
CoArList="${CoArList}$(print_br_item '<code>__ITEM__</code>' ${sw_pkg})"
487+
comment_artifacts_list="${comment_artifacts_list}$(print_br_item '<code>__ITEM__</code>' ${sw_pkg})"
448488
done <<< "${software_pkgs}"
449489
else
450-
CoArList="${CoArList}$(print_br_item '__ITEM__' 'no software packages in tarball')"
490+
comment_artifacts_list="${comment_artifacts_list}$(print_br_item '__ITEM__' 'no software packages in tarball')"
451491
fi
452-
CoArList="${CoArList}</pre>"
453-
CoArList="${CoArList}$(print_br_item 'other under ___ITEM___' ${prefix})"
454-
CoArList="${CoArList}<pre>"
492+
comment_artifacts_list="${comment_artifacts_list}</pre>"
493+
comment_artifacts_list="${comment_artifacts_list}$(print_br_item 'other under ___ITEM___' ${prefix})"
494+
comment_artifacts_list="${comment_artifacts_list}<pre>"
455495
if [[ ! -z ${other_shortened} ]]; then
456496
while IFS= read -r other ; do
457-
CoArList="${CoArList}$(print_br_item '<code>__ITEM__</code>' ${other})"
497+
comment_artifacts_list="${comment_artifacts_list}$(print_br_item '<code>__ITEM__</code>' ${other})"
458498
done <<< "${other_shortened}"
459499
else
460-
CoArList="${CoArList}$(print_br_item '__ITEM__' 'no other files in tarball')"
500+
comment_artifacts_list="${comment_artifacts_list}$(print_br_item '__ITEM__' 'no other files in tarball')"
461501
fi
462-
CoArList="${CoArList}</pre>"
502+
comment_artifacts_list="${comment_artifacts_list}</pre>"
463503
else
464-
CoArList="${CoArList}$(print_dd_item 'No artefacts were created or found.' '')"
504+
comment_artifacts_list="${comment_artifacts_list}$(print_dd_item 'No artefacts were created or found.' '')"
465505
fi
466506

507+
comment_artefact_details_fmt="<details>__ARTEFACT_SUMMARY____ARTEFACT_DETAILS__</details>"
467508
comment_artefacts_details="${comment_artefact_details_fmt/__ARTEFACT_SUMMARY__/${artefact_summary}}"
468-
comment_artefacts_details="${comment_artefacts_details/__ARTEFACT_DETAILS__/${CoArList}}"
469-
comment_artefacts="${comment_artefacts_fmt/__ARTEFACTS_LIST__/${comment_artefacts_details}}"
509+
comment_artefacts_details="${comment_artefacts_details/__ARTEFACT_DETAILS__/${comment_artifacts_list}}"
470510

471-
# now put all pieces together creating comment_details from comment_template
472-
comment_description=${comment_template/__SUMMARY_FMT__/${comment_summary}}
473-
comment_description=${comment_description/__DETAILS_FMT__/${comment_details}}
511+
comment_artefacts_fmt="<dt>_Artefacts_</dt><dd>__ARTEFACTS_LIST__</dd>"
512+
comment_artefacts="${comment_artefacts_fmt/__ARTEFACTS_LIST__/${comment_artefacts_details}}"
474513
comment_description=${comment_description/__ARTEFACTS_FMT__/${comment_artefacts}}
475514

476515
echo "${comment_description}" >> ${job_result_file}

check_missing_installations.sh

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,15 @@
1010

1111
TOPDIR=$(dirname $(realpath $0))
1212

13-
if [ $# -ne 1 ]; then
14-
echo "ERROR: Usage: $0 <path to easystack file>" >&2
13+
if [ "$#" -eq 1 ]; then
14+
true
15+
elif [ "$#" -eq 2 ]; then
16+
echo "Using $2 to give create exceptions for PR filtering of easystack"
17+
# Find lines that are added and use from-pr, make them unique, grab the
18+
# PR numbers and use them to construct something we can use within awk
19+
pr_exceptions=$(grep ^+ $2 | grep from-pr | uniq | awk '{print $3}' | xargs -i echo " || /'{}'/")
20+
else
21+
echo "ERROR: Usage: $0 <path to easystack file> (<optional path to PR diff>)" >&2
1522
exit 1
1623
fi
1724
easystack=$1
@@ -24,7 +31,7 @@ export EASYBUILD_ROBOT_PATHS=$LOCAL_TMPDIR/easyconfigs/easybuild/easyconfigs
2431

2532
# All PRs used in EESSI are supposed to be merged, so we can strip out all cases of from-pr
2633
tmp_easystack=${LOCAL_TMPDIR}/$(basename ${easystack})
27-
grep -v from-pr ${easystack} > ${tmp_easystack}
34+
grep -v from-pr ${easystack} > ${tmp_easystack}
2835

2936
source $TOPDIR/scripts/utils.sh
3037

@@ -40,6 +47,30 @@ exit_code=${PIPESTATUS[0]}
4047

4148
ok_msg="Command 'eb --missing ...' succeeded, analysing output..."
4249
fail_msg="Command 'eb --missing ...' failed, check log '${eb_missing_out}'"
50+
if [ "$exit_code" -ne 0 ] && [ ! -z $pr_exceptions ]; then
51+
# We might have failed due to unmerged PRs. Try to make exceptions for --from-pr added in this PR
52+
# to software-layer, and see if then it passes. If so, we can report a more specific fail_msg
53+
# Note that if no --from-pr's were used in this PR, $pr_exceptions will be empty and we might as
54+
# well skip this check - unmerged PRs can not be the reason for the non-zero exit code in that scenario
55+
56+
# Let's use awk so we can allow for exceptions if we are given a PR diff file
57+
awk_command="awk '\!/'from-pr'/ EXCEPTIONS' $easystack"
58+
awk_command=${awk_command/\\/} # Strip out the backslash we needed for !
59+
eval ${awk_command/EXCEPTIONS/$pr_exceptions} > ${tmp_easystack}
60+
61+
msg=">> Checking for missing installations in ${EASYBUILD_INSTALLPATH},"
62+
msg="${msg} allowing for --from-pr's that were added in this PR..."
63+
echo ${msg}
64+
eb_missing_out=$LOCAL_TMPDIR/eb_missing_with_from_pr.out
65+
${EB:-eb} --easystack ${tmp_easystack} --missing 2>&1 | tee ${eb_missing_out}
66+
exit_code_with_from_pr=${PIPESTATUS[0]}
67+
68+
# If now we succeeded, the reason must be that we originally stripped the --from-pr's
69+
if [ "$exit_code_with_from_pr" -eq 0 ]; then
70+
fail_msg="$fail_msg (are you sure all PRs referenced have been merged in EasyBuild?)"
71+
fi
72+
fi
73+
4374
check_exit_code ${exit_code} "${ok_msg}" "${fail_msg}"
4475

4576
# the above assesses the installed software for each easyconfig provided in

0 commit comments

Comments
 (0)