diff --git a/.github/workflows/build-image.yaml b/.github/workflows/build-image.yaml new file mode 100644 index 0000000..3246c82 --- /dev/null +++ b/.github/workflows/build-image.yaml @@ -0,0 +1,105 @@ +name: Build and Push Image + +on: + workflow_call: + inputs: + mode: + description: "Build mode: 'prod' or 'pr'" + required: true + type: string + image_repo: + description: "Docker image repository (e.g., user/app)" + required: false + default: "lukastrkan/cc-app-demo" + type: string + context: + description: "Docker build context path" + required: false + default: "7project/backend" + type: string + pr_number: + description: "PR number (required when mode=pr)" + required: false + type: string + secrets: + DOCKER_USER: + required: true + DOCKER_PASSWORD: + required: true + outputs: + digest: + description: "Built image digest" + value: ${{ jobs.build.outputs.digest }} + image_repo: + description: "Image repository used" + value: ${{ jobs.build.outputs.image_repo }} + +jobs: + build: + runs-on: ubuntu-latest + outputs: + digest: ${{ steps.set.outputs.digest }} + image_repo: ${{ steps.set.outputs.image_repo }} + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + id: buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USER }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Compute image repo and tags + id: meta + env: + MODE: ${{ inputs.mode }} + IMAGE_REPO: ${{ inputs.image_repo }} + PR: ${{ inputs.pr_number }} + run: | + set -euo pipefail + if [ -z "${IMAGE_REPO:-}" ]; then IMAGE_REPO="lukastrkan/cc-app-demo"; fi + echo "IMAGE_REPO=$IMAGE_REPO" >> $GITHUB_ENV + SHA_SHORT="${GITHUB_SHA::12}" + case "$MODE" in + prod) + TAG1="prod-$SHA_SHORT" + TAG2="latest" + ;; + pr) + if [ -z "${PR:-}" ]; then echo "pr_number input is required for mode=pr"; exit 1; fi + TAG1="pr-$PR" + TAG2="pr-$PR-$SHA_SHORT" + ;; + *) + echo "Unknown mode '$MODE' (expected 'prod' or 'pr')"; exit 1; + ;; + esac + echo "TAG1=$TAG1" >> $GITHUB_ENV + echo "TAG2=$TAG2" >> $GITHUB_ENV + + - name: Build and push image + id: build + uses: docker/build-push-action@v5 + with: + context: ${{ inputs.context }} + push: true + tags: | + ${{ env.IMAGE_REPO }}:${{ env.TAG1 }} + ${{ env.IMAGE_REPO }}:${{ env.TAG2 }} + platforms: linux/amd64 + + - name: Set outputs + id: set + env: + IMAGE_REPO: ${{ env.IMAGE_REPO }} + run: | + echo "digest=${{ steps.build.outputs.digest }}" >> $GITHUB_OUTPUT + echo "image_repo=$IMAGE_REPO" >> $GITHUB_OUTPUT diff --git a/.github/workflows/deploy-pr.yaml b/.github/workflows/deploy-pr.yaml index c1ca03e..7e7b5d1 100644 --- a/.github/workflows/deploy-pr.yaml +++ b/.github/workflows/deploy-pr.yaml @@ -9,6 +9,17 @@ permissions: pull-requests: write jobs: + build: + if: github.event.action != 'closed' + name: Build and push image (reusable) + uses: ./.github/workflows/build-image.yaml + with: + mode: pr + image_repo: lukastrkan/cc-app-demo + context: 7project/backend + pr_number: ${{ github.event.pull_request.number }} + secrets: inherit + deploy: if: github.event.action != 'closed' name: Helm upgrade/install (PR preview) @@ -16,6 +27,7 @@ jobs: concurrency: group: pr-${{ github.event.pull_request.number }} cancel-in-progress: false + needs: [build] steps: - name: Checkout uses: actions/checkout@v4 @@ -36,45 +48,13 @@ jobs: echo "$KUBE_CONFIG" > ~/.kube/config chmod 600 ~/.kube/config - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 - - - name: Set up Docker Buildx - id: buildx - uses: docker/setup-buildx-action@v3 - - - name: Log in to Docker Hub - uses: docker/login-action@v3 - with: - username: ${{ secrets.DOCKER_USER }} - password: ${{ secrets.DOCKER_PASSWORD }} - - - name: Compute image repo and tags (PR) - run: | - IMAGE_REPO="${IMAGE_REPO:-lukastrkan/cc-app-demo}" - echo "IMAGE_REPO=$IMAGE_REPO" >> $GITHUB_ENV - PR=${{ github.event.pull_request.number }} - SHA_SHORT="${GITHUB_SHA::12}" - echo "TAG1=pr-$PR" >> $GITHUB_ENV - echo "TAG2=pr-$PR-$SHA_SHORT" >> $GITHUB_ENV - - - name: Build and push image - id: build - uses: docker/build-push-action@v5 - with: - context: 7project/backend - push: true - tags: | - ${{ env.IMAGE_REPO }}:${{ env.TAG1 }} - ${{ env.IMAGE_REPO }}:${{ env.TAG2 }} - platforms: linux/amd64 - - name: Helm upgrade/install PR preview env: DEV_BASE_DOMAIN: ${{ secrets.BASE_DOMAIN }} RABBITMQ_PASSWORD: ${{ secrets.RABBITMQ_PASSWORD }} DB_PASSWORD: ${{ secrets.DB_PASSWORD }} - IMAGE_REPO: ${{ env.IMAGE_REPO }} + IMAGE_REPO: ${{ needs.build.outputs.image_repo }} + DIGEST: ${{ needs.build.outputs.digest }} run: | PR=${{ github.event.pull_request.number }} if [ -z "$PR" ]; then echo "PR number missing"; exit 1; fi @@ -84,7 +64,6 @@ jobs: RELEASE=myapp-pr-$PR NAMESPACE=pr-$PR DOMAIN=pr-$PR.$DEV_BASE_DOMAIN - DIGEST='${{ steps.build.outputs.digest }}' if [ -z "$IMAGE_REPO" ]; then IMAGE_REPO="lukastrkan/cc-app-demo"; fi helm upgrade --install "$RELEASE" ./7project/charts/myapp-chart \ -n "$NAMESPACE" --create-namespace \ diff --git a/.github/workflows/deploy-prod.yaml b/.github/workflows/deploy-prod.yaml index 82fcc93..c1a6c28 100644 --- a/.github/workflows/deploy-prod.yaml +++ b/.github/workflows/deploy-prod.yaml @@ -16,9 +16,19 @@ concurrency: cancel-in-progress: false jobs: + build: + name: Build and push image (reusable) + uses: ./.github/workflows/build-image.yaml + with: + mode: prod + image_repo: lukastrkan/cc-app-demo + context: 7project/backend + secrets: inherit + deploy: name: Helm upgrade/install (prod) runs-on: vhs + needs: [build] steps: - name: Checkout uses: actions/checkout@v4 @@ -39,44 +49,13 @@ jobs: echo "$KUBE_CONFIG" > ~/.kube/config chmod 600 ~/.kube/config - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 - - - name: Set up Docker Buildx - id: buildx - uses: docker/setup-buildx-action@v3 - - - name: Log in to Docker Hub - uses: docker/login-action@v3 - with: - username: ${{ secrets.DOCKER_USER }} - password: ${{ secrets.DOCKER_PASSWORD }} - - - name: Compute image repo and tags (prod) - run: | - IMAGE_REPO="${IMAGE_REPO:-lukastrkan/cc-app-demo}" - echo "IMAGE_REPO=$IMAGE_REPO" >> $GITHUB_ENV - SHA_SHORT="${GITHUB_SHA::12}" - echo "TAG1=prod-$SHA_SHORT" >> $GITHUB_ENV - echo "TAG2=latest" >> $GITHUB_ENV - - - name: Build and push image - id: build - uses: docker/build-push-action@v5 - with: - context: 7project/backend - push: true - tags: | - ${{ env.IMAGE_REPO }}:${{ env.TAG1 }} - ${{ env.IMAGE_REPO }}:${{ env.TAG2 }} - platforms: linux/amd64 - - name: Helm upgrade/install prod env: DOMAIN: ${{ secrets.PROD_DOMAIN }} RABBITMQ_PASSWORD: ${{ secrets.PROD_RABBITMQ_PASSWORD }} DB_PASSWORD: ${{ secrets.PROD_DB_PASSWORD }} - IMAGE_REPO: ${{ env.IMAGE_REPO }} + IMAGE_REPO: ${{ needs.build.outputs.image_repo }} + DIGEST: ${{ needs.build.outputs.digest }} run: | if [ -z "$DOMAIN" ]; then echo "Secret PROD_DOMAIN is required (e.g., app.example.com)"; exit 1; fi @@ -84,7 +63,6 @@ jobs: echo "Secret PROD_RABBITMQ_PASSWORD is required"; exit 1; fi if [ -z "$DB_PASSWORD" ]; then echo "Secret PROD_DB_PASSWORD is required"; exit 1; fi - DIGEST="${{ steps.build.outputs.digest }}" if [ -z "$IMAGE_REPO" ]; then IMAGE_REPO="lukastrkan/cc-app-demo"; fi helm upgrade --install myapp ./7project/charts/myapp-chart \ -n prod --create-namespace \