[GHF] Add submodule updates check (#95885)

Originally planned to integrate it somehow into the `lintrunner`, but this poses too many challenges, one of them is that it deliberately ignores submodule updates.

On the other hand, almost all the information, other than list of the submodules is already present in the GitHubPR info.

Incorporate small BE change into `test_trymerge.py`, that moves `@mock.patch` from individual test to the class definition.

Fixes https://github.com/pytorch/pytorch/issues/74326 and https://github.com/pytorch/test-infra/issues/1521
Pull Request resolved: https://github.com/pytorch/pytorch/pull/95885
Approved by: https://github.com/ZainRizvi, https://github.com/huydhn
This commit is contained in:
Nikita Shulga
2023-03-02 18:05:26 +00:00
committed by PyTorch MergeBot
parent 7ebd816aab
commit 61fa43a1f2
3 changed files with 2440 additions and 50 deletions

View File

@ -441,6 +441,22 @@ query ($owner: String!, $name: String!, $number: Int!, $cursor: String!) {
}
"""
GH_GET_REPO_SUBMODULES = """
query ($owner: String!, $name: String!) {
repository(owner: $owner, name: $name) {
submodules(first: 100) {
nodes {
path
}
pageInfo {
endCursor
hasNextPage
}
}
}
}
"""
RE_GHSTACK_HEAD_REF = re.compile(r"^(gh/[^/]+/[0-9]+/)head$")
RE_GHSTACK_DESC = re.compile(r'Stack.*:\r?\n(\* [^\r\n]+\r?\n)+', re.MULTILINE)
RE_PULL_REQUEST_RESOLVED = re.compile(
@ -650,6 +666,7 @@ class GitHubPR:
self._authors: Optional[List[Tuple[str, str]]] = None
self._reviews: Optional[List[Tuple[str, str]]] = None
self.merge_base: Optional[str] = None
self.submodules: Optional[List[str]] = None
def is_closed(self) -> bool:
return bool(self.info["closed"])
@ -725,6 +742,29 @@ class GitHubPR:
raise RuntimeError("Changed file count mismatch")
return self.changed_files
def get_submodules(self) -> List[str]:
if self.submodules is None:
rc = gh_graphql(GH_GET_REPO_SUBMODULES,
name=self.project,
owner=self.org)
info = rc["data"]["repository"]["submodules"]
self.submodules = [s["path"] for s in info["nodes"]]
return self.submodules
def get_changed_submodules(self) -> List[str]:
submodules = self.get_submodules()
return [f for f in self.get_changed_files() if f in submodules]
def has_invalid_submodule_updates(self) -> bool:
""" Submodule updates in PR are invalid if submodule keyword
is not mentioned in neither the title nor body/description
nor in any of the labels.
"""
return (len(self.get_changed_submodules()) > 0 and
"submodule" not in self.get_title().lower() and
"submodule" not in self.get_body().lower() and
all("submodule" not in label for label in self.get_labels()))
def _get_reviews(self) -> List[Tuple[str, str]]:
if self._reviews is None:
self._reviews = []
@ -1734,6 +1774,12 @@ def main() -> None:
gh_post_pr_comment(org, project, args.pr_num, "Cross-repo ghstack merges are not supported", dry_run=args.dry_run)
return
if not args.force and pr.has_invalid_submodule_updates():
message = f"This PR updates submodules {', '.join(pr.get_changed_submodules())}\n"
message += "\nIf those updates are intentional, please add \"submodule\" keyword to PR title/description."
gh_post_pr_comment(org, project, args.pr_num, message, dry_run=args.dry_run)
return
try:
merge(args.pr_num, repo,
dry_run=args.dry_run,