Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fall back to main branch protection rules for PRs targeting branches without protection rules #1900

Merged
merged 3 commits into from
May 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
from collections import defaultdict
from dataclasses import dataclass

from requests import HTTPError

from common.github import GitHubAPI


Expand Down Expand Up @@ -135,9 +137,7 @@ def base_repo_name(pr: dict):
_BRANCH_PROTECTION_CACHE = defaultdict(dict)


def get_branch_protection(gh: GitHubAPI, pr: dict) -> dict:
repo = base_repo_name(pr)
branch_name = pr["base"]["ref"]
def get_branch_protection(gh: GitHubAPI, repo: str, branch_name: str) -> dict:
if branch_name not in _BRANCH_PROTECTION_CACHE[repo]:
_BRANCH_PROTECTION_CACHE[repo][branch_name] = gh.get_branch_protection(
repo, branch_name
Expand All @@ -147,7 +147,20 @@ def get_branch_protection(gh: GitHubAPI, pr: dict) -> dict:


def get_min_required_approvals(gh: GitHubAPI, pr: dict) -> int:
branch_protection_rules = get_branch_protection(gh, pr)
repo = base_repo_name(pr)
branch_name = pr["base"]["ref"]

try:
branch_protection_rules = get_branch_protection(gh, repo, branch_name)
except HTTPError as e:
# If the base branch does not have protection rules, the request
# above will 404. In that case, fall back to the rules for `main`
# as a safe default.
if e.response is not None and e.response.status_code == 404:
branch_protection_rules = get_branch_protection(gh, repo, "main")
else:
raise e

return branch_protection_rules["required_pull_request_reviews"][
"required_approving_review_count"
]
Expand Down
45 changes: 35 additions & 10 deletions catalog/tests/dags/maintenance/test_pr_review_reminders.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from datetime import datetime, timedelta

import pytest
from requests import HTTPError, Request, Response

from catalog.dags.maintenance.pr_review_reminders.pr_review_reminders import (
Urgency,
Expand Down Expand Up @@ -100,6 +101,13 @@ def get_reviews(*args, **kwargs):
def get_branch_protection(*args, **kwargs):
repo = args[1]
branch = args[2]
if repo not in branch_protection or branch not in branch_protection[repo]:
response = Response()
response.status_code = 404
request = Request(method="GET", url="https://api.github.com/")
response.request = request
raise HTTPError(response=response)

return branch_protection[repo][branch]

def patch_gh_fn(fn, impl):
Expand Down Expand Up @@ -131,11 +139,16 @@ def freeze_friday(freeze_time):


def _setup_branch_protection(github: dict, pr: dict, min_required_approvals: int = 2):
branch_protection = make_branch_protection(min_required_approvals)

repo = pr["base"]["repo"]["name"]
branch = pr["base"]["ref"]

_setup_branch_protection_for_branch(github, repo, branch, min_required_approvals)


def _setup_branch_protection_for_branch(
github: dict, repo: str, branch: str, min_required_approvals: int = 2
):
branch_protection = make_branch_protection(min_required_approvals)
github["branch_protection"][repo][branch] = branch_protection


Expand Down Expand Up @@ -247,22 +260,25 @@ def test_does_reping_past_due_if_reminder_is_outdated(github, urgency):
# tested elsewhere.
("APPROVED",) + UNAPPROVED_REVIEW_STATES,
)
@pytest.mark.parametrize("base_branch", ("main", "not_main"))
def test_does_ping_if_pr_has_less_than_min_required_approvals(
github, urgency, first_review_state, second_review_state
github, urgency, first_review_state, second_review_state, base_branch
):
reviews = [
make_review(state)
for state in (first_review_state, second_review_state)
if state is not None
]
past_due_pull = make_pull(urgency, past_due=True)
past_due_pull = make_pull(urgency, past_due=True, base_branch=base_branch)
past_due_pull["requested_reviewers"] = [
make_requested_reviewer(f"reviewer-due-{i}") for i in range(2)
]

_setup_branch_protection(
# Always use `main` to exercise fallback for non-main branches
_setup_branch_protection_for_branch(
github,
pr=past_due_pull,
repo="openverse",
branch="main",
min_required_approvals=2,
)

Expand All @@ -275,17 +291,26 @@ def test_does_ping_if_pr_has_less_than_min_required_approvals(


@parametrize_urgency
def test_does_not_ping_if_pr_has_min_required_approvals(github, urgency):
past_due_pull = make_pull(urgency, past_due=True)
@pytest.mark.parametrize(
("base_branch"),
(
"main",
"not_main", # should fallback to use `main`
),
)
def test_does_not_ping_if_pr_has_min_required_approvals(github, urgency, base_branch):
past_due_pull = make_pull(urgency, past_due=True, base_branch=base_branch)
past_due_pull["requested_reviewers"] = [
make_requested_reviewer(f"reviewer-due-{i}") for i in range(2)
]

min_required_approvals = 4

_setup_branch_protection(
# Always use `main` to exercise fallback for non-main branches
_setup_branch_protection_for_branch(
github,
pr=past_due_pull,
repo="openverse",
branch="main",
min_required_approvals=min_required_approvals,
)

Expand Down
6 changes: 5 additions & 1 deletion catalog/tests/factories/github/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def walk_backwards_in_time_until_weekday_count(today: datetime.datetime, count:
_pr_count = 1


def make_pull(urgency: Urgency, past_due: bool) -> dict:
def make_pull(urgency: Urgency, past_due: bool, base_branch: str = "main") -> dict:
"""
Create a PR object like the one returned by the GitHub API.

Expand Down Expand Up @@ -70,6 +70,10 @@ def make_pull(urgency: Urgency, past_due: bool) -> dict:

pull["updated_at"] = _gh_date(updated_at)

base = pull["base"]
base["ref"] = base_branch
base["label"] = f"WordPress:{base_branch}"

return pull


Expand Down
28 changes: 14 additions & 14 deletions catalog/tests/factories/github/pull.json
Original file line number Diff line number Diff line change
Expand Up @@ -272,12 +272,12 @@
"subscribers_url": "https://api.github.com/repos/helpful-contributor/openverse/subscribers",
"subscription_url": "https://api.github.com/repos/helpful-contributor/openverse/subscription",
"svn_url": "https://github.com/helpful-contributor/openverse",
"tags_url": "https://api.github.com/repos/helpful-contributor/openverse-frontend/tags",
"teams_url": "https://api.github.com/repos/helpful-contributor/openverse-frontend/teams",
"tags_url": "https://api.github.com/repos/helpful-contributor/openverse/tags",
"teams_url": "https://api.github.com/repos/helpful-contributor/openverse/teams",
"topics": [],
"trees_url": "https://api.github.com/repos/helpful-contributor/openverse-frontend/git/trees{/sha}",
"trees_url": "https://api.github.com/repos/helpful-contributor/openverse/git/trees{/sha}",
"updated_at": "2022-03-28T08:10:33Z",
"url": "https://api.github.com/repos/helpful-contributor/openverse-frontend",
"url": "https://api.github.com/repos/helpful-contributor/openverse",
"visibility": "public",
"watchers": 0,
"watchers_count": 0
Expand All @@ -304,9 +304,9 @@
"url": "https://api.github.com/users/helpful-contributor"
}
},
"html_url": "https://github.com/WordPress/openverse-frontend/pull/0",
"html_url": "https://github.com/WordPress/openverse/pull/0",
"id": 123412341234,
"issue_url": "https://api.github.com/repos/WordPress/openverse-frontend/issues/0",
"issue_url": "https://api.github.com/repos/WordPress/openverse/issues/0",
"labels": [
{
"color": "ffcc00",
Expand All @@ -315,7 +315,7 @@
"id": 3029513057,
"name": "\ud83d\udfe8 priority: medium",
"node_id": "MDU6TGFiZWwzMDI5NTEzMDU3",
"url": "https://api.github.com/repos/WordPress/openverse-frontend/labels/%F0%9F%9F%A8%20priority:%20medium"
"url": "https://api.github.com/repos/WordPress/openverse/labels/%F0%9F%9F%A8%20priority:%20medium"
},
{
"color": "ffffff",
Expand All @@ -324,7 +324,7 @@
"id": 3029513140,
"name": "\ud83d\udee0 goal: fix",
"node_id": "MDU6TGFiZWwzMDI5NTEzMTQw",
"url": "https://api.github.com/repos/WordPress/openverse-frontend/labels/%F0%9F%9B%A0%20goal:%20fix"
"url": "https://api.github.com/repos/WordPress/openverse/labels/%F0%9F%9B%A0%20goal:%20fix"
},
{
"color": "04338c",
Expand All @@ -333,7 +333,7 @@
"id": 3029513145,
"name": "\ud83d\udcc4 aspect: text",
"node_id": "MDU6TGFiZWwzMDI5NTEzMTQ1",
"url": "https://api.github.com/repos/WordPress/openverse-frontend/labels/%F0%9F%93%84%20aspect:%20text"
"url": "https://api.github.com/repos/WordPress/openverse/labels/%F0%9F%93%84%20aspect:%20text"
}
],
"locked": false,
Expand All @@ -342,16 +342,16 @@
"milestone": null,
"node_id": "PR_asdfasdfasdfasdfasdfasdf",
"number": 0,
"patch_url": "https://github.com/WordPress/openverse-frontend/pull/0.patch",
"patch_url": "https://github.com/WordPress/openverse/pull/0.patch",
"requested_reviewers": [],
"requested_teams": [],
"review_comment_url": "https://api.github.com/repos/WordPress/openverse-frontend/pulls/comments{/number}",
"review_comments_url": "https://api.github.com/repos/WordPress/openverse-frontend/pulls/0/comments",
"review_comment_url": "https://api.github.com/repos/WordPress/openverse/pulls/comments{/number}",
"review_comments_url": "https://api.github.com/repos/WordPress/openverse/pulls/0/comments",
"state": "open",
"statuses_url": "https://api.github.com/repos/WordPress/openverse-frontend/statuses/asdfasdfasdfasdfasdfasdfasdf",
"statuses_url": "https://api.github.com/repos/WordPress/openverse/statuses/asdfasdfasdfasdfasdfasdfasdf",
"title": "Super cool PR to add amazing new features.",
"updated_at": "2022-06-16T11:57:28Z",
"url": "https://api.github.com/repos/WordPress/openverse-frontend/pulls/0",
"url": "https://api.github.com/repos/WordPress/openverse/pulls/0",
"user": {
"avatar_url": "https://avatars.githubusercontent.com/u/0?v=4",
"events_url": "https://api.github.com/users/helpful-contributor/events{/privacy}",
Expand Down