Unverified Commit 3bef0dcf authored by Wolfgang Walther's avatar Wolfgang Walther
Browse files

ci/request-reviews: move get-code-owners to eval/compare

This moves the parsing of ci/OWNERS into the Nix sandbox. We also get
rid of checking out the nixpkgs repo another time in the reviewers
workflow - we already have everything we need in the eval/compare job.

The creation of owners.txt in this way is only temporary, it should
eventually be moved further, similar to how maintainers.json is
currently migrating to a maintainer map for the whole repo stored on the
target branch as artifact.
parent 18ab6b72
Loading
Loading
Loading
Loading
+1 −8
Original line number Diff line number Diff line
@@ -63,13 +63,6 @@ jobs:
          permission-members: read
          permission-pull-requests: write

      - name: Determining code owner reviews
        env:
          REPOSITORY: ${{ github.repository }}
          NUMBER: ${{ github.event.number }}
        run: |
          result/bin/request-code-owner-reviews.sh "$REPOSITORY" "$NUMBER" ci/OWNERS > owners.txt

      - name: Log current API rate limits (github.token)
        env:
          GH_TOKEN: ${{ github.token }}
@@ -149,7 +142,7 @@ jobs:
          # There appears to be no API to request reviews based on GitHub IDs
          jq -r 'keys[]' comparison/maintainers.json \
            | while read -r id; do gh api /user/"$id" --jq .login; done \
            | cat owners.txt - \
            | cat comparison/owners.txt - \
            | GH_TOKEN="$APP_GH_TOKEN" result/bin/request-reviewers.sh "$REPOSITORY" "$NUMBER" "$AUTHOR"

      - name: Log current API rate limits (app-token)
