- 
                Notifications
    You must be signed in to change notification settings 
- Fork 3.7k
Feature/configure branch name #1009
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
ce2c497
              7fdc1f4
              18cb593
              0951aa9
              File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|  | @@ -4,6 +4,8 @@ set -e | |||||||||||||||||||||||||||
|  | ||||||||||||||||||||||||||||
| JSON_MODE=false | ||||||||||||||||||||||||||||
| SHORT_NAME="" | ||||||||||||||||||||||||||||
| BRANCH_PREFIX_ARG="" | ||||||||||||||||||||||||||||
| SPEC_NUM_ARG="" | ||||||||||||||||||||||||||||
| ARGS=() | ||||||||||||||||||||||||||||
| i=1 | ||||||||||||||||||||||||||||
| while [ $i -le $# ]; do | ||||||||||||||||||||||||||||
|  | @@ -26,17 +28,50 @@ while [ $i -le $# ]; do | |||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||
| SHORT_NAME="$next_arg" | ||||||||||||||||||||||||||||
| ;; | ||||||||||||||||||||||||||||
| --branch-prefix) | ||||||||||||||||||||||||||||
| if [ $((i + 1)) -gt $# ]; then | ||||||||||||||||||||||||||||
| echo 'Error: --branch-prefix requires a value' >&2 | ||||||||||||||||||||||||||||
| exit 1 | ||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||
| i=$((i + 1)) | ||||||||||||||||||||||||||||
| next_arg="${!i}" | ||||||||||||||||||||||||||||
| # Check if the next argument is another option (starts with --) | ||||||||||||||||||||||||||||
| if [[ "$next_arg" == --* ]]; then | ||||||||||||||||||||||||||||
| echo 'Error: --branch-prefix requires a value' >&2 | ||||||||||||||||||||||||||||
| exit 1 | ||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||
| BRANCH_PREFIX_ARG="$next_arg" | ||||||||||||||||||||||||||||
| ;; | ||||||||||||||||||||||||||||
| --spec-number) | ||||||||||||||||||||||||||||
| if [ $((i + 1)) -gt $# ]; then | ||||||||||||||||||||||||||||
| echo 'Error: --spec-number requires a value' >&2 | ||||||||||||||||||||||||||||
| exit 1 | ||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||
| i=$((i + 1)) | ||||||||||||||||||||||||||||
| next_arg="${!i}" | ||||||||||||||||||||||||||||
| # Check if the next argument is another option (starts with --) | ||||||||||||||||||||||||||||
| if [[ "$next_arg" == --* ]]; then | ||||||||||||||||||||||||||||
| echo 'Error: --spec-number requires a value' >&2 | ||||||||||||||||||||||||||||
| exit 1 | ||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||
| SPEC_NUM_ARG="$next_arg" | ||||||||||||||||||||||||||||
| ;; | ||||||||||||||||||||||||||||
| --help|-h) | ||||||||||||||||||||||||||||
| echo "Usage: $0 [--json] [--short-name <name>] <feature_description>" | ||||||||||||||||||||||||||||
| echo "Usage: $0 [--json] [--short-name <name>] [--branch-prefix <prefix>] [--spec-number <number>] <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 " --json Output in JSON format" | ||||||||||||||||||||||||||||
| echo " --short-name <name> Provide a custom short name (2-4 words) for the branch" | ||||||||||||||||||||||||||||
| echo " --branch-prefix <prefix> Override branch prefix (e.g., 'feature/', 'bugfix/')" | ||||||||||||||||||||||||||||
| echo " --spec-number <number> Specify a custom spec number (e.g., to match issue tracker)" | ||||||||||||||||||||||||||||
| 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'" | ||||||||||||||||||||||||||||
| echo " $0 'Fix login bug' --branch-prefix 'bugfix/'" | ||||||||||||||||||||||||||||
| echo " $0 'Add payment processing' --spec-number 42" | ||||||||||||||||||||||||||||
| echo " $0 'Implement search feature' --spec-number 1234 --branch-prefix 'feature/'" | ||||||||||||||||||||||||||||
| exit 0 | ||||||||||||||||||||||||||||
| ;; | ||||||||||||||||||||||||||||
| *) | ||||||||||||||||||||||||||||
|  | @@ -87,19 +122,96 @@ cd "$REPO_ROOT" | |||||||||||||||||||||||||||
| SPECS_DIR="$REPO_ROOT/specs" | ||||||||||||||||||||||||||||
| mkdir -p "$SPECS_DIR" | ||||||||||||||||||||||||||||
|  | ||||||||||||||||||||||||||||
| HIGHEST=0 | ||||||||||||||||||||||||||||
| if [ -d "$SPECS_DIR" ]; then | ||||||||||||||||||||||||||||
| for dir in "$SPECS_DIR"/*; do | ||||||||||||||||||||||||||||
| [ -d "$dir" ] || continue | ||||||||||||||||||||||||||||
| dirname=$(basename "$dir") | ||||||||||||||||||||||||||||
| number=$(echo "$dirname" | grep -o '^[0-9]\+' || echo "0") | ||||||||||||||||||||||||||||
| number=$((10#$number)) | ||||||||||||||||||||||||||||
| if [ "$number" -gt "$HIGHEST" ]; then HIGHEST=$number; fi | ||||||||||||||||||||||||||||
| done | ||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||
| # Function to get spec number from various sources | ||||||||||||||||||||||||||||
| get_spec_number() { | ||||||||||||||||||||||||||||
| # Priority: 1. Command-line argument, 2. Environment variable, 3. Auto-increment | ||||||||||||||||||||||||||||
| if [ -n "$SPEC_NUM_ARG" ]; then | ||||||||||||||||||||||||||||
| # Validate it's a positive integer | ||||||||||||||||||||||||||||
| if ! [[ "$SPEC_NUM_ARG" =~ ^[0-9]+$ ]]; then | ||||||||||||||||||||||||||||
| echo "Error: --spec-number must be a positive integer" >&2 | ||||||||||||||||||||||||||||
| exit 1 | ||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||
|  | ||||||||||||||||||||||||||||
| # Pad to at least 3 digits | ||||||||||||||||||||||||||||
| if [ "$SPEC_NUM_ARG" -lt 100 ]; then | ||||||||||||||||||||||||||||
| printf "%03d" "$SPEC_NUM_ARG" | ||||||||||||||||||||||||||||
| else | ||||||||||||||||||||||||||||
| echo "$SPEC_NUM_ARG" | ||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||
| return | ||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||
|  | ||||||||||||||||||||||||||||
| if [ -n "$SPECIFY_SPEC_NUMBER" ]; then | ||||||||||||||||||||||||||||
| # Validate it's a positive integer | ||||||||||||||||||||||||||||
| if ! [[ "$SPECIFY_SPEC_NUMBER" =~ ^[0-9]+$ ]]; then | ||||||||||||||||||||||||||||
| echo "Error: SPECIFY_SPEC_NUMBER must be a positive integer" >&2 | ||||||||||||||||||||||||||||
| exit 1 | ||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||
|  | ||||||||||||||||||||||||||||
| # Pad to at least 3 digits | ||||||||||||||||||||||||||||
| if [ "$SPECIFY_SPEC_NUMBER" -lt 100 ]; then | ||||||||||||||||||||||||||||
| printf "%03d" "$SPECIFY_SPEC_NUMBER" | ||||||||||||||||||||||||||||
| else | ||||||||||||||||||||||||||||
| echo "$SPECIFY_SPEC_NUMBER" | ||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||
| return | ||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||
|  | ||||||||||||||||||||||||||||
| # Auto-increment: find highest existing number | ||||||||||||||||||||||||||||
| local highest=0 | ||||||||||||||||||||||||||||
| if [ -d "$SPECS_DIR" ]; then | ||||||||||||||||||||||||||||
| for dir in "$SPECS_DIR"/*; do | ||||||||||||||||||||||||||||
| [ -d "$dir" ] || continue | ||||||||||||||||||||||||||||
| local dirname=$(basename "$dir") | ||||||||||||||||||||||||||||
| local number=$(echo "$dirname" | grep -o '^[0-9]\+' || echo "0") | ||||||||||||||||||||||||||||
| number=$((10#$number)) | ||||||||||||||||||||||||||||
| if [ "$number" -gt "$highest" ]; then highest=$number; fi | ||||||||||||||||||||||||||||
| done | ||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||
|  | ||||||||||||||||||||||||||||
| local next=$((highest + 1)) | ||||||||||||||||||||||||||||
| printf "%03d" "$next" | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|  | ||||||||||||||||||||||||||||
| FEATURE_NUM=$(get_spec_number) | ||||||||||||||||||||||||||||
|  | ||||||||||||||||||||||||||||
| # Check for conflicts with existing spec numbers | ||||||||||||||||||||||||||||
| for dir in "$SPECS_DIR"/*; do | ||||||||||||||||||||||||||||
| [ -d "$dir" ] || continue | ||||||||||||||||||||||||||||
| dirname=$(basename "$dir") | ||||||||||||||||||||||||||||
| if [[ "$dirname" =~ ^${FEATURE_NUM}- ]]; then | ||||||||||||||||||||||||||||
| echo "Error: Spec number $FEATURE_NUM already exists in directory: $dirname" >&2 | ||||||||||||||||||||||||||||
| echo "Please choose a different spec number or remove the existing spec." >&2 | ||||||||||||||||||||||||||||
| exit 1 | ||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||
| done | ||||||||||||||||||||||||||||
|  | ||||||||||||||||||||||||||||
| NEXT=$((HIGHEST + 1)) | ||||||||||||||||||||||||||||
| FEATURE_NUM=$(printf "%03d" "$NEXT") | ||||||||||||||||||||||||||||
| # Function to get branch prefix from config or environment variable | ||||||||||||||||||||||||||||
| get_branch_prefix() { | ||||||||||||||||||||||||||||
| # Priority: 1. Command-line argument, 2. Environment variable, 3. Config file, 4. Default (empty) | ||||||||||||||||||||||||||||
| if [ -n "$BRANCH_PREFIX_ARG" ]; then | ||||||||||||||||||||||||||||
| echo "$BRANCH_PREFIX_ARG" | ||||||||||||||||||||||||||||
| return | ||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||
|  | ||||||||||||||||||||||||||||
| if [ -n "$SPECIFY_BRANCH_PREFIX" ]; then | ||||||||||||||||||||||||||||
| echo "$SPECIFY_BRANCH_PREFIX" | ||||||||||||||||||||||||||||
| return | ||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||
|  | ||||||||||||||||||||||||||||
| local config_file="$REPO_ROOT/.specify/config.json" | ||||||||||||||||||||||||||||
| if [ -f "$config_file" ]; then | ||||||||||||||||||||||||||||
| # Use grep and sed to extract the prefix value from JSON | ||||||||||||||||||||||||||||
| # This avoids requiring jq to be installed | ||||||||||||||||||||||||||||
| local prefix=$(grep -o '"prefix"[[:space:]]*:[[:space:]]*"[^"]*"' "$config_file" | sed 's/.*"prefix"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/') | ||||||||||||||||||||||||||||
| 
      Comment on lines
    
      +204
     to 
      +206
    
   
     | ||||||||||||||||||||||||||||
| # Use grep and sed to extract the prefix value from JSON | |
| # This avoids requiring jq to be installed | |
| local prefix=$(grep -o '"prefix"[[:space:]]*:[[:space:]]*"[^"]*"' "$config_file" | sed 's/.*"prefix"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/') | |
| # Use jq to extract the prefix value from JSON. jq correctly handles escaped quotes and special characters. | |
| # If jq is not available, fall back to grep/sed but warn about limitations. | |
| local prefix="" | |
| if command -v jq >/dev/null 2>&1; then | |
| prefix=$(jq -r '.prefix // empty' "$config_file") | |
| else | |
| echo "Warning: jq not found. Falling back to regex-based JSON parsing, which may fail for escaped quotes or special characters in the prefix value." >&2 | |
| # Fallback: regex-based extraction (does not handle escaped quotes/special chars) | |
| prefix=$(grep -o '"prefix"[[:space:]]*:[[:space:]]*"[^"]*"' "$config_file" | sed 's/.*"prefix"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/') | |
| fi | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The bash validation allows zero as a valid spec number (regex
^[0-9]+$matches "0"), but this could create ambiguous directory names like000-feature-name. The PowerShell version has the same issue. Both scripts should reject zero to ensure spec numbers start from 1.