mirror of
https://github.com/zebrajr/pytorch.git
synced 2025-12-06 12:20:52 +01:00
Addresses https://github.com/pytorch/test-infra/issues/3950 Test Plan: Ran a dry run on this pr. The label showed up while trying to merge <img width="354" alt="Screenshot 2023-04-06 at 4 57 48 PM" src="https://user-images.githubusercontent.com/13758638/230514276-1ac70b58-d2d1-4e4b-892b-a957bf156063.png"> And then disappeared after failing <img width="373" alt="Screenshot 2023-04-06 at 5 00 11 PM" src="https://user-images.githubusercontent.com/13758638/230514470-38b15ec7-cfd9-4efe-b6e8-0f9af5577c62.png"> There's also the trail of adding and removing the "merging" label at the bottom Notes: This is slightly buggy sometimes. For example when the merge failed when I was editing this textbox, the label did not disappear. Pull Request resolved: https://github.com/pytorch/pytorch/pull/98543 Approved by: https://github.com/malfet
118 lines
3.8 KiB
Python
118 lines
3.8 KiB
Python
"""GitHub Label Utilities."""
|
|
|
|
import json
|
|
|
|
from functools import lru_cache
|
|
from typing import Any, List, Tuple, TYPE_CHECKING, Union
|
|
from urllib.request import Request, urlopen
|
|
|
|
from github_utils import gh_fetch_url, GitHubComment
|
|
|
|
# TODO: this is a temp workaround to avoid circular dependencies,
|
|
# and should be removed once GitHubPR is refactored out of trymerge script.
|
|
if TYPE_CHECKING:
|
|
from trymerge import GitHubPR
|
|
|
|
BOT_AUTHORS = ["github-actions", "pytorchmergebot", "pytorch-bot"]
|
|
|
|
LABEL_ERR_MSG_TITLE = "This PR needs a label"
|
|
LABEL_ERR_MSG = f"""# {LABEL_ERR_MSG_TITLE}
|
|
If your changes are user facing and intended to be a part of release notes, please use a label starting with `release notes:`.
|
|
|
|
If not, please add the `topic: not user facing` label.
|
|
|
|
To add a label, you can comment to pytorchbot, for example
|
|
`@pytorchbot label "topic: not user facing"`
|
|
|
|
For more information, see
|
|
https://github.com/pytorch/pytorch/wiki/PyTorch-AutoLabel-Bot#why-categorize-for-release-notes-and-how-does-it-work.
|
|
"""
|
|
|
|
|
|
# Modified from https://github.com/pytorch/pytorch/blob/b00206d4737d1f1e7a442c9f8a1cadccd272a386/torch/hub.py#L129
|
|
def _read_url(url: Request) -> Tuple[Any, Any]:
|
|
with urlopen(url) as r:
|
|
return r.headers, r.read().decode(r.headers.get_content_charset("utf-8"))
|
|
|
|
|
|
def request_for_labels(url: str) -> Tuple[Any, Any]:
|
|
headers = {"Accept": "application/vnd.github.v3+json"}
|
|
return _read_url(Request(url, headers=headers))
|
|
|
|
|
|
def update_labels(labels: List[str], info: str) -> None:
|
|
labels_json = json.loads(info)
|
|
labels.extend([x["name"] for x in labels_json])
|
|
|
|
|
|
def get_last_page_num_from_header(header: Any) -> int:
|
|
# Link info looks like: <https://api.github.com/repositories/65600975/labels?per_page=100&page=2>;
|
|
# rel="next", <https://api.github.com/repositories/65600975/labels?per_page=100&page=3>; rel="last"
|
|
link_info = header["link"]
|
|
prefix = "&page="
|
|
suffix = ">;"
|
|
return int(
|
|
link_info[link_info.rindex(prefix) + len(prefix) : link_info.rindex(suffix)]
|
|
)
|
|
|
|
|
|
@lru_cache()
|
|
def gh_get_labels(org: str, repo: str) -> List[str]:
|
|
prefix = f"https://api.github.com/repos/{org}/{repo}/labels?per_page=100"
|
|
header, info = request_for_labels(prefix + "&page=1")
|
|
labels: List[str] = []
|
|
update_labels(labels, info)
|
|
|
|
last_page = get_last_page_num_from_header(header)
|
|
assert (
|
|
last_page > 0
|
|
), "Error reading header info to determine total number of pages of labels"
|
|
for page_number in range(2, last_page + 1): # skip page 1
|
|
_, info = request_for_labels(prefix + f"&page={page_number}")
|
|
update_labels(labels, info)
|
|
|
|
return labels
|
|
|
|
|
|
def gh_add_labels(
|
|
org: str, repo: str, pr_num: int, labels: Union[str, List[str]]
|
|
) -> None:
|
|
gh_fetch_url(
|
|
url=f"https://api.github.com/repos/{org}/{repo}/issues/{pr_num}/labels",
|
|
data={"labels": labels},
|
|
)
|
|
|
|
|
|
def gh_remove_label(org: str, repo: str, pr_num: int, label: str) -> None:
|
|
gh_fetch_url(
|
|
url=f"https://api.github.com/repos/{org}/{repo}/issues/{pr_num}/labels/{label}",
|
|
method="DELETE",
|
|
)
|
|
|
|
|
|
def get_release_notes_labels(org: str, repo: str) -> List[str]:
|
|
return [
|
|
label
|
|
for label in gh_get_labels(org, repo)
|
|
if label.lstrip().startswith("release notes:")
|
|
]
|
|
|
|
|
|
def has_required_labels(pr: "GitHubPR") -> bool:
|
|
pr_labels = pr.get_labels()
|
|
# Check if PR is not user facing
|
|
is_not_user_facing_pr = any(
|
|
label.strip() == "topic: not user facing" for label in pr_labels
|
|
)
|
|
return is_not_user_facing_pr or any(
|
|
label.strip() in get_release_notes_labels(pr.org, pr.project)
|
|
for label in pr_labels
|
|
)
|
|
|
|
|
|
def is_label_err_comment(comment: GitHubComment) -> bool:
|
|
return (
|
|
comment.body_text.lstrip(" #").startswith(LABEL_ERR_MSG_TITLE)
|
|
and comment.author_login in BOT_AUTHORS
|
|
)
|