mirror of
https://github.com/grafana/grafana.git
synced 2025-07-24 14:02:12 +08:00
150 lines
3.8 KiB
Bash
Executable File
150 lines
3.8 KiB
Bash
Executable File
#!/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
|