| 490 | |
| 491 | |
| 492 | def render_markdown(plan: TestImpactPlan) -> str: |
| 493 | lines = [ |
| 494 | "## Test Impact Plan", |
| 495 | "", |
| 496 | "Deterministic summary of how this PR changes tests, CI runners, and coverage-risk signals.", |
| 497 | "", |
| 498 | "### Summary", |
| 499 | "", |
| 500 | "| Area | Added | Changed | Deleted |", |
| 501 | "|---|---:|---:|---:|", |
| 502 | f"| Test files | {plan.file_deltas.test_added} | {plan.file_deltas.test_changed} | {plan.file_deltas.test_deleted} |", |
| 503 | f"| E2E/journey files | {plan.file_deltas.e2e_added} | {plan.file_deltas.e2e_changed} | {plan.file_deltas.e2e_deleted} |", |
| 504 | f"| Workflow files | {plan.file_deltas.workflow_added} | {plan.file_deltas.workflow_changed} | {plan.file_deltas.workflow_deleted} |", |
| 505 | "", |
| 506 | "### Signals", |
| 507 | "", |
| 508 | f"- Test cases: +{plan.test_cases_added} / -{plan.test_cases_removed}", |
| 509 | f"- Assertions: +{plan.assertions_added} / -{plan.assertions_removed}", |
| 510 | f"- Skips or known failures added: {plan.skips_added}", |
| 511 | f"- Workflow `continue-on-error` added: {plan.continue_on_error_added}", |
| 512 | f"- Workflow path filters added: {plan.path_filters_added}", |
| 513 | f"- Test commands removed from `justfile`: {plan.test_commands_removed}", |
| 514 | f"- E2E/journey retry lines added: {plan.retry_lines_added}", |
| 515 | "", |
| 516 | f"**Coverage risk: {plan.coverage_risk}**", |
| 517 | ] |
| 518 | |
| 519 | if plan.warnings: |
| 520 | lines.extend(["", "### Warnings", ""]) |
| 521 | for warning in plan.warnings: |
| 522 | lines.append(f"- **{warning.title}** ({warning.severity.replace('_', ' ')})") |
| 523 | lines.extend(bullet_list(warning.details)) |
| 524 | else: |
| 525 | lines.extend(["", "No coverage-reduction warnings detected."]) |
| 526 | |
| 527 | return "\n".join(lines) + "\n" |
| 528 | |
| 529 | |
| 530 | def run_git(repo: Path, args: list[str]) -> list[str]: |