blob: 6249adc915f91b90147be05c5babf3eefe37356e [file]
#!/usr/bin/env bash
# Parse the Bazel console log into one record per test target that actually ran,
# so the weekly report has both halves of a flake rate: how often a target ran,
# and how often it only passed because it was retried.
#
# Two ways a test shows up as flaky:
# retry-recovered bazel's own --flaky_test_attempts saved it in place
# rerun-recovered it failed the run outright, then passed in the debug rerun
#
# Cached results are skipped. A replayed result is not an execution and cannot
# flake, so counting it would inflate the denominator.
set -euo pipefail
FAILURES=build/failures
RESULTS="$FAILURES/results.tsv"
mkdir -p "$FAILURES"
: > "$RESULTS"
[ -f build/bazel-console.log ] || exit 0
# Bazel's test summary, once colours are stripped (it runs with --color=yes):
# //foo:bar PASSED in 1.2s
# //foo:bar (cached) PASSED in 0.0s
# //foo:bar FLAKY, failed in 1 out of 2 in 3.4s
# //foo:bar FAILED in 2 out of 2 in 12.0s
# //foo:bar FAILED in 2.0s <- no retries configured
awk -v out="$RESULTS" '
{ gsub(/\033\[[0-9;]*m/, "") }
$1 !~ /^\/\// { next }
$2 == "(cached)" { next }
$2 ~ /^FLAKY/ { print $1 "\tretry-recovered\t" $5 "\t" $8 > out; next }
$3 != "in" { next }
$2 == "PASSED" { print $1 "\tpassed\t0\t1" > out; next }
$2 ~ /(FAILED|TIMEOUT|INCOMPLETE)/ {
if ($5 == "out") { print $1 "\tfailed\t" $4 "\t" $7 > out }
else { print $1 "\tfailed\t1\t1" > out }
}
' build/bazel-console.log
# A target counts as recovered only when the rerun actually reported it passing.
# Inferring it from absence in _run2.txt would also sweep up a rerun that timed
# out, came back incomplete, or aborted before printing any summary at all --
# _run2.txt records FAILED only, so all of those look identical to a pass.
if [ -f build/bazel-console2.log ]; then
awk '{ gsub(/\033\[[0-9;]*m/, "") }
$1 ~ /^\/\// && $2 == "PASSED" && $3 == "in" { print $1 }' build/bazel-console2.log \
| sort -u > "$FAILURES/_recovered.txt"
awk -F'\t' -v recovered="$FAILURES/_recovered.txt" '
BEGIN { while ((getline t < recovered) > 0) { recover[t] = 1 } }
$1 in recover { print $1 "\trerun-recovered\t" $3 "\t" ($4 + 1); next }
{ print }
' "$RESULTS" > "$RESULTS.tmp" && mv "$RESULTS.tmp" "$RESULTS"
fi
[ -s "$RESULTS" ] || exit 0
if awk -F'\t' '$2 ~ /-recovered$/ { found = 1 } END { exit !found }' "$RESULTS"; then
{
echo "### Flaky tests"
echo
awk -F'\t' '$2 ~ /-recovered$/ { printf "- `%s` failed %s of %s attempts (%s)\n", $1, $3, $4, $2 }' "$RESULTS"
echo
} >> "${GITHUB_STEP_SUMMARY:-/dev/null}"
fi
jq -Rc \
--arg os "${RUNNER_OS:-}" \
--arg timestamp "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
'select(length > 0) | split("\t")
| { target: .[0], status: .[1], failed: (.[2] | tonumber), attempts: (.[3] | tonumber),
os: $os, timestamp: $timestamp }' \
"$RESULTS" > "$FAILURES/results.jsonl"
echo "results=true" >> "${GITHUB_OUTPUT:-/dev/null}"
echo "Recorded $(wc -l < "$RESULTS" | tr -d ' ') test results"