#!/usr/bin/env bash # land-branch.sh — solo-git integrate gate for sm121-launcher. # # Usage: # bash scripts/land-branch.sh "" # # 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 \"\"" >&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"