Created
July 15, 2026 21:08
-
-
Save florentdestremau/545e0937218cff0f686b969e1bf7ac56 to your computer and use it in GitHub Desktop.
worktree-init.sh
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| # | |
| # Initialise une stack Docker Compose complète et INDÉPENDANTE pour ce git worktree, | |
| # en parallèle de la stack principale `suf_sf`, puis prépare tout pour lancer la | |
| # suite de tests. | |
| # | |
| # Isolation : | |
| # - Le nom de projet Compose est dérivé du dossier du worktree (ex. `worktree-management`), | |
| # donc réseau / volumes / base de données sont automatiquement séparés de `suf_sf`. | |
| # - Les PORTS publiés sont scannés dynamiquement (port libre suivant) et écrits | |
| # dans `.env.worktree.local` (gitignoré), passé à `docker compose up` via --env-file. | |
| # - Un DOMAINE dédié `suf-<branche>.localhost` est dérivé de la branche : | |
| # * SERVER_NAME (Caddy) -> .env.worktree.local (lu par Docker) | |
| # * SITE_BASE_HOST/SCHEME -> .env.dev.local (lu par Symfony, env dev seulement, | |
| # pour ne pas perturber les tests) | |
| # - La BASE dev est clonée depuis la stack source par copie du volume Docker | |
| # (Postgres source coupé le temps de la copie, puis redémarré). | |
| # | |
| # Usage : | |
| # bin/worktree-init.sh | |
| # | |
| # Variables d'environnement : | |
| # WORKTREE_SEED_DB=0 désactive la copie du volume de la DB dev | |
| # WORKTREE_SOURCE_PROJECT=nom projet Compose source à cloner (défaut: suf_sf) | |
| # | |
| set -euo pipefail | |
| cd "$(dirname "$0")/.." | |
| ENV_OVERRIDE=".env.worktree.local" | |
| # Projet Compose (dérivé du dossier) = préfixe des volumes/conteneurs. | |
| PROJECT="$(docker compose config 2>/dev/null | awk '/^name:/{print $2; exit}')" | |
| # Stack SOURCE d'où l'on clone la base dev (défaut: stack principale `suf_sf`). | |
| SOURCE_PROJECT="${WORKTREE_SOURCE_PROJECT:-suf_sf}" | |
| # Copier le volume de données de la DB dev depuis la source (défaut: oui). | |
| SEED_DB="${WORKTREE_SEED_DB:-1}" | |
| # Domaine dédié dérivé de la branche courante (slug: minuscules, non-alnum -> '-') | |
| BRANCH="$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo worktree)" | |
| SLUG="$(printf '%s' "$BRANCH" | tr '[:upper:]' '[:lower:]' | sed -E 's/[^a-z0-9]+/-/g; s/^-+|-+$//g')" | |
| WT_HOST="suf-${SLUG}.localhost" | |
| echo "==> Worktree : $(pwd)" | |
| echo "==> Projet Compose : $PROJECT" | |
| echo "==> Domaine : https://$WT_HOST" | |
| # --- Scan de ports libres ----------------------------------------------------- | |
| declare -a RESERVED=() | |
| port_in_use() { | |
| local p="$1" | |
| # 1) déjà réservé par ce run 2) écouté sur l'hôte (ss) 3) publié par un conteneur Docker | |
| local r | |
| for r in "${RESERVED[@]:-}"; do [ "$r" = "$p" ] && return 0; done | |
| if command -v ss >/dev/null 2>&1; then | |
| ss -ltnH "sport = :$p" 2>/dev/null | grep -q . && return 0 | |
| fi | |
| docker ps --format '{{.Ports}}' 2>/dev/null | grep -qE "(^|[^0-9]):$p->" && return 0 | |
| return 1 | |
| } | |
| free_port() { # free_port <port_de_base> | |
| local p="$1" | |
| while port_in_use "$p"; do p=$((p + 1)); done | |
| RESERVED+=("$p") | |
| echo "$p" | |
| } | |
| # --- Copie du volume de la DB dev depuis la stack source ---------------------- | |
| # Coupe proprement le Postgres source, copie son volume de données au niveau | |
| # fichier (cohérent car la source est arrêtée — bien plus rapide qu'un pg_dump), | |
| # puis le redémarre. Fait AVANT `up` pour que le Postgres du worktree boote | |
| # directement sur les données copiées (pas d'initdb d'un cluster vide). | |
| seed_db_volume() { | |
| local src_vol="${SOURCE_PROJECT}_database_data" | |
| local dst_vol="${PROJECT}_database_data" | |
| local src_ctn="${SOURCE_PROJECT}-database-1" | |
| if ! docker volume inspect "$src_vol" >/dev/null 2>&1; then | |
| echo "==> Copie DB ignorée : volume source '$src_vol' introuvable." | |
| return 0 | |
| fi | |
| # Idempotent : si le volume worktree contient déjà un cluster, on n'écrase pas. | |
| if docker run --rm -v "$dst_vol":/d alpine test -f /d/PG_VERSION >/dev/null 2>&1; then | |
| echo "==> Copie DB ignorée : '$dst_vol' déjà initialisé." | |
| return 0 | |
| fi | |
| local was_running=0 | |
| if [ "$(docker inspect -f '{{.State.Running}}' "$src_ctn" 2>/dev/null)" = "true" ]; then | |
| was_running=1 | |
| echo "==> Coupure du Postgres source ($src_ctn) pour copie cohérente…" | |
| docker stop "$src_ctn" >/dev/null | |
| fi | |
| echo "==> Copie du volume $src_vol -> $dst_vol…" | |
| docker run --rm -v "$src_vol":/from:ro -v "$dst_vol":/to alpine \ | |
| sh -c 'rm -rf /to/* /to/..?* /to/.[!.]* 2>/dev/null; cp -a /from/. /to/' | |
| if [ "$was_running" = 1 ]; then | |
| echo "==> Redémarrage du Postgres source…" | |
| docker start "$src_ctn" >/dev/null | |
| fi | |
| echo "==> Volume DB copié." | |
| } | |
| # 1. Fichier de ports remappés — recalculé à chaque init (les conteneurs déjà up | |
| # gardent leurs ports ; on ne régénère que si absent pour rester stable). | |
| if [ ! -f "$ENV_OVERRIDE" ]; then | |
| HTTP_PORT=$(free_port 8080) | |
| HTTPS_PORT=$(free_port 8443) | |
| POSTGRES_PORT=$(free_port 5432) | |
| PORT_MYSQL=$(free_port 3306) | |
| REDIS_PORT=$(free_port 6379) | |
| ADMINER_PORT=$(free_port 8090) | |
| MAILPIT_PORT=$(free_port 8030) | |
| MAILPIT_PORT_WEB=$(free_port 8095) | |
| cat > "$ENV_OVERRIDE" <<EOF | |
| # Ports libres scannés + domaine, pour une stack Docker indépendante par worktree. | |
| # Généré par bin/worktree-init.sh — gitignoré via .env.*.local | |
| HTTP_PORT=$HTTP_PORT | |
| HTTPS_PORT=$HTTPS_PORT | |
| HTTP3_PORT=$HTTPS_PORT | |
| POSTGRES_PORT=$POSTGRES_PORT | |
| PORT_MYSQL=$PORT_MYSQL | |
| REDIS_PORT=$REDIS_PORT | |
| ADMINER_PORT=$ADMINER_PORT | |
| MAILPIT_PORT=$MAILPIT_PORT | |
| MAILPIT_PORT_WEB=$MAILPIT_PORT_WEB | |
| SERVER_NAME=$WT_HOST | |
| EOF | |
| echo "==> $ENV_OVERRIDE créé (ports : http=$HTTP_PORT https=$HTTPS_PORT pg=$POSTGRES_PORT redis=$REDIS_PORT)" | |
| else | |
| echo "==> $ENV_OVERRIDE déjà présent (réutilisé)" | |
| fi | |
| # 1b. Host Symfony (génération d'URL en dev) -> .env.dev.local, si pas déjà défini. | |
| # On y met le host:port effectif pour que les liens générés soient cliquables. | |
| HTTPS_EFF="$(awk -F= '/^HTTPS_PORT=/{print $2}' "$ENV_OVERRIDE")" | |
| if ! grep -qs '^SITE_BASE_HOST=' .env.dev.local; then | |
| cat >> .env.dev.local <<EOF | |
| # Worktree $BRANCH — host utilisé par Symfony pour les URL générées (dev only). | |
| # Généré par bin/worktree-init.sh — gitignoré via .env.*.local | |
| SITE_BASE_SCHEME=https | |
| SITE_BASE_HOST=$WT_HOST:$HTTPS_EFF | |
| EOF | |
| echo "==> .env.dev.local : SITE_BASE_HOST=$WT_HOST:$HTTPS_EFF" | |
| fi | |
| # 2. Copie de la base dev depuis la stack source (avant `up`). | |
| if [ "$SEED_DB" = "1" ]; then | |
| seed_db_volume | |
| else | |
| echo "==> Copie DB désactivée (WORKTREE_SEED_DB=0)." | |
| fi | |
| # 3. Démarrage de la stack (le --env-file n'est requis QUE pour `up`, car seul | |
| # `up` publie des ports ; les commandes `exec`/`run` suivantes retrouvent la | |
| # stack par le nom de projet dérivé du dossier). | |
| echo "==> Démarrage des conteneurs…" | |
| docker compose --env-file .env --env-file "$ENV_OVERRIDE" up --detach --wait | |
| # 3. Dépendances PHP | |
| echo "==> composer install…" | |
| docker compose exec -T php composer install --no-interaction --no-progress | |
| # 4. Dépendances JS + build Vite (service `node`, profil tools) | |
| echo "==> yarn install…" | |
| docker compose run --rm node yarn install --frozen-lockfile | |
| echo "==> yarn build (Vite)…" | |
| docker compose run --rm node yarn build | |
| # NB : ni fixtures ni tests ne sont lancés ici — l'init prépare seulement | |
| # l'environnement. Les commandes ci-dessous restent possibles quand tu veux. | |
| cat <<EOF | |
| ==> Worktree prêt (stack isolée up, dépendances installées, build Vite fait, | |
| base dev clonée depuis $SOURCE_PROJECT). Ni fixtures ni tests lancés : | |
| App (données dev) : https://$WT_HOST:$HTTPS_EFF | |
| (cert Caddy auto-signé par worktree -> accepter l'avertissement, | |
| ou `make trust-cert` depuis ce worktree — note: même nickname | |
| que la stack principale, donc une seule CA de confiance à la fois) | |
| Toute la suite : make test # base cephee_test à part ; charge les fixtures puis paratest | |
| (Re)charger les fixtures : DB_NAME=cephee_test bash bin/load-fixtures.sh | |
| Un fichier : docker compose exec -e APP_ENV=test php vendor/bin/paratest --no-progress tests/Chemin/MonTest.php | |
| Arrêter la stack : docker compose down | |
| (les volumes DB restent isolés de la stack principale suf_sf) | |
| EOF |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment