stages: - test - build - deploy variables: DOCKER_DRIVER: overlay2 # 1️⃣ Tests Laravel (SQLite en mémoire) test: stage: test image: laravelsail/php84-composer variables: APP_ENV: testing APP_KEY: base64:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= DB_CONNECTION: sqlite DB_DATABASE: ":memory:" before_script: - apt-get update && apt-get install -y git zip unzip - composer install --no-interaction --prefer-dist # on génère un .env de base pour que Laravel soit content - cp .env.example .env || touch .env script: - php artisan test # 2️⃣ Build + push image dans le registry GitLab docker-build-push: stage: build image: docker:24 services: - docker:24-dind variables: DOCKER_TLS_CERTDIR: "/certs" IMAGE_TAG: "$CI_REGISTRY_IMAGE:${CI_COMMIT_SHORT_SHA}" before_script: # Login au registry GitLab - echo "$CI_REGISTRY_PASSWORD" | docker login -u "$CI_REGISTRY_USER" --password-stdin "$CI_REGISTRY" script: # Build de l'image à partir du Dockerfile de la racine - docker build -t "$IMAGE_TAG" . # Tag 'latest' en plus (optionnel mais pratique) - docker tag "$IMAGE_TAG" "$CI_REGISTRY_IMAGE:latest" # Push des tags - docker push "$IMAGE_TAG" - docker push "$CI_REGISTRY_IMAGE:latest" only: - main # 3️⃣ Déploiement : création / update de la stack Portainer via API deploy-to-portainer: stage: deploy image: alpine:latest needs: - docker-build-push only: - main before_script: - apk add --no-cache curl jq gettext script: - echo "📦 Génération du docker-compose.rendered.yml avec les variables de prod..." - envsubst < docker-compose.prod.yml > docker-compose.rendered.yml - | echo "🔍 Vérif des variables Portainer..." echo "PORTAINER_URL=$PORTAINER_URL" echo "PORTAINER_ENDPOINT_ID=$PORTAINER_ENDPOINT_ID" echo "PORTAINER_STACK_NAME=$PORTAINER_STACK_NAME" echo "🔍 Test de connexion à $PORTAINER_URL/api/stacks ..." RESP=$(curl -s -w "HTTPSTATUS:%{http_code}" -H "X-API-Key: $PORTAINER_API_KEY" "$PORTAINER_URL/api/stacks") BODY=$(echo "$RESP" | sed -e 's/HTTPSTATUS:.*//g') STATUS=$(echo "$RESP" | tr -d '\n' | sed -e 's/.*HTTPSTATUS://') echo "➡️ HTTP status: $STATUS" echo "➡️ Body: $BODY" if [ "$STATUS" != "200" ]; then echo "❌ Erreur HTTP $STATUS en appelant l'API Portainer. Vérifie PORTAINER_URL / le port / l'accessibilité." exit 1 fi echo "✅ Connexion Portainer OK, on continue..." STACKS_JSON="$BODY" STACK_ID=$(echo "$STACKS_JSON" | jq ".[] | select(.Name == \"$PORTAINER_STACK_NAME\") | .Id") STACK_FILE_PATH="docker-compose.rendered.yml" if [ -z "$STACK_ID" ]; then echo "🆕 Aucune stack '$PORTAINER_STACK_NAME' trouvée, création en cours..." JSON_PAYLOAD=$(jq -n \ --arg name "$PORTAINER_STACK_NAME" \ --rawfile content "$STACK_FILE_PATH" \ '{name: $name, stackFileContent: $content, prune: true}') CREATE_RESP=$(curl -s -w "HTTPSTATUS:%{http_code}" \ -X POST "$PORTAINER_URL/api/stacks/create/standalone/string?endpointId=$PORTAINER_ENDPOINT_ID" \ -H "X-API-Key: $PORTAINER_API_KEY" \ -H "Content-Type: application/json" \ --data "$JSON_PAYLOAD") CREATE_BODY=$(echo "$CREATE_RESP" | sed -e 's/HTTPSTATUS:.*//g') CREATE_STATUS=$(echo "$CREATE_RESP" | tr -d '\n' | sed -e 's/.*HTTPSTATUS://') echo "➡️ Create status: $CREATE_STATUS" echo "➡️ Create body: $CREATE_BODY" if [ "$CREATE_STATUS" != "200" ] && [ "$CREATE_STATUS" != "201" ]; then echo "❌ Erreur lors de la création de la stack (HTTP $CREATE_STATUS)" exit 1 fi echo "✅ Stack créée." else echo "♻️ Stack '$PORTAINER_STACK_NAME' trouvée (ID=$STACK_ID), mise à jour..." JSON_PAYLOAD=$(jq -n \ --arg id "$STACK_ID" \ --rawfile content "$STACK_FILE_PATH" \ '{id: ($id|tonumber), stackFileContent: $content, prune: true}') UPDATE_RESP=$(curl -s -w "HTTPSTATUS:%{http_code}" \ -X PUT "$PORTAINER_URL/api/stacks/$STACK_ID?endpointId=$PORTAINER_ENDPOINT_ID" \ -H "X-API-Key: $PORTAINER_API_KEY" \ -H "Content-Type: application/json" \ --data "$JSON_PAYLOAD") UPDATE_BODY=$(echo "$UPDATE_RESP" | sed -e 's/HTTPSTATUS:.*//g') UPDATE_STATUS=$(echo "$UPDATE_RESP" | tr -d '\n' | sed -e 's/.*HTTPSTATUS://') echo "➡️ Update status: $UPDATE_STATUS" echo "➡️ Update body: $UPDATE_BODY" if [ "$UPDATE_STATUS" != "200" ]; then echo "❌ Erreur lors de la mise à jour de la stack (HTTP $UPDATE_STATUS)" exit 1 fi echo "✅ Stack mise à jour." fi