Lines Matching +full:repo +full:- +full:owner
5 # This source code is licensed under the BSD-style license found in the
8 # NB: the following functions are used in Meta-internal workflows
185 query ($owner: String!, $name: String!, $number: Int!) {
186 repository(owner: $owner, name: $name) {
278 query ($owner: String!, $name: String!, $number: Int!, $cursor: String!) {
279 repository(name: $name, owner: $owner) {
298 query ($owner: String!, $name: String!, $number: Int!, $cursor: String!) {
299 repository(name: $name, owner: $owner) {
318 query ($owner: String!, $name: String!, $number: Int!, $cs_cursor: String, $cr_cursor: String!) {
319 repository(name: $name, owner: $owner) {
352 query ($owner: String!, $name: String!, $number: Int!, $cursor: String!) {
353 repository(name: $name, owner: $owner) {
379 # This query needs read-org permission
401 query ($owner: String!, $name: String!, $number: Int!, $cursor: String) {
402 repository(name: $name, owner: $owner) {
416 query ($owner: String!, $name: String!, $number: Int!, $cursor: String!) {
417 repository(name: $name, owner: $owner) {
429 query ($owner: String!, $name: String!) {
430 repository(owner: $owner, name: $name) {
444 RE_GHSTACK_HEAD_REF = re.compile(r"^(gh/[^/]+/[0-9]+/)head$")
448 r"https://github.com/(?P<owner>[^/]+)/(?P<repo>[^/]+)/pull/(?P<number>[0-9]+)",
452 RE_DIFF_REV = re.compile(r"^Differential Revision:.+?(D[0-9]+)", re.MULTILINE)
460 INTERNAL_CHANGES_CHECKRUN_NAME = "Meta Internal-Only Changes Check"
464 # This could be set to -1 to ignore all flaky and broken trunk failures. On the
469 def gh_get_pr_info(org: str, proj: str, pr_no: int) -> Any:
470 rc = gh_graphql(GH_GET_PR_INFO_QUERY, name=proj, owner=org, number=pr_no)
475 def gh_get_team_members(org: str, name: str) -> List[str]:
489 warn(f"Requested non-existing team {org}/{name}")
496 def get_check_run_name_prefix(workflow_run: Any) -> str:
503 def is_passing_status(status: Optional[str]) -> bool:
511 ) -> JobNameToStateDict:
515 # workflow -> job -> job info
521 def add_conclusions(edges: Any) -> None:
598 def parse_args() -> Any:
602 parser.add_argument("--dry-run", action="store_true")
603 parser.add_argument("--revert", action="store_true")
604 parser.add_argument("--force", action="store_true")
605 parser.add_argument("--ignore-current", action="store_true")
606 parser.add_argument("--check-mergeability", action="store_true")
607 parser.add_argument("--comment-id", type=int)
608 parser.add_argument("--reason", type=str)
613 def can_skip_internal_checks(pr: "GitHubPR", comment_id: Optional[int] = None) -> bool:
619 return comment.author_login == "facebook-github-bot"
623 repo: GitRepo,
627 ) -> List[Tuple["GitHubPR", str]]:
630 msg = repo.commit_message(rev)
634 f"Could not find PR-resolved string in {msg} of ghstacked PR {pr.pr_num}"
636 if pr.org != m.group("owner") or pr.project != m.group("repo"):
638 f"PR {m.group('number')} resolved to wrong owner/repo pair"
649 repo: GitRepo, pr: "GitHubPR", open_only: bool = True
650 ) -> List[Tuple["GitHubPR", str]]:
655 # For ghstack, cherry-pick commits based from origin
656 orig_ref = f"{repo.remote}/{pr.get_ghstack_orig_ref()}"
657 rev_list = repo.revlist(f"{pr.default_branch()}..{orig_ref}")
659 def skip_func(idx: int, candidate: "GitHubPR") -> bool:
668 entire_stack = _revlist_to_prs(repo, pr, reversed(rev_list), skip_func)
675 base_ref = repo.get_merge_base(
676 f"{repo.remote}/{base_ref}", f"{repo.remote}/{stacked_pr.head_ref()}"
678 if not are_ghstack_branches_in_sync(repo, stacked_pr.head_ref(), base_ref):
689 def __init__(self, org: str, project: str, pr_num: int) -> None:
704 def is_closed(self) -> bool:
707 def is_cross_repo(self) -> bool:
710 def base_ref(self) -> str:
713 def default_branch(self) -> str:
716 def head_ref(self) -> str:
719 def is_ghstack_pr(self) -> bool:
722 def get_ghstack_orig_ref(self) -> str:
726 def is_base_repo_private(self) -> bool:
729 def get_changed_files_count(self) -> int:
732 def last_commit(self) -> Any:
733 return self.info["commits"]["nodes"][-1]["commit"]
735 def get_merge_base(self) -> str:
757 def get_changed_files(self) -> List[str]:
769 owner=self.org,
780 def get_submodules(self) -> List[str]:
782 rc = gh_graphql(GH_GET_REPO_SUBMODULES, name=self.project, owner=self.org)
787 def get_changed_submodules(self) -> List[str]:
791 def has_invalid_submodule_updates(self) -> bool:
803 def _get_reviews(self) -> List[Tuple[str, str]]:
817 owner=self.org,
828 def get_approved_by(self) -> List[str]:
831 def get_commit_count(self) -> int:
834 def get_pr_creator_login(self) -> str:
837 def _fetch_authors(self) -> List[Tuple[str, str]]:
842 def add_authors(info: Dict[str, Any]) -> None:
861 owner=self.org,
869 def get_committer_login(self, num: int = 0) -> str:
872 def get_committer_author(self, num: int = 0) -> str:
875 def get_labels(self) -> List[str]:
886 def get_checkrun_conclusions(self) -> JobNameToStateDict:
887 """Returns dict of checkrun -> [conclusion, url]"""
894 ) -> Any:
898 owner=self.org,
900 cs_cursor=edges[edge_idx - 1]["cursor"] if edge_idx > 0 else None,
904 -1
906 checkruns = last_commit["checkSuites"]["nodes"][-1]["checkRuns"]
909 def get_pr_next_checksuites(checksuites: Any) -> Any:
913 owner=self.org,
915 cursor=checksuites["edges"][-1]["cursor"],
918 last_commit = info["commits"]["nodes"][-1]["commit"]
945 def get_authors(self) -> Dict[str, str]:
952 def get_author(self) -> str:
963 def get_title(self) -> str:
966 def get_body(self) -> str:
969 def get_merge_commit(self) -> Optional[str]:
973 def get_pr_url(self) -> str:
977 def _comment_from_node(node: Any) -> GitHubComment:
989 def get_comments(self) -> List[GitHubComment]:
1004 owner=self.org,
1011 def get_last_comment(self) -> GitHubComment:
1012 return self._comment_from_node(self.info["comments"]["nodes"][-1])
1014 def get_comment_by_id(self, database_id: int) -> GitHubComment:
1016 # Fastpath - try searching in partial prefetched comments
1037 def get_diff_revision(self) -> Optional[str]:
1041 def has_internal_changes(self) -> bool:
1050 def has_no_connected_diff(self) -> bool:
1059 repo: GitRepo,
1063 ) -> List["GitHubPR"]:
1066 repo, self, open_only=False
1081 repo,
1085 repo.cherry_pick(rev)
1086 repo.amend_commit_message(commit_msg)
1094 ) -> str:
1109 # Mention PR co-authors
1112 msg += f"\nCo-authored-by: {author_name}"
1120 def add_numbered_label(self, label_base: str, dry_run: bool) -> None:
1132 repo: GitRepo,
1138 ) -> None:
1147 repo,
1153 repo, skip_mandatory_checks, comment_id
1156 repo.push(self.default_branch(), dry_run)
1165 merge_commit_sha = repo.rev_parse(name=REMOTE_MAIN_BRANCH)
1173 owner=self.org,
1196 repo: GitRepo,
1201 ) -> List["GitHubPR"]:
1203 … :param skip_all_rule_checks: If true, skips all rule checks, useful for dry-running merge locally
1206 if repo.current_branch() != branch_to_merge_into:
1207 repo.checkout(branch_to_merge_into)
1210 pr_branch_name = f"__pull-request-{self.pr_num}__init__"
1211 repo.fetch(f"pull/{self.pr_num}/head", pr_branch_name)
1212 repo._run_git("merge", "--squash", pr_branch_name)
1213 repo._run_git("commit", f'--author="{self.get_author()}"', "-m", msg)
1217 repo,
1225 def __init__(self, message: str, rule: Optional["MergeRule"] = None) -> None:
1248 org: str, project: str, labels: List[str], template: str = "bug-report.yml"
1249 ) -> str:
1259 repo: Optional[GitRepo], org: str, project: str
1260 ) -> List[MergeRule]:
1261 """Returns the list of all merge rules for the repo or project.
1263 NB: this function is used in Meta-internal workflows, see the comment
1267 if repo is None:
1276 rules_path = Path(repo.repo_dir) / repo_relative_rules_path
1287 repo: Optional[GitRepo] = None,
1291 ) -> Tuple[
1301 NB: this function is used in Meta-internal workflows, see the comment at the top of
1314 rules = read_merge_rules(repo, pr.org, pr.project)
1338 # Score 0 to 10K - how many files rule matched
1339 # Score 10K - matched all files, but no overlapping approvers
1340 # Score 20K - matched all files and approvers, but mandatory checks are pending
1341 # Score 30k - Matched all files and approvers, but mandatory checks failed
1353 num_matching_files = len(changed_files) - len(non_matching_files)
1359 … f"{num_matching_files} files matched, but there are still non-matching files:",
1391 … f"- {name} ({', '.join(approved_by[:5])}{', ...' if len(approved_by) > 5 else ''})"
1482 def checks_to_str(checks: List[Tuple[str, Optional[str]]]) -> str:
1488 ) -> List[str]:
1490 f"- [{c[0]}]({c[1]})" if c[1] is not None else f"- {c[0]}" for c in checks[:5]
1499 owner: str,
1517 ) -> None:
1522 # Decide not to save the record to Rockset if dry-run is set to not pollute
1534 "owner": owner,
1568 def get_rockset_results(head_sha: str, merge_base: str) -> List[Dict[str, Any]]:
1598 def get_drci_classifications(pr_num: int, project: str = "pytorch") -> Any:
1606 data=f"repo={project}",
1618 REMOVE_JOB_NAME_SUFFIX_REGEX = re.compile(r", [0-9]+, [0-9]+, .+\)$")
1621 def remove_job_name_suffix(name: str, replacement: str = ")") -> str:
1628 ) -> bool:
1642 ) -> bool:
1654 ) -> bool:
1656 After https://github.com/pytorch/test-infra/pull/4579, invalid cancelled
1680 ) -> Dict[str, JobCheckState]:
1686 def get_readable_drci_results(drci_classifications: Any) -> str:
1789 ) -> List[JobCheckState]:
1793 def get_pr_commit_sha(repo: GitRepo, pr: GitHubPR) -> str:
1797 commits = repo.commits_resolving_gh_pr(pr.pr_num)
1804 repo: GitRepo, pr: GitHubPR, *, comment_id: Optional[int] = None
1805 ) -> Tuple[str, str]:
1815 allowed_reverters = ["COLLABORATOR", "MEMBER", "OWNER"]
1816 # For some reason, one can not be a member of private repo, only CONTRIBUTOR
1827 pr, repo, skip_mandatory_checks=True, skip_internal_checks=True
1829 commit_sha = get_pr_commit_sha(repo, pr)
1834 repo: GitRepo, pr: GitHubPR, only_closed: bool = True
1835 ) -> List[Tuple[str, GitHubPR]]:
1841 orig_ref = f"{repo.remote}/{pr.get_ghstack_orig_ref()}"
1842 rev_list = repo.revlist(f"{pr.default_branch()}..{orig_ref}")
1847 skip_len = len(rev_list) - 1
1848 for branch in repo.branches_containing_ref(orig_ref):
1849 candidate = repo.revlist(f"{pr.default_branch()}..{branch}")
1853 # Validate that candidate always ends rev-list
1854 if rev_list[-len(candidate) :] != candidate:
1860 rev_list = rev_list[:-skip_len]
1862 for pr_, sha in _revlist_to_prs(repo, pr, rev_list):
1867 commit_sha = get_pr_commit_sha(repo, pr_)
1873 repo: GitRepo,
1880 ) -> None:
1886 repo.checkout(pr.default_branch())
1887 repo.revert(commit_sha)
1888 msg = repo.commit_message("HEAD")
1891 repo.amend_commit_message(msg)
1892 repo.push(shas_and_prs[0][1].default_branch(), dry_run)
1905 revert_message += "\ncc: @pytorch/pytorch-dev-infra"
1917 repo: GitRepo,
1923 ) -> None:
1925 author_login, commit_sha = validate_revert(repo, pr, comment_id=comment_id)
1939 shas_and_prs = get_ghstack_dependent_prs(repo, pr)
1948 repo,
1957 def prefix_with_github_url(suffix_str: str) -> str:
1961 def check_for_sev(org: str, project: str, skip_mandatory_checks: bool) -> None:
1968 params={"q": f'repo:{org}/{project} is:open is:issue label:"ci: sev"'},
1982 def has_label(labels: List[str], pattern: Pattern[str] = CIFLOW_LABEL) -> bool:
1990 ) -> Tuple[
2068 repo: GitRepo,
2075 ) -> None:
2093 # ignored and is toggled by the --ignore-current flag
2097 get_ghstack_prs(repo, pr) # raises error if out of sync
2110 repo,
2117 find_matching_merge_rule(pr, repo, skip_mandatory_checks=True)
2148 elapsed_time = current_time - start_time
2163 pr, repo, ignore_current_checks=ignore_current_checks
2213 repo,
2228 gh_add_labels(pr.org, pr.project, pr.pr_num, ["land-failed"], dry_run)
2232 def main() -> None:
2234 repo = GitRepo(get_git_repo_dir(), get_git_remote_name())
2235 org, project = repo.gh_owner_and_name()
2238 def handle_exception(e: Exception, title: str = "Merge failed") -> None:
2277 repo,
2302 "Cross-repo ghstack merges are not supported",
2309 get_ghstack_prs(repo, pr) # raises error if out of sync
2311 repo,
2327 repo,
2344 owner=org,