Skip to content

Commit 9b255aa

Browse files
Laszlo KindratZolotukhinM
authored andcommitted
Mark PRs temporarily draft while submitting
When running `stack-pr submit`, patches in a stack need to have their base branches temporarily changed to avoid accidental closures. This has the unfortunate side effect that in this transient state, the PRs seem like multi-commit PRs pointing to main, resulting in GH notifying reviewers for every commit on the branch (as opposed to just the one that corresponds to the stacked PR). This patch fixes this by marking PRs temporarily draft while we manipulate their bases. stack-info: PR: #111, branch: laszlokindrat/stack/2
1 parent ce1a739 commit 9b255aa

File tree

1 file changed

+25
-5
lines changed

1 file changed

+25
-5
lines changed

src/stack_pr/cli.py

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,7 @@ class StackEntry:
294294
_pr: str | None = None
295295
_base: str | None = None
296296
_head: str | None = None
297-
need_update: bool = False
297+
is_tmp_draft: bool = False
298298

299299
@property
300300
def pr(self) -> str:
@@ -783,7 +783,7 @@ def toc_entry(se: StackEntry) -> str:
783783
return f"Stacked PRs:\n{''.join(entries)}\n"
784784

785785

786-
def get_current_pr_body(e: StackEntry) -> str:
786+
def get_pr_body(e: StackEntry) -> str:
787787
out = get_command_output(
788788
["gh", "pr", "view", e.pr, "--json", "body"],
789789
)
@@ -815,7 +815,7 @@ def add_cross_links(st: list[StackEntry], *, keep_body: bool, verbose: bool) ->
815815

816816
if keep_body:
817817
# Keep current body of the PR after the cross links component
818-
current_pr_body = get_current_pr_body(e)
818+
current_pr_body = get_pr_body(e)
819819
body_content = current_pr_body.split(CROSS_LINKS_DELIMETER, 1)[-1].lstrip()
820820

821821
pr_body = [*header, body_content]
@@ -831,6 +831,13 @@ def add_cross_links(st: list[StackEntry], *, keep_body: bool, verbose: bool) ->
831831
raise RuntimeError
832832

833833

834+
def is_draft_pr(e: StackEntry) -> bool:
835+
out = get_command_output(
836+
["gh", "pr", "view", e.pr, "--json", "isDraft"],
837+
)
838+
return json.loads(out)["isDraft"]
839+
840+
834841
# Temporarily set base branches of existing PRs to the bottom of the stack.
835842
# This needs to be done to avoid PRs getting closed when commits are
836843
# rearranged.
@@ -852,14 +859,21 @@ def add_cross_links(st: list[StackEntry], *, keep_body: bool, verbose: bool) ->
852859
# stack/2. If we push stack/1, then PR #2 gets automatically closed, since its
853860
# head branch will contain all the commits from its base branch.
854861
#
855-
# To avoid this, we temporarily set all base branches to point to 'main' - once
856-
# all the branches are pushed we can set the actual base branches.
862+
# To avoid this, we temporarily set all base branches to point to 'main'. To ensure
863+
# we don't accidentally notify reviewers in this transient state (where the PRs are
864+
# pointing to 'main'), we mark the PRs as draft - once all the branches are pushed
865+
# we can set the actual base branches and undraft the PRs.
857866
def reset_remote_base_branches(
858867
st: list[StackEntry], target: str, *, verbose: bool
859868
) -> None:
860869
log(h("Resetting remote base branches"), level=2)
861870

862871
for e in filter(lambda e: e.has_pr(), st):
872+
# We need to check if the PR is already draft, otherwise we would
873+
# unintentionally undo the draft status later.
874+
if not is_draft_pr(e):
875+
run_shell_command(["gh", "pr", "ready", e.pr, "--undo"], quiet=not verbose)
876+
e.is_tmp_draft = True
863877
run_shell_command(["gh", "pr", "edit", e.pr, "-B", target], quiet=not verbose)
864878

865879

@@ -1117,6 +1131,12 @@ def command_submit(
11171131
log(h("Adding cross-links to PRs"), level=1)
11181132
add_cross_links(st, keep_body=keep_body, verbose=args.verbose)
11191133

1134+
# Undraft the PRs if they were marked as temporary drafts.
1135+
for e in st:
1136+
if e.is_tmp_draft:
1137+
run_shell_command(["gh", "pr", "ready", e.pr], quiet=not args.verbose)
1138+
e.is_tmp_draft = False
1139+
11201140
if need_to_rebase_current:
11211141
log(h(f"Rebasing the original branch '{current_branch}'"), level=2)
11221142
run_shell_command(

0 commit comments

Comments
 (0)