---
description: Merge multiple migrations into one (for releases)
agent: efcore-squash
model: sonnet
---

# EF Core Squash - Consolidate Migrations

Merges multiple migrations into a single consolidated migration using EF Core CLI only.

**USAGE:** Before creating a release branch to clean up migration history.

**WARNING:** This operation is **DESTRUCTIVE**. Migration history will be lost.

---

## RÈGLES DE CONFORMITÉ (OBLIGATOIRE)

> **INTERDIT - Violations CLAUDE.md:**
> - ❌ Génération de scripts SQL dans le repository (`./scripts/migrations/*.sql`)
> - ❌ Fichiers .sql versionnés dans Git
> - ❌ `migrationBuilder.Sql()` avec SQL brut
>
> **OBLIGATOIRE - Méthodes autorisées:**
> - ✅ `dotnet ef migrations add` pour créer la migration consolidée
> - ✅ `dotnet ef migrations remove` pour supprimer les anciennes
> - ✅ Backup des fichiers .cs dans `.claude/gitflow/backup/` (non versionné)
>
> **Contact support:** support@atlshub.ch

---

## STEP 1: Check prerequisites

```bash
# Check branch
CURRENT_BRANCH=$(git branch --show-current)
echo "Current branch: $CURRENT_BRANCH"

# Check clean state
if [ -n "$(git status --porcelain)" ]; then
  echo "ERROR: Working directory not clean"
  exit 1
fi

# Find EF Core projects
STARTUP_PROJECT=$(find . -name "*.Api.csproj" -o -name "*Web.csproj" | head -1)
INFRA_PROJECT=$(find . -name "*Infrastructure.csproj" | head -1)

if [ -z "$INFRA_PROJECT" ]; then
  INFRA_PROJECT=$(find . -name "*.csproj" -exec grep -l "Microsoft.EntityFrameworkCore" {} \; | head -1)
fi

PROJECT_DIR=$(dirname "$INFRA_PROJECT")
MIGRATIONS_DIR="$PROJECT_DIR/Migrations"

# List migrations
ALL_MIGRATIONS=$(find "$MIGRATIONS_DIR" -name "*.cs" 2>/dev/null | grep -v "Designer" | grep -v "Snapshot" | sort)
MIGRATION_COUNT=$(echo "$ALL_MIGRATIONS" | grep -c "." || echo "0")

echo "Migrations found: $MIGRATION_COUNT"
echo "Project directory: $PROJECT_DIR"
```

---

## STEP 2: Request confirmation

```javascript
AskUserQuestion({
  questions: [{
    question: "You are about to merge " + MIGRATION_COUNT + " migrations into one. This operation is DESTRUCTIVE. Continue?",
    header: "Squash",
    options: [
      { label: "Yes, squash all", description: "Merge all migrations into one" },
      { label: "Cancel", description: "Do nothing" }
    ],
    multiSelect: false
  }]
})
```

---

## STEP 3: Full backup (local only - NOT in repository)

```bash
# Create backup in .claude directory (gitignored)
BACKUP_DIR=".claude/gitflow/backup/migrations/squash_$(date +%Y%m%d_%H%M%S)"
mkdir -p "$BACKUP_DIR"

echo "Backup to $BACKUP_DIR (local only, not in Git)"
cp "$MIGRATIONS_DIR"/*.cs "$BACKUP_DIR/" 2>/dev/null
echo "  $(ls -1 "$BACKUP_DIR" | wc -l) files backed up"

# Keep ModelSnapshot for reference
cp "$MIGRATIONS_DIR"/*ModelSnapshot.cs "$BACKUP_DIR/ModelSnapshot_backup.cs" 2>/dev/null
```

---

## STEP 4: Delete all migrations

```bash
echo "Deleting migrations..."

# Delete all migration files (except ModelSnapshot)
for file in $(find "$MIGRATIONS_DIR" -name "*.cs" -not -name "*ModelSnapshot.cs" 2>/dev/null); do
  rm -f "$file"
  echo "  - $(basename "$file")"
done

# Also delete Designer files
for file in $(find "$MIGRATIONS_DIR" -name "*.Designer.cs" 2>/dev/null); do
  rm -f "$file"
  echo "  - $(basename "$file")"
done
```

---

## STEP 5: Create consolidated migration

