Select reviewers based on a diff and a set of rules.
Requirements: uv.
$ uv venv
$ uv pip install -e .
In its simplest form, the script accepts a diff on stdin. It processes the diff according to a rule file passed as an argument, and outputs a list of individual and groups of reviewers.
$ uv run reviewer-selector samples/herald_rules.sample.json < samples/sample.diff
#example-group shtrom
The group prefix can be changed with --group-prefix. The reviewer separator
can be changed with --reviewer-separator. The --repo option allows the user
to specify a specific repository (to be used when evaluating conditions in some
rules.
The current rules files, as shown in the sample is not final and not normative. It is used as a bootstrapping stop-gap, and should not be expected to remain stable at this stage.
To generate a GitHub application token based on a TaskCluster secret, use the
gh-token-generator script. The secret should contain two values, named
GITHUB_APP_ID and GITHUB_APP_PRIVKEY.
The generator relies on Standard TaskCluster Environment
Variables to obtain
the secret named with ID TC_SECRET_ID. Those variables can be set with the
Taskcluster shell
client,
taskcluster signin.
Building the Taskcluster Client for Shell
Requirements: golang
$ git clone https://github.com/taskcluster/taskcluster
$ cd taskcluster/clients/client-shell
$ go build -o taskcluster .
$ eval $(/PATH/TO/taskcluster/clients/client-shell/taskcluster signin) # follow the web prompts
$ export ORG_NAME=mozilla-firefox
$ export REPO_NAME=infra-testing
$ uv run gh-token-generator
then
$ GITHUB_TOKEN=$(uv run gh-token-generator)
$ gh ...
All the commands in this section rely on the development dependencies being installed.
$ uv pip install -e .[dev]
$ uv run pytest
Ruff has a linter and a formatter. We use both,
$ uv run ruff format
$ uv run ruff check --fix
or simply,
$ make format
Runtime dependencies only.
$ uv run pip-compile --quiet --generate-hashes --allow-unsafe -o requirements.txt
Include dev and testing dependencies.
$ uv run pip-compile --quiet --generate-hashes --extra=dev --allow-unsafe -o requirements-dev.txt
For use as part of a more complex pipeline, a docker image can be built. It is setup to take most of its arguments from environment variables, and will update a GitHub pull request directly if enough information is available.
Requirements: docker.
$ docker build -f docker/Dockerfile -t reviewer-selector .
The default behaviour is to search the target repository/branch for a herald_rules.json file.
If missing, a fallback from the container is used.
Herald rules can be extracted from Phabricator using the Herald Crawler.
$ herald-scraper --url https://phabricator.services.mozilla.com \
--conduit-token $PHAB_TOKEN --pmo-cookie $PEOPLE_MOZILLA_COOKIE \
--output herald_rules.json \
Get/create your $PHAB_TOKEN from https://phabricator.services.mozilla.com/settings/user//page/apitokens/. Get your $PEOPLE_MOZILLA_COOKIE from the pmo-access cookie after logging in to https://people.mozilla.org/
This file can then be bundled as default in the container image.
$ docker build -f docker/Dockerfile \
--build-arg BUILTIN_HERALD_RULES=herald_rules.json \
-t reviewer-selector \
.
$ docker tag reviewer-selector omehani/moz-reviewer-selector
$ docker push omehani/moz-reviewer-selector
This is the image tag that the CI hook currently uses.
XXX: update this tag
For convenience, the sample rules are shipped with the container image. The reviewers string is formatted for use with GitHub's gh CLI.
$ docker run --rm -i reviewer-selector < samples/sample.diff
No REPO_URL in environment, using built-in rules ...
No DIFF_URL in environment, reading from stdin ...
No ORG_NAME in environment, using # as group prefix ...
No REPO_NAME or TARGET_BRANCH_NAME in environment, not matching repository-based rules ...
No PR_URL or GITHUB_TOKEN in environment, outputing to stdout ...
@example-group,shtrom
The warnings are output to stderr.
A more advanced example would mount a real ruleset into the container at
/app/herald_rules.json. The diff data can be fetched from a pull request and
piped into the container.
$ curl --silent --location https://github.com/mozilla-firefox/infra-testing/pull/30.diff \
| docker run --rm -i \
-v ./herald_rules.real.json:/app/herald_rules.json \
reviewer-selector
No REPO_URL in environment, using built-in rules ...
No DIFF_URL in environment, reading from stdin ...
No ORG_NAME in environment, using # as group prefix ...
No REPO_NAME or TARGET_BRANCH_NAME in environment, not matching repository-based rules ...
No PR_URL or GITHUB_TOKEN in environment, outputing to stdout ...
@android-reviewers
The container's behaviour can be entirely parametrised via environment variables.
$ docker run --rm -i \
-v ./herald_rules.real.json:/app/herald_rules.json \
-e DIFF_URL=https://github.com/mozilla-firefox/infra-testing/pull/30.diff \
-e PR_URL=https://github.com/mozilla-firefox/infra-testing/pull/30 \
-e REPO_URL=https://github.com/mozilla-firefox/infra-testing \
-e ORG_NAME=mozilla-firefox -e REPO_NAME=infra-testing \
-e GITHUB_TOKEN=[REDACTED] \
reviewer-selector
Adding reviewers to https://github.com/mozilla-firefox/infra-testing/pull/30 ...
- If
DIFF_URLis given, it will be fetched and passed into the selector's stdin. - If
GITHUB_TOKENandPR_URLare provided, the container will attempt to set the reviewers on the target PR.
Some other optional behaviours can be triggered by providing additional context in environment variables:
- If
ORG_NAMEis passed, it will be used to scope reviewers groups to that org. - If
REPO_NAMEandTARGET_BRANCH_NAMEare provided, rules that specifically match a given repository and/or branch will also be applied. - If
REPO_URLis given, the script will attempt to fetch a rules file from themainbranch of the repository. If it fails, it will fallback to built-in rules. - If
TC_SECRET_IDis provided, it is expected to containGITHUB_APP_IDandGITHUB_APP_PRIVKEYvalues. They will be used to generate aGITHUB_TOKEN(if unspecified) forORG_NAME/REPO_NAME.