workflows/reviewers: First-class team package maintainer review requests
This commit is contained in:
11
.github/workflows/reviewers.yml
vendored
11
.github/workflows/reviewers.yml
vendored
@@ -146,19 +146,14 @@ jobs:
|
|||||||
- name: Requesting maintainer reviews
|
- name: Requesting maintainer reviews
|
||||||
if: ${{ steps.app-token.outputs.token }}
|
if: ${{ steps.app-token.outputs.token }}
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{ github.token }}
|
GH_TOKEN: ${{ steps.app-token.outputs.token }}
|
||||||
APP_GH_TOKEN: ${{ steps.app-token.outputs.token }}
|
|
||||||
REPOSITORY: ${{ github.repository }}
|
REPOSITORY: ${{ github.repository }}
|
||||||
|
ORG_ID: ${{ github.repository_owner_id }}
|
||||||
NUMBER: ${{ github.event.number }}
|
NUMBER: ${{ github.event.number }}
|
||||||
AUTHOR: ${{ github.event.pull_request.user.login }}
|
AUTHOR: ${{ github.event.pull_request.user.login }}
|
||||||
# Don't request reviewers on draft PRs
|
# Don't request reviewers on draft PRs
|
||||||
DRY_MODE: ${{ github.event.pull_request.draft && '1' || '' }}
|
DRY_MODE: ${{ github.event.pull_request.draft && '1' || '' }}
|
||||||
run: |
|
run: result/bin/request-maintainers-reviews.sh "$ORG_ID" "$REPOSITORY" "$NUMBER" "$AUTHOR" comparison
|
||||||
# maintainers.json contains GitHub IDs. Look up handles to request reviews from.
|
|
||||||
# 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 \
|
|
||||||
| GH_TOKEN="$APP_GH_TOKEN" result/bin/request-reviewers.sh "$REPOSITORY" "$NUMBER" "$AUTHOR"
|
|
||||||
|
|
||||||
- name: Log current API rate limits (app-token)
|
- name: Log current API rate limits (app-token)
|
||||||
if: ${{ steps.app-token.outputs.token }}
|
if: ${{ steps.app-token.outputs.token }}
|
||||||
|
|||||||
@@ -179,8 +179,12 @@ runCommand "compare"
|
|||||||
jq
|
jq
|
||||||
cmp-stats
|
cmp-stats
|
||||||
];
|
];
|
||||||
maintainers = builtins.toJSON maintainers;
|
maintainers = builtins.toJSON maintainers.users;
|
||||||
passAsFile = [ "maintainers" ];
|
teams = builtins.toJSON maintainers.teams;
|
||||||
|
passAsFile = [
|
||||||
|
"maintainers"
|
||||||
|
"teams"
|
||||||
|
];
|
||||||
}
|
}
|
||||||
''
|
''
|
||||||
mkdir $out
|
mkdir $out
|
||||||
@@ -223,4 +227,5 @@ runCommand "compare"
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
cp "$maintainersPath" "$out/maintainers.json"
|
cp "$maintainersPath" "$out/maintainers.json"
|
||||||
|
cp "$teamsPath" "$out/teams.json"
|
||||||
''
|
''
|
||||||
|
|||||||
@@ -51,15 +51,16 @@ let
|
|||||||
# updates to .json files.
|
# updates to .json files.
|
||||||
# TODO: Support by-name package sets.
|
# TODO: Support by-name package sets.
|
||||||
filenames = lib.optional (lib.length path == 1) "pkgs/by-name/${sharded (lib.head path)}/";
|
filenames = lib.optional (lib.length path == 1) "pkgs/by-name/${sharded (lib.head path)}/";
|
||||||
# TODO: Refactor this so we can ping entire teams instead of the individual members.
|
# meta.maintainers also contains all individual team members.
|
||||||
# Note that this will require keeping track of GH team IDs in "maintainers/teams.nix".
|
# We only want to ping individuals if they're added individually as maintainers, not via teams.
|
||||||
maintainers = package.meta.maintainers or [ ];
|
maintainers = package.meta.nonTeamMaintainers or [ ];
|
||||||
|
teams = package.meta.teams or [ ];
|
||||||
}
|
}
|
||||||
))
|
))
|
||||||
# No need to match up packages without maintainers with their files.
|
# No need to match up packages without maintainers with their files.
|
||||||
# This also filters out attributes where `packge = null`, which is the
|
# This also filters out attributes where `packge = null`, which is the
|
||||||
# case for libintl, for example.
|
# case for libintl, for example.
|
||||||
(lib.filter (pkg: pkg.maintainers != [ ]))
|
(lib.filter (pkg: pkg.maintainers != [ ] || pkg.teams != [ ]))
|
||||||
];
|
];
|
||||||
|
|
||||||
relevantFilenames =
|
relevantFilenames =
|
||||||
@@ -94,20 +95,43 @@ let
|
|||||||
|
|
||||||
attrsWithModifiedFiles = lib.filter (pkg: anyMatchingFiles pkg.filenames) attrsWithFilenames;
|
attrsWithModifiedFiles = lib.filter (pkg: anyMatchingFiles pkg.filenames) attrsWithFilenames;
|
||||||
|
|
||||||
listToPing = lib.concatMap (
|
userPings =
|
||||||
pkg:
|
pkg:
|
||||||
map (maintainer: {
|
map (maintainer: {
|
||||||
id = maintainer.githubId;
|
type = "user";
|
||||||
inherit (maintainer) github;
|
user = toString maintainer.githubId;
|
||||||
packageName = pkg.name;
|
packageName = pkg.name;
|
||||||
dueToFiles = pkg.filenames;
|
});
|
||||||
}) pkg.maintainers
|
|
||||||
|
teamPings =
|
||||||
|
pkg: team:
|
||||||
|
if team ? github then
|
||||||
|
[
|
||||||
|
{
|
||||||
|
type = "team";
|
||||||
|
team = toString team.githubId;
|
||||||
|
packageName = pkg.name;
|
||||||
|
}
|
||||||
|
]
|
||||||
|
else
|
||||||
|
userPings pkg team.members;
|
||||||
|
|
||||||
|
maintainersToPing = lib.concatMap (
|
||||||
|
pkg: userPings pkg pkg.maintainers ++ lib.concatMap (teamPings pkg) pkg.teams
|
||||||
) attrsWithModifiedFiles;
|
) attrsWithModifiedFiles;
|
||||||
|
|
||||||
byMaintainer = lib.groupBy (ping: toString ping.id) listToPing;
|
byType = lib.groupBy (ping: ping.type) maintainersToPing;
|
||||||
|
|
||||||
packagesPerMaintainer = lib.mapAttrs (
|
byUser = lib.pipe (byType.user or [ ]) [
|
||||||
maintainer: packages: map (pkg: pkg.packageName) packages
|
(lib.groupBy (ping: ping.user))
|
||||||
) byMaintainer;
|
(lib.mapAttrs (_user: lib.map (pkg: pkg.packageName)))
|
||||||
|
];
|
||||||
|
byTeam = lib.pipe (byType.team or [ ]) [
|
||||||
|
(lib.groupBy (ping: ping.team))
|
||||||
|
(lib.mapAttrs (_team: lib.map (pkg: pkg.packageName)))
|
||||||
|
];
|
||||||
in
|
in
|
||||||
packagesPerMaintainer
|
{
|
||||||
|
users = byUser;
|
||||||
|
teams = byTeam;
|
||||||
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ stdenvNoCC.mkDerivation {
|
|||||||
./get-code-owners.sh
|
./get-code-owners.sh
|
||||||
./request-reviewers.sh
|
./request-reviewers.sh
|
||||||
./request-code-owner-reviews.sh
|
./request-code-owner-reviews.sh
|
||||||
|
./request-maintainers-reviews.sh
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
nativeBuildInputs = [ makeWrapper ];
|
nativeBuildInputs = [ makeWrapper ];
|
||||||
@@ -26,6 +27,7 @@ stdenvNoCC.mkDerivation {
|
|||||||
for bin in *.sh; do
|
for bin in *.sh; do
|
||||||
mv "$bin" "$out/bin"
|
mv "$bin" "$out/bin"
|
||||||
wrapProgram "$out/bin/$bin" \
|
wrapProgram "$out/bin/$bin" \
|
||||||
|
--set PAGER cat \
|
||||||
--set PATH ${
|
--set PATH ${
|
||||||
lib.makeBinPath [
|
lib.makeBinPath [
|
||||||
coreutils
|
coreutils
|
||||||
|
|||||||
39
ci/request-reviews/request-maintainers-reviews.sh
Executable file
39
ci/request-reviews/request-maintainers-reviews.sh
Executable file
@@ -0,0 +1,39 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Requests maintainer reviews for a PR
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
SCRIPT_DIR=$(dirname "$0")
|
||||||
|
|
||||||
|
if (( $# < 5 )); then
|
||||||
|
echo >&2 "Usage: $0 ORG_ID GITHUB_REPO PR_NUMBER AUTHOR COMPARISON_PATH"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
orgId=$1
|
||||||
|
baseRepo=$2
|
||||||
|
prNumber=$3
|
||||||
|
prAuthor=$4
|
||||||
|
comparisonPath=$5
|
||||||
|
|
||||||
|
org="${baseRepo%/*}"
|
||||||
|
|
||||||
|
# maintainers.json/teams.json contains GitHub IDs. Look up handles to request reviews from.
|
||||||
|
# There appears to be no API to request reviews based on IDs
|
||||||
|
{
|
||||||
|
jq -r 'keys[]' "$comparisonPath"/maintainers.json \
|
||||||
|
| while read -r id; do
|
||||||
|
if login=$(gh api /user/"$id" --jq .login); then
|
||||||
|
echo "$login"
|
||||||
|
else
|
||||||
|
echo >&2 "Skipping user with id $id: $login"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
jq -r 'keys[]' "$comparisonPath"/teams.json \
|
||||||
|
| while read -r id; do
|
||||||
|
if slug=$(gh api /organizations/"$orgId"/team/"$id" --jq .slug); then
|
||||||
|
echo "$org/$slug"
|
||||||
|
else
|
||||||
|
echo >&2 "Skipping team with id $id: $slug"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
} | "$SCRIPT_DIR"/request-reviewers.sh "$baseRepo" "$prNumber" "$prAuthor"
|
||||||
@@ -397,6 +397,7 @@ let
|
|||||||
];
|
];
|
||||||
sourceProvenance = listOf attrs;
|
sourceProvenance = listOf attrs;
|
||||||
maintainers = listOf (attrsOf any); # TODO use the maintainer type from lib/tests/maintainer-module.nix
|
maintainers = listOf (attrsOf any); # TODO use the maintainer type from lib/tests/maintainer-module.nix
|
||||||
|
nonTeamMaintainers = listOf (attrsOf any); # TODO use the maintainer type from lib/tests/maintainer-module.nix
|
||||||
teams = listOf (attrsOf any); # TODO similar to maintainers, use a teams type
|
teams = listOf (attrsOf any); # TODO similar to maintainers, use a teams type
|
||||||
priority = int;
|
priority = int;
|
||||||
pkgConfigModules = listOf str;
|
pkgConfigModules = listOf str;
|
||||||
@@ -670,6 +671,10 @@ let
|
|||||||
maintainers =
|
maintainers =
|
||||||
attrs.meta.maintainers or [ ] ++ concatMap (team: team.members or [ ]) attrs.meta.teams or [ ];
|
attrs.meta.maintainers or [ ] ++ concatMap (team: team.members or [ ]) attrs.meta.teams or [ ];
|
||||||
|
|
||||||
|
# Needed for CI to be able to avoid requesting reviews from individual
|
||||||
|
# team members
|
||||||
|
nonTeamMaintainers = attrs.meta.maintainers or [ ];
|
||||||
|
|
||||||
identifiers =
|
identifiers =
|
||||||
let
|
let
|
||||||
# nix-env writes a warning for each derivation that has null in its meta values, so
|
# nix-env writes a warning for each derivation that has null in its meta values, so
|
||||||
|
|||||||
Reference in New Issue
Block a user