From 991be7a55d37e5ca0b53a61de1be3cb0db111c14 Mon Sep 17 00:00:00 2001 From: Yannik Zbick Date: Mon, 19 Oct 2026 17:07:19 +0200 Subject: [PATCH] feat(proxy): setup dev deployment workflow --- .github/workflows/deploy-data-dev.yml | 300 ++++++++++++++++++++++++++ 1 file changed, 300 insertions(+) create mode 100644 .github/workflows/deploy-data-dev.yml diff --git a/.github/workflows/deploy-data-dev.yml b/.github/workflows/deploy-data-dev.yml new file mode 100644 index 000000000000..16f1d4631c59 --- /dev/null +++ b/.github/workflows/deploy-data-dev.yml @@ -0,0 +1,300 @@ +name: Deploy Data Reply DEV Instance + +on: + workflow_dispatch: + inputs: + force_build: + description: 'Force rebuild all images' + type: boolean + default: true + + +permissions: + id-token: write + contents: read + +defaults: + run: + shell: bash + working-directory: ./terraform/litellm/aws/ + +env: + AWS_REGION: eu-central-1 + IMAGE_TAG: ${{ github.sha }} + +jobs: + terraform: + name: Terraform Deploy DEV + if: github.ref == 'refs/heads/datareply/dev' + runs-on: ubuntu-latest + + steps: + - name: Checkout Code + uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 + with: + fetch-depth: 0 + + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@7474bc4690e29a8392af63c5b98e7449536d5c3a # v4.3.1 + with: + audience: sts.amazonaws.com + role-to-assume: arn:aws:iam::${{ vars.AWS_ACCOUNT_ID }}:role/github-oidc-provider-role + role-session-name: github-actions + aws-region: ${{ env.AWS_REGION }} + + - name: Setup Terraform + uses: hashicorp/setup-terraform@b9cd54a3c349d3f38e8881555d616ced269862dd # v3.1.2 + with: + terraform_version: "1.15.7" + + - name: Detect image-related changes + id: image_changes + env: + BEFORE_SHA: ${{ github.event.before }} + run: | + if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then + if [ "${{ inputs.force_build }}" = "true" ]; then + base_ref="" # force all builds + else + base_ref="HEAD^" + fi + elif [ "${{ github.event_name }}" = "push" ] && \ + [ -n "$BEFORE_SHA" ] && \ + [ "$BEFORE_SHA" != "0000000000000000000000000000000000000000" ]; then + base_ref="$BEFORE_SHA" + elif git rev-parse --verify HEAD^ >/dev/null 2>&1; then + base_ref="HEAD^" + else + base_ref="" + fi + + if [ -z "$base_ref" ]; then + { + echo "gateway_changed=true" + echo "backend_changed=true" + echo "ui_changed=true" + echo "migrations_changed=true" + } >> "$GITHUB_OUTPUT" + exit 0 + fi + + if git diff --quiet "$base_ref"...HEAD -- \ + .dockerignore \ + gateway/ \ + litellm/ \ + litellm-proxy-extras/ \ + enterprise/ \ + pyproject.toml \ + uv.lock \ + schema.prisma; then + gateway_changed=false + else + gateway_changed=true + fi + + if git diff --quiet "$base_ref"...HEAD -- \ + .dockerignore \ + backend/ \ + litellm/ \ + litellm-proxy-extras/ \ + enterprise/ \ + pyproject.toml \ + uv.lock \ + schema.prisma; then + backend_changed=false + else + backend_changed=true + fi + + if git diff --quiet "$base_ref"...HEAD -- \ + .dockerignore \ + ui/; then + ui_changed=false + else + ui_changed=true + fi + + if git diff --quiet "$base_ref"...HEAD -- \ + .dockerignore \ + migrations/ \ + litellm/ \ + litellm-proxy-extras/ \ + enterprise/ \ + pyproject.toml \ + uv.lock \ + schema.prisma; then + migrations_changed=false + else + migrations_changed=true + fi + + { + echo "gateway_changed=$gateway_changed" + echo "backend_changed=$backend_changed" + echo "ui_changed=$ui_changed" + echo "migrations_changed=$migrations_changed" + } >> "$GITHUB_OUTPUT" + + - name: Terraform Init + run: terraform init -backend-config=config/dev/backend.tfbackend + + - name: Terraform Validate + run: terraform validate + + - name: Bootstrap ECR repositories + run: | + terraform apply -auto-approve \ + -var-file=config/dev/terraform.tfvars \ + -target=aws_ecr_repository.gateway \ + -target=aws_ecr_repository.backend \ + -target=aws_ecr_repository.ui \ + -target=aws_ecr_repository.migrations + + - name: Read ECR repository URLs + id: ecr + run: | + { + echo "gateway_repo=$(terraform output -raw gateway_ecr_repository_url)" + echo "backend_repo=$(terraform output -raw backend_ecr_repository_url)" + echo "ui_repo=$(terraform output -raw ui_ecr_repository_url)" + echo "migrations_repo=$(terraform output -raw migrations_ecr_repository_url)" + } >> "$GITHUB_OUTPUT" + + - name: Resolve ECS image refs + id: image_refs + env: + GATEWAY_CHANGED: ${{ steps.image_changes.outputs.gateway_changed }} + BACKEND_CHANGED: ${{ steps.image_changes.outputs.backend_changed }} + UI_CHANGED: ${{ steps.image_changes.outputs.ui_changed }} + MIGRATIONS_CHANGED: ${{ steps.image_changes.outputs.migrations_changed }} + GATEWAY_CANDIDATE: ${{ steps.ecr.outputs.gateway_repo }}:${{ env.IMAGE_TAG }} + BACKEND_CANDIDATE: ${{ steps.ecr.outputs.backend_repo }}:${{ env.IMAGE_TAG }} + UI_CANDIDATE: ${{ steps.ecr.outputs.ui_repo }}:${{ env.IMAGE_TAG }} + MIGRATIONS_CANDIDATE: ${{ steps.ecr.outputs.migrations_repo }}:${{ env.IMAGE_TAG }} + run: | + state_resources="$(terraform state list 2>/dev/null || true)" + + current_image() { + terraform show -json 2>/dev/null \ + | jq -r --arg res "$1" ' + .values.root_module.resources[] + | select(.address == $res) + | .values.container_definitions + | fromjson + | .[0].image // empty + ' \ + | head -n1 + } + + gateway_current_image="$(current_image aws_ecs_task_definition.gateway)" + backend_current_image="$(current_image aws_ecs_task_definition.backend)" + ui_current_image="$(current_image aws_ecs_task_definition.ui)" + migrations_current_image="$(current_image aws_ecs_task_definition.migrations)" + + if [ "$GATEWAY_CHANGED" = "true" ] || [ -z "$gateway_current_image" ]; then + gateway_build=true + gateway_image="$GATEWAY_CANDIDATE" + else + gateway_build=false + gateway_image="$gateway_current_image" + fi + + if [ "$BACKEND_CHANGED" = "true" ] || [ -z "$backend_current_image" ]; then + backend_build=true + backend_image="$BACKEND_CANDIDATE" + else + backend_build=false + backend_image="$backend_current_image" + fi + + if [ "$UI_CHANGED" = "true" ] || [ -z "$ui_current_image" ]; then + ui_build=true + ui_image="$UI_CANDIDATE" + else + ui_build=false + ui_image="$ui_current_image" + fi + + if [ "$MIGRATIONS_CHANGED" = "true" ] || [ -z "$migrations_current_image" ]; then + migrations_build=true + migrations_image="$MIGRATIONS_CANDIDATE" + else + migrations_build=false + migrations_image="$migrations_current_image" + fi + + if [ "$gateway_build" = "true" ] || [ "$backend_build" = "true" ] || [ "$ui_build" = "true" ] || [ "$migrations_build" = "true" ]; then + any_build=true + else + any_build=false + fi + + { + echo "any_build=$any_build" + echo "gateway_build=$gateway_build" + echo "backend_build=$backend_build" + echo "ui_build=$ui_build" + echo "migrations_build=$migrations_build" + echo "gateway_image=$gateway_image" + echo "backend_image=$backend_image" + echo "ui_image=$ui_image" + echo "migrations_image=$migrations_image" + } >> "$GITHUB_OUTPUT" + + - name: Set up Docker Buildx + if: steps.image_refs.outputs.any_build == 'true' + uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0 + + - name: Login to Amazon ECR + if: steps.image_refs.outputs.any_build == 'true' + uses: aws-actions/amazon-ecr-login@4625ce35226a7557230889aae2f52eb50ec3dcda # v2.0.1 + + - name: Build and push gateway image + if: steps.image_refs.outputs.gateway_build == 'true' + uses: docker/build-push-action@0adf9959216b96bec444f325f1e493d4aa344497 # v6.14.0 + with: + context: . + file: ./gateway/Dockerfile + push: true + tags: ${{ steps.ecr.outputs.gateway_repo }}:${{ env.IMAGE_TAG }} + + - name: Build and push backend image + if: steps.image_refs.outputs.backend_build == 'true' + uses: docker/build-push-action@0adf9959216b96bec444f325f1e493d4aa344497 # v6.14.0 + with: + context: . + file: ./backend/Dockerfile + push: true + tags: ${{ steps.ecr.outputs.backend_repo }}:${{ env.IMAGE_TAG }} + + - name: Build and push UI image + if: steps.image_refs.outputs.ui_build == 'true' + uses: docker/build-push-action@0adf9959216b96bec444f325f1e493d4aa344497 # v6.14.0 + with: + context: . + file: ./ui/Dockerfile + push: true + tags: ${{ steps.ecr.outputs.ui_repo }}:${{ env.IMAGE_TAG }} + + - name: Build and push migrations image + if: steps.image_refs.outputs.migrations_build == 'true' + uses: docker/build-push-action@0adf9959216b96bec444f325f1e493d4aa344497 # v6.14.0 + with: + context: . + file: ./migrations/Dockerfile + push: true + tags: ${{ steps.ecr.outputs.migrations_repo }}:${{ env.IMAGE_TAG }} + + - name: Terraform Plan + run: | + terraform plan \ + -var-file=config/dev/terraform.tfvars \ + -var="gateway_image=${{ steps.image_refs.outputs.gateway_image }}" \ + -var="backend_image=${{ steps.image_refs.outputs.backend_image }}" \ + -var="ui_image=${{ steps.image_refs.outputs.ui_image }}" \ + -var="migrations_image=${{ steps.image_refs.outputs.migrations_image }}" \ + -out=tfplan + + - name: Terraform Apply + if: github.ref == 'refs/heads/datareply/dev' + run: terraform apply -auto-approve tfplan