Skip to content

Commit 673fa46

Browse files
varunkasyapjacobtylerwalls
authored andcommitted
Fixed #37046 -- Allowed Ready for checkin Trac status in PR checks.
1 parent d3ccbde commit 673fa46

3 files changed

Lines changed: 36 additions & 27 deletions

File tree

scripts/pr_quality/check_pr.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@
5757
PR_TEMPLATE_DATE = date(2024, 3, 4) # 3fcef50 -- PR template introduced
5858
AI_DISCLOSURE_DATE = date(2026, 1, 8) # 4f580c4 -- AI disclosure added
5959

60+
ALLOWED_STAGES = ("Accepted", "Ready for checkin")
61+
6062
logger = logging.getLogger(__name__)
6163

6264

@@ -215,7 +217,8 @@ def check_trac_ticket(pr_body, total_changes, threshold=LARGE_PR_THRESHOLD):
215217

216218

217219
def check_trac_status(ticket_id, ticket_data):
218-
"""The referenced Trac ticket must be Accepted, unresolved, and assigned.
220+
"""The referenced Trac ticket must be Accepted or Ready for checkin,
221+
unresolved, and assigned.
219222
220223
ticket_data is the dict returned by fetch_trac_ticket(). Passing None
221224
skips the check (non-fatal fetch error). Passing TICKET_NOT_FOUND fails
@@ -232,10 +235,10 @@ def check_trac_status(ticket_id, ticket_data):
232235
stage = ticket_data.get("custom", {}).get("stage", "").strip()
233236
resolution = (ticket_data.get("resolution") or "").strip()
234237
status = ticket_data.get("status", "").strip()
235-
if stage == "Accepted" and not resolution and status == "assigned":
238+
if stage in ALLOWED_STAGES and not resolution and status == "assigned":
236239
return None
237240
current_state = [
238-
f"{stage=}" if stage != "Accepted" else "",
241+
f"{stage=}" if stage not in ALLOWED_STAGES else "",
239242
f"{resolution=}" if resolution else "",
240243
f"{status=}" if status != "assigned" else "",
241244
]
@@ -480,7 +483,7 @@ def main(
480483

481484
results = [
482485
("Trac ticket referenced", ticket_result, LEVEL_ERROR),
483-
("Trac ticket status is Accepted", ticket_status_result, LEVEL_ERROR),
486+
("Trac ticket is ready for work", ticket_status_result, LEVEL_ERROR),
484487
("Trac ticket has_patch flag set", ticket_has_patch_result, LEVEL_WARNING),
485488
("PR title includes ticket number", pr_title_result, LEVEL_WARNING),
486489
("Branch description provided", check_branch_description(pr_body), LEVEL_ERROR),

scripts/pr_quality/errors.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -56,18 +56,17 @@ def as_details(self, level=LEVEL_ERROR):
5656
INVALID_TRAC_STATUS = (
5757
"Trac Ticket Not Ready for a Pull Request",
5858
"The referenced ticket **ticket-{ticket_id}** is not ready for a pull request. "
59-
"A ticket must be in the *Accepted* stage, *assigned* status, and have no "
60-
"resolution.\n\n"
59+
"A ticket must be in the *Accepted* or *Ready for checkin* stage, "
60+
"*assigned* status, and have no resolution.\n\n"
6161
"**Current state:** {current_state}\n\n"
6262
"**What to do:**\n\n"
6363
f"1. Check the ticket at {TRAC_URL}/ticket/{{ticket_id}}.\n"
6464
"2. If *Unreviewed*, wait for a community member to accept it. "
6565
"A ticket cannot be accepted by its reporter.\n"
66-
"3. If *Ready for Checkin*, there is already a solution for it.\n"
67-
"4. If *Someday/Maybe*, discuss on the "
66+
"3. If *Someday/Maybe*, discuss on the "
6867
f"[Django Forum]({FORUM_URL}/c/internals/5) before proceeding.\n"
69-
"5. If resolved or closed, it is not eligible for a PR.\n"
70-
"6. If not *assigned*, claim it by setting yourself as the owner.\n\n"
68+
"4. If resolved or closed, it is not eligible for a PR.\n"
69+
"5. If not *assigned*, claim it by setting yourself as the owner.\n\n"
7170
f"For more information on the Django triage process see {TRIAGING_URL}.",
7271
)
7372

scripts/pr_quality/tests/test_check_pr.py

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -318,27 +318,34 @@ def test_accepted_assigned_unresolved_passes(self):
318318
data = make_trac_json(stage="Accepted", status="assigned", resolution=None)
319319
self.assertIsNone(check_pr.check_trac_status("36991", data))
320320

321+
def test_ready_for_checkin_assigned_unresolved_passes(self):
322+
data = make_trac_json(
323+
stage="Ready for checkin", status="assigned", resolution=None
324+
)
325+
self.assertIsNone(check_pr.check_trac_status("36991", data))
326+
321327
def test_non_accepted_stage_fails(self):
322-
for stage in ["Unreviewed", "Ready for Checkin", "Someday/Maybe"]:
328+
for stage in ["Unreviewed", "Someday/Maybe"]:
323329
with self.subTest(stage=stage):
324330
data = make_trac_json(stage=stage)
325331
self.assertIsNotNone(check_pr.check_trac_status("36991", data))
326332

327333
def test_resolved_ticket_fails(self):
328-
for resolution in [
329-
"fixed",
330-
"wontfix",
331-
"duplicate",
332-
"invalid",
333-
"worksforme",
334-
"needsinfo",
335-
"needsnewfeatureprocess",
336-
]:
337-
with self.subTest(resolution=resolution):
338-
data = make_trac_json(
339-
stage="Accepted", status="assigned", resolution=resolution
340-
)
341-
self.assertIsNotNone(check_pr.check_trac_status("36991", data))
334+
for stage in ("Accepted", "Ready for checkin"):
335+
for resolution in [
336+
"fixed",
337+
"wontfix",
338+
"duplicate",
339+
"invalid",
340+
"worksforme",
341+
"needsinfo",
342+
"needsnewfeatureprocess",
343+
]:
344+
with self.subTest(stage=stage, resolution=resolution):
345+
data = make_trac_json(
346+
stage=stage, status="assigned", resolution=resolution
347+
)
348+
self.assertIsNotNone(check_pr.check_trac_status("36991", data))
342349

343350
def test_unassigned_ticket_fails(self):
344351
for status in ["new", "closed", ""]:
@@ -743,7 +750,7 @@ def test_no_ticket_results_include_skipped_sentinels(self):
743750
_, mock_summary, _ = self.call_main(pr_body=body)
744751
_, results, _ = mock_summary.call_args.args
745752
result_map = {name: result for name, result, _ in results}
746-
self.assertIs(result_map["Trac ticket status is Accepted"], check_pr.SKIPPED)
753+
self.assertIs(result_map["Trac ticket is ready for work"], check_pr.SKIPPED)
747754
self.assertIs(result_map["Trac ticket has_patch flag set"], check_pr.SKIPPED)
748755
self.assertIs(result_map["PR title includes ticket number"], check_pr.SKIPPED)
749756

@@ -754,7 +761,7 @@ def test_non_accepted_ticket_skips_has_patch(self):
754761
)
755762
_, results, _ = mock_summary.call_args.args
756763
result_map = {name: result for name, result, _ in results}
757-
self.assertIsNotNone(result_map["Trac ticket status is Accepted"])
764+
self.assertIsNotNone(result_map["Trac ticket is ready for work"])
758765
self.assertIs(result_map["Trac ticket has_patch flag set"], check_pr.SKIPPED)
759766

760767
def test_established_author_skips_all_checks(self):

0 commit comments

Comments
 (0)