land-branch.sh 3.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. #!/usr/bin/env bash
  2. # land-branch.sh — solo-git integrate gate for sm121-launcher.
  3. #
  4. # Usage:
  5. # bash scripts/land-branch.sh "<conventional-commit-message>"
  6. #
  7. # Runs all quality gates, blocks AI-attribution footers, commits staged
  8. # changes onto the current branch, and pushes to origin.
  9. #
  10. # Designed for the solo-git workflow (workflow_mode: solo-git in
  11. # specs/state.yaml). When work is on a feature branch, the caller is
  12. # expected to have already squash-merged onto main (or run from main
  13. # directly with staged changes).
  14. #
  15. # Exit codes:
  16. # 0 — landed successfully
  17. # 1 — gates failed, commit blocked, or push rejected
  18. set -euo pipefail
  19. cd "$(dirname "$0")/.."
  20. if [ -t 2 ]; then
  21. RED=$'\033[31m'; GREEN=$'\033[32m'; YELLOW=$'\033[33m'; RESET=$'\033[0m'
  22. else
  23. RED=""; GREEN=""; YELLOW=""; RESET=""
  24. fi
  25. step() { printf '%s==> %s%s\n' "$YELLOW" "$*" "$RESET" >&2; }
  26. ok() { printf '%s ✓ %s%s\n' "$GREEN" "$*" "$RESET" >&2; }
  27. die() { printf '%s ✗ %s%s\n' "$RED" "$*" "$RESET" >&2; exit 1; }
  28. # ── Args ──────────────────────────────────────────────────────────────
  29. if [ "$#" -lt 1 ]; then
  30. echo "Usage: $0 \"<conventional-commit-message>\"" >&2
  31. exit 1
  32. fi
  33. COMMIT_MSG="$1"
  34. # ── 1. Quality gates ──────────────────────────────────────────────────
  35. step "Running quality gates (make check)"
  36. if ! make check; then
  37. die "Quality gates failed — commit aborted"
  38. fi
  39. ok "gates passed"
  40. # ── 2. Conventional Commit check ───────────────────────────────────────
  41. step "Verifying conventional commit format"
  42. if ! echo "$COMMIT_MSG" | grep -qE '^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(\(.+\))?!?: .+$'; then
  43. die "Commit message does not follow Conventional Commits: $COMMIT_MSG"
  44. fi
  45. ok "commit message is conventional"
  46. # ── 3. Block AI attribution ────────────────────────────────────────────
  47. step "Checking for AI attribution footers"
  48. if echo "$COMMIT_MSG" | grep -qiE 'co[- ]authored[- ]by'; then
  49. die "Co-authored-by footer detected — blocked by P1 rule (CONVENTIONS.md § Git Attribution)"
  50. fi
  51. ok "no AI attribution"
  52. # ── 4. Commit staged changes ───────────────────────────────────────────
  53. step "Committing staged changes"
  54. if ! git diff --cached --quiet; then
  55. git commit -m "$COMMIT_MSG"
  56. ok "changes committed"
  57. else
  58. echo " (no staged changes to commit)"
  59. fi
  60. # ── 5. Push ───────────────────────────────────────────────────────────
  61. step "Pushing to origin"
  62. BRANCH=$(git symbolic-ref --short HEAD)
  63. if git push origin "$BRANCH"; then
  64. ok "pushed to origin/$BRANCH"
  65. else
  66. die "push failed — check for remote divergence"
  67. fi
  68. echo
  69. printf '%sLanded: %s%s\n' "$GREEN" "$COMMIT_MSG" "$RESET"