|
| 1 | +#!/usr/bin/env bash |
| 2 | +# Draft a PR body for the current branch based on the diff vs origin/main. |
| 3 | +# |
| 4 | +# Writes to PR_BODY.md in the repo root (gitignored — see end of script). |
| 5 | +# Pre-fills the structure required by .github/pull_request_template.md |
| 6 | +# and flags whether screenshots are required based on touched paths. |
| 7 | +# |
| 8 | +# Usage: |
| 9 | +# ./scripts/pr-evidence.sh # writes ./PR_BODY.md |
| 10 | +# ./scripts/pr-evidence.sh > /tmp/body.md # write to stdout |
| 11 | + |
| 12 | +set -euo pipefail |
| 13 | + |
| 14 | +OUTPUT="${1:-PR_BODY.md}" |
| 15 | + |
| 16 | +# Find the base branch (default origin/main) the current branch diverged from. |
| 17 | +BASE_REF="${BASE_REF:-origin/main}" |
| 18 | +git fetch origin main --quiet 2>/dev/null || true |
| 19 | + |
| 20 | +MERGE_BASE=$(git merge-base HEAD "$BASE_REF" 2>/dev/null || echo "$BASE_REF") |
| 21 | +CHANGED=$(git diff --name-only "$MERGE_BASE"...HEAD) |
| 22 | +ADDED=$(git diff --name-status --diff-filter=A "$MERGE_BASE"...HEAD | awk '{print $2}') |
| 23 | +MODIFIED=$(git diff --name-status --diff-filter=M "$MERGE_BASE"...HEAD | awk '{print $2}') |
| 24 | +DELETED=$(git diff --name-status --diff-filter=D "$MERGE_BASE"...HEAD | awk '{print $2}') |
| 25 | + |
| 26 | +# Heuristic: any touched path under packages/web/src/{components,routes} or |
| 27 | +# packages/desktop counts as a UI change and requires screenshots. |
| 28 | +UI_CHANGED=0 |
| 29 | +if echo "$CHANGED" | grep -qE '^(packages/web/src/(components|routes)|packages/desktop)/'; then |
| 30 | + UI_CHANGED=1 |
| 31 | +fi |
| 32 | + |
| 33 | +# Commits since base — useful for the "What" section. |
| 34 | +COMMITS=$(git log --pretty=format:'- %s' "$MERGE_BASE"..HEAD) |
| 35 | + |
| 36 | +# Tests touched? |
| 37 | +TESTS_TOUCHED=$(echo "$CHANGED" | grep -E '(\.test\.|/test/|/e2e/)' || true) |
| 38 | + |
| 39 | +BRANCH=$(git rev-parse --abbrev-ref HEAD) |
| 40 | + |
| 41 | +draft() { |
| 42 | + cat <<EOF |
| 43 | +<!-- |
| 44 | +Auto-drafted by scripts/pr-evidence.sh from the diff vs ${BASE_REF}. |
| 45 | +Fill in the prose sections; the file lists and checklist are pre-populated. |
| 46 | +--> |
| 47 | +
|
| 48 | +## Why |
| 49 | +
|
| 50 | +<!-- The problem this solves, in 1–3 sentences. What pain or gap does this close? --> |
| 51 | +
|
| 52 | +## What |
| 53 | +
|
| 54 | +$(if [ -n "$COMMITS" ]; then printf 'Commits on this branch:\n%s\n' "$COMMITS"; else echo '<!-- describe the change -->'; fi) |
| 55 | +
|
| 56 | +$(if [ -n "$ADDED" ]; then printf '\n**Added:**\n'; printf '%s\n' "$ADDED" | sed 's/^/- /'; fi) |
| 57 | +$(if [ -n "$MODIFIED" ]; then printf '\n**Modified:**\n'; printf '%s\n' "$MODIFIED" | sed 's/^/- /'; fi) |
| 58 | +$(if [ -n "$DELETED" ]; then printf '\n**Deleted:**\n'; printf '%s\n' "$DELETED" | sed 's/^/- /'; fi) |
| 59 | +
|
| 60 | +## Screenshots |
| 61 | +
|
| 62 | +EOF |
| 63 | + |
| 64 | + if [ $UI_CHANGED -eq 1 ]; then |
| 65 | + cat <<EOF |
| 66 | +**Required** — this PR touches packages/web/src/{components,routes} or packages/desktop. |
| 67 | +Commit screenshots under \`docs/screenshots/<feature-slug>/\` and reference here: |
| 68 | +
|
| 69 | +\`\`\`markdown |
| 70 | + |
| 71 | +\`\`\` |
| 72 | +
|
| 73 | +See \`.claude/rules/workflows.md\` → "Open a PR" for capture + commit guidance. |
| 74 | +
|
| 75 | +EOF |
| 76 | + else |
| 77 | + cat <<EOF |
| 78 | +<!-- No packages/web/src/{components,routes} or packages/desktop paths touched — |
| 79 | + screenshots not strictly required. Delete this section if truly docs-only. --> |
| 80 | +
|
| 81 | +EOF |
| 82 | + fi |
| 83 | + |
| 84 | + cat <<EOF |
| 85 | +## QA checklist |
| 86 | +
|
| 87 | +- [ ] \`pnpm typecheck\` clean locally |
| 88 | +- [ ] \`pnpm lint\` clean locally |
| 89 | +- [ ] \`pnpm test\` green locally |
| 90 | +$(if [ -n "$TESTS_TOUCHED" ]; then echo '- [x] Tests touched on this branch:'; printf '%s\n' "$TESTS_TOUCHED" | sed 's/^/ - /'; else echo '- [ ] Tests added for new behaviour (or note why none are needed)'; fi) |
| 91 | +- [ ] Manual verification: <!-- which Honcho instance, which workspace/peer, what you clicked, what you saw --> |
| 92 | +$(if echo "$CHANGED" | grep -qE '^packages/desktop/'; then echo '- [ ] \`pnpm --filter @openconcho/desktop cargo-check\` passes'; fi) |
| 93 | +- [x] Worked in a git worktree (current branch: \`${BRANCH}\`) |
| 94 | +
|
| 95 | +## Out-of-scope |
| 96 | +
|
| 97 | +<!-- What was intentionally left out and why. --> |
| 98 | +
|
| 99 | +## Notes |
| 100 | +
|
| 101 | +<!-- Caveats, follow-ups, anything reviewers should know. --> |
| 102 | +EOF |
| 103 | +} |
| 104 | + |
| 105 | +if [ "$OUTPUT" = "-" ] || [ -t 1 ]; then |
| 106 | + # When piped or first arg is "-", write to stdout. |
| 107 | + if [ "${1:-}" = "-" ]; then |
| 108 | + draft |
| 109 | + exit 0 |
| 110 | + fi |
| 111 | +fi |
| 112 | + |
| 113 | +draft > "$OUTPUT" |
| 114 | + |
| 115 | +echo "✓ Drafted PR body → ${OUTPUT}" |
| 116 | +echo " Open it, fill in Why / Manual verification / Out-of-scope / Notes, then use as the PR body." |
0 commit comments