Example #1
0
    def merge_into(self,
                   repo: GitRepo,
                   *,
                   force: bool = False,
                   dry_run: bool = False,
                   comment_id: Optional[int] = None) -> None:
        # Raises exception if matching rule is not found
        find_matching_merge_rule(self,
                                 repo,
                                 force=force,
                                 skip_internal_checks=can_skip_internal_checks(
                                     self, comment_id))
        if repo.current_branch() != self.default_branch():
            repo.checkout(self.default_branch())
        if not self.is_ghstack_pr():
            # Adding the url here makes it clickable within the Github UI
            approved_by_urls = ', '.join(
                prefix_with_github_url(login)
                for login in self.get_approved_by())
            msg = self.get_title() + f" (#{self.pr_num})\n\n" + self.get_body()
            msg += f"\nPull Request resolved: {self.get_pr_url()}\n"
            msg += f"Approved by: {approved_by_urls}\n"
            pr_branch_name = f"__pull-request-{self.pr_num}__init__"
            repo.fetch(f"pull/{self.pr_num}/head", pr_branch_name)
            repo._run_git("merge", "--squash", pr_branch_name)
            repo._run_git("commit", f"--author=\"{self.get_author()}\"", "-m",
                          msg)
        else:
            self.merge_ghstack_into(repo, force, comment_id=comment_id)

        repo.push(self.default_branch(), dry_run)
        if not dry_run:
            gh_add_labels(self.org, self.project, self.pr_num, ["merged"])
Example #2
0
def try_revert(repo: GitRepo,
               pr: GitHubPR,
               *,
               dry_run: bool = False,
               comment_id: Optional[int] = None,
               reason: Optional[str] = None) -> None:
    def post_comment(msg: str) -> None:
        gh_post_comment(pr.org, pr.project, pr.pr_num, msg, dry_run=dry_run)

    if not pr.is_closed():
        return post_comment(f"Can't revert open PR #{pr.pr_num}")
    comment = pr.get_last_comment(
    ) if comment_id is None else pr.get_comment_by_id(comment_id)
    if not RE_REVERT_CMD.match(
            comment.body_text) and not RE_REVERT_CMD_CLI.match(
                comment.body_text):
        raise RuntimeError(
            f"Comment {comment.body_text} does not seem to be a valid revert command"
        )
    if comment.editor_login is not None:
        return post_comment("Don't want to revert based on edited command")
    author_association = comment.author_association
    author_login = comment.author_login
    # For some reason, one can not be a member of private repo, only CONTRIBUTOR
    expected_association = "CONTRIBUTOR" if pr.is_base_repo_private(
    ) else "MEMBER"
    if author_association != expected_association and author_association != "OWNER":
        return post_comment(
            f"Will not revert as @{author_login} is not a {expected_association}, but {author_association}"
        )
    skip_internal_checks = can_skip_internal_checks(pr, comment_id)

    # Raises exception if matching rule is not found, but ignores all status checks
    find_matching_merge_rule(pr,
                             repo,
                             force=True,
                             skip_internal_checks=skip_internal_checks)
    commit_sha = pr.get_merge_commit()
    if commit_sha is None:
        commits = repo.commits_resolving_gh_pr(pr.pr_num)
        if len(commits) == 0:
            raise RuntimeError("Can't find any commits resolving PR")
        commit_sha = commits[0]
    msg = repo.commit_message(commit_sha)
    rc = RE_DIFF_REV.search(msg)
    if rc is not None and not can_skip_internal_checks:
        raise RuntimeError(
            f"Can't revert PR that was landed via phabricator as {rc.group(1)}"
        )
    repo.checkout(pr.default_branch())
    repo.revert(commit_sha)
    msg = repo.commit_message("HEAD")
    msg = re.sub(RE_PULL_REQUEST_RESOLVED, "", msg)
    msg += f"\nReverted {pr.get_pr_url()} on behalf of {prefix_with_github_url(author_login)}"
    msg += f" due to {reason}\n" if reason is not None else "\n"
    repo.amend_commit_message(msg)
    repo.push(pr.default_branch(), dry_run)
    if not dry_run:
        gh_add_labels(pr.org, pr.project, pr.pr_num, ["reverted"])
Example #3
0
    def merge_into(self, repo: GitRepo, *,
                   force: bool = False,
                   dry_run: bool = False,
                   comment_id: Optional[int] = None) -> None:
        # Raises exception if matching rule is not found
        find_matching_merge_rule(self, repo, force=force, skip_internal_checks=can_skip_internal_checks(self, comment_id))
        self.merge_changes(repo, force, comment_id)

        repo.push(self.default_branch(), dry_run)
        if not dry_run:
            gh_add_labels(self.org, self.project, self.pr_num, ["merged"])
