name: 🚀 Docker Build and Push on: push: branches: - main # Un push qui ne touche que la doc ne reconstruit rien : aucun Markdown n'entre dans # l'image. Un push mêlant code et doc lance toujours la CI. paths-ignore: - '**.md' - 'docs/**' # Chaque nuit (heure UTC) : les images publiées sont testées et, si apt leur propose des mises # à jour, reconstruites et republiées. # Voir docs/decisions/0005-mises-a-jour-nocturnes-pilotees-par-apt.md. schedule: - cron: '30 3 * * *' workflow_dispatch: jobs: build-and-push: runs-on: ubuntu-latest strategy: matrix: pg_version: [15, 16, 17, 18] # Aucune action externe, construction par le démon Docker du runner (sans Buildx) dont le # cache persiste d'une CI à l'autre, et une seule construction par version : l'image testée # est celle qui est poussée. Voir docs/decisions/0004-ci-sans-action-externe.md. env: IMAGE: gitea.killinger.fr/${{ github.repository }} PREVIOUS: postgres-ts-vectors-previous:pg${{ matrix.pg_version }} steps: # Le seul commit poussé, sans historique : c'est tout ce que la construction lit. - 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 # On demande à apt, dans l'image publiée, s'il lui reste des mises à jour : # - oui, ou image jamais publiée : nouvelle clé APT_REFRESH, les couches apt sont rejouées ; # - non : la clé de l'image publiée (label apt-refresh) est reprise et le cache sert. # L'exécution planifiée ne reconstruit ni ne pousse alors rien : elle teste l'image publiée. # L'image publiée est gardée sous $PREVIOUS : les tests y créent une base, que l'image # reconstruite doit savoir reprendre. - name: 🔎 Check for updates id: updates run: | refresh=""; previous="" if docker pull -q "$IMAGE:pg${{ matrix.pg_version }}" >/dev/null 2>&1; then docker tag "$IMAGE:pg${{ matrix.pg_version }}" "$PREVIOUS"; previous="$PREVIOUS" upgrade=$(docker run --rm --entrypoint sh "$PREVIOUS" -c \ 'apt-get update -qq -o APT::Update::Error-Mode=any && apt-get -s upgrade --with-new-pkgs') if pending=$(echo "$upgrade" | grep '^Inst'); then echo "Mises à jour disponibles :"; echo "$pending" else refresh=$(docker image inspect -f '{{ index .Config.Labels "fr.killinger.apt-refresh" }}' "$PREVIOUS") fi fi build=true if [ -n "$refresh" ] && [ "${{ github.event_name }}" = schedule ]; then echo "Image publiée à jour : rien à reconstruire"; build=false; previous="" fi echo "refresh=${refresh:-$(date -u +%Y%m%dT%H%M%SZ)}" >> "$GITHUB_OUTPUT" echo "build=$build" >> "$GITHUB_OUTPUT" echo "previous=$previous" >> "$GITHUB_OUTPUT" # `--pull` : l'image de base (tensorchord/vchord-postgres) est vérifiée à chaque construction, # pour recevoir une republication sous la même étiquette malgré le cache persistant. # Labels OCI propres à la construction ; les labels fixes sont dans le Dockerfile. - name: 📦 Build Docker image if: steps.updates.outputs.build == 'true' run: | docker build --pull \ --build-arg PG_VERSION=${{ matrix.pg_version }} \ --build-arg APT_REFRESH=${{ steps.updates.outputs.refresh }} \ --label fr.killinger.apt-refresh=${{ steps.updates.outputs.refresh }} \ --label org.opencontainers.image.url=https://gitea.killinger.fr/${{ github.repository }} \ --label org.opencontainers.image.revision=${{ github.sha }} \ --label org.opencontainers.image.version=pg${{ matrix.pg_version }} \ --label org.opencontainers.image.created="$(date -u +%Y-%m-%dT%H:%M:%SZ)" \ -t "$IMAGE:pg${{ matrix.pg_version }}" . # La même commande qu'en local. Sans reconstruction, c'est l'image publiée qui est testée. - name: 🧪 Tests run: bash tests.sh "$IMAGE:pg${{ matrix.pg_version }}" ${{ steps.updates.outputs.previous }} # Poussée seulement si les tests sont passés. - name: 🚀 Push Docker image if: steps.updates.outputs.build == 'true' run: docker push -q "$IMAGE:pg${{ matrix.pg_version }}" # Voir docs/decisions/0006-latest-reste-sur-postgresql-17.md. - name: 🏷️ Tag latest (PG17 only) if: steps.updates.outputs.build == 'true' && 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. - name: 🧹 Cleanup Docker images if: always() run: | docker rmi "$PREVIOUS" >/dev/null 2>&1 || true docker builder prune -f --keep-storage 8GB >/dev/null docker image prune -f >/dev/null