The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
grafana/scripts/ci/backend-tests/shard.sh

149 lines
3.8 KiB

#!/usr/bin/env bash
set -euo pipefail
usage() {
{
echo "shard.sh: Shard tests for parallel execution in CI."
echo "usage: $0 [-h] -n <shard> -m <total_shards> [-d <directory>] [-s]"
echo
echo " -h: Show this help message."
echo " -n: The shard number (1-indexed)."
echo " -m: The total number of shards. Must be equal to or greater than -n."
echo " -N: The shard in shard notation (n/m), corresponding to -n and -m."
echo " -d: The directory to find packages with tests in."
echo " Can be a path or a /... style pattern."
echo " Can be repeated to specify multiple directories."
echo " Can be - to read from stdin."
echo " Default: ./..."
echo " -s: Split final package list with spaces rather than newlines."
} >&2
}
is_int() {
# we can't just return the result of the regex match shellcheck is unhappy...
if [[ "$1" =~ ^[0-9]+$ ]]; then
return 0
else
return 1
fi
}
n=0
m=0
dirs=()
s=0
while getopts ":hn:m:d:sN:" opt; do
case $opt in
h)
usage
exit 0
;;
n)
if ! is_int "$OPTARG"; then
echo "Error: -n must be an integer." >&2
usage
exit 1
fi
n=$OPTARG
;;
m)
if ! is_int "$OPTARG"; then
echo "Error: -m must be an integer." >&2
usage
exit 1
fi
m=$OPTARG
;;
N)
if [[ "$OPTARG" =~ ^([0-9]+)/([0-9]+)$ ]]; then
n="${BASH_REMATCH[1]}"
m="${BASH_REMATCH[2]}"
else
echo "Error: -N must be in the form n/m." >&2
usage
exit 1
fi
;;
d)
dirs+=("$OPTARG")
;;
s)
s=1
;;
\?)
echo "Invalid option: -$OPTARG" >&2
usage
exit 1
;;
:)
echo "Option -$OPTARG requires an argument." >&2
usage
exit 1
;;
esac
done
shift $((OPTIND - 1))
if [[ $n -eq 0 || $m -eq 0 ]]; then
echo "Error: -n and -m are required." >&2
usage
exit 1
fi
if [[ $n -lt 1 || $m -lt 1 ]]; then
echo "Error: -n and -m must be greater than 0." >&2
usage
exit 1
fi
if [[ $n -gt $m ]]; then
echo "Error: -n must be less than or equal to -m." >&2
usage
exit 1
fi
if [[ ${#dirs[@]} -eq 0 ]]; then
readarray -t dirs <<< "$(find . -type f -name 'go.mod' -exec dirname '{}' ';' | awk '{ print $1 "/..."; }')"
fi
# If dirs is just ("-"), read from stdin instead.
if [[ ${#dirs[@]} -eq 1 && "${dirs[0]}" == "-" ]]; then
dirs=()
while IFS= read -r line; do
dirs+=("$line")
done
fi
if [[ $n -eq 1 && $m -eq 1 ]]; then
# If there is only one shard, just return all packages.
for pkg in "${dirs[@]}"; do
if [ $s -eq 1 ]; then
printf "%s " "$pkg"
else
printf "%s\n" "$pkg"
fi
done
exit 0
fi
readarray -t PACKAGES <<< "$(go list -f '{{.Dir}}' -e "${dirs[@]}")"
if [[ ${#PACKAGES[@]} -eq 0 ]]; then
echo "No packages found in directories: ${dirs[*]}" >&2
exit 1
fi
for i in "${!PACKAGES[@]}"; do
if [ -z "$(find "${PACKAGES[i]}" -maxdepth 1 -type f -name '*_test.go' -printf '.' -quit)" ]; then
# There are no test files in this package.
unset 'PACKAGES[i]'
fi
done
for i in "${!PACKAGES[@]}"; do
if (( (i % m) + 1 != n )); then
unset 'PACKAGES[i]'
fi
done
for pkg in "${PACKAGES[@]}"; do
if [ $s -eq 1 ]; then
printf "%s " "$pkg"
else
printf "%s\n" "$pkg"
fi
done