7f5ea857be45e43cece2cfb37093c6c51b23f79d braney Sun Sep 6 08:23:15 2026 -0700 docent: run the nightly regression out of a checkout of its own The header of this script has said since it was written that once the tests were on master the cron should read them out of a clone of its own, the way catalogNightly has one under /hive/users/braney, so that an ordinary day's editing in ~/kent cannot change what the cron measures. The suite landed on master yesterday, so this does it. The clone is /hive/users/braney/docentNightly/kent, beside the log directory the job already writes to. Nothing here is built, so it needs no submodules and no make. --update brings that clone to origin/master and then re-runs this script from the result. The re-exec is why this is a flag here rather than a separate driver script beside the crontab: the whole job stays in the tree where it can be reviewed and committed, and a change to this file takes effect the same night as a change to a test instead of a night later. --update will only ever touch a checkout that is a pristine mirror of origin/master. A working tree with uncommitted edits, or one holding a commit that has not been pushed, is left alone and reported rather than reset, because `reset --hard` in ~/kent would throw away work. That guard is what makes it safe for the flag to live in a script that also sits in a working tree. Both refusals mail with the same subject shape as a finished run, since a night when nothing ran must not read as a quiet night. refs #38252 diff --git src/hg/utils/docent/tests/regress/nightly.sh src/hg/utils/docent/tests/regress/nightly.sh index f3bc5d90ed2..c710d6e1ad0 100755 --- src/hg/utils/docent/tests/regress/nightly.sh +++ src/hg/utils/docent/tests/regress/nightly.sh @@ -1,95 +1,150 @@ #!/bin/bash # Nightly Docent regression run against genome-test, for cron. refs #38252 # # Mails a report every night whether anything failed or not, on purpose and to match # the catalogNightly job: no mail means the cron itself has stopped, rather than # meaning the browser is fine. Always exits 0, so cron does not send a second mail # of its own on top of this one. # # Runs the tests that are COMMITTED, listed from git rather than from the directory. # The directory also holds work in progress -- scripts written against a ticket whose # recipe is not right yet -- and those must not mail a failure every night. A newly # committed test is picked up with no edit here. # -# It runs out of whatever checkout this script itself lives in, so a second copy in a -# second checkout needs no argument. While the tests live only on branch -# docentTests37892 that means Brian's worktree. Once the branch is on master this -# should move to a checkout of its own, the way catalogNightly has one under -# /hive/users/braney, so that an ordinary day's editing cannot change what the cron -# measures. +# It runs out of whatever checkout this script itself lives in, so a copy in a second +# checkout needs no argument. The cron runs it out of a clone of its own, +# +# /hive/users/braney/docentNightly/kent +# +# the way catalogNightly has one under /hive/users/braney, so that an ordinary day's +# editing in ~/kent cannot change what the cron measures. Nothing here is built, so +# the clone needs no submodules and no make. +# +# --update brings that clone to origin/master and then re-runs this script from the +# result. Two reasons for the re-exec rather than a separate driver script beside the +# crontab: the whole job stays in the tree where it can be reviewed and committed, and +# a change to this file takes effect the same night as a change to a test, instead of +# a night later. +# +# --update will only ever touch a checkout that is a pristine mirror of origin/master. +# A working tree with uncommitted edits, or one holding a commit that has not been +# pushed, is left alone and reported, because a `reset --hard` there would throw away +# work. That is what makes it safe for the flag to exist in a script that also sits in +# a working tree. set -u export PATH=/usr/bin:/bin:/usr/local/bin:$PATH HERE=$(cd "$(dirname "$0")" && pwd) PW=/hive/groups/browser/uiTest/pw PW_ENV="env PLAYWRIGHT_BROWSERS_PATH=$PW/browsers NODE_PATH=$PW/node_modules" TO=${DOCENT_NIGHTLY_TO:-braney@ucsc.edu} LOGDIR=${DOCENT_NIGHTLY_LOGS:-/hive/users/braney/docentNightly/logs} STAMP=$(date +%Y-%m-%d_%H%M) mkdir -p "$LOGDIR" OUT="$LOGDIR/$STAMP.txt" +# A job that could not start has to arrive looking like the others, or a night when +# nothing ran reads as a quiet night. Same subject shape, same log file, exit 0. +bail() { +{ + echo "Docent regression run, $(date)" + echo "checkout: $HERE" + echo + echo "$@" + echo + echo "Nothing was tested. This is a problem with this job, not with the browser." +} > "$OUT" 2>&1 +mail -s "docent regression: BROKEN (0 ok) $(date +%F)" "$TO" < "$OUT" +exit 0 +} + +if [ "${1:-}" = --update ] && [ -z "${DOCENT_NIGHTLY_UPDATED:-}" ]; then + shift + dirty=$(git -C "$HERE" status --porcelain --untracked-files=no 2>&1) + if [ -n "$dirty" ]; then + bail "--update will not reset $HERE: it has uncommitted changes. + +$dirty" + fi + git -C "$HERE" fetch -q origin master 2>&1 || \ + bail "--update could not fetch origin master into $HERE." + ahead=$(git -C "$HERE" rev-list --oneline FETCH_HEAD..HEAD 2>&1) + if [ -n "$ahead" ]; then + bail "--update will not reset $HERE: it holds commits that are not on origin/master. + +$ahead" + fi + git -C "$HERE" reset -q --hard FETCH_HEAD 2>&1 || \ + bail "--update could not move $HERE to FETCH_HEAD." + # Re-open this file by name, which is now the copy that just arrived. + export DOCENT_NIGHTLY_UPDATED=1 + exec "$0" "$@" +fi + # The committed scripts, as bare test names. `make test T=` takes a list. TESTS=$(cd "$HERE" && git ls-files '*.docent.yaml' 2>/dev/null \ | sed 's#.*/##; s#\.docent\.yaml$##' | tr '\n' ' ') { echo "Docent regression run, $(date)" echo "checkout: $HERE" echo "branch: $(git -C "$HERE" rev-parse --abbrev-ref HEAD 2>/dev/null)" echo "commit: $(git -C "$HERE" rev-parse --short HEAD 2>/dev/null)" + if [ -n "${DOCENT_NIGHTLY_UPDATED:-}" ]; then + echo "updated: this checkout was reset to origin/master before the run" + fi echo if [ -z "${TESTS// /}" ]; then echo "NO COMMITTED TESTS FOUND -- git ls-files returned nothing in $HERE." echo "That is a problem with this job, not with the browser." subject_state="BROKEN" else echo "tests: $TESTS" echo echo "--- preflight (the sessions and hubs these tests depend on) ---" # Reported separately from the tests on purpose. A session that has been deleted # or a hub that has moved is not a browser regression, and the two must not arrive # as the same red. # # preflight is given the committed list rather than left to scan the directory, so a # dead fixture belonging to a work-in-progress script is not reported as a problem # with a run that never included it. if (cd "$HERE" && $PW_ENV node ../preflight.js . $TESTS 2>&1); then pf=ok else pf=MISSING fi echo echo "--- tests ---" if (cd "$HERE" && make test T="$TESTS" 2>&1); then tests=pass else tests=FAIL fi if [ "$tests" = FAIL ] && [ "$pf" = MISSING ]; then subject_state="FAIL (fixtures missing too)" elif [ "$tests" = FAIL ]; then subject_state="FAIL" elif [ "$pf" = MISSING ]; then subject_state="pass, but a fixture is missing" else subject_state="pass" fi fi echo echo "full log kept at $OUT" } > "$OUT" 2>&1 # subject_state is set inside the block above, which runs in this shell, so it survives. n=$(grep -c '^ ok$' "$OUT" 2>/dev/null || echo 0) mail -s "docent regression: ${subject_state:-unknown} ($n ok) $(date +%F)" "$TO" < "$OUT" # Keep two months of logs and no more. find "$LOGDIR" -name '*.txt' -mtime +60 -delete 2>/dev/null exit 0