name: Laravel CI-CD on: push: branches: ["main"] env: REGISTRY: gitea.leonmorival.com IMAGE_NAME: daily_meal/bemeal-api jobs: # ========================= # TESTS # ========================= test: name: Tests Unitaires runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 - name: Run Tests uses: docker://laravelsail/php84-composer:latest env: APP_ENV: testing APP_KEY: base64:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= DB_CONNECTION: sqlite DB_DATABASE: ":memory:" with: args: > bash -c "composer install --no-interaction --ignore-platform-req=ext-intl && php artisan test" # ========================= # BUILD & PUSH # ========================= build: name: Build & Push Docker needs: test runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 - name: Login to Gitea Registry run: | echo "${{ secrets.TOKEN_GITEA }}" \ | docker login $REGISTRY \ -u "${{ github.actor }}" \ --password-stdin - name: Build & Push image run: | IMAGE=$REGISTRY/$IMAGE_NAME docker build -t "$IMAGE:${{ github.sha }}" -t "$IMAGE:latest" . docker push "$IMAGE:${{ github.sha }}" docker push "$IMAGE:latest" # ========================= # DEPLOY BLUE / GREEN (CADDY GÈRE LE ROUTING) # ========================= deploy: name: Deploy Blue/Green (Caddy routing) needs: build runs-on: ubuntu-latest steps: - name: Checkout deploy files uses: actions/checkout@v4 - name: Upload docker-compose uses: appleboy/scp-action@v0.1.7 with: host: ${{ secrets.SSH_HOST }} username: ${{ secrets.SSH_USER }} key: ${{ secrets.SSH_PRIVATE_KEY }} source: docker-compose.prod.yml target: /opt/bemeal - name: Deploy via SSH uses: appleboy/ssh-action@v1.0.3 env: IMAGE_TAG: ${{ github.sha }} REGISTRY: gitea.leonmorival.com IMAGE_NAME: daily_meal/bemeal-api with: host: ${{ secrets.SSH_HOST }} username: ${{ secrets.SSH_USER }} key: ${{ secrets.SSH_PRIVATE_KEY }} envs: IMAGE_TAG,REGISTRY,IMAGE_NAME script: | set -eu cd /opt/bemeal ls -la COMPOSE="docker compose --env-file .env.prod -f /opt/bemeal/docker-compose.prod.yml" IMAGE="$REGISTRY/$IMAGE_NAME:$IMAGE_TAG" docker pull "$IMAGE" echo "Deploy shared infra" $COMPOSE up -d pgsql redis meilisearch # detect active ACTIVE="" if docker ps | grep -q bemeal-api-blue && \ [ "$(docker inspect -f '{{.State.Health.Status}}' bemeal-api-blue 2>/dev/null || true)" = "healthy" ]; then ACTIVE=blue fi if docker ps | grep -q bemeal-api-green && \ [ "$(docker inspect -f '{{.State.Health.Status}}' bemeal-api-green 2>/dev/null || true)" = "healthy" ]; then ACTIVE=green fi if [ "$ACTIVE" = "blue" ]; then TARGET=green else TARGET=blue fi TARGET_SERVICE="bemeal-api-$TARGET" echo "Deploy $TARGET_SERVICE" IMAGE="$IMAGE" $COMPOSE up -d --no-deps --force-recreate "$TARGET_SERVICE" # wait health for i in $(seq 1 60); do STATUS=$(docker inspect -f '{{.State.Health.Status}}' "$TARGET_SERVICE" || true) [ "$STATUS" = "healthy" ] && break sleep 2 done [ "$STATUS" != "healthy" ] && exit 1 # 👉 SWITCH ULTRA SIMPLE echo "bemeal-api-$TARGET" > /opt/caddy/active docker exec caddy caddy reload