|
|
|
|
@@ -3,18 +3,46 @@
|
|
|
|
|
set -e
|
|
|
|
|
|
|
|
|
|
JSON_MODE=false
|
|
|
|
|
SHORT_NAME=""
|
|
|
|
|
ARGS=()
|
|
|
|
|
for arg in "$@"; do
|
|
|
|
|
i=0
|
|
|
|
|
while [ $i -lt $# ]; do
|
|
|
|
|
arg="${!i}"
|
|
|
|
|
case "$arg" in
|
|
|
|
|
--json) JSON_MODE=true ;;
|
|
|
|
|
--help|-h) echo "Usage: $0 [--json] <feature_description>"; exit 0 ;;
|
|
|
|
|
*) ARGS+=("$arg") ;;
|
|
|
|
|
--json)
|
|
|
|
|
JSON_MODE=true
|
|
|
|
|
;;
|
|
|
|
|
--short-name)
|
|
|
|
|
if [ $((i + 1)) -ge $# ]; then
|
|
|
|
|
echo 'Error: --short-name requires a value' >&2
|
|
|
|
|
exit 1
|
|
|
|
|
fi
|
|
|
|
|
i=$((i + 1))
|
|
|
|
|
SHORT_NAME="${!i}"
|
|
|
|
|
;;
|
|
|
|
|
--help|-h)
|
|
|
|
|
echo "Usage: $0 [--json] [--short-name <name>] <feature_description>"
|
|
|
|
|
echo ""
|
|
|
|
|
echo "Options:"
|
|
|
|
|
echo " --json Output in JSON format"
|
|
|
|
|
echo " --short-name <name> Provide a custom short name (2-4 words) for the branch"
|
|
|
|
|
echo " --help, -h Show this help message"
|
|
|
|
|
echo ""
|
|
|
|
|
echo "Examples:"
|
|
|
|
|
echo " $0 'Add user authentication system' --short-name 'user-auth'"
|
|
|
|
|
echo " $0 'Implement OAuth2 integration for API'"
|
|
|
|
|
exit 0
|
|
|
|
|
;;
|
|
|
|
|
*)
|
|
|
|
|
ARGS+=("$arg")
|
|
|
|
|
;;
|
|
|
|
|
esac
|
|
|
|
|
i=$((i + 1))
|
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
FEATURE_DESCRIPTION="${ARGS[*]}"
|
|
|
|
|
if [ -z "$FEATURE_DESCRIPTION" ]; then
|
|
|
|
|
echo "Usage: $0 [--json] <feature_description>" >&2
|
|
|
|
|
echo "Usage: $0 [--json] [--short-name <name>] <feature_description>" >&2
|
|
|
|
|
exit 1
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
@@ -67,9 +95,84 @@ fi
|
|
|
|
|
NEXT=$((HIGHEST + 1))
|
|
|
|
|
FEATURE_NUM=$(printf "%03d" "$NEXT")
|
|
|
|
|
|
|
|
|
|
BRANCH_NAME=$(echo "$FEATURE_DESCRIPTION" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g' | sed 's/-\+/-/g' | sed 's/^-//' | sed 's/-$//')
|
|
|
|
|
WORDS=$(echo "$BRANCH_NAME" | tr '-' '\n' | grep -v '^$' | head -3 | tr '\n' '-' | sed 's/-$//')
|
|
|
|
|
BRANCH_NAME="${FEATURE_NUM}-${WORDS}"
|
|
|
|
|
# Function to generate branch name with stop word filtering and length filtering
|
|
|
|
|
generate_branch_name() {
|
|
|
|
|
local description="$1"
|
|
|
|
|
|
|
|
|
|
# Common stop words to filter out
|
|
|
|
|
local stop_words="^(i|a|an|the|to|for|of|in|on|at|by|with|from|is|are|was|were|be|been|being|have|has|had|do|does|did|will|would|should|could|can|may|might|must|shall|this|that|these|those|my|your|our|their|want|need|add|get|set)$"
|
|
|
|
|
|
|
|
|
|
# Convert to lowercase and split into words
|
|
|
|
|
local clean_name=$(echo "$description" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/ /g')
|
|
|
|
|
|
|
|
|
|
# Filter words: remove stop words and words shorter than 3 chars (unless they're uppercase acronyms in original)
|
|
|
|
|
local meaningful_words=()
|
|
|
|
|
for word in $clean_name; do
|
|
|
|
|
# Skip empty words
|
|
|
|
|
[ -z "$word" ] && continue
|
|
|
|
|
|
|
|
|
|
# Keep words that are NOT stop words AND (length >= 3 OR are potential acronyms)
|
|
|
|
|
if ! echo "$word" | grep -qiE "$stop_words"; then
|
|
|
|
|
if [ ${#word} -ge 3 ]; then
|
|
|
|
|
meaningful_words+=("$word")
|
|
|
|
|
elif echo "$description" | grep -q "\b${word^^}\b"; then
|
|
|
|
|
# Keep short words if they appear as uppercase in original (likely acronyms)
|
|
|
|
|
meaningful_words+=("$word")
|
|
|
|
|
fi
|
|
|
|
|
fi
|
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
# If we have meaningful words, use first 3-4 of them
|
|
|
|
|
if [ ${#meaningful_words[@]} -gt 0 ]; then
|
|
|
|
|
local max_words=3
|
|
|
|
|
if [ ${#meaningful_words[@]} -eq 4 ]; then max_words=4; fi
|
|
|
|
|
|
|
|
|
|
local result=""
|
|
|
|
|
local count=0
|
|
|
|
|
for word in "${meaningful_words[@]}"; do
|
|
|
|
|
if [ $count -ge $max_words ]; then break; fi
|
|
|
|
|
if [ -n "$result" ]; then result="$result-"; fi
|
|
|
|
|
result="$result$word"
|
|
|
|
|
count=$((count + 1))
|
|
|
|
|
done
|
|
|
|
|
echo "$result"
|
|
|
|
|
else
|
|
|
|
|
# Fallback to original logic if no meaningful words found
|
|
|
|
|
echo "$description" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g' | sed 's/-\+/-/g' | sed 's/^-//' | sed 's/-$//' | tr '-' '\n' | grep -v '^$' | head -3 | tr '\n' '-' | sed 's/-$//'
|
|
|
|
|
fi
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Generate branch name
|
|
|
|
|
if [ -n "$SHORT_NAME" ]; then
|
|
|
|
|
# Use provided short name, just clean it up
|
|
|
|
|
BRANCH_SUFFIX=$(echo "$SHORT_NAME" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g' | sed 's/-\+/-/g' | sed 's/^-//' | sed 's/-$//')
|
|
|
|
|
else
|
|
|
|
|
# Generate from description with smart filtering
|
|
|
|
|
BRANCH_SUFFIX=$(generate_branch_name "$FEATURE_DESCRIPTION")
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
BRANCH_NAME="${FEATURE_NUM}-${BRANCH_SUFFIX}"
|
|
|
|
|
|
|
|
|
|
# GitHub enforces a 244-byte limit on branch names
|
|
|
|
|
# Validate and truncate if necessary
|
|
|
|
|
MAX_BRANCH_LENGTH=244
|
|
|
|
|
if [ ${#BRANCH_NAME} -gt $MAX_BRANCH_LENGTH ]; then
|
|
|
|
|
# Calculate how much we need to trim from suffix
|
|
|
|
|
# Account for: feature number (3) + hyphen (1) = 4 chars
|
|
|
|
|
MAX_SUFFIX_LENGTH=$((MAX_BRANCH_LENGTH - 4))
|
|
|
|
|
|
|
|
|
|
# Truncate suffix at word boundary if possible
|
|
|
|
|
TRUNCATED_SUFFIX=$(echo "$BRANCH_SUFFIX" | cut -c1-$MAX_SUFFIX_LENGTH)
|
|
|
|
|
# Remove trailing hyphen if truncation created one
|
|
|
|
|
TRUNCATED_SUFFIX=$(echo "$TRUNCATED_SUFFIX" | sed 's/-$//')
|
|
|
|
|
|
|
|
|
|
ORIGINAL_BRANCH_NAME="$BRANCH_NAME"
|
|
|
|
|
BRANCH_NAME="${FEATURE_NUM}-${TRUNCATED_SUFFIX}"
|
|
|
|
|
|
|
|
|
|
>&2 echo "[specify] Warning: Branch name exceeded GitHub's 244-byte limit"
|
|
|
|
|
>&2 echo "[specify] Original: $ORIGINAL_BRANCH_NAME (${#ORIGINAL_BRANCH_NAME} bytes)"
|
|
|
|
|
>&2 echo "[specify] Truncated to: $BRANCH_NAME (${#BRANCH_NAME} bytes)"
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
if [ "$HAS_GIT" = true ]; then
|
|
|
|
|
git checkout -b "$BRANCH_NAME"
|
|
|
|
|
@@ -94,4 +197,4 @@ else
|
|
|
|
|
echo "SPEC_FILE: $SPEC_FILE"
|
|
|
|
|
echo "FEATURE_NUM: $FEATURE_NUM"
|
|
|
|
|
echo "SPECIFY_FEATURE environment variable set to: $BRANCH_NAME"
|
|
|
|
|
fi
|
|
|
|
|
fi
|