Compare commits

...

1 Commits

Author SHA1 Message Date
Zeyi (Rice) Fan f95f9912f8 chore: change pr template 2026-06-24 11:19:22 -07:00
5 changed files with 114 additions and 129 deletions
+9 -6
View File
@@ -1,6 +1,6 @@
<!--
For AI-written descriptions:
- Follow this template (Related issue, Summary, Type of change, Test coverage, Coverage rationale).
- Follow this template (Related issue, Summary, Test Plan, Type of change, Test coverage, Coverage notes).
- Keep it concise; reviewers skim long descriptions.
- For non-trivial changes, include an ELI5 and a diagram (ASCII or mermaid).
- Leave every checkbox in place. The PR Template check fails if required sections
@@ -23,6 +23,10 @@ Closes #
<!-- What changed and why, in 1-3 bullets or a short paragraph. -->
## Test Plan
<!-- How was this change tested? Describe the steps, commands, or scenarios used to verify it. Include a screenshot or recording where helpful. -->
## Type of change
- [ ] Bug fix
@@ -43,11 +47,10 @@ Closes #
- [ ] Existing tests cover this change
- [ ] Not applicable
## Coverage rationale
## Coverage notes
<!--
Describe the exact commands run and the coverage added/updated. If you did not
add or run tests, explain why the existing coverage is enough or why tests are
not applicable. For E2E-relevant changes, call out the E2E scenario exercised or
why no E2E coverage was added.
Optional — but required if you checked "Manual verification completed" or
"Not applicable" above. Describe what you verified manually, or why automated
test coverage is not needed for this change.
-->
+9 -3
View File
@@ -40,6 +40,12 @@ def format_body(body: str) -> str:
elif not _has_heading(body, "Summary"):
body = f"## Summary\n\n{body}"
body = _append_section(
body,
"Test Plan",
"How was this change tested? Describe the steps, commands, or scenarios "
"used to verify it (autoformat added this section — please replace it).",
)
body = _append_section(
body,
"ELI5",
@@ -54,9 +60,9 @@ def format_body(body: str) -> str:
body = _append_section(body, "Test coverage", _checkbox_block(TEST_LABELS))
body = _append_section(
body,
"Coverage rationale",
"Autoformat added this section; please add commands run or explain why "
"coverage is sufficient.",
"Coverage notes",
"<!-- Optional; required if you checked 'Manual verification completed' "
"or 'Not applicable' above. -->",
)
return body.rstrip() + "\n"
+19 -27
View File
@@ -14,9 +14,9 @@ import sys
REQUIRED_HEADINGS = (
"Summary",
"Test Plan",
"Type of change",
"Test coverage",
"Coverage rationale",
)
TYPE_LABELS = (
@@ -40,10 +40,8 @@ TEST_LABELS = (
PLACEHOLDER_FRAGMENTS = (
"what changed and why",
"check all that apply",
"describe the exact commands",
"describe below",
"explain why",
"if you did not add or run tests",
"how was this change tested",
)
@@ -121,6 +119,12 @@ def validate_pr_body(body: str) -> ValidationResult:
elif _contains_placeholder(summary):
errors.append("Summary still contains template placeholder text.")
test_plan = _meaningful_text(_section(body, spans, "Test Plan"))
if not test_plan:
errors.append("Test Plan must describe how the change was tested.")
elif _contains_placeholder(test_plan):
errors.append("Test Plan still contains template placeholder text.")
type_section = _section(body, spans, "Type of change")
missing_type_labels = _missing_labels(type_section, TYPE_LABELS)
if missing_type_labels:
@@ -141,31 +145,19 @@ def validate_pr_body(body: str) -> ValidationResult:
if not checked_tests:
errors.append("Check at least one Test coverage checkbox.")
rationale = _meaningful_text(_section(body, spans, "Coverage rationale"))
if not rationale:
errors.append(
"Coverage rationale must explain tests run/added, or why more coverage is not needed."
)
elif _contains_placeholder(rationale):
errors.append("Coverage rationale still contains template placeholder text.")
automated_tests = {
"Unit tests added / updated",
"Integration tests added / updated",
"E2E tests added / updated",
"Existing tests cover this change",
}
if checked_tests and checked_tests.isdisjoint(automated_tests):
if len(rationale.split()) < 8:
# Coverage notes are optional in general, but required whenever "Manual
# verification completed" or "Not applicable" is checked — those choices
# need a written justification.
if checked_tests & {"Manual verification completed", "Not applicable"}:
coverage_notes = _meaningful_text(_section(body, spans, "Coverage notes"))
if not coverage_notes:
errors.append(
"When no automated test coverage checkbox is selected, "
"the rationale must explain why."
"Coverage notes are required when 'Manual verification completed' or "
"'Not applicable' is selected — describe what you verified or why "
"automated coverage is not needed."
)
if "Not applicable" in checked_tests and rationale and len(rationale.split()) < 8:
errors.append(
"Not applicable test coverage requires a concrete explanation in Coverage rationale."
)
elif _contains_placeholder(coverage_notes):
errors.append("Coverage notes still contains template placeholder text.")
return ValidationResult(ok=not errors, errors=errors)
+2 -1
View File
@@ -32,4 +32,5 @@ def test_preserves_existing_sections_and_adds_missing_optional_context() -> None
assert formatted.count("## Type of change") == 1
assert "## ELI5" in formatted
assert "## Diagram" in formatted
assert "## Coverage rationale" in formatted
assert "## Test Plan" in formatted
assert "## Coverage notes" in formatted
+75 -92
View File
@@ -17,6 +17,10 @@ spec.loader.exec_module(module)
def _valid_body(
*,
summary: str = "- Improves the agent handoff flow and fixes stale polling.",
test_plan: str = (
"Added focused unit coverage for the cursor math and an E2E regression "
"that exercises the REPL path."
),
type_checkboxes: str = """
- [x] Bug fix
- [ ] Feature
@@ -33,33 +37,50 @@ def _valid_body(
- [ ] Existing tests cover this change
- [ ] Not applicable
""",
rationale: str = (
"Added focused unit coverage for the cursor math and an E2E regression "
"that exercises the REPL path."
),
coverage_notes: str | None = None,
) -> str:
notes_section = "" if coverage_notes is None else f"\n## Coverage notes\n\n{coverage_notes}\n"
return f"""
## Summary
{summary}
## Test Plan
{test_plan}
## Type of change
{type_checkboxes}
## Test coverage
{test_checkboxes}
## Coverage rationale
{test_checkboxes}{notes_section}"""
{rationale}
_MANUAL_ONLY = """
- [ ] Unit tests added / updated
- [ ] Integration tests added / updated
- [ ] E2E tests added / updated
- [x] Manual verification completed
- [ ] Existing tests cover this change
- [ ] Not applicable
"""
_NOT_APPLICABLE_ONLY = """
- [ ] Unit tests added / updated
- [ ] Integration tests added / updated
- [ ] E2E tests added / updated
- [ ] Manual verification completed
- [ ] Existing tests cover this change
- [x] Not applicable
"""
def test_valid_body_with_e2e_rationale() -> None:
def test_valid_body() -> None:
result = module.validate_pr_body(_valid_body())
assert result.ok, result.errors
def test_validate_pr_body_accepts_leading_bom() -> None:
result = module.validate_pr_body("\ufeff" + _valid_body())
result = module.validate_pr_body("" + _valid_body())
assert result.ok, result.errors
@@ -81,7 +102,6 @@ def test_requires_type_and_test_checkboxes() -> None:
- [ ] Existing tests cover this change
- [ ] Not applicable
""",
rationale="No tests because this is a documentation-only link update.",
)
result = module.validate_pr_body(body)
assert not result.ok
@@ -89,34 +109,6 @@ def test_requires_type_and_test_checkboxes() -> None:
assert "Check at least one Test coverage checkbox." in result.errors
def test_requires_explanation_when_not_applicable() -> None:
body = _valid_body(
type_checkboxes="""
- [ ] Bug fix
- [ ] Feature
- [ ] Refactor / chore
- [x] Docs
- [ ] Test / CI
- [ ] Breaking change
""",
test_checkboxes="""
- [ ] Unit tests added / updated
- [ ] Integration tests added / updated
- [ ] E2E tests added / updated
- [ ] Manual verification completed
- [ ] Existing tests cover this change
- [x] Not applicable
""",
rationale="Docs only.",
)
result = module.validate_pr_body(body)
assert not result.ok
assert (
"Not applicable test coverage requires a concrete explanation in Coverage rationale."
in result.errors
)
def test_rejects_missing_template_labels() -> None:
body = _valid_body(
type_checkboxes="""
@@ -125,7 +117,6 @@ def test_rejects_missing_template_labels() -> None:
test_checkboxes="""
- [x] Unit tests added / updated
""",
rationale="Added tests for the changed parser behavior.",
)
result = module.validate_pr_body(body)
assert not result.ok
@@ -134,80 +125,72 @@ def test_rejects_missing_template_labels() -> None:
def test_rejects_missing_required_heading() -> None:
body = _valid_body().replace("## Coverage rationale", "## Test notes")
body = _valid_body().replace("## Test Plan", "## Test notes")
result = module.validate_pr_body(body)
assert not result.ok
assert "Missing required section: ## Coverage rationale" in result.errors
assert (
"Coverage rationale must explain tests run/added, or why more coverage is not needed."
in result.errors
)
assert "Missing required section: ## Test Plan" in result.errors
assert "Test Plan must describe how the change was tested." in result.errors
def test_rejects_placeholder_summary_and_rationale() -> None:
def test_rejects_placeholder_summary_and_test_plan() -> None:
body = _valid_body(
summary="<!-- Replace this with what changed and why. -->\nWhat changed and why?",
rationale="Describe the exact commands you ran and coverage added.",
test_plan="How was this change tested?",
)
result = module.validate_pr_body(body)
assert not result.ok
assert "Summary still contains template placeholder text." in result.errors
assert "Coverage rationale still contains template placeholder text." in result.errors
assert "Test Plan still contains template placeholder text." in result.errors
def test_rejects_empty_summary_and_rationale_after_html_comments() -> None:
def test_rejects_empty_summary_and_test_plan_after_html_comments() -> None:
body = _valid_body(
summary="<!-- Summary will be ignored because it is an HTML comment. -->",
rationale="<!-- Rationale will be ignored because it is an HTML comment. -->",
test_plan="<!-- Test Plan will be ignored because it is an HTML comment. -->",
)
result = module.validate_pr_body(body)
assert not result.ok
assert "Summary must describe what changed and why." in result.errors
assert (
"Coverage rationale must explain tests run/added, or why more coverage is not needed."
in result.errors
)
assert "Test Plan must describe how the change was tested." in result.errors
def test_requires_explanation_when_only_manual_coverage_selected() -> None:
def test_coverage_notes_optional_for_automated_coverage() -> None:
# Default body checks Unit + E2E and omits the Coverage notes section.
result = module.validate_pr_body(_valid_body())
assert result.ok, result.errors
def test_manual_verification_requires_coverage_notes() -> None:
body = _valid_body(test_checkboxes=_MANUAL_ONLY)
result = module.validate_pr_body(body)
assert not result.ok
assert any(error.startswith("Coverage notes are required") for error in result.errors)
def test_not_applicable_requires_coverage_notes() -> None:
body = _valid_body(test_checkboxes=_NOT_APPLICABLE_ONLY)
result = module.validate_pr_body(body)
assert not result.ok
assert any(error.startswith("Coverage notes are required") for error in result.errors)
def test_manual_verification_with_coverage_notes_passes() -> None:
body = _valid_body(
test_checkboxes="""
- [ ] Unit tests added / updated
- [ ] Integration tests added / updated
- [ ] E2E tests added / updated
- [x] Manual verification completed
- [ ] Existing tests cover this change
- [ ] Not applicable
""",
rationale="Ran locally.",
test_checkboxes=_MANUAL_ONLY,
coverage_notes=(
"Verified manually by running the REPL handoff flow and confirming "
"polling resumes after a reconnect."
),
)
result = module.validate_pr_body(body)
assert result.ok, result.errors
def test_not_applicable_with_empty_coverage_notes_after_comment_is_rejected() -> None:
body = _valid_body(
test_checkboxes=_NOT_APPLICABLE_ONLY,
coverage_notes="<!-- nothing meaningful here -->",
)
result = module.validate_pr_body(body)
assert not result.ok
assert (
"When no automated test coverage checkbox is selected, the rationale must explain why."
in result.errors
)
def test_empty_not_applicable_rationale_does_not_duplicate_short_rationale_error() -> None:
body = _valid_body(
test_checkboxes="""
- [ ] Unit tests added / updated
- [ ] Integration tests added / updated
- [ ] E2E tests added / updated
- [ ] Manual verification completed
- [ ] Existing tests cover this change
- [x] Not applicable
""",
rationale="",
)
result = module.validate_pr_body(body)
assert not result.ok
assert (
"Coverage rationale must explain tests run/added, or why more coverage is not needed."
in result.errors
)
assert (
"Not applicable test coverage requires a concrete explanation in Coverage rationale."
not in result.errors
)
assert any(error.startswith("Coverage notes are required") for error in result.errors)