|
|
@@ -0,0 +1,80 @@
|
|
|
+#!/usr/bin/env bash
|
|
|
+# land-branch.sh — solo-git integrate gate for sm121-launcher.
|
|
|
+#
|
|
|
+# Usage:
|
|
|
+# bash scripts/land-branch.sh "<conventional-commit-message>"
|
|
|
+#
|
|
|
+# Runs all quality gates, blocks AI-attribution footers, commits staged
|
|
|
+# changes onto the current branch, and pushes to origin.
|
|
|
+#
|
|
|
+# Designed for the solo-git workflow (workflow_mode: solo-git in
|
|
|
+# specs/state.yaml). When work is on a feature branch, the caller is
|
|
|
+# expected to have already squash-merged onto main (or run from main
|
|
|
+# directly with staged changes).
|
|
|
+#
|
|
|
+# Exit codes:
|
|
|
+# 0 — landed successfully
|
|
|
+# 1 — gates failed, commit blocked, or push rejected
|
|
|
+
|
|
|
+set -euo pipefail
|
|
|
+
|
|
|
+cd "$(dirname "$0")/.."
|
|
|
+
|
|
|
+if [ -t 2 ]; then
|
|
|
+ RED=$'\033[31m'; GREEN=$'\033[32m'; YELLOW=$'\033[33m'; RESET=$'\033[0m'
|
|
|
+else
|
|
|
+ RED=""; GREEN=""; YELLOW=""; RESET=""
|
|
|
+fi
|
|
|
+
|
|
|
+step() { printf '%s==> %s%s\n' "$YELLOW" "$*" "$RESET" >&2; }
|
|
|
+ok() { printf '%s ✓ %s%s\n' "$GREEN" "$*" "$RESET" >&2; }
|
|
|
+die() { printf '%s ✗ %s%s\n' "$RED" "$*" "$RESET" >&2; exit 1; }
|
|
|
+
|
|
|
+# ── Args ──────────────────────────────────────────────────────────────
|
|
|
+if [ "$#" -lt 1 ]; then
|
|
|
+ echo "Usage: $0 \"<conventional-commit-message>\"" >&2
|
|
|
+ exit 1
|
|
|
+fi
|
|
|
+COMMIT_MSG="$1"
|
|
|
+
|
|
|
+# ── 1. Quality gates ──────────────────────────────────────────────────
|
|
|
+step "Running quality gates (make check)"
|
|
|
+if ! make check; then
|
|
|
+ die "Quality gates failed — commit aborted"
|
|
|
+fi
|
|
|
+ok "gates passed"
|
|
|
+
|
|
|
+# ── 2. Conventional Commit check ───────────────────────────────────────
|
|
|
+step "Verifying conventional commit format"
|
|
|
+if ! echo "$COMMIT_MSG" | grep -qE '^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(\(.+\))?!?: .+$'; then
|
|
|
+ die "Commit message does not follow Conventional Commits: $COMMIT_MSG"
|
|
|
+fi
|
|
|
+ok "commit message is conventional"
|
|
|
+
|
|
|
+# ── 3. Block AI attribution ────────────────────────────────────────────
|
|
|
+step "Checking for AI attribution footers"
|
|
|
+if echo "$COMMIT_MSG" | grep -qiE 'co[- ]authored[- ]by'; then
|
|
|
+ die "Co-authored-by footer detected — blocked by P1 rule (CONVENTIONS.md § Git Attribution)"
|
|
|
+fi
|
|
|
+ok "no AI attribution"
|
|
|
+
|
|
|
+# ── 4. Commit staged changes ───────────────────────────────────────────
|
|
|
+step "Committing staged changes"
|
|
|
+if ! git diff --cached --quiet; then
|
|
|
+ git commit -m "$COMMIT_MSG"
|
|
|
+ ok "changes committed"
|
|
|
+else
|
|
|
+ echo " (no staged changes to commit)"
|
|
|
+fi
|
|
|
+
|
|
|
+# ── 5. Push ───────────────────────────────────────────────────────────
|
|
|
+step "Pushing to origin"
|
|
|
+BRANCH=$(git symbolic-ref --short HEAD)
|
|
|
+if git push origin "$BRANCH"; then
|
|
|
+ ok "pushed to origin/$BRANCH"
|
|
|
+else
|
|
|
+ die "push failed — check for remote divergence"
|
|
|
+fi
|
|
|
+
|
|
|
+echo
|
|
|
+printf '%sLanded: %s%s\n' "$GREEN" "$COMMIT_MSG" "$RESET"
|