Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion docs/upload.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ revup upload - Modify or create code reviews.
`[--status] [--no-update-pr-body] [--review-graph]`
`[--trim-tags] [--create-local-branches] [--patchsets] [--auto-add-users=<o>]`
`[--force-reviewers] [--pr-body-source=<src>] [--skip-empty-first-commit]`
`[--draft-on-create-only]`
`[--labels=<labels>] [<topics>]`

# DESCRIPTION
Expand Down Expand Up @@ -72,7 +73,8 @@ name in github exactly. If a label cannot be found a warning is printed.

**Draft:**
: Accepts "true" or "false" and marks or unmarks the PR as a draft. PRs are
not drafts if this tag is omitted.
not drafts if this tag is omitted. See --draft-on-create-only to only apply
this tag when the PR is created.

**Uploader:**
: Optionally specifies a custom uploader name that will be used instead of the
Expand Down Expand Up @@ -236,5 +238,10 @@ If "a2r", add users from the Assignees tag as reviewers. If "both", do both of t
using an empty commit purely for PR title and body text without that commit appearing in
the merged history.

**--draft-on-create-only**
: Only use the "Draft:" tag to decide draft status when creating a PR, and never
change it afterwards. This allows marking a PR ready for review in github without
revup turning it back into a draft.

**--head**
: The name or commit of the branch to be uploaded. If not specified, defaults to HEAD.
1 change: 1 addition & 0 deletions revup/revup.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ def build_parser() -> Tuple[RevupArgParser, List[RevupArgParser]]:
default=PrBodySource.FIRST_COMMIT,
)
upload_parser.add_argument("--skip-empty-first-commit", action="store_true")
upload_parser.add_argument("--draft-on-create-only", action="store_true")
upload_parser.add_argument("--head", default="HEAD")

restack_parser.add_argument("--topicless-last", "-t", action="store_true")
Expand Down
6 changes: 5 additions & 1 deletion revup/topic_stack.py
Original file line number Diff line number Diff line change
Expand Up @@ -1267,6 +1267,7 @@ def populate_update_info(
update_pr_body_arg: bool,
force_reviewers: bool = False,
pr_body_source: PrBodySource = PrBodySource.FIRST_COMMIT,
draft_on_create_only: bool = False,
) -> None:
"""
Populate information necessary to do PR creation / update on the forge.
Expand Down Expand Up @@ -1391,7 +1392,10 @@ def populate_update_info(
review.pr_update.body = body
if update_pr_body and review.pr_info.title != title:
review.pr_update.title = title
if review.pr_info.is_draft != review.is_draft:
if draft_on_create_only:
# The forge's draft status wins, since the user may have changed it there
review.is_draft = review.pr_info.is_draft
elif review.pr_info.is_draft != review.is_draft:
review.pr_update.is_draft = review.is_draft
review.pr_update.label_ids = label_ids
review.pr_update.reviewer_ids = reviewer_ids
Expand Down
7 changes: 6 additions & 1 deletion revup/upload.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,12 @@ async def run(
return

if not args.push_only:
topics.populate_update_info(args.update_pr_body, args.force_reviewers, args.pr_body_source)
topics.populate_update_info(
args.update_pr_body,
args.force_reviewers,
args.pr_body_source,
args.draft_on_create_only,
)
if not args.skip_confirm and topics.num_reviews_changed() > 0:
topics.print(not args.verbose)
if git_ctx.sh.wait_for_confirmation():
Expand Down
39 changes: 39 additions & 0 deletions tests/test_upload.py
Original file line number Diff line number Diff line change
Expand Up @@ -1429,6 +1429,7 @@ def make_forge_upload_args(**kwargs):
"verbose": False,
"force_reviewers": False,
"pr_body_source": PrBodySource.FIRST_COMMIT,
"draft_on_create_only": False,
}
defaults.update(kwargs)
return argparse.Namespace(**defaults)
Expand Down Expand Up @@ -1731,6 +1732,44 @@ async def test_draft_tag_creates_draft_pr(self):
pr = forge.created_prs[0]
assert pr.is_draft is True

@async_test
async def test_draft_tag_redrafts_undrafted_pr(self):
async with GitTestEnvironment() as env:
await setup_repo(env)
forge = FakeForge()
await env.commit("feat\n\nTopic: alpha\nDraft: true", {"a.txt": "a"})

await full_upload_pipeline(env, forge)

# Simulate the user marking the pr ready for review in github
pr = list(forge.prs.values())[0]
pr.is_draft = False

topics = await full_upload_pipeline(env, forge)

assert topics.topics["alpha"].reviews["origin/main"].pr_update.is_draft is True
assert pr.is_draft is True

@async_test
async def test_draft_on_create_only_keeps_pr_undrafted(self):
async with GitTestEnvironment() as env:
await setup_repo(env)
forge = FakeForge()
await env.commit("feat\n\nTopic: alpha\nDraft: true", {"a.txt": "a"})

await full_upload_pipeline(env, forge, draft_on_create_only=True)
assert forge.created_prs[0].is_draft is True

pr = list(forge.prs.values())[0]
pr.is_draft = False

topics = await full_upload_pipeline(env, forge, draft_on_create_only=True)

review = topics.topics["alpha"].reviews["origin/main"]
assert review.pr_update.is_draft is None
assert review.is_draft is False
assert pr.is_draft is False


class TestForgeReviewGraph:
@async_test
Expand Down
Loading