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

feat: assume a closed pr with no osc label is internal #276 #284

Merged
merged 4 commits into from
Dec 7, 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
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ test-html-coverage-report: test ## Run tests and show coverage report in browser
open htmlcov/index.html

pylint: ## Run pylint
-pylint --rcfile=pylintrc openedx_webhooks tests bin setup.py
-pylint --rcfile=pylintrc openedx_webhooks tests setup.py

TYPEABLE = openedx_webhooks tests
mypy: ## Run mypy to check type annotations
Expand Down
46 changes: 0 additions & 46 deletions bin/get_task_result_errors.py

This file was deleted.

6 changes: 6 additions & 0 deletions changelog.d/20231205_183822_nedbat_exedx_276.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.. A new scriv changelog fragment.

- When a pull request is closed, if it doesn't have a
"open-source-contribution" label on it, it is considered an internal pull
request. We assume that it was processed when it was opened, and since it
didn't get the label then, the author must have been internal at the time.
9 changes: 7 additions & 2 deletions docs/details.rst
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,13 @@ draft.
When a pull request is closed
-----------------------------

The bot leaves a comment asking the author to complete a survey about the pull
request.
On internal pull requests, the bot leaves a comment asking the author to
complete a survey about the pull request.

When a pull request is being closed, it will be considered an internal pull
request if it has no "open-source-contribution" label, on the assumption that
it was processed when it was opened, so the lack of a label means the author
was internal at the time the pull request was created.


When a pull request is re-opened
Expand Down
20 changes: 9 additions & 11 deletions openedx_webhooks/tasks/pr_tracking.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,17 +135,12 @@

bot_comments: Set[BotComment] = field(default_factory=set)
bot_comments_to_remove: Set[BotComment] = field(default_factory=set)
jira_project: Optional[str] = None
jira_title: Optional[str] = None
jira_description: Optional[str] = None

# The Jira instances we want to have issues on.
jira_nicks: Set[str] = field(default_factory=set)

# The Jira status we want to set on an existing issue. Can be None if we
# don't need to force a new status, but can leave the existing status.
jira_status: Optional[str] = None

# The bot-controlled labels we want to on the pull request.
# See labels.py:CATEGORY_LABELS
github_labels: Set[str] = field(default_factory=set)
Expand Down Expand Up @@ -204,10 +199,18 @@
user = pr["user"]["login"]
repo = pr["base"]["repo"]["full_name"]
num = pr["number"]
label_names = set(lbl["name"] for lbl in pr["labels"])

user_is_bot = is_bot_pull_request(pr)
no_cla_is_needed = is_private_repo_no_cla_pull_request(pr)
is_internal = is_internal_pull_request(pr)
if not is_internal:
if pr["state"] == "closed" and "open-source-contribution" not in label_names:
# If we are closing a PR, and it isn't already an OSPR, then it
# shouldn't be considered one now.
logger.info(f"{repo}#{num} is closing, but seemed to be internal originally")
is_internal = True

if user_is_bot:
logger.info(f"@{user} is a bot, not an ospr.")
elif no_cla_is_needed:
Expand All @@ -229,7 +232,6 @@
state = "closed"

# A label of jira:xyz means we want a Jira issue in the xyz Jira.
label_names = set(lbl["name"] for lbl in pr["labels"])
desired.jira_nicks = {name.partition(":")[-1] for name in label_names if name.startswith("jira:")}

if "crash!123" in label_names:
Expand Down Expand Up @@ -286,11 +288,7 @@
if not has_signed_agreement:
desired.bot_comments.add(BotComment.NEED_CLA)

if state == "closed":
desired.jira_status = "Rejected"
elif state == "merged":
desired.jira_status = "Merged"
elif state == "reopened":
if state == "reopened":
desired.bot_comments_to_remove.add(BotComment.SURVEY)

