# GitFlow - Shared Functions

> **Usage:** This file contains reusable functions. Reference with `{{REF:section_name}}` in other files.

---

## DETECT_PROVIDER

Detects GitHub or Azure DevOps from remote URL.

```bash
detect_git_provider() {
  REMOTE_URL=$(git remote get-url origin 2>/dev/null || echo "")

  if [[ "$REMOTE_URL" == *"dev.azure.com"* ]] || [[ "$REMOTE_URL" == *"visualstudio.com"* ]]; then
    GIT_PROVIDER="azuredevops"
    [[ "$REMOTE_URL" =~ dev\.azure\.com/([^/]+)/([^/]+)/_git/([^/]+) ]] && {
      AZURE_ORG="${BASH_REMATCH[1]}"
      AZURE_PROJECT="${BASH_REMATCH[2]}"
      AZURE_REPO="${BASH_REMATCH[3]}"
    }
  elif [[ "$REMOTE_URL" == *"github.com"* ]]; then
    GIT_PROVIDER="github"
  else
    GIT_PROVIDER="unknown"
  fi
}
```

---

## NORMALIZE_NAME

Normalizes a branch name (accents, spaces, special characters).

```bash
normalize_branch_name() {
  local input="$1" max_length="${2:-50}"
  echo "$input" | tr '[:upper:]' '[:lower:]' | \
    sed 'y/àâäéèêëïîôùûüçœæ/aaaeeeeiioouucoa/' | \
    sed "s/[ _']/-/g" | sed 's/[^a-z0-9-]//g' | \
    sed 's/--*/-/g' | sed 's/^-//;s/-$//' | cut -c1-$max_length | sed 's/-$//'
}
```

---

## RESOLVE_CONFIG_PATH

Resolves the config.json path regardless of current working directory.
Searches in: pwd, develop worktree, then git root.

```bash
resolve_gitflow_config_path() {
  # 1. Try current directory
  [ -f ".claude/gitflow/config.json" ] && { echo ".claude/gitflow/config.json"; return 0; }

  # 2. Try to find develop worktree from git worktree list
  local DEVELOP_PATH
  DEVELOP_PATH=$(git worktree list --porcelain 2>/dev/null | grep -A1 "branch refs/heads/develop" | grep "^worktree " | sed 's/^worktree //')
  [ -n "$DEVELOP_PATH" ] && [ -f "$DEVELOP_PATH/.claude/gitflow/config.json" ] && {
    echo "$DEVELOP_PATH/.claude/gitflow/config.json"
    return 0
  }

  # 3. Try git toplevel
  local GIT_ROOT
  GIT_ROOT=$(git rev-parse --show-toplevel 2>/dev/null)
  [ -n "$GIT_ROOT" ] && [ -f "$GIT_ROOT/.claude/gitflow/config.json" ] && {
    echo "$GIT_ROOT/.claude/gitflow/config.json"
    return 0
  }

  return 1
}
```

---

## READ_GITFLOW_CONFIG

Reads GitFlow configuration from config.json. Exposes all variables needed by steps and phases.

