#!/usr/bin/env bash # Commit and optionally push a completed feature using Conventional Commits. # Usage: ./scripts/commit_feature.sh set -euo pipefail FEATURE_ID="${1:-}" if [ -z "$FEATURE_ID" ]; then echo "[FAIL] Usage: $0 " >&2 exit 1 fi # Check if git repo if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then echo "[SKIP] Not a git repository, skipping commit" exit 0 fi feature_meta() { python3 - "$FEATURE_ID" <<'PY' import json import re import sys from pathlib import Path fid = sys.argv[1] path = Path('backlog/features.json') commit_type = 'feat' title = 'completed feature' if path.exists(): data = json.loads(path.read_text(encoding='utf-8')) for feature in data.get('features', []): if str(feature.get('id')) == fid: ftype = str(feature.get('type', 'feature')).lower() commit_type = { 'feature': 'feat', 'fix': 'fix', 'bug': 'fix', 'chore': 'chore', }.get(ftype, 'feat') title = feature.get('title') or feature.get('description') or title break subject = re.sub(r'\s+', ' ', str(title)).strip() subject = subject[0].lower() + subject[1:] if subject else 'completed feature' subject = subject.rstrip('.') print(commit_type) print(subject[:120]) PY } mapfile -t META < <(feature_meta) COMMIT_TYPE="${META[0]:-feat}" COMMIT_SUBJECT="${META[1]:-completed feature}" SCOPE=$(printf '%s' "$FEATURE_ID" | tr '[:upper:]' '[:lower:]' | tr -c 'a-z0-9._/-' '-') COMMIT_MSG="$COMMIT_TYPE($SCOPE): $COMMIT_SUBJECT" # Validate before touching git state. python3 scripts/validate_conventional_commit.py --message "$COMMIT_MSG" # Stage all changes (excluding node_modules, dist, .next, etc. via .gitignore) git add -A # Check if there are changes to commit if git diff --cached --quiet; then echo "[SKIP] No changes to commit for $FEATURE_ID" exit 0 fi # Commit git commit -m "$COMMIT_MSG" echo "[OK] Committed $FEATURE_ID: $COMMIT_MSG" # Check if remote exists and push if git remote get-url origin >/dev/null 2>&1; then BRANCH=$(git rev-parse --abbrev-ref HEAD) echo "[INFO] Pushing to origin/$BRANCH..." if git push origin "$BRANCH"; then echo "[OK] Pushed to origin/$BRANCH" else echo "[WARN] Push failed (you can push manually later)" fi else echo "[SKIP] No remote 'origin' configured, skipping push" fi