if state in ["closed", "merged"]:
Expand Down Expand Up @@ -343,7 +341,7 @@
"""
try:
yield
except Exception as exc: # pylint: disable=broad-exception-caught

Check warning on line 344 in openedx_webhooks/tasks/pr_tracking.py

View check run for this annotation

Codecov / codecov/patch

openedx_webhooks/tasks/pr_tracking.py#L344

Added line #L344 was not covered by tests
self.exceptions.append(exc)

def fix(self) -> None:
Expand Down
29 changes: 12 additions & 17 deletions tests/test_pull_request_closed.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
CLA_STATUS_GOOD,
CLA_STATUS_NO_CONTRIBUTIONS,
)
from openedx_webhooks.gh_projects import pull_request_projects
from openedx_webhooks.tasks.github import pull_request_changed
from .helpers import check_issue_link_in_markdown, random_text

Expand All @@ -36,6 +37,7 @@ def closed_pull_request(is_merged, fake_github, fake_jira):
Returns (pr, issue_key)
"""
pr = fake_github.make_pull_request(
owner="openedx",
user="tusbar",
title=random_text(),
)
Expand Down Expand Up @@ -105,36 +107,29 @@ def test_cc_pr_closed(fake_github, fake_jira, is_merged):
assert len(pr_comments) == 2 # 1 welcome, 1 survey


@pytest.mark.parametrize("user", ["tusbar", "feanil"])
def test_pr_in_nocontrib_repo_closed(fake_github, user):
repo = fake_github.make_repo("edx", "some-public-repo")
pr = repo.make_pull_request(user=user)
pr.close(merge=False)
result = pull_request_changed(pr.as_json())
assert not result.jira_issues
# We don't want the bot to write a comment on a closed pull request.
assert len(pr.list_comments()) == 0
# User has a cla, but we aren't accepting contributions.
assert pr.status(CLA_CONTEXT) == CLA_STATUS_NO_CONTRIBUTIONS


def test_pr_closed_after_employee_leaves(fake_github, mocker):
@pytest.mark.parametrize("org", ["openedx", "edx"])
def test_pr_closed_after_employee_leaves(org, is_merged, fake_github, mocker):
# Ned is internal.
pr = fake_github.make_pull_request("edx", user="nedbat")
pr = fake_github.make_pull_request(org, user="nedbat")
result = pull_request_changed(pr.as_json())

assert not result.jira_issues
# No comments, labels or projects because Ned is internal.
assert len(pr.list_comments()) == 0
assert pr.status(CLA_CONTEXT) == CLA_STATUS_GOOD
assert pr.labels == set()
assert pull_request_projects(pr.as_json()) == set()

# Ned is fired for malfeasance.
mocker.patch("openedx_webhooks.tasks.pr_tracking.is_internal_pull_request", lambda pr: False)

# His PR is closed.
pr.close(merge=False)
pr.close(merge=is_merged)
result = pull_request_changed(pr.as_json())

assert not result.jira_issues
# We don't want the bot to write a comment on a closed pull request.
assert len(pr.list_comments()) == 0
assert pr.status(CLA_CONTEXT) == CLA_STATUS_NO_CONTRIBUTIONS
assert pr.status(CLA_CONTEXT) == CLA_STATUS_GOOD
assert pr.labels == set()
assert pull_request_projects(pr.as_json()) == set()
33 changes: 0 additions & 33 deletions tests/test_pull_request_opened.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
)
from openedx_webhooks import settings
from openedx_webhooks.gh_projects import pull_request_projects
from openedx_webhooks.info import get_jira_server_info
from openedx_webhooks.tasks.github import pull_request_changed

from .helpers import check_issue_link_in_markdown
Expand Down Expand Up @@ -279,38 +278,6 @@ def test_draft_pr_opened(pr_type, fake_github, mocker):
assert 'click "Ready for Review"' in body


def test_handle_closed_pr(is_merged, fake_github):
pr = fake_github.make_pull_request(user="tusbar", number=11237, state="closed", merged=is_merged)
prj = pr.as_json()
result = pull_request_changed(prj)
assert not result.jira_issues

# Check the GitHub comment that was created.
pr_comments = pr.list_comments()
assert len(pr_comments) == 1
body = pr_comments[0].body
check_issue_link_in_markdown(body, None)
if is_merged:
assert "Although this pull request is already merged," in body
else:
assert "Although this pull request is already closed," in body
assert is_comment_kind(BotComment.WELCOME, body)
assert is_comment_kind(BotComment.WELCOME_CLOSED, body)
assert not is_comment_kind(BotComment.NEED_CLA, body)

