Something went wrong. Try again.
What happens if I push all of nixpkgs
Something went wrong. Try again.
3.4 kB · 97 lines
Shell
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798#!/usr/bin/env bash
# Get the code owners of the files changed by a PR, returning one username per line
set -euo pipefail
log() { echo "$@" >&2}
if (( "$#" < 4 )); then log "Usage: $0 GIT_REPO OWNERS_FILE BASE_REF HEAD_REF" exit 1fi
gitRepo=$1ownersFile=$2baseRef=$3headRef=$4
tmp=$(mktemp -d)trap 'rm -rf "$tmp"' exit
git -C "$gitRepo" diff --name-only --merge-base "$baseRef" "$headRef" > "$tmp/touched-files"readarray -t touchedFiles < "$tmp/touched-files"log "This PR touches ${#touchedFiles[@]} files"
# Get the owners file from the base, because we don't want to allow PRs to# remove code owners to avoid pinging themgit -C "$gitRepo" show "$baseRef":"$ownersFile" > "$tmp"/codeowners
# Associative array with the user as the key for easy de-duplication# Make sure to always lowercase keys to avoid duplicates with different casingsdeclare -A users=()
for file in "${touchedFiles[@]}"; do result=$(codeowners --file "$tmp"/codeowners "$file")
# Remove the file prefix and trim the surrounding spaces read -r owners <<< "${result#"$file"}" if [[ "$owners" == "(unowned)" ]]; then log "File $file is unowned" continue fi log "File $file is owned by $owners"
# Split up multiple owners, separated by arbitrary amounts of spaces IFS=" " read -r -a entries <<< "$owners"
for entry in "${entries[@]}"; do # GitHub technically also supports Emails as code owners, # but we can't easily support that, so let's not if [[ ! "$entry" =~ @(.*) ]]; then warn -e "\e[33mCodeowner \"$entry\" for file $file is not valid: Must start with \"@\"\e[0m" >&2 # Don't fail, because the PR for which this script runs can't fix it, # it has to be fixed in the base branch continue fi # The first regex match is everything after the @ entry=${BASH_REMATCH[1]}
if [[ "$entry" =~ (.*)/(.*) ]]; then # Teams look like $org/$team org=${BASH_REMATCH[1]} team=${BASH_REMATCH[2]}
# Instead of requesting a review from the team itself, # we request reviews from the individual users. # This is because once somebody from a team reviewed the PR, # the API doesn't expose that the team was already requested for a review, # so we wouldn't be able to avoid rerequesting reviews # without saving some some extra state somewhere
# We could also consider implementing a more advanced heuristic # in the future that e.g. only pings one team member, # but escalates to somebody else if that member doesn't respond in time. gh api \ --cache=1h \ -H "Accept: application/vnd.github+json" \ -H "X-GitHub-Api-Version: 2022-11-28" \ "/orgs/$org/teams/$team/members" \ --jq '.[].login' > "$tmp/team-members" readarray -t members < "$tmp/team-members" log "Team $entry has these members: ${members[*]}"
for user in "${members[@]}"; do users[${user,,}]= done else # Everything else is a user users[${entry,,}]= fi done
done
printf "%s\n" "${!users[@]}"