88 lines
2.4 KiB
Bash
Executable File
88 lines
2.4 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Commit and optionally push a completed feature using Conventional Commits.
|
|
# Usage: ./scripts/commit_feature.sh <feature_id>
|
|
|
|
set -euo pipefail
|
|
|
|
FEATURE_ID="${1:-}"
|
|
if [ -z "$FEATURE_ID" ]; then
|
|
echo "[FAIL] Usage: $0 <feature_id>" >&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
|