sapling/eden/scm/ghstack/land.py
Michael Bolin 732d512647 chore: apply Black formatter to ghstack fork
Summary:
Historically, we avoided running the Black autoformatter on our
fork of ghstack so that the code would be easier to diff with
upstream. Now that Black is run on upstream ghstack:

e5eca89cb3

we have no reason to exclude it from our linter.

Going forward, we should update the GitHub CI to run `black --check`
and report back so that contributors get this signal as well.

Reviewed By: zsol

Differential Revision: D42494629

fbshipit-source-id: 7f09ec46f687e56662f4f6ac477fd2fd077709d6
2023-01-24 12:48:13 -08:00

126 lines
4.2 KiB
Python

import re
import ghstack.git
import ghstack.github
import ghstack.github_utils
import ghstack.sapling_shell
import ghstack.shell
from ghstack.ghs_types import GitCommitHash
def main(
pull_request: str,
remote_name: str,
github: ghstack.github.GitHubEndpoint,
sh: ghstack.shell.Shell,
github_url: str,
) -> None:
import ghstack
if isinstance(sh, ghstack.sapling_shell.SaplingShell):
import ghstack.sapling_land
return ghstack.sapling_land.main(
pull_request, remote_name, github, sh, github_url
)
# We land the entire stack pointed to by a URL.
# Local state is ignored; PR is source of truth
# Furthermore, the parent commits of PR are ignored: we always
# take the canonical version of the patch from any given pr
params = ghstack.github_utils.parse_pull_request(pull_request)
default_branch = ghstack.github_utils.get_github_repo_info(
github=github,
sh=sh,
repo_owner=params["owner"],
repo_name=params["name"],
github_url=github_url,
remote_name=remote_name,
)["default_branch"]
orig_ref = ghstack.github_utils.lookup_pr_to_orig_ref(
github,
owner=params["owner"],
name=params["name"],
number=params["number"],
)
# Get up-to-date
sh.git("fetch", "--prune", remote_name)
remote_orig_ref = remote_name + "/" + orig_ref
base = GitCommitHash(
sh.git("merge-base", f"{remote_name}/{default_branch}", remote_orig_ref)
)
# compute the stack of commits in chronological order (does not
# include base)
stack = ghstack.git.parse_header(
sh.git("rev-list", "--reverse", "--header", "^" + base, remote_orig_ref),
github_url=github_url,
)
# Switch working copy
try:
prev_ref = sh.git("symbolic-ref", "--short", "HEAD")
except RuntimeError:
prev_ref = sh.git("rev-parse", "HEAD")
# If this fails, we don't have to reset
sh.git("checkout", f"{remote_name}/{default_branch}")
try:
# Compute the metadata for each commit
stack_orig_refs = []
for s in stack:
pr_resolved = s.pull_request_resolved
# We got this from GitHub, this better not be corrupted
assert pr_resolved is not None
stack_orig_refs.append(
ghstack.github_utils.lookup_pr_to_orig_ref(
github,
owner=pr_resolved.owner,
name=pr_resolved.repo,
number=pr_resolved.number,
)
)
# OK, actually do the land now
for orig_ref in stack_orig_refs:
try:
sh.git("cherry-pick", f"{remote_name}/{orig_ref}")
except BaseException:
sh.git("cherry-pick", "--abort")
raise
# Advance base to head to "close" the PR for all PRs.
# This has to happen before the push because the push
# will trigger a closure, but we want a *merge*. This should
# happen after the cherry-pick, because the cherry-picks can
# fail
# TODO: It might be helpful to advance orig to reflect the true
# state of upstream at the time we are doing the land, and then
# directly *merge* head into base, so that the PR accurately
# reflects what we ACTUALLY merged to master, as opposed to
# this synthetic thing I'm doing right now just to make it look
# like the PR got closed
for orig_ref in stack_orig_refs:
# TODO: regex here so janky
base_ref = re.sub(r"/orig$", "/base", orig_ref)
head_ref = re.sub(r"/orig$", "/head", orig_ref)
sh.git("push", remote_name, f"{remote_name}/{head_ref}:{base_ref}")
# All good! Push!
sh.git("push", remote_name, f"HEAD:refs/heads/{default_branch}")
# Delete the branches
for orig_ref in stack_orig_refs:
# TODO: regex here so janky
base_ref = re.sub(r"/orig$", "/base", orig_ref)
head_ref = re.sub(r"/orig$", "/head", orig_ref)
sh.git("push", remote_name, "--delete", orig_ref, base_ref, head_ref)
finally:
sh.git("checkout", prev_ref)