#!/bin/bash # Configuration USER_FILE="${HOME:?HOME not set}/.qtx_branch_last_user" VALID_TYPES=("feature" "hotfix" "refactor" "improvement" "doc" "fix") # Trap for clean Ctrl+C handling trap 'echo ""; echo "Cancelled."; exit 130' INT TERM # Check dependencies if ! command -v git &> /dev/null; then echo "Error: 'git' command not found" >&2 exit 1 fi # Check we're in project root if [[ ! -f "Makefile" ]]; then echo "Error: Makefile not found. Run this script from project root." >&2 exit 1 fi echo "=== Make Branch Helper ===" echo "" # Load last user safely using shell built-in LAST_USER="" if [[ -f "$USER_FILE" && -r "$USER_FILE" && ! -L "$USER_FILE" ]]; then # Use shell built-in instead of cat, only read first line LAST_USER=$(head -n 1 "$USER_FILE" 2>/dev/null || true) fi if [[ -n "$LAST_USER" ]]; then echo "Last user found: $LAST_USER" fi # Select branch type echo "" echo "Select branch type:" select TYPE in "${VALID_TYPES[@]}"; do if [[ -n "$TYPE" ]]; then echo "Selected type: $TYPE" break else echo "Invalid selection. Please try again." fi done # Get user with validation echo "" while true; do read -r -p "Enter user (alphanumeric, _, or -) [${LAST_USER:-none}]: " USER USER="${USER:-$LAST_USER}" if [[ -z "$USER" ]]; then echo "Error: user is required (e.g., jdoe, fsmith)" >&2 continue fi if [[ ! "$USER" =~ ^[a-zA-Z0-9_-]+$ ]]; then echo "Error: user must be alphanumeric with optional _ or - (e.g., jdoe, f_smith)" >&2 continue fi break done # Save user preference securely with umask if [[ -n "$HOME" ]]; then # Remove if it's a symlink (prevent symlink attacks) [[ -L "$USER_FILE" ]] && rm -f "$USER_FILE" # Create with restricted permissions (600) (umask 077 && echo "$USER" > "$USER_FILE") fi # Get issue number with numeric validation echo "" while true; do read -r -p "Enter issue number (numeric only): " ISSUE if [[ -z "$ISSUE" ]]; then echo "Error: issue number is required (e.g., 123, 456)" >&2 continue fi if [[ ! "$ISSUE" =~ ^[0-9]+$ ]]; then echo "Error: issue number must be numeric only (e.g., 39, 123)" >&2 continue fi break done # Get summary with validation echo "" while true; do read -r -p "Enter summary (max 100 chars): " SUMMARY # Trim leading/trailing whitespace SUMMARY=$(echo "$SUMMARY" | xargs) if [[ -z "$SUMMARY" ]]; then echo "Error: summary is required (e.g., 'add new endpoint', 'fix login bug')" >&2 continue fi if [[ ${#SUMMARY} -gt 100 ]]; then echo "Error: summary too long (${#SUMMARY} chars, max 100)" >&2 continue fi # Basic validation - allow common characters if [[ ! "$SUMMARY" =~ ^[a-zA-Z0-9\ _\-]+$ ]]; then echo "Warning: summary contains special characters. Use only letters, numbers, spaces, hyphens, and underscores." >&2 read -r -p "Continue anyway? (y/N): " CONFIRM if [[ ! "$CONFIRM" =~ ^[Yy]$ ]]; then continue fi fi break done # Get ISSUE_PREFIX from Makefile.common (default to SKL if not found) ISSUE_PREFIX="SKL" if [[ -f "Makefile.common" ]]; then # Extract ISSUE_PREFIX from Makefile.common PREFIX_LINE=$(grep "^ISSUE_PREFIX" Makefile.common 2>/dev/null || true) if [[ -n "$PREFIX_LINE" ]]; then ISSUE_PREFIX=$(echo "$PREFIX_LINE" | cut -d'=' -f2 | tr -d ' ') fi fi # Build branch name: type/user/PREFIX-number/summary_with_underscores BRANCH_NAME="$TYPE/$USER/$ISSUE_PREFIX-$ISSUE/${SUMMARY// /_}" # Show summary and execute echo "" echo "Creating branch:" echo " Type: $TYPE" echo " User: $USER" echo " Issue: $ISSUE_PREFIX-$ISSUE" echo " Summary: $SUMMARY" echo " Branch: $BRANCH_NAME" echo "" # Create the git branch if git checkout -b "$BRANCH_NAME"; then echo "" echo "✓ Branch '$BRANCH_NAME' created and checked out successfully" exit 0 else echo "" >&2 echo "✗ Failed to create branch '$BRANCH_NAME'" >&2 exit 1 fi