```bash
read_gitflow_config() {
  local CONFIG_FILE
  CONFIG_FILE=$(resolve_gitflow_config_path) || {
    echo "❌ GitFlow config not found. Run /gitflow init first."
    return 1
  }

  # Repository
  GF_PROJECT_NAME=$(grep -oP '"name":\s*"\K[^"]+' "$CONFIG_FILE" | head -1)
  GF_ROOT_FOLDER=$(grep -oP '"rootFolder":\s*"\K[^"]+' "$CONFIG_FILE" | head -1)
  GF_REMOTE_URL=$(grep -oP '"remoteUrl":\s*"\K[^"]+' "$CONFIG_FILE" | head -1)

  # Git provider and branches
  GF_PROVIDER=$(grep -oP '"provider":\s*"\K[^"]+' "$CONFIG_FILE" | head -1)
  GF_MAIN_BRANCH=$(grep -oP '"main":\s*"\K[^"]+' "$CONFIG_FILE" | head -1)
  GF_DEVELOP_BRANCH=$(grep -oP '"develop":\s*"\K[^"]+' "$CONFIG_FILE" | head -1)

  # Prefixes
  GF_FEATURE_PREFIX=$(grep -oP '"feature":\s*"\K[^"]+' "$CONFIG_FILE" | head -1)
  GF_RELEASE_PREFIX=$(grep -oP '"release":\s*"\K[^"]+' "$CONFIG_FILE" | head -1)
  GF_HOTFIX_PREFIX=$(grep -oP '"hotfix":\s*"\K[^"]+' "$CONFIG_FILE" | head -1)

  # Worktrees
  GF_WORKTREE_MODE=$(grep -oP '"mode":\s*"\K[^"]+' "$CONFIG_FILE" | head -1)
  GF_MAIN_PATH=$(grep -A1 '"structure"' "$CONFIG_FILE" | grep -oP '"main":\s*"\K[^"]+' | head -1)
  GF_DEVELOP_PATH=$(grep -A2 '"structure"' "$CONFIG_FILE" | grep -oP '"develop":\s*"\K[^"]+' | head -1)
  GF_FEATURES_PATH=$(grep -oP '"features":\s*"\K[^"]+' "$CONFIG_FILE" | head -1)
  GF_RELEASES_PATH=$(grep -oP '"releases":\s*"\K[^"]+' "$CONFIG_FILE" | head -1)
  GF_HOTFIXES_PATH=$(grep -oP '"hotfixes":\s*"\K[^"]+' "$CONFIG_FILE" | head -1)

  # Language
  GF_LANG=$(grep -oP '"code":\s*"\K[^"]+' "$CONFIG_FILE" | head -1)

  # Versioning
  GF_VERSION=$(grep -oP '"current":\s*"\K[^"]+' "$CONFIG_FILE" | head -1)
  GF_TAG_PREFIX=$(grep -oP '"tagPrefix":\s*"\K[^"]+' "$CONFIG_FILE" | head -1)

  # Defaults for missing values
  GF_LANG=${GF_LANG:-en}
  GF_WORKTREE_MODE=${GF_WORKTREE_MODE:-organized}
  GF_MAIN_BRANCH=${GF_MAIN_BRANCH:-main}
  GF_DEVELOP_BRANCH=${GF_DEVELOP_BRANCH:-develop}
  GF_FEATURE_PREFIX=${GF_FEATURE_PREFIX:-feature/}
  GF_RELEASE_PREFIX=${GF_RELEASE_PREFIX:-release/}
  GF_HOTFIX_PREFIX=${GF_HOTFIX_PREFIX:-hotfix/}
  GF_TAG_PREFIX=${GF_TAG_PREFIX:-v}
  GF_VERSION=${GF_VERSION:-0.1.0}

  # Export config file path for steps that need to update it
  GF_CONFIG_FILE="$CONFIG_FILE"
}
```

---

## DETECT_WORKTREE_MODE

Detects worktree mode. Reads config first, falls back to filesystem detection.

```bash
detect_worktree_mode() {
  # 1. Try config first (authoritative)
  local CONFIG_FILE
  CONFIG_FILE=$(resolve_gitflow_config_path 2>/dev/null)
  if [ -n "$CONFIG_FILE" ] && [ -f "$CONFIG_FILE" ]; then
    WORKTREE_MODE=$(grep -oP '"mode":\s*"\K[^"]+' "$CONFIG_FILE" | head -1)
    [ -n "$WORKTREE_MODE" ] && return 0
  fi

  # 2. Fallback: filesystem detection
  if [ -d "../features" ] && [ -d "../releases" ] && [ -d "../hotfixes" ]; then
    WORKTREE_MODE="organized"
  elif [ -d "../01-Main" ] && [ -d "../02-Develop" ]; then
    WORKTREE_MODE="organized"
  elif [ -d "../worktrees" ]; then
    WORKTREE_MODE="adjacent"
  else
    WORKTREE_MODE="organized"
  fi
}
```

---

## CLEANUP_WORKTREE

Cleans up a worktree for a given branch. Uses config paths when available.

