From 3a691f1a7315e298cbad9a0f4faf8c816c985d94 Mon Sep 17 00:00:00 2001 From: Guilherme Gomes Date: Thu, 2 Jul 2026 18:31:01 -0300 Subject: [PATCH] ci: adiciona pipeline de build/push da imagem Docker Espelha o docker-publish.yml do evo-ai-crm-community e implementa o build por PR previsto no docs/pr-review-testing-workflow.md (secao 6.1). - push main/develop/tags: build multi-arch (amd64+arm64) por digest, merge de manifest e push pro Docker Hub evoapicloud/evo-flow-community (:develop/:develop-, :latest/:main-, :versao). - pull_request: build single-arch amd64 (ambiente de review e uma maquina so), push das tags efemeras :pr- (mutavel, move a cada push) e :sha- (imutavel, do head do PR). concurrency cancela builds de PR superados. Ajustes vs template do CRM: Dockerfile na raiz (./Dockerfile) e sem os build-args de Rails (o Dockerfile do flow, Node/NestJS, nao tem ARGs). --- .github/workflows/docker-publish.yml | 176 +++++++++++++++++++++++++++ 1 file changed, 176 insertions(+) create mode 100644 .github/workflows/docker-publish.yml diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml new file mode 100644 index 0000000..c18652d --- /dev/null +++ b/.github/workflows/docker-publish.yml @@ -0,0 +1,176 @@ +name: Build & Publish Docker Image + +on: + push: + branches: [main, develop] + tags: ["v*.*.*"] + pull_request: + branches: [main, develop] + +permissions: + contents: read + +# PR builds move the mutable :pr- tag on every push — cancel superseded +# runs so a retest always reflects the latest commit. Never cancel a +# push-to-develop/main build (those promote real tags). +concurrency: + group: docker-publish-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + +env: + IMAGE_NAME: evoapicloud/evo-flow-community + +jobs: + # --------------------------------------------------------------------------- + # PR builds: single-arch amd64 (review env is one machine — half the cost of + # multi-arch), pushed to the ephemeral :pr- (mutable, for the reviewer) and + # :sha- (immutable, from the PR head, for audit). See + # docs/pr-review-testing-workflow.md §6.1. + # --------------------------------------------------------------------------- + build-pr: + if: github.event_name == 'pull_request' + name: Build PR image (amd64) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + fetch-depth: 1 + + - uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0 + + - uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Resolve PR tags + id: tags + env: + HEAD_SHA: ${{ github.event.pull_request.head.sha }} + PR_NUMBER: ${{ github.event.pull_request.number }} + run: | + IMAGE="${{ env.IMAGE_NAME }}" + SHA_SHORT="${HEAD_SHA:0:7}" + echo "tags=${IMAGE}:pr-${PR_NUMBER},${IMAGE}:sha-${SHA_SHORT}" >> "$GITHUB_OUTPUT" + + - name: Build and push (amd64) + uses: docker/build-push-action@14487ce63c7a62a4a324b0bfb37086795e31c6c1 # v6.16.0 + with: + context: . + file: ./Dockerfile + platforms: linux/amd64 + push: true + tags: ${{ steps.tags.outputs.tags }} + # Shares the amd64 scope with the branch build so PRs warm off + # develop's cache. GHA ref-scoping keeps PR writes isolated from base. + cache-from: type=gha,scope=linux/amd64 + cache-to: type=gha,scope=linux/amd64,mode=max + + # --------------------------------------------------------------------------- + # Branch/tag builds: multi-arch (amd64 + arm64) by digest, merged into a + # manifest and pushed to the promoted tags (:develop, :latest, :vX.Y.Z). + # --------------------------------------------------------------------------- + build: + if: github.event_name != 'pull_request' + name: Build ${{ matrix.platform == 'linux/amd64' && 'amd64' || 'arm64' }} + runs-on: ${{ matrix.runner }} + strategy: + fail-fast: false + matrix: + include: + - platform: linux/amd64 + runner: ubuntu-latest + - platform: linux/arm64 + runner: ubuntu-24.04-arm + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + fetch-depth: 1 + + - uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0 + + - uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Build and push by digest + id: build + uses: docker/build-push-action@14487ce63c7a62a4a324b0bfb37086795e31c6c1 # v6.16.0 + with: + context: . + file: ./Dockerfile + platforms: ${{ matrix.platform }} + push: true + provenance: mode=max + sbom: true + outputs: type=image,name=${{ env.IMAGE_NAME }},push-by-digest=true,name-canonical=true + cache-from: type=gha,scope=${{ matrix.platform }} + cache-to: type=gha,scope=${{ matrix.platform }},mode=max + + - name: Export digest + run: | + mkdir -p /tmp/digests + digest="${{ steps.build.outputs.digest }}" + touch "/tmp/digests/${digest#sha256:}" + + - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: digest-${{ matrix.platform == 'linux/amd64' && 'amd64' || 'arm64' }} + path: /tmp/digests/* + retention-days: 1 + + merge: + if: github.event_name != 'pull_request' + name: Merge Manifests & Tag + needs: build + runs-on: ubuntu-latest + steps: + - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 + with: + pattern: digest-* + path: /tmp/digests + merge-multiple: true + + - uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0 + + - uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Resolve tags + id: tags + env: + GH_REF: ${{ github.ref }} + GH_REF_NAME: ${{ github.ref_name }} + GH_SHA: ${{ github.sha }} + run: | + IMAGE="${{ env.IMAGE_NAME }}" + SHA_SHORT="${GH_SHA:0:7}" + TAGS="" + + if [[ "${GH_REF}" == refs/tags/v* ]]; then + VERSION="${GH_REF_NAME#v}" + TAGS="${IMAGE}:${VERSION},${IMAGE}:latest" + elif [[ "${GH_REF}" == refs/heads/main ]]; then + TAGS="${IMAGE}:latest,${IMAGE}:main-${SHA_SHORT}" + elif [[ "${GH_REF}" == refs/heads/develop ]]; then + TAGS="${IMAGE}:develop,${IMAGE}:develop-${SHA_SHORT}" + fi + + echo "tags=${TAGS}" >> "$GITHUB_OUTPUT" + + - name: Create and push manifest + working-directory: /tmp/digests + env: + MERGE_TAGS: ${{ steps.tags.outputs.tags }} + run: | + IFS=',' read -ra TAG_ARRAY <<< "${MERGE_TAGS}" + TAG_ARGS="" + for tag in "${TAG_ARRAY[@]}"; do + TAG_ARGS="${TAG_ARGS} -t ${tag}" + done + + docker buildx imagetools create ${TAG_ARGS} \ + $(printf '${{ env.IMAGE_NAME }}@sha256:%s ' *)