mirror of https://github.com/grafana/grafana.git
				
				
				
			
		
			
				
	
	
		
			150 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
			
		
		
	
	
			150 lines
		
	
	
		
			3.7 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
 | 
						|
    dirs+=("./...")
 | 
						|
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
 |