```bash
cleanup_worktree_for_branch() {
  local BRANCH=$1 WORKTREE_PATH=""

  # Try config-based paths first (absolute, reliable)
  read_gitflow_config 2>/dev/null
  if [ -n "$GF_FEATURES_PATH" ]; then
    case "$BRANCH" in
      feature/*) WORKTREE_PATH="$GF_FEATURES_PATH/${BRANCH#feature/}" ;;
      release/*) WORKTREE_PATH="$GF_RELEASES_PATH/${BRANCH#release/}" ;;
      hotfix/*)  WORKTREE_PATH="$GF_HOTFIXES_PATH/${BRANCH#hotfix/}" ;;
    esac
  else
    # Fallback: relative paths
    case "$BRANCH" in
      feature/*) WORKTREE_PATH="../features/${BRANCH#feature/}" ;;
      release/*) WORKTREE_PATH="../releases/${BRANCH#release/}" ;;
      hotfix/*)  WORKTREE_PATH="../hotfixes/${BRANCH#hotfix/}" ;;
    esac
  fi

  [ -n "$WORKTREE_PATH" ] && [ -d "$WORKTREE_PATH" ] && {
    git worktree remove "$WORKTREE_PATH" --force 2>/dev/null || rm -rf "$WORKTREE_PATH"
    git worktree prune
    echo "✓ Worktree cleaned: $WORKTREE_PATH"
  }
}
```

---

## SYNC_REMOTE

Syncs with remote and displays status.

```bash
sync_with_remote() {
  git fetch --all --quiet
  local BRANCH=$(git branch --show-current)
  local AHEAD=$(git rev-list --count origin/$BRANCH..HEAD 2>/dev/null || echo "0")
  local BEHIND=$(git rev-list --count HEAD..origin/$BRANCH 2>/dev/null || echo "0")

  [ "$BEHIND" -gt 0 ] && echo "⚠️ $BRANCH: $BEHIND commit(s) behind"
  [ "$AHEAD" -gt 0 ] && echo "ℹ️ $BRANCH: $AHEAD commit(s) not pushed"
}
```

---

## CONFIG_TEMPLATE

GitFlow configuration JSON template v2.0.0 (aligned with `templates/config.json`).

```json
{
  "version": "2.0.0",
  "repository": {
    "name": "",
    "rootFolder": "",
    "nameVariants": {
      "pascalCaseDot": "",
      "pascalCase": "",
      "kebabCase": "",
      "snakeCase": "",
      "displayName": ""
    },
    "defaultBranch": "main",
    "remoteUrl": ""
  },
  "git": {
    "provider": "",
    "branches": {
      "main": "main",
      "develop": "develop"
    },
    "prefixes": {
      "feature": "feature/",
      "release": "release/",
      "hotfix": "hotfix/"
    }
  },
  "worktrees": {
    "enabled": true,
    "mode": "organized",
    "structure": {
      "main": "",
      "develop": "",
      "features": "",
      "releases": "",
      "hotfixes": ""
    }
  },
  "versioning": {
    "strategy": "semver",
    "current": "0.1.0",
    "tagPrefix": "v",
    "sources": ["csproj", "package.json", "VERSION"]
  },
  "efcore": {
    "enabled": true,
    "validateOnCommit": true,
    "blockDestructive": true,
    "migrationNaming": "{context}_v{version}_{sequence}_{Description}"
  },
  "workflow": {
    "push": {
      "afterCommit": "worktree"
    },
    "pr": {
      "autoLabels": true,
      "requireReview": true
    }
  },
  "language": {
    "code": "en"
  }
}
```

**worktrees.mode options:**
- `organized`: Uses absolute paths from config (`structure.features`, etc.)
- `adjacent`: `{rootFolder}/worktrees/{type}/`
- `disabled`: No worktrees

---

## PR_COMMANDS

PR commands by provider.

### GitHub
```bash
gh pr create --title "$TITLE" --body "$BODY" --base "$BASE"
gh pr view $NUMBER --json state,mergeable,reviews
gh pr merge $NUMBER --squash --delete-branch
```

### Azure DevOps
```bash
az repos pr create --title "$TITLE" --description "$BODY" --source-branch "$SOURCE" --target-branch "$BASE"
az repos pr show --id $NUMBER --query "{status:status,mergeStatus:mergeStatus}"
az repos pr update --id $NUMBER --status completed --squash true --delete-source-branch true
```

---

## OUTPUT_FORMAT

Standard output format (replaces ASCII art).

```bash
output_header() { echo -e "\n## $1\n"; }
output_section() { echo "### $1"; }
output_item() { echo "- $1"; }
output_success() { echo "✓ $1"; }
output_warning() { echo "⚠️ $1"; }
output_error() { echo "❌ $1"; }
output_next() { echo "→ Next: $1"; }
```