# Check the GitHub labels that got applied.
expected_labels = {"open-source-contribution"}
assert pr.labels == expected_labels
assert pull_request_projects(pr.as_json()) == {settings.GITHUB_OSPR_PROJECT}

# Rescan the pull request.
result2 = pull_request_changed(pr.as_json())
assert not result2.jira_issues

# No new GitHub comment was created.
assert len(pr.list_comments()) == 1


def test_dont_add_internal_prs_to_project(fake_github):
pr = fake_github.make_pull_request(owner="openedx", repo="credentials", user="nedbat")
pull_request_changed(pr.as_json())
Expand Down
35 changes: 18 additions & 17 deletions tests/test_rescan.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,10 @@ def make_rescannable_repo(fake_github, org_name="an-org", repo_name="a-repo"):
closed_at=datetime(2020,7,1))
repo.make_pull_request(user="feanil", number=105, created_at=datetime(2019, 4, 1))
repo.make_pull_request(user="tusbar", number=106, created_at=datetime(2019, 5, 1))
repo.make_pull_request(user="tusbar", number=108, state="closed", created_at=datetime(2019, 6, 1),
closed_at=datetime(2020,7,1))
# A closed PR that had been processed when it opened.
pr = repo.make_pull_request(user="tusbar", number=108, created_at=datetime(2019, 6, 1), closed_at=datetime(2020,7,1))
pull_request_changed(pr.as_json())
pr.close(merge=False)
# One of the PRs already has a bot comment with a Jira issue.
pr = repo.make_pull_request(user="tusbar", number=110, state="closed", merged=True, created_at=datetime(2019, 7, 1),
closed_at=datetime(2020,7,1))
Expand Down Expand Up @@ -84,10 +86,14 @@ def test_rescan_repository(rescannable_repo, pull_request_changed_fn, allpr):


def test_rescan_repository_dry_run(rescannable_repo, fake_github, fake_jira, pull_request_changed_fn):
# The fixtures could have made GitHub or Jira writes, reset them.
fake_github.reset_mock()
fake_jira.reset_mock()

# Rescan as a dry run.
ret = rescan_repository(rescannable_repo.full_name, allpr=True, dry_run=True)

# We shouldn't have made any writes to GitHub or Jira.
# We shouldn't have made any writes to GitHub or Jira because dry_run=True.
fake_github.assert_readonly()
fake_jira.assert_readonly()

Expand All @@ -96,35 +102,30 @@ def test_rescan_repository_dry_run(rescannable_repo, fake_github, fake_jira, pul

# Get the names of the actions. We won't worry about the details, those
# are tested in the non-dry-run tests of rescanning pull requests.
import json,sys; json.dump(ret["dry_run_actions"], sys.stdout, indent=4)
actions = {k: [name for name, kwargs in actions] for k, actions in ret["dry_run_actions"].items()}
assert actions == {
102: [
"initial_state",
"set_cla_status",
"update_labels_on_pull_request",
"add_comment_to_pull_request",
"set_cla_status", # "The author is authorized to contribute"
"update_labels_on_pull_request", # ["open-source-contribution"]
"add_comment_to_pull_request", # "Thanks for the pull request, @tusbar!"
"add_pull_request_to_project",
],
106: [
"initial_state",
"set_cla_status",
"update_labels_on_pull_request",
"add_comment_to_pull_request",
"set_cla_status", # "The author is authorized to contribute"
"update_labels_on_pull_request", # ["open-source-contribution"]
"add_comment_to_pull_request", # "Thanks for the pull request, @tusbar!"
"add_pull_request_to_project",
],
108: [
"initial_state",
"set_cla_status",
"update_labels_on_pull_request",
"add_comment_to_pull_request",
"add_pull_request_to_project",
"add_comment_to_pull_request", # "Even though your pull request wasn't merged"
],
110: [
"initial_state",
"set_cla_status",
"update_labels_on_pull_request",
"add_comment_to_pull_request",
"add_pull_request_to_project",
"set_cla_status", # "The author is authorized to contribute"
],
}

Expand Down
Loading