```bash
# Version
VERSION=$(grep -oP '(?<=<Version>).*(?=</Version>)' "$INFRA_PROJECT" 2>/dev/null | head -1 || echo "1.0.0")
VERSION_CLEAN=$(echo "$VERSION" | sed 's/\./_/g')

# Migration name
if [[ "$CURRENT_BRANCH" == release/* ]]; then
  MIGRATION_NAME="Release_${VERSION_CLEAN}_Initial"
else
  MIGRATION_NAME="Consolidated_${VERSION_CLEAN}_AllMigrations"
fi

echo ""
echo "Creating consolidated migration: $MIGRATION_NAME"

dotnet ef migrations add "$MIGRATION_NAME" \
  --project "$INFRA_PROJECT" \
  --startup-project "$STARTUP_PROJECT" \
  --verbose

if [ $? -eq 0 ]; then
  echo "  Migration created successfully"
else
  echo "  ERROR - restoring backup"
  cp "$BACKUP_DIR"/*.cs "$MIGRATIONS_DIR/"
  exit 1
fi
```

---

## STEP 6: Validation (NO SQL script generation)

```bash
echo ""
echo "Validation..."

# Build
dotnet build --no-restore
if [ $? -ne 0 ]; then
  echo "  ERROR: Build failed"
  echo "  Restoring backup..."
  cp "$BACKUP_DIR"/*.cs "$MIGRATIONS_DIR/"
  exit 1
fi
echo "  Build OK"

# Verify migration can be listed
dotnet ef migrations list \
  --project "$INFRA_PROJECT" \
  --startup-project "$STARTUP_PROJECT" \
  --no-build 2>/dev/null

if [ $? -ne 0 ]; then
  echo "  ERROR: Migration list failed"
  exit 1
fi
echo "  Migration list OK"
```

---

## STEP 7: Summary

```
================================================================================
                    SQUASH COMPLETE
================================================================================

BRANCH:          {current_branch}
BACKUP:          {backup_dir} (local only)

BEFORE:
  Migrations: {old_count}

AFTER:
  Migration:  {migration_name}

COMPLIANT: ✓ EF Core CLI only (no SQL scripts in repository)

================================================================================
IMPORTANT - PRODUCTION DEPLOYMENT
================================================================================

Pour déployer en production, vous avez DEUX options:

OPTION 1 - EF Core CLI (Recommandé):
────────────────────────────────────────────────────────────────────────────────
dotnet ef database update {migration_name} \
  --project "$INFRA_PROJECT" \
  --startup-project "$STARTUP_PROJECT" \
  --connection "Server=...;Database=...;..."
────────────────────────────────────────────────────────────────────────────────

OPTION 2 - Si migrations déjà appliquées (mark as applied):
────────────────────────────────────────────────────────────────────────────────
# Insérer manuellement dans __EFMigrationsHistory via SSMS/Azure
# INSERT INTO __EFMigrationsHistory (MigrationId, ProductVersion)
# VALUES ('{migration_name}', '10.0.0')
────────────────────────────────────────────────────────────────────────────────

⚠️  NE PAS générer de scripts SQL dans le repository!
    Utilisez toujours EF Core CLI pour les déploiements.

================================================================================
NEXT STEPS
================================================================================

1. Vérifier le contenu de la migration consolidée
2. Tester sur dev DB: /efcore:db-reset && /efcore:db-deploy
3. Commit: /gitflow:3-commit

================================================================================
RESTORE (if needed)
================================================================================

cp {backup_dir}/*.cs {migrations_dir}/

================================================================================
```

---

## Options

| Option | Description |
|--------|-------------|
| `--no-backup` | Don't create backup (dangerous) |
| `--name <name>` | Force a migration name |
| `--keep-snapshot` | Keep current ModelSnapshot |
| `--dry-run` | Show without executing |

---

## When to use Squash

| Situation | Use Squash? |
|-----------|-------------|
| Before release | YES - clean up history |
| After merging multiple features | YES - consolidate |
| In production | NO - use EF Core CLI directly |
| Feature branch in progress | CAUTION - prefer rebase-snapshot |

---

## Forbidden Patterns

```
❌ INTERDIT - Ne jamais faire:
────────────────────────────────────────────────────────────────────────────────
# Génération de script SQL dans le repo
dotnet ef migrations script -o ./scripts/migrations/*.sql

# Stockage de fichiers .sql versionnés
./scripts/migrations/Release_1_0_0.sql
./scripts/seed.sql
────────────────────────────────────────────────────────────────────────────────

✅ CORRECT - Toujours utiliser:
────────────────────────────────────────────────────────────────────────────────
# EF Core CLI pour déploiement
dotnet ef database update

# Backup local uniquement (gitignored)
.claude/gitflow/backup/migrations/
────────────────────────────────────────────────────────────────────────────────
```

---

## Support

> **Questions ou problèmes avec le squash EF Core?**
>
> 📧 **support@atlshub.ch**
