From 59363734ff785f0ca7d0b8baaa46b5ade2140b6e Mon Sep 17 00:00:00 2001 From: Lucas Rayan Date: Fri, 30 Oct 2026 08:48:44 -0300 Subject: [PATCH] ci: publish images to the Gitea registry, use the gitea context Release now pushes to git.lucasrguerra.dev.br instead of ghcr.io, tags each architecture separately (no artifact upload, no gha cache) and joins them with imagetools. GITHUB_OUTPUT and GITHUB_STEP_SUMMARY stay: they are the runner's own interface and the GITEA_* equivalents are not set. Co-Authored-By: Claude Sonnet 5.5 --- .env.example | 4 +- .env.production.example | 4 +- .gitea/workflows/ci.yml | 2 +- .gitea/workflows/release.yml | 76 ++++++++++++++---------------------- docker-compose.yaml | 12 +++--- docs/DEPLOYMENT.md | 4 +- 6 files changed, 42 insertions(+), 60 deletions(-) diff --git a/.env.example b/.env.example index ce9df51..e0cf2e1 100644 --- a/.env.example +++ b/.env.example @@ -1,10 +1,10 @@ # --- Container images --- -# Published to GHCR by .github/workflows/release.yml, multi-architecture +# Published to the Gitea registry by .gitea/workflows/release.yml, multi-architecture # (linux/amd64 and linux/arm64). The deploy host pulls these instead of # compiling: `docker compose pull && docker compose up -d`. Running # `docker compose build` locally still overrides them with a local build. # Pin IMAGE_TAG to a released version (e.g. 1.2.3) or a sha- tag to roll back. -IMAGE_NAMESPACE=ghcr.io/lucasrguerra/lambdamail +IMAGE_NAMESPACE=git.lucasrguerra.dev.br/lucasrguerra/lambdamail IMAGE_TAG=latest # --- Postgres --- diff --git a/.env.production.example b/.env.production.example index 4157295..6d3f0e3 100644 --- a/.env.production.example +++ b/.env.production.example @@ -10,9 +10,9 @@ # and must be URL-safe - see the note above them. # --- Container images ------------------------------------------------------- -# Published by .github/workflows/release.yml for linux/amd64 and linux/arm64. +# Published by .gitea/workflows/release.yml for linux/amd64 and linux/arm64. # Pin IMAGE_TAG to a released version or a sha- tag to roll back. -IMAGE_NAMESPACE=ghcr.io/lucasrguerra/lambdamail +IMAGE_NAMESPACE=git.lucasrguerra.dev.br/lucasrguerra/lambdamail IMAGE_TAG=latest # --- Identity --------------------------------------------------------------- diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index a7a5438..3307d32 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -15,7 +15,7 @@ on: workflow_call: concurrency: - group: ci-${{ github.ref }} + group: ci-${{ gitea.ref }} cancel-in-progress: true jobs: diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml index 2f04576..3c2c272 100644 --- a/.gitea/workflows/release.yml +++ b/.gitea/workflows/release.yml @@ -1,8 +1,9 @@ name: Release -# Publishes the four service images to GHCR after a merge into main, and again -# under semver tags when a v* tag is pushed. The deploy host only pulls, so -# nothing has to be built on the server. +# Publishes the service images to the Gitea container registry after a merge +# into main, and again under semver tags when a v* tag is pushed. The deploy +# host only pulls, so nothing has to be built on the server. Needs the user +# secret REGISTRY_TOKEN (a Gitea token with the write:package scope). on: push: branches: [main] @@ -14,15 +15,15 @@ concurrency: cancel-in-progress: false env: - REGISTRY: ghcr.io + REGISTRY: git.lucasrguerra.dev.br jobs: # Nothing is published unless the full suite passes first. ci: - uses: ./.github/workflows/ci.yml + uses: ./.gitea/workflows/ci.yml - # GHCR rejects an uppercase path, and this repository is "lucasrguerra/LambdaMail". - # Lowercasing github.repository here keeps the workflow fork-safe instead of + # Registry paths must be lowercase, and this repository is "lucasrguerra/LambdaMail". + # Lowercasing gitea.repository here keeps the workflow fork-safe instead of # hardcoding the owner. prepare: name: Namespace das imagens @@ -31,7 +32,10 @@ jobs: namespace: ${{ steps.namespace.outputs.value }} steps: - id: namespace - run: echo "value=${GITHUB_REPOSITORY,,}" >> "$GITHUB_OUTPUT" + # GITHUB_OUTPUT is the runner's own interface: Gitea sets it under that name. + run: | + repo='${{ gitea.repository }}' + echo "value=${repo,,}" >> "$GITHUB_OUTPUT" # Each architecture is built on a runner of its own kind. QEMU emulation # would also work, but it makes the Go and Next builds roughly an order of @@ -54,7 +58,7 @@ jobs: platform: [linux/amd64, linux/arm64] include: - platform: linux/amd64 - runner: ubuntu-latest + runner: linux-amd64 arch: amd64 - platform: linux/arm64 runner: ubuntu-24.04-arm @@ -64,12 +68,12 @@ jobs: - uses: docker/setup-buildx-action@v4 - - name: Autentica no GHCR + - name: Autentica no registro uses: docker/login-action@v4 with: registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} + username: ${{ gitea.actor }} + password: ${{ secrets.REGISTRY_TOKEN }} - name: Metadados id: meta @@ -77,9 +81,10 @@ jobs: with: images: ${{ env.REGISTRY }}/${{ needs.prepare.outputs.namespace }}/${{ matrix.service }} - # Pushed by digest only: the tags are attached later, once both - # architectures exist and can be joined into a single manifest list. - - name: Build e push por digest + # Each architecture is pushed under its own tag (no digest artifacts: they + # are not portable to Gitea). The final tags are attached later, once both + # exist and can be joined into a single manifest list. + - name: Build e push por arquitetura id: build uses: docker/build-push-action@v7 with: @@ -87,26 +92,10 @@ jobs: file: services/${{ matrix.service }}/Dockerfile platforms: ${{ matrix.platform }} labels: ${{ steps.meta.outputs.labels }} - outputs: type=image,name=${{ env.REGISTRY }}/${{ needs.prepare.outputs.namespace }}/${{ matrix.service }},push-by-digest=true,name-canonical=true,push=true - cache-from: type=gha,scope=${{ matrix.service }}-${{ matrix.arch }} - cache-to: type=gha,mode=max,scope=${{ matrix.service }}-${{ matrix.arch }} - - - name: Exporta o digest - run: | - mkdir -p /tmp/digests - # The output already carries the `sha256:` prefix; the file name must - # not, since the merge step prepends it again. - digest='${{ steps.build.outputs.digest }}' - touch "/tmp/digests/${digest#sha256:}" - - - name: Guarda o digest - uses: actions/upload-artifact@v7 - with: - # Slashes are not allowed in artifact names, hence the arch alias. - name: digest-${{ matrix.service }}-${{ matrix.arch }} - path: /tmp/digests/* - retention-days: 1 - if-no-files-found: error + push: true + tags: ${{ env.REGISTRY }}/${{ needs.prepare.outputs.namespace }}/${{ matrix.service }}:build-${{ gitea.sha }}-${{ matrix.arch }} + cache-from: type=registry,ref=${{ env.REGISTRY }}/${{ needs.prepare.outputs.namespace }}/${{ matrix.service }}:buildcache-${{ matrix.arch }} + cache-to: type=registry,ref=${{ env.REGISTRY }}/${{ needs.prepare.outputs.namespace }}/${{ matrix.service }}:buildcache-${{ matrix.arch }},mode=max publish: name: Publica ${{ matrix.service }} @@ -124,19 +113,12 @@ jobs: - uses: docker/setup-buildx-action@v4 - - name: Autentica no GHCR + - name: Autentica no registro uses: docker/login-action@v4 with: registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Recupera os digests - uses: actions/download-artifact@v7 - with: - pattern: digest-${{ matrix.service }}-* - merge-multiple: true - path: /tmp/digests + username: ${{ gitea.actor }} + password: ${{ secrets.REGISTRY_TOKEN }} # `latest` is what compose pulls. The semver tags only materialise on a # v* tag push and make it possible to pin or roll back to an exact @@ -156,11 +138,11 @@ jobs: # Joins both architectures under one manifest list, so `docker pull` # resolves to the right one automatically. - name: Cria o manifesto multi-arquitetura - working-directory: /tmp/digests run: | + image='${{ env.REGISTRY }}/${{ needs.prepare.outputs.namespace }}/${{ matrix.service }}' docker buildx imagetools create \ $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< '${{ steps.meta.outputs.json }}') \ - $(printf '${{ env.REGISTRY }}/${{ needs.prepare.outputs.namespace }}/${{ matrix.service }}@sha256:%s ' *) + "$image:build-${{ gitea.sha }}-amd64" "$image:build-${{ gitea.sha }}-arm64" - name: Confere o resultado run: | diff --git a/docker-compose.yaml b/docker-compose.yaml index 2a0e2a8..a450802 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -60,7 +60,7 @@ services: # probe - a health check on a container that is meant to stop would report # unhealthy exactly when it has done its job. migrate: - image: ${IMAGE_NAMESPACE:-ghcr.io/lucasrguerra/lambdamail}/migrations:${IMAGE_TAG:-latest} + image: ${IMAGE_NAMESPACE:-git.lucasrguerra.dev.br/lucasrguerra/lambdamail}/migrations:${IMAGE_TAG:-latest} # "latest" is a moving tag and Docker considers a tag it already holds # locally to be satisfied, so recreating this container silently reused # the cached image and the newly published one was never fetched: the @@ -80,7 +80,7 @@ services: # ------------------------------------------------------------ RSPAMD rspamd: - image: ${IMAGE_NAMESPACE:-ghcr.io/lucasrguerra/lambdamail}/rspamd:${IMAGE_TAG:-latest} + image: ${IMAGE_NAMESPACE:-git.lucasrguerra.dev.br/lucasrguerra/lambdamail}/rspamd:${IMAGE_TAG:-latest} # "latest" is a moving tag and Docker considers a tag it already holds # locally to be satisfied, so recreating this container silently reused # the cached image and the newly published one was never fetched: the @@ -140,7 +140,7 @@ services: # -------------------------------------------------------------- AUTH auth: - image: ${IMAGE_NAMESPACE:-ghcr.io/lucasrguerra/lambdamail}/auth:${IMAGE_TAG:-latest} + image: ${IMAGE_NAMESPACE:-git.lucasrguerra.dev.br/lucasrguerra/lambdamail}/auth:${IMAGE_TAG:-latest} # "latest" is a moving tag and Docker considers a tag it already holds # locally to be satisfied, so recreating this container silently reused # the cached image and the newly published one was never fetched: the @@ -178,7 +178,7 @@ services: # ----------------------------------------------------------- STORAGE storage: - image: ${IMAGE_NAMESPACE:-ghcr.io/lucasrguerra/lambdamail}/storage:${IMAGE_TAG:-latest} + image: ${IMAGE_NAMESPACE:-git.lucasrguerra.dev.br/lucasrguerra/lambdamail}/storage:${IMAGE_TAG:-latest} # "latest" is a moving tag and Docker considers a tag it already holds # locally to be satisfied, so recreating this container silently reused # the cached image and the newly published one was never fetched: the @@ -214,7 +214,7 @@ services: # --------------------------------------------------------- PROTOCOLS protocols: - image: ${IMAGE_NAMESPACE:-ghcr.io/lucasrguerra/lambdamail}/protocols:${IMAGE_TAG:-latest} + image: ${IMAGE_NAMESPACE:-git.lucasrguerra.dev.br/lucasrguerra/lambdamail}/protocols:${IMAGE_TAG:-latest} # "latest" is a moving tag and Docker considers a tag it already holds # locally to be satisfied, so recreating this container silently reused # the cached image and the newly published one was never fetched: the @@ -297,7 +297,7 @@ services: # -------------------------------------------------------------- WEB web: - image: ${IMAGE_NAMESPACE:-ghcr.io/lucasrguerra/lambdamail}/webmail:${IMAGE_TAG:-latest} + image: ${IMAGE_NAMESPACE:-git.lucasrguerra.dev.br/lucasrguerra/lambdamail}/webmail:${IMAGE_TAG:-latest} # "latest" is a moving tag and Docker considers a tag it already holds # locally to be satisfied, so recreating this container silently reused # the cached image and the newly published one was never fetched: the diff --git a/docs/DEPLOYMENT.md b/docs/DEPLOYMENT.md index c43357f..7b4d411 100644 --- a/docs/DEPLOYMENT.md +++ b/docs/DEPLOYMENT.md @@ -176,7 +176,7 @@ have propagated and the IP has some sending history. ## Upgrading -Images are published to GHCR for `linux/amd64` and `linux/arm64` on every merge +Images are published to the Gitea container registry for `linux/amd64` and `linux/arm64` on every merge to `main`. ```bash @@ -198,7 +198,7 @@ every release, which is what forces the pull. IMAGE_TAG=sha- The tags are published by `release.yml`; `docker buildx imagetools inspect -ghcr.io//lambdamail/webmail:latest` shows what `latest` currently points +git.lucasrguerra.dev.br//lambdamail/webmail:latest` shows what `latest` currently points at. **Pinning has a second edge: bump it on every release.** A pinned tag is an