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: Update the community PR message #288

Merged
merged 2 commits into from
Jul 17, 2024
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
36 changes: 35 additions & 1 deletion openedx_webhooks/bot_comments.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@
import binascii
import json
import re
from collections import namedtuple

from enum import Enum, auto
from typing import Dict
from typing import Dict, Literal

import arrow
from flask import render_template
Expand All @@ -16,9 +17,15 @@
get_jira_server_info,
is_draft_pull_request,
pull_request_has_cla,
get_catalog_info,
)
from openedx_webhooks.types import JiraId, PrDict

# Author association values for which we should consider the author new
GITHUB_NEW_AUTHOR_ASSOCIATIONS = (
"FIRST_TIMER", # Author has not previously committed to GitHub.
"FIRST_TIME_CONTRIBUTOR", # Author has not previously committed to the repository.
)

class BotComment(Enum):
"""
Expand Down Expand Up @@ -79,13 +86,34 @@ class BotComment(Enum):
BotComment.NO_CONTRIBUTIONS,
}


def is_comment_kind(kind: BotComment, text: str) -> bool:
"""
Is this `text` a comment of this `kind`?
"""
return any(snip in text for snip in BOT_COMMENT_INDICATORS[kind])


Lifecycle = Literal["experimental", "production", "deprecated"]
RepoSpec: (str | None, Lifecycle | None) = namedtuple('RepoSpec', ['owner', 'lifecycle'])


def _get_repo_spec(repo_full_name: str) -> RepoSpec:
"""
Get the owner of the repo from its catalog-info.yaml file.
"""
catalog_info = get_catalog_info(repo_full_name)
if not catalog_info:
return RepoSpec(None, None)
owner = catalog_info["spec"].get("owner", "")
owner_type = None
if ":" in owner:
owner_type, owner = owner.split(":")
if owner_type == "group":
owner = f"openedx/{owner}"
return RepoSpec(owner, catalog_info["spec"]["lifecycle"])


def github_community_pr_comment(pull_request: PrDict) -> str:
"""
For a newly-created pull request from an open source contributor,
Expand All @@ -95,12 +123,18 @@ def github_community_pr_comment(pull_request: PrDict) -> str:
* check for contributor agreement
* contain a link to our process documentation
"""
is_first_time = pull_request.get("author_association", None) in GITHUB_NEW_AUTHOR_ASSOCIATIONS
spec = _get_repo_spec(pull_request["base"]["repo"]["full_name"])

return render_template(
"github_community_pr_comment.md.j2",
user=pull_request["user"]["login"],
has_signed_agreement=pull_request_has_cla(pull_request),
is_draft=is_draft_pull_request(pull_request),
is_merged=pull_request.get("merged", False),
is_first_time=is_first_time,
owner=spec.owner,
lifecycle=spec.lifecycle,
)


Expand Down
7 changes: 4 additions & 3 deletions openedx_webhooks/info.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,10 @@ def _read_data_file(filename):
"""
Read the text of an openedx-webhooks-data file.
"""
return _read_github_file("openedx/openedx-webhooks-data", filename)
return read_github_file("openedx/openedx-webhooks-data", filename)


def _read_github_file(repo_fullname: str, file_path: str, not_there: Optional[str] = None) -> str:
def read_github_file(repo_fullname: str, file_path: str, not_there: Optional[str] = None) -> str:
"""
Read a GitHub file from the main or master branch of a repo.