+39 −0
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@
  python3,
  stdenvNoCC,
  makeWrapper,
  codeowners,
}:
let
  python = python3.withPackages (ps: [
@@ -48,6 +49,7 @@ in
{
  combinedDir,
  touchedFilesJson,
  ownersFile ? ../../OWNERS,
}:
let
  # Usually we expect a derivation, but when evaluating in multiple separate steps, we pass
@@ -174,6 +176,7 @@ runCommand "compare"
    nativeBuildInputs = map lib.getBin [
      jq
      cmp-stats
      codeowners
    ];
    maintainers = builtins.toJSON maintainers;
    packages = builtins.toJSON packages;
@@ -222,6 +225,42 @@ runCommand "compare"
      } >> $out/step-summary.md
    fi

    jq -r '.[]' "${touchedFilesJson}" > ./touched-files
    readarray -t touchedFiles < ./touched-files
    echo "This PR touches ''${#touchedFiles[@]} files"

    # TODO: Move ci/OWNERS to Nix and produce owners.json instead of owners.txt.
    for file in "''${touchedFiles[@]}"; do
        result=$(codeowners --file "${ownersFile}" "$file")

        # Remove the file prefix and trim the surrounding spaces
        read -r owners <<< "''${result#"$file"}"
        if [[ "$owners" == "(unowned)" ]]; then
            echo "File $file is unowned"
            continue
        fi
        echo "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
                echo -e "\e[33mCodeowner \"$entry\" for file $file is not valid: Must start with \"@\"\e[0m"
                # 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]}

            echo "$entry" >> "$out/owners.txt"
        done

    done

    cp "$maintainersPath" "$out/maintainers.json"
    cp "$packagesPath" "$out/packages.json"
  ''
+0 −8
Original line number Diff line number Diff line
@@ -3,20 +3,15 @@
  stdenvNoCC,
  makeWrapper,
  coreutils,
  codeowners,
  jq,
  curl,
  github-cli,
  gitMinimal,
}:
stdenvNoCC.mkDerivation {
  name = "request-reviews";
  src = lib.fileset.toSource {
    root = ./.;
    fileset = lib.fileset.unions [
      ./get-code-owners.sh
      ./request-reviewers.sh
      ./request-code-owner-reviews.sh
    ];
  };
  nativeBuildInputs = [ makeWrapper ];
@@ -29,11 +24,8 @@ stdenvNoCC.mkDerivation {
        --set PATH ${
          lib.makeBinPath [
            coreutils
            codeowners
            jq
            curl
            github-cli
            gitMinimal
          ]
        }
    done
+0 −51
Original line number Diff line number Diff line
#!/usr/bin/env bash

# Get the code owners of the files changed by a PR, returning one username or team per line

set -euo pipefail

log() {
    echo "$@" >&2
}

if (( "$#" < 4 )); then
    log "Usage: $0 TOUCHED_FILES_FILE OWNERS_FILE"
    exit 1
fi

touchedFilesFile=$1
ownersFile=$2

readarray -t touchedFiles < "$touchedFilesFile"
log "This PR touches ${#touchedFiles[@]} files"

for file in "${touchedFiles[@]}"; do
    result=$(codeowners --file "$ownersFile" "$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]}

        echo "$entry"
    done

done
+0 −63
Original line number Diff line number Diff line
#!/usr/bin/env bash

# Requests reviews for a PR

set -euo pipefail
tmp=$(mktemp -d)
trap 'rm -rf "$tmp"' exit
SCRIPT_DIR=$(dirname "$0")

log() {
    echo "$@" >&2
}

if (( $# < 3 )); then
    log "Usage: $0 GITHUB_REPO PR_NUMBER OWNERS_FILE"
    exit 1
fi
baseRepo=$1
prNumber=$2
ownersFile=$3

log "Fetching PR info"
prInfo=$(gh api \
  -H "Accept: application/vnd.github+json" \
  -H "X-GitHub-Api-Version: 2022-11-28" \
  "/repos/$baseRepo/pulls/$prNumber")

baseBranch=$(jq -r .base.ref <<< "$prInfo")
log "Base branch: $baseBranch"
prRepo=$(jq -r .head.repo.full_name <<< "$prInfo")
log "PR repo: $prRepo"
prBranch=$(jq -r .head.ref <<< "$prInfo")
log "PR branch: $prBranch"

extraArgs=()
if pwdRepo=$(git rev-parse --show-toplevel 2>/dev/null); then
    # Speedup for local runs
    extraArgs+=(--reference-if-able "$pwdRepo")
fi

log "Fetching Nixpkgs commit history"
# We only need the commit history, not the contents, so we can do a tree-less clone using tree:0
# https://github.blog/open-source/git/get-up-to-speed-with-partial-clone-and-shallow-clone/#user-content-quick-summary
git clone --bare --filter=tree:0 --no-tags --origin upstream "${extraArgs[@]}" https://github.com/"$baseRepo".git "$tmp"/nixpkgs.git

log "Fetching the PR commit history"
# Fetch the PR
git -C "$tmp/nixpkgs.git" remote add fork https://github.com/"$prRepo".git
# This remote config is the same as --filter=tree:0 when cloning
git -C "$tmp/nixpkgs.git" config remote.fork.partialclonefilter tree:0
git -C "$tmp/nixpkgs.git" config remote.fork.promisor true

git -C "$tmp/nixpkgs.git" fetch --no-tags fork "$prBranch"
headRef=$(git -C "$tmp/nixpkgs.git" rev-parse refs/remotes/fork/"$prBranch")

git -C "$tmp/nixpkgs.git" diff --name-only --merge-base "$baseBranch" "$headRef" > "$tmp/touched-files"

# Get the owners file from the base, because we don't want to allow PRs to
# remove code owners to avoid pinging them
git -C "$tmp/nixpkgs.git" show "$baseBranch":"$ownersFile" > "$tmp"/codeowners

log "Requesting reviews from code owners"
"$SCRIPT_DIR"/get-code-owners.sh "$tmp/touched-files" "$tmp"/codeowners