152 lines
4.9 KiB
YAML
152 lines
4.9 KiB
YAML
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")
|
||
|
||
# Contenu du compose rendu (une seule ligne, guillemets échappés)
|
||
STACK_FILE_CONTENT=$(sed 's/"/\\"/g' docker-compose.rendered.yml | tr -d '\n')
|
||
|
||
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" \
|
||
--arg content "$STACK_FILE_CONTENT" \
|
||
'{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" \
|
||
--arg content "$STACK_FILE_CONTENT" \
|
||
'{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
|