Expand All @@ -67,6 +67,7 @@ def _read_github_file(repo_fullname: str, file_path: str, not_there: Optional[st
"""
return _read_github_url(_github_file_url(repo_fullname, file_path), not_there)


def _read_github_url(url: str, not_there: Optional[str] = None) -> str:
"""
Read the content of a GitHub URL.
Expand Down Expand Up @@ -302,7 +303,7 @@ def get_bot_comments(prid: PrId) -> Iterable[PrCommentDict]:

def get_catalog_info(repo_fullname: str) -> Dict:
"""Get the parsed catalog-info.yaml data from a repo, or {} if missing."""
yml = _read_github_file(repo_fullname, "catalog-info.yaml", not_there="{}")
yml = read_github_file(repo_fullname, "catalog-info.yaml", not_there="{}")
return yaml.safe_load(yml)


Expand Down
135 changes: 94 additions & 41 deletions openedx_webhooks/templates/github_community_pr_comment.md.j2
Original file line number Diff line number Diff line change
@@ -1,52 +1,105 @@
{% filter replace("\n", " ")|trim %}
Thanks for the pull request, @{{ user }}!
Please note that it may take us up to several weeks or months to complete a review and merge your PR.
{% endfilter %}

Feel free to add as much of the following information to the ticket as you can:
- supporting documentation
- [Open edX discussion forum threads](https://discuss.openedx.org/)
- timeline information ("this must be merged by XX date", and why that is)
- partner information ("this is a course on edx.org")
- any other information that can help Product understand the context for the PR

{% filter replace("\n", " ")|trim %}
All technical communication about the code itself will be done via the
GitHub pull request interface. As a reminder,
[our process documentation is here](http://edx-developer-guide.readthedocs.org/en/latest/process/overview.html).
{% endfilter %}

### What's next?

*Please work through the following steps to get your changes ready for engineering review:*

#### :radio_button: Get product approval

If you haven't already, [check this list](https://openedx.atlassian.net/wiki/spaces/COMM/pages/3875962884/How+to+submit+an+open+source+contribution+for+Product+Review#Does-my-contribution-require-Product-Review%3F) to see if your contribution needs to go through the product review process.

- If it does, you'll need to submit a product proposal for your contribution, and have it reviewed by the [Product Working Group](https://openedx.atlassian.net/wiki/spaces/COMM/pages/3449028609/Product+Working+Group).
- This process (including the steps you'll need to take) is documented [here](https://openedx.atlassian.net/wiki/spaces/COMM/pages/3875962884/How+to+submit+an+open+source+contribution+for+Product+Review#Product-Review-Process).
- If it doesn't, simply proceed with the next step.

#### :radio_button: Provide context

To help your reviewers and other members of the community understand the purpose and larger context of your changes, feel free to add as much of the following information to the PR description as you can:

- Dependencies
> This PR must be merged before / after / at the same time as ...
- Blockers
> This PR is waiting for OEP-1234 to be accepted.
- Timeline information
> This PR must be merged by XX date **because** ...
- Partner information
> This is for a course on edx.org.
- Supporting documentation
- Relevant [Open edX discussion forum](https://discuss.openedx.org/) threads

{% if not has_signed_agreement %}
#### :radio_button: Submit a signed contributor agreement (CLA)

:warning: We ask all contributors to the Open edX project to submit a [signed contributor agreement](https://openedx.org/cla) or indicate their institutional affiliation.
Please see the [CONTRIBUTING](https://github.com/openedx/.github/blob/master/CONTRIBUTING.md) file for more information.

If you've signed an agreement in the past, you may need to re-sign.
See [The New Home of the Open edX Codebase](https://open.edx.org/blog/the-new-home-of-the-open-edx-codebase/) for details.

Once you've signed the CLA, please allow 1 business day for it to be processed.
After this time, you can re-run the CLA check by adding a comment below that you have signed it.
If the CLA check continues to fail, you can tag the `@openedx/cla-problems` team in a comment for further assistance.

<!-- comment:no_cla -->
{% endif %}

{% if is_first_time %}
#### :radio_button: Wait for tests to be enabled

It looks like you are contributing to this repository for the first time.
This means that automated tests won't run automatically, and that you'll need to wait for a test run to be authorized.

If you're experiencing a delay of two weeks or more at this step, tag the [community contributions project managers](https://openedx.atlassian.net/wiki/spaces/COMM/pages/3548807177/Community+Contributions+Project+Manager#Current-OSPR-Project-Managers) in a comment and ask for help.
{% endif %}

#### :radio_button: Get a green build

If one or more checks are failing, continue working on your changes until this is no longer the case and your build turns green.

{% if is_draft %}
{% filter replace("\n", " ")|trim %}
This is currently a draft pull request. When it is ready for our review and all tests are green,
click "Ready for Review", or remove "WIP" from the title, as appropriate.
{% endfilter %}
#### :radio_button: Update the status of your PR

Your PR is currently marked as a draft. After completing the steps above, update its status by clicking "Ready for Review", or removing "WIP" from the title, as appropriate.

<!-- comment:end_of_wip -->
{% else %}
Please let us know once your PR is ready for our review and all tests are green.
{% endif %}

{% if not has_signed_agreement %}
{%- filter replace("\n", " ")|trim %}
:warning: We can't start reviewing your pull request until you've submitted a
[signed contributor agreement](https://openedx.org/cla)
or indicated your institutional affiliation. Please see the [CONTRIBUTING](https://github.com/openedx/.github/blob/master/CONTRIBUTING.md)
file for more information.
If you've signed an agreement in the past, you may need to re-sign. See
[The New Home of the Open edX Codebase](https://open.edx.org/blog/the-new-home-of-the-open-edx-codebase/)
for details.
{%- endfilter %}

{{ '\n' }}

{%- filter replace("\n", " ")|trim %}
Once you've signed the CLA, please allow 1 business day for it to be processed. After this time, you can re-run the
CLA check by adding a comment here that you have signed it. If the problem persists, you can tag the `@openedx/cla-problems` team in a
comment on your PR for further assistance.
{%- endfilter %}
#### :radio_button: Let us know that your PR is ready for review:

<!-- comment:no_cla -->
### Who will review my changes?

{% if owner %}
This repository is currently maintained by `@{{ owner }}`. Tag them in a comment and let them know that your changes are ready for review.
{% else %}
{% if lifecycle == 'production' %}
This repository has no maintainer (yet).
{% else %}
This repository is currently unmaintained.
{% endif %}
To get help with finding a technical reviewer, tag the community contributions project manager for this PR in a comment and let them know that your changes are ready for review:

1. On the right-hand side of the PR, find the Contributions project, click the caret in the top right corner to expand it, and check the "Primary PM" field for the name of your PM.
2. Find their GitHub handle [here](https://openedx.atlassian.net/wiki/spaces/COMM/pages/3548807177/Community+Contributions+Project+Manager#Current-OSPR-Project-Managers).
{% endif %}

### Where can I find more information?

If you'd like to get more details on all aspects of the review process for open source pull requests (OSPRs), check out the following resources:

- [Overview of Review Process for Community Contributions](https://docs.openedx.org/en/latest/developers/references/developer_guide/process/FAQ-about-pull-requests.html)
- [Pull Request Status Guide](https://docs.openedx.org/en/latest/developers/references/developer_guide/process/pull-request-statuses.html)
- [Making changes to your pull request](https://docs.openedx.org/en/latest/documentors/how-tos/make_changes_to_your_pull_request.html)

### When can I expect my changes to be merged?

Our goal is to get community contributions seen and reviewed as efficiently as possible.

However, the amount of time that it takes to review and merge a PR can vary significantly based on factors such as:

- The size and impact of the changes that it introduces
- The need for product review
- Maintenance status of the parent repository

:bulb: *As a result it may take up to several weeks or months to complete a review and merge your PR.*

<!-- comment:external_pr -->
49 changes: 41 additions & 8 deletions tests/test_pull_request_opened.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
"""Tests of tasks/github.py:pull_request_changed for opening pull requests."""

import textwrap
from unittest import mock

import pytest

from openedx_webhooks import settings
from openedx_webhooks.bot_comments import (
BotComment,
is_comment_kind,
Expand All @@ -16,10 +18,8 @@
CLA_STATUS_NO_CONTRIBUTIONS,
CLA_STATUS_PRIVATE,
)
from openedx_webhooks import settings
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

# These tests should run when we want to test flaky GitHub behavior.
Expand Down Expand Up @@ -75,6 +75,42 @@ def test_pr_in_nocontrib_repo_opened(fake_github, user):
assert pull_request_projects(pr.as_json()) == set()


@pytest.mark.parametrize("owner,tag", [
("group:arch-bom", "@openedx/arch-bom"),
("user:feanil", "@feanil"),
("feanil", "@feanil"),
])
@mock.patch("openedx_webhooks.bot_comments.get_catalog_info")
def test_pr_with_owner_repo_opened(get_catalog_info, fake_github, owner, tag):
get_catalog_info.return_value = {
'spec': {'owner': owner, 'lifecycle': 'production'}
}
pr = fake_github.make_pull_request(owner="openedx", repo="edx-platform")
result = pull_request_changed(pr.as_json())
assert not result.jira_issues
pr_comments = pr.list_comments()
assert len(pr_comments) == 1
body = pr_comments[0].body
assert f"This repository is currently maintained by `{tag}`" in body

@pytest.mark.parametrize("lifecycle", ["production", "deprecated", None])
@mock.patch("openedx_webhooks.bot_comments.get_catalog_info")
def test_pr_without_owner_repo_opened(get_catalog_info, fake_github, lifecycle):
get_catalog_info.return_value = {
'spec': {'lifecycle': lifecycle}
} if lifecycle else None
pr = fake_github.make_pull_request(owner="openedx", repo="edx-platform")
result = pull_request_changed(pr.as_json())
assert not result.jira_issues
pr_comments = pr.list_comments()
assert len(pr_comments) == 1
body = pr_comments[0].body
if lifecycle == "production":
assert f"This repository has no maintainer (yet)." in body
else:
assert f"This repository is currently unmaintained." in body


def test_pr_opened_by_bot(fake_github):
fake_github.make_user(login="some_bot", type="Bot")
pr = fake_github.make_pull_request(user="some_bot")
Expand Down Expand Up @@ -235,8 +271,7 @@ def test_draft_pr_opened(pr_type, fake_github, mocker):
pr_comments = pr.list_comments()
assert len(pr_comments) == 1
body = pr_comments[0].body
assert 'This is currently a draft pull request' in body
assert 'click "Ready for Review"' in body
assert is_comment_kind(BotComment.END_OF_WIP, body)
expected_labels = set()
expected_labels.add("blended" if pr_type == "blended" else "open-source-contribution")
assert pr.labels == expected_labels
Expand All @@ -263,8 +298,7 @@ def test_draft_pr_opened(pr_type, fake_github, mocker):
pr_comments = pr.list_comments()
assert len(pr_comments) == 1
body = pr_comments[0].body
assert 'This is currently a draft pull request' not in body
assert 'click "Ready for Review"' not in body
assert not is_comment_kind(BotComment.END_OF_WIP, body)

# Oops, it goes back to draft!
pr.title = title1
Expand All @@ -274,8 +308,7 @@ def test_draft_pr_opened(pr_type, fake_github, mocker):
pr_comments = pr.list_comments()
assert len(pr_comments) == 1
body = pr_comments[0].body
assert 'This is currently a draft pull request' in body
assert 'click "Ready for Review"' in body
assert is_comment_kind(BotComment.END_OF_WIP, body)


def test_dont_add_internal_prs_to_project(fake_github):
Expand Down
Loading