Example #4
0
    def merge_into(self, repo: GitRepo, dry_run: bool = False) -> None:
        check_if_should_be_merged(self, repo)
        if repo.current_branch() != self.default_branch():
            repo.checkout(self.default_branch())
        if not self.is_ghstack_pr():
            msg = self.get_title() + "\n\n" + self.get_body()
            msg += f"\nPull Request resolved: {self.get_pr_url()}\n"
            repo._run_git("merge", "--squash", f"{repo.remote}/{self.head_ref()}")
            repo._run_git("commit", f"--author=\"{self.get_author()}\"", "-m", msg)
        else:
            self.merge_ghstack_into(repo)

        if not dry_run:
            repo.push(self.default_branch(), dry_run)
Example #5
0
    def merge_into(self, repo: GitRepo, dry_run: bool = False) -> None:
        # Raises exception if matching rule is not found
        find_matching_merge_rule(self, repo)
        if repo.current_branch() != self.default_branch():
            repo.checkout(self.default_branch())
        if not self.is_ghstack_pr():
            msg = self.get_title() + "\n\n" + self.get_body()
            msg += f"\nPull Request resolved: {self.get_pr_url()}\n"
            pr_branch_name = f"__pull-request-{self.pr_num}__init__"
            repo.fetch(f"pull/{self.pr_num}/head", pr_branch_name)
            repo._run_git("merge", "--squash", pr_branch_name)
            repo._run_git("commit", f"--author=\"{self.get_author()}\"", "-m",
                          msg)
        else:
            self.merge_ghstack_into(repo)

        repo.push(self.default_branch(), dry_run)
Example #6
0
def try_revert(repo: GitRepo, pr: GitHubPR, dry_run: bool = False) -> None:
    def post_comment(msg: str) -> None:
        gh_post_comment(pr.org, pr.project, pr.pr_num, msg, dry_run=dry_run)

    if not pr.is_closed():
        return post_comment(f"Can't revert open PR #{pr.pr_num}")
    if not RE_REVERT_CMD.match(pr.get_comment_body()):
        raise RuntimeError(
            f"Comment {pr.get_comment_body()} does not seem to be a valid revert command"
        )
    if pr.get_comment_editor_login() is not None:
        return post_comment("Don't want to revert based on edited command")
    author_association = pr.get_comment_author_association()
    author_login = pr.get_comment_author_login()
    # For some reason, one can not be a member of private repo, only CONTRIBUTOR
    expected_association = "CONTRIBUTOR" if pr.is_base_repo_private(
    ) else "MEMBER"
    if author_association != expected_association and author_association != "OWNER":
        return post_comment(
            f"Will not revert as @{author_login} is not a {expected_association}, but {author_association}"
        )

    # Raises exception if matching rule is not found
    find_matching_merge_rule(pr, repo)
    commit_sha = pr.get_merge_commit()
    if commit_sha is None:
        commits = repo.commits_resolving_gh_pr(pr.pr_num)
        if len(commits) == 0:
            raise RuntimeError("Can't find any commits resolving PR")
        commit_sha = commits[0]
    msg = repo.commit_message(commit_sha)
    rc = RE_DIFF_REV.search(msg)
    if rc is not None:
        raise RuntimeError(
            f"Can't revert PR that was landed via phabricator as {rc.group(1)}"
        )
    repo.checkout(pr.default_branch())
    repo.revert(commit_sha)
    msg = repo.commit_message("HEAD")
    msg = re.sub(RE_PULL_REQUEST_RESOLVED, "", msg)
    msg += f"\nReverted {pr.get_pr_url()} on behalf of @{author_login}\n"
    repo.amend_commit_message(msg)
    repo.push(pr.default_branch(), dry_run)
    if not dry_run:
        gh_add_labels(pr.org, pr.project, pr.pr_num, ["reverted"])
Example #7
0
    def merge_into(self, repo: GitRepo, *, force: bool = False, dry_run: bool = False) -> None:
        # Raises exception if matching rule is not found
        find_matching_merge_rule(self, repo, force=force)
        if self.has_internal_changes():
            raise RuntimeError("This PR must be landed via phabricator")
        if repo.current_branch() != self.default_branch():
            repo.checkout(self.default_branch())
        if not self.is_ghstack_pr():
            # Adding the url here makes it clickable within the Github UI
            approved_by_urls = ', '.join(prefix_with_github_url(login) for login in self.get_approved_by())
            msg = self.get_title() + "\n\n" + self.get_body()
            msg += f"\nPull Request resolved: {self.get_pr_url()}\n"
            msg += f"Approved by: {approved_by_urls}\n"
            pr_branch_name = f"__pull-request-{self.pr_num}__init__"
            repo.fetch(f"pull/{self.pr_num}/head", pr_branch_name)
            repo._run_git("merge", "--squash", pr_branch_name)
            repo._run_git("commit", f"--author=\"{self.get_author()}\"", "-m", msg)
        else:
            self.merge_ghstack_into(repo, force)

        repo.push(self.default_branch(), dry_run)
Example #8
0
def main() -> None:
    args = parse_args()
    repo = GitRepo(get_git_repo_dir(), debug=args.debug)
    repo.cherry_pick_commits(args.sync_branch, args.default_branch)
    repo.push(args.default_branch, args.dry_run)