The OpenShift Test Platform team at Red Hat maintains and operates the CI system for OpenShift. This includes maintaining and enhancing: the kubernetes/test-infra, all of the openshift/ci-tools that go into running a CI system, documentation for the system in openshift/ci-docs, and certain aspects of the CI configuration in openshift/release.
This necessitates that the team review and approve PRs in the preceding repos from contributors both inside and outside of the team itself. The team wants to provide a quick and easy experience for contributors and strives to provide PR reviews in a timely manner. This lofty goal makes relying on GitHub's chatty notification system difficult and distracting.
I thought a lot about how the team could be responsive to our contributors while not distracting ourselves from our other important duties. What if each member of the team received a slack message each day detailing all of the PRs where their input has been requested? Then they could simply review it at a time that made sense for them, and act on each PR. This would ensure that no contributor would ever have to wait for more than a day for their PR to be seen.
A YAML configuration file could be defined for this tool to: enumerate our team members, team name, and repos that we want to check:
teamMembers:
- sgoeddel
''
teamName: test-platform
repos:
- openshift/ci-tools
- openshift/ci-docs
- openshift/release
- kubernetes/test-infra
GitHub provides a REST API that has an endpoint to list PRs for a repo. Utilizing that, we can obtain every open PR for the repos that we maintain:
prs, err := ghClient.GetPullRequests(org, repo)
if err != nil {
logrus.Errorf("failed to get pull requests: %v", err)
}
Then check to see which, if any, of our team members have been requested to review the PR:
for _, pr := range prs {
for i, u := range users {
if u.requestedToReview(pr) {
u.PrRequests = append(u.PrRequests, prRequest{
Repo: orgRepo,
Number: pr.Number,
Url: pr.HTMLURL,
Title: pr.Title,
Author: pr.User.Login,
Created: pr.CreatedAt,
LastUpdated: pr.UpdatedAt,
})
users[i] = u
}
}
}
Determining if a given user has been requested to review a PR requires checking if the user themselves have been requested or if the configured team has been requested:
func (u *user) requestedToReview(pr github.PullRequest) bool {
// only check PRs that the user is not the author of, as they could have requested their own team
if u.GithubId != pr.User.Login {
for _, team := range pr.RequestedTeams {
if u.TeamName == team.Slug {
return true
}
}
for _, reviewer := range pr.RequestedReviewers {
if u.GithubId == reviewer.Login {
return true
}
}
}
return false
}
In order for the resulting reminder message to be most useful we need a good ordering of the PRs:
// sort by most recent update first
sort.Slice(user.PrRequests, func(i, j int) bool {
return user.PrRequests[i].LastUpdated.After(user.PrRequests[j].LastUpdated)
})
It is also helpful to have a simple colored emoji next to each PR so that they are easily filtered by date created:
const (
recent = ":large_green_circle:"
normal = ":large_orange_circle:"
old = ":red_circle:"
twoDays = time.Hour * 24 * 2
oneWeek = time.Hour * 24 * 7
)
func (p prRequest) recency() string {
now := time.Now()
if p.Created.After(now.Add(-twoDays)) {
return recent
} else if p.Created.After(now.Add(-oneWeek)) {
return normal
} else {
return old
}
}
Slack also provides an API that allows us to post a message. Using their constructs we can format a nice message to display:
for _, pr := range user.PrRequests {
message = append(message, &slack.ContextBlock{
Type: slack.MBTContext,
ContextElements: slack.ContextElements{
Elements: []slack.MixedElement{
&slack.TextBlockObject{
Type: slack.MarkdownType,
Text: pr.link(),
},
&slack.TextBlockObject{
Type: slack.MarkdownType,
Text: pr.createdUpdatedMessage(),
},
},
},
})
}
We decided that it was most useful if this tool was scheduled to run daily, and since our team is geographically dispersed we chose to run it at 8 am UTC on weekdays. Putting it all together, each member of our team gets a message like the following at the beginning of their work day.

The full source code can be found in ci-tools/cmd/pr-reminder.
