def rebase_onto(pr: GitHubPR, repo: GitRepo, onto_branch: str, dry_run: bool = False) -> None: branch = f"pull/{pr.pr_num}/head" onto_branch = f"refs/remotes/origin/{onto_branch}" remote_url = f"https://github.com/{pr.info['headRepository']['nameWithOwner']}.git" refspec = f"{branch}:{pr.head_ref()}" repo.fetch(branch, branch) repo._run_git("rebase", onto_branch, branch) if dry_run: push_result = repo._run_git("push", "--dry-run", "-f", remote_url, refspec) else: push_result = repo._run_git("push", "-f", remote_url, refspec) if "Everything up-to-date" in push_result: gh_post_comment( pr.org, pr.project, pr.pr_num, f"Tried to rebase and push PR #{pr.pr_num}, but it was already up to date", dry_run=dry_run) else: gh_post_comment( pr.org, pr.project, pr.pr_num, f"Successfully rebased `{pr.head_ref()}` onto `{onto_branch}`, please pull locally " + f"before adding more changes (for example, via `git checkout {pr.head_ref()} && " + "git pull --rebase`)", dry_run=dry_run)
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"])
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)
def merge_changes(self, repo: GitRepo, force: bool = False, comment_id: Optional[int] = None, branch: Optional[str] = None) -> None: branch_to_merge_into = self.default_branch() if branch is None else branch if repo.current_branch() != branch_to_merge_into: repo.checkout(branch_to_merge_into) if not self.is_ghstack_pr(): msg = self.gen_commit_message() 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)
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)
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)
def create_land_time_check_branch( self, repo: GitRepo, branch: str, force: bool = False, comment_id: Optional[int] = None, ) -> str: self.merge_changes(repo, branch=branch, force=force, comment_id=comment_id) land_check_branch = f'landchecks/{self.pr_num}' try: repo._run_git('branch', "-D", land_check_branch) except Exception: pass repo._run_git('checkout', "-b", land_check_branch) repo._run_git('push', '-u', 'origin', land_check_branch, '--force') commit = repo.get_commit('HEAD').commit_hash gh_post_pr_comment( self.org, self.project, self.pr_num, '@pytorchbot successfully started a merge and created land time checks.' + f' See merge status [here]({os.getenv("GH_RUN_URL")}) ' + 'and land check progress [here](https://hud.pytorch.org/{self.org}/{self.project}/commit/{commit})' ) return commit
def rebase_ghstack_onto(pr: GitHubPR, repo: GitRepo, onto_branch: str, dry_run: bool = False) -> None: if subprocess.run([sys.executable, "-m", "ghstack", "--help"], capture_output=True).returncode != 0: subprocess.run([sys.executable, "-m", "pip", "install", "ghstack"]) orig_ref = f"{re.sub(r'/head$', '/orig', pr.head_ref())}" onto_branch = f"refs/remotes/origin/{onto_branch}" repo.fetch(orig_ref, orig_ref) repo._run_git("rebase", onto_branch, orig_ref) # steal the identity of the committer of the commit on the orig branch email = repo._run_git("log", orig_ref, "--pretty=format:%ae", "-1") name = repo._run_git("log", orig_ref, "--pretty=format:%an", "-1") repo._run_git("config", "--global", "user.name", name) repo._run_git("config", "--global", "user.email", email) os.environ["OAUTH_TOKEN"] = os.environ["GITHUB_TOKEN"] with open('.ghstackrc', 'w+') as f: f.write('[ghstack]\n' + "github_url=github.com\n" + "github_username=pytorchmergebot\n" + "remote_name=origin") if dry_run: print("Don't know how to dry-run ghstack") else: ghstack_result = subprocess.run(["ghstack"], capture_output=True) push_result = ghstack_result.stdout.decode("utf-8") print(push_result) if ghstack_result.returncode != 0: raise Exception(f"\n```{push_result}```") # The contents of a successful push result should look like: # Summary of changes (ghstack 0.6.0) # - Updated https://github.com/clee2000/random-testing/pull/2 # - Updated https://github.com/clee2000/random-testing/pull/1 # Facebook employees can import your changes by running # (on a Facebook machine): # ghimport -s https://github.com/clee2000/random-testing/pull/2 # If you want to work on this diff stack on another machine: # ghstack checkout https://github.com/clee2000/random-testing/pull/2 org, project = repo.gh_owner_and_name() for line in push_result.splitlines(): if "Updated" in line: pr_num = int(line.split("/")[-1]) if pr_num != pr.pr_num: gh_post_comment( pr.org, pr.project, pr_num, f"Rebased `{orig_ref}` onto `{onto_branch}` because #{pr.pr_num} was rebased, " "please pull locally before adding more changes (for example, via `ghstack " + f"checkout https://github.com/{org}/{project}/pull/{pr_num}`)", dry_run=dry_run) else: gh_post_comment( pr.org, pr.project, pr_num, f"Successfully rebased `{orig_ref}` onto `{onto_branch}`, please pull locally " + "before adding more changes (for example, via `ghstack " + f"checkout https://github.com/{org}/{project}/pull/{pr.pr_num}`)", dry_run=dry_run) if f"Skipped https://github.com/{org}/{project}/pull/{pr.pr_num}" in push_result: gh_post_comment( pr.org, pr.project, pr.pr_num, f"Tried to rebase and push PR #{pr.pr_num}, but it was already up to date", dry_run=dry_run)
def rebase_ghstack_onto(pr: GitHubPR, repo: GitRepo, dry_run: bool = False, stable: bool = False) -> None: if subprocess.run([sys.executable, "-m", "ghstack", "--help"], capture_output=True).returncode != 0: subprocess.run([sys.executable, "-m", "pip", "install", "ghstack"]) orig_ref = f"{re.sub(r'/head$', '/orig', pr.head_ref())}" onto_branch = "refs/remotes/origin/viable/strict" if stable else pr.default_branch( ) repo.fetch(orig_ref, orig_ref) repo._run_git("rebase", onto_branch, orig_ref) if dry_run: print("Don't know how to dry-run ghstack") else: ghstack_result = subprocess.run(["ghstack"], capture_output=True) push_result = ghstack_result.stdout.decode("utf-8") print(push_result) if ghstack_result.returncode != 0: raise Exception(f"\n```{push_result}```") # The contents of a successful push result should look like: # Summary of changes (ghstack 0.6.0) # - Updated https://github.com/clee2000/random-testing/pull/2 # - Updated https://github.com/clee2000/random-testing/pull/1 # Facebook employees can import your changes by running # (on a Facebook machine): # ghimport -s https://github.com/clee2000/random-testing/pull/2 # If you want to work on this diff stack on another machine: # ghstack checkout https://github.com/clee2000/random-testing/pull/2 org, project = repo.gh_owner_and_name() for line in push_result.splitlines(): if "Updated" in line: pr_num = int(line.split("/")[-1]) if pr_num != pr.pr_num: gh_post_comment( pr.org, pr.project, pr_num, f"Rebased `{orig_ref}` onto `{onto_branch}` because #{pr.pr_num} was rebased, " "please pull locally before adding more changes (for example, via `git checkout " f"{orig_ref} && git pull --rebase`)", dry_run=dry_run) else: gh_post_comment( pr.org, pr.project, pr_num, f"Successfully rebased `{orig_ref}` onto `{onto_branch}`, please pull locally " + f"before adding more changes (for example, via `git checkout {orig_ref} && " + "git pull --rebase`)", dry_run=dry_run) if f"Skipped https://github.com/{org}/{project}/pull/{pr.pr_num}" in push_result: gh_post_comment( pr.org, pr.project, pr.pr_num, f"Tried to rebase and push PR #{pr.pr_num}, but it was already up to date", dry_run=dry_run)