diff --git a/.gitea/workflows/docker.yml b/.gitea/workflows/docker.yml new file mode 100644 index 0000000..1853012 --- /dev/null +++ b/.gitea/workflows/docker.yml @@ -0,0 +1,103 @@ +name: 🚀 Docker Build and Push + +on: + push: + branches: + - main + +jobs: + build-and-push: + runs-on: ubuntu-latest + strategy: + matrix: + pg_version: [15, 16, 17] + # Accélération (2026-09-27) : + # - aucune action externe : checkout, login et build-push étaient téléchargés depuis GitHub à + # chaque job, ~20 s par action ; + # - construction par le démon Docker du runner, sans Buildx : « Set up Docker Buildx » créait + # un constructeur neuf, sans cache, et TimescaleDB était recompilé à chaque job (7 à 9 min). + # Le cache du démon persiste d'une CI à l'autre : la compilation n'est rejouée que si la + # version de TimescaleDB, de PostgreSQL ou l'image de base change ; + # - une seule construction : l'image testée est celle qui est poussée (étiquetage), au lieu de + # la reconstruire pour le push puis pour `latest`. + env: + IMAGE: gitea.killinger.fr/${{ github.repository }} + TEST: pg${{ matrix.pg_version }}-test-${{ github.run_id }} + steps: + - name: 📥 Checkout code + env: + TOKEN: ${{ github.token }} + run: | + git init -q . + git fetch -q --depth 1 "https://oauth2:${TOKEN}@gitea.killinger.fr/${{ github.repository }}.git" "${{ github.sha }}" + git checkout -q FETCH_HEAD + + - name: 🔐 Login to Gitea Registry + env: + DOCKER_TOKEN: ${{ secrets.DOCKER_TOKEN }} + run: echo "$DOCKER_TOKEN" | docker login gitea.killinger.fr -u maxime.killinger --password-stdin + + # `--pull` : l'image de base (tensorchord/vchord-postgres) est vérifiée à chaque construction, + # sinon ses correctifs de sécurité ne seraient jamais repris avec le cache persistant. + - name: 📦 Build Docker image + run: | + docker build --pull \ + --build-arg PG_VERSION=${{ matrix.pg_version }} \ + --label org.opencontainers.image.revision=${{ github.sha }} \ + --label org.opencontainers.image.created="$(date -u +%Y-%m-%dT%H:%M:%SZ)" \ + -t "$IMAGE:pg${{ matrix.pg_version }}" . + + # Prête quand l'initialisation est terminée (extensions créées, serveur temporaire arrêté) ET + # que le serveur définitif accepte les connexions — au lieu d'un `sleep 10` fixe. + - name: 🧪 Test image - Start container + run: | + docker run -d --name "$TEST" -e POSTGRES_PASSWORD=testpass "$IMAGE:pg${{ matrix.pg_version }}" >/dev/null + for i in $(seq 1 90); do + if docker logs "$TEST" 2>&1 | grep -q "PostgreSQL init process complete" \ + && docker exec "$TEST" pg_isready -U postgres -q; then + echo "PostgreSQL prêt en ${i} s"; exit 0 + fi + sleep 1 + done + docker logs "$TEST" 2>&1 | tail -30 + exit 1 + + - name: ⚙️ Setup Tests + run: docker cp tests/ "$TEST":/tmp/tests/ + + - name: "🧪 Test 1: Configuration" + run: docker exec "$TEST" psql -U postgres -f /tmp/tests/test-1-config.sql + + - name: "🧪 Test 2: TimescaleDB" + run: docker exec "$TEST" psql -U postgres -f /tmp/tests/test-2-timescale.sql + + - name: "🧪 Test 3: VectorChord" + run: docker exec "$TEST" psql -U postgres -f /tmp/tests/test-3-vector.sql + + - name: "🧪 Test 4: Hybrid Scenarios" + run: docker exec "$TEST" psql -U postgres -f /tmp/tests/test-4-hybrid.sql + + - name: "🧪 Test 5: PostGIS" + run: docker exec "$TEST" psql -U postgres -f /tmp/tests/test-5-postgis.sql + + - name: 🧹 Cleanup test container + if: always() + run: docker rm -f "$TEST" >/dev/null 2>&1 || true + + # Poussée seulement si tous les tests sont passés (étapes précédentes sans `if: always()`). + - name: 🚀 Push Docker image + run: docker push -q "$IMAGE:pg${{ matrix.pg_version }}" + + - name: 🏷️ Tag latest (PG17 only) + if: matrix.pg_version == 17 + run: | + docker tag "$IMAGE:pg17" "$IMAGE:latest" + docker push -q "$IMAGE:latest" + + # Cache borné : il ne doit pas remplir le disque de Tower (la compilation de TimescaleDB + # pour trois versions de PostgreSQL y tient largement). + - name: 🧹 Cleanup Docker images + if: always() + run: | + docker builder prune -f --keep-storage 8GB >/dev/null + docker image prune -f >/dev/null