25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.

generate_deploy_test_plan.py 3.0 KiB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. """
  4. Scaffold a deploy / QA note from a git commit range.
  5. Usage (from repo root):
  6. python scripts/generate_deploy_test_plan.py HEAD~5..HEAD
  7. python scripts/generate_deploy_test_plan.py abc1234..def5678 --out docs/deploy/20260801_example.md
  8. The script lists commits and touched files. You (or the agent) still fill
  9. test steps and expected results after reading the diffs.
  10. """
  11. from __future__ import annotations
  12. import argparse
  13. import subprocess
  14. import sys
  15. from datetime import date
  16. from pathlib import Path
  17. ROOT = Path(__file__).resolve().parents[1]
  18. def run(args: list[str]) -> str:
  19. r = subprocess.run(
  20. args,
  21. cwd=ROOT,
  22. capture_output=True,
  23. text=True,
  24. encoding="utf-8",
  25. errors="replace",
  26. )
  27. if r.returncode != 0:
  28. raise SystemExit(r.stderr or r.stdout or f"command failed: {args}")
  29. return r.stdout.strip()
  30. def main() -> None:
  31. p = argparse.ArgumentParser(description="Scaffold deploy test plan from git range")
  32. p.add_argument(
  33. "range",
  34. help="Git revision range, e.g. HEAD~5..HEAD or origin/production..HEAD",
  35. )
  36. p.add_argument(
  37. "--out",
  38. type=Path,
  39. default=None,
  40. help="Optional output path under docs/deploy/",
  41. )
  42. p.add_argument("--title", default="Deploy note (draft)", help="Document title")
  43. args = p.parse_args()
  44. log = run(["git", "log", "--oneline", args.range])
  45. if not log:
  46. print("No commits in range.", file=sys.stderr)
  47. sys.exit(1)
  48. stat = run(["git", "diff", "--stat", args.range])
  49. name_status = run(["git", "diff", "--name-status", args.range])
  50. commits = [ln for ln in log.splitlines() if ln.strip()]
  51. commit_bullets = "\n".join(f"- `{c[:7]}` — {c[8:]}" for c in commits)
  52. body = f"""# {args.title}
  53. Date: {date.today().isoformat()}
  54. Branch / build: (fill)
  55. Range: `{args.range}`
  56. Author: (fill)
  57. > Auto-scaffolded from git. **Replace the Test plan with real steps** after reviewing the diff.
  58. ## Summary
  59. - (TODO: 1–3 bullets — user-facing impact)
  60. ## Scope
  61. - Backend: (see files below)
  62. - Frontend: (check paired repo if UI)
  63. - DB / Liquibase: (none / list changelog files)
  64. - Config / ops: (none / list)
  65. ## Commits
  66. {commit_bullets}
  67. ## Files touched
  68. ```
  69. {name_status}
  70. ```
  71. ### Diffstat
  72. ```
  73. {stat}
  74. ```
  75. ## Test plan
  76. | # | Steps (who / where / data) | Expected result |
  77. |---|----------------------------|-----------------|
  78. | 1 | TODO — happy path | TODO |
  79. | 2 | TODO — edge / failure case | TODO |
  80. | 3 | TODO — regression on related screen | TODO |
  81. ## Out of scope / not tested
  82. - (TODO)
  83. ## Rollback
  84. - Revert range `{args.range}` / redeploy previous build
  85. """
  86. if args.out:
  87. out = args.out if args.out.is_absolute() else ROOT / args.out
  88. out.parent.mkdir(parents=True, exist_ok=True)
  89. out.write_text(body, encoding="utf-8")
  90. print(f"Wrote {out.relative_to(ROOT)}")
  91. else:
  92. sys.stdout.reconfigure(encoding="utf-8")
  93. print(body)
  94. if __name__ == "__main__":
  95. main()