From 7146ce512d601b3597bb5688ec25fcf17539fa04 Mon Sep 17 00:00:00 2001 From: Waleed Date: Thu, 25 Sep 2025 17:37:12 -0700 Subject: [PATCH] feat(ci): use blacksmith for ci (#1454) * feat(ci): use blacksmith for ci * consolidate ecr + ghcr builds for linux/amd64 --- .github/workflows/build-ecr.yml | 10 +- .github/workflows/build-ghcr-build.yml | 84 ------ .github/workflows/build-ghcr-push.yml | 149 ---------- .github/workflows/build.yml | 360 +++++++++++++++++------ .github/workflows/ci.yml | 43 ++- .github/workflows/docs-embeddings.yml | 2 +- .github/workflows/i18n.yml | 4 +- .github/workflows/publish-cli.yml | 2 +- .github/workflows/publish-python-sdk.yml | 2 +- .github/workflows/publish-ts-sdk.yml | 2 +- .github/workflows/trigger-deploy.yml | 2 +- 11 files changed, 296 insertions(+), 364 deletions(-) delete mode 100644 .github/workflows/build-ghcr-build.yml delete mode 100644 .github/workflows/build-ghcr-push.yml diff --git a/.github/workflows/build-ecr.yml b/.github/workflows/build-ecr.yml index 9178e7dc0f..7490ff8c1f 100644 --- a/.github/workflows/build-ecr.yml +++ b/.github/workflows/build-ecr.yml @@ -23,7 +23,7 @@ jobs: - dockerfile: ./docker/realtime.Dockerfile ecr_repo_secret: ECR_REALTIME service_type: monitoring - runs-on: ubuntu-latest + runs-on: blacksmith-4vcpu-ubuntu-2404 steps: - name: Checkout repository @@ -46,7 +46,7 @@ jobs: password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + uses: useblacksmith/setup-docker-builder@v1 - name: Generate image tags id: meta @@ -67,21 +67,19 @@ jobs: echo "full_image=$FULL_IMAGE" >> $GITHUB_OUTPUT - name: Build and push Docker image - uses: docker/build-push-action@v6 + uses: useblacksmith/build-push-action@v2 with: context: . file: ${{ matrix.dockerfile }} push: true tags: ${{ steps.meta.outputs.full_image }} platforms: linux/amd64 - cache-from: type=gha,scope=build-ecr-${{ matrix.service_type }} - cache-to: type=gha,mode=max,scope=build-ecr-${{ matrix.service_type }} provenance: false sbom: false update-ecs-services: needs: build-and-push-ecr - runs-on: ubuntu-latest + runs-on: blacksmith-4vcpu-ubuntu-2404 strategy: fail-fast: false matrix: diff --git a/.github/workflows/build-ghcr-build.yml b/.github/workflows/build-ghcr-build.yml deleted file mode 100644 index a629d3bfa0..0000000000 --- a/.github/workflows/build-ghcr-build.yml +++ /dev/null @@ -1,84 +0,0 @@ -name: Build GHCR Images (Build Only) - -on: - workflow_call: - workflow_dispatch: - -permissions: - contents: read - packages: write - -jobs: - build: - strategy: - fail-fast: false - matrix: - include: - # AMD64 builds on x86 runners - - dockerfile: ./docker/app.Dockerfile - image: ghcr.io/simstudioai/simstudio - platform: linux/amd64 - arch: amd64 - runner: linux-x64-8-core - - dockerfile: ./docker/db.Dockerfile - image: ghcr.io/simstudioai/migrations - platform: linux/amd64 - arch: amd64 - runner: linux-x64-8-core - - dockerfile: ./docker/realtime.Dockerfile - image: ghcr.io/simstudioai/realtime - platform: linux/amd64 - arch: amd64 - runner: linux-x64-8-core - # ARM64 builds on native ARM64 runners - - dockerfile: ./docker/app.Dockerfile - image: ghcr.io/simstudioai/simstudio - platform: linux/arm64 - arch: arm64 - runner: linux-arm64-8-core - - dockerfile: ./docker/db.Dockerfile - image: ghcr.io/simstudioai/migrations - platform: linux/arm64 - arch: arm64 - runner: linux-arm64-8-core - - dockerfile: ./docker/realtime.Dockerfile - image: ghcr.io/simstudioai/realtime - platform: linux/arm64 - arch: arm64 - runner: linux-arm64-8-core - runs-on: ${{ matrix.runner }} - permissions: - contents: read - packages: write - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - - name: Extract metadata (tags, labels) for Docker - id: meta - uses: docker/metadata-action@v5 - with: - images: ${{ matrix.image }} - tags: | - type=raw,value=latest-${{ matrix.arch }},enable=${{ github.ref == 'refs/heads/main' }} - type=raw,value=staging-${{ matrix.arch }},enable=${{ github.ref == 'refs/heads/staging' }} - type=raw,value=staging-${{ github.sha }}-${{ matrix.arch }},enable=${{ github.ref == 'refs/heads/staging' }} - type=sha,format=long,suffix=-${{ matrix.arch }} - - - name: Build Docker image (no push) - uses: docker/build-push-action@v6 - with: - context: . - file: ${{ matrix.dockerfile }} - platforms: ${{ matrix.platform }} - push: false - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - cache-from: type=gha,scope=build-v3 - cache-to: type=gha,mode=max,scope=build-v3 - provenance: false - sbom: false \ No newline at end of file diff --git a/.github/workflows/build-ghcr-push.yml b/.github/workflows/build-ghcr-push.yml deleted file mode 100644 index 63840b6a24..0000000000 --- a/.github/workflows/build-ghcr-push.yml +++ /dev/null @@ -1,149 +0,0 @@ -name: Push GHCR Images - -on: - workflow_call: - workflow_dispatch: - -permissions: - contents: read - packages: write - -jobs: - push: - strategy: - fail-fast: false - matrix: - include: - # AMD64 builds - - dockerfile: ./docker/app.Dockerfile - image: ghcr.io/simstudioai/simstudio - platform: linux/amd64 - arch: amd64 - - dockerfile: ./docker/db.Dockerfile - image: ghcr.io/simstudioai/migrations - platform: linux/amd64 - arch: amd64 - - dockerfile: ./docker/realtime.Dockerfile - image: ghcr.io/simstudioai/realtime - platform: linux/amd64 - arch: amd64 - # ARM64 builds - - dockerfile: ./docker/app.Dockerfile - image: ghcr.io/simstudioai/simstudio - platform: linux/arm64 - arch: arm64 - - dockerfile: ./docker/db.Dockerfile - image: ghcr.io/simstudioai/migrations - platform: linux/arm64 - arch: arm64 - - dockerfile: ./docker/realtime.Dockerfile - image: ghcr.io/simstudioai/realtime - platform: linux/arm64 - arch: arm64 - runs-on: ubuntu-latest - permissions: - contents: read - packages: write - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - - name: Log in to the Container registry - uses: docker/login-action@v3 - with: - registry: ghcr.io - username: ${{ github.repository_owner }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Extract metadata (tags, labels) for Docker - id: meta - uses: docker/metadata-action@v5 - with: - images: ${{ matrix.image }} - tags: | - type=raw,value=latest-${{ matrix.arch }},enable=${{ github.ref == 'refs/heads/main' }} - type=raw,value=staging-${{ matrix.arch }},enable=${{ github.ref == 'refs/heads/staging' }} - type=raw,value=staging-${{ github.sha }}-${{ matrix.arch }},enable=${{ github.ref == 'refs/heads/staging' }} - type=sha,format=long,suffix=-${{ matrix.arch }} - - - name: Push Docker image from cache - uses: docker/build-push-action@v6 - with: - context: . - file: ${{ matrix.dockerfile }} - platforms: ${{ matrix.platform }} - push: true - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - cache-from: type=gha,scope=build-v3 - cache-to: type=gha,mode=max,scope=build-v3 - provenance: false - sbom: false - - create-manifests: - runs-on: ubuntu-latest - needs: push - strategy: - matrix: - include: - - image: ghcr.io/simstudioai/simstudio - - image: ghcr.io/simstudioai/migrations - - image: ghcr.io/simstudioai/realtime - permissions: - contents: read - packages: write - - steps: - - name: Log in to the Container registry - uses: docker/login-action@v3 - with: - registry: ghcr.io - username: ${{ github.repository_owner }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Extract metadata for manifest - id: meta - uses: docker/metadata-action@v5 - with: - images: ${{ matrix.image }} - tags: | - type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }} - type=raw,value=staging,enable=${{ github.ref == 'refs/heads/staging' }} - type=sha,format=long - - - name: Create and push manifest - run: | - # Extract the tags from metadata (these are the final manifest tags we want) - MANIFEST_TAGS="${{ steps.meta.outputs.tags }}" - - # Create manifest for each tag - for manifest_tag in $MANIFEST_TAGS; do - echo "Creating manifest for $manifest_tag" - - # The architecture-specific images have -amd64 and -arm64 suffixes - amd64_image="${manifest_tag}-amd64" - arm64_image="${manifest_tag}-arm64" - - echo "Looking for images: $amd64_image and $arm64_image" - - # Check if both architecture images exist - if docker manifest inspect "$amd64_image" >/dev/null 2>&1 && docker manifest inspect "$arm64_image" >/dev/null 2>&1; then - echo "Both images found, creating manifest..." - docker manifest create "$manifest_tag" \ - "$amd64_image" \ - "$arm64_image" - docker manifest push "$manifest_tag" - echo "Successfully created and pushed manifest for $manifest_tag" - else - echo "Error: One or both architecture images not found" - echo "Checking AMD64 image: $amd64_image" - docker manifest inspect "$amd64_image" || echo "AMD64 image not found" - echo "Checking ARM64 image: $arm64_image" - docker manifest inspect "$arm64_image" || echo "ARM64 image not found" - exit 1 - fi - done \ No newline at end of file diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4ccb55b176..a2f4df8b2b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,4 +1,4 @@ -name: Build and Publish Docker Image +name: Unified Build and Push on: workflow_call: @@ -7,94 +7,293 @@ on: permissions: contents: read packages: write + id-token: write jobs: - build-and-push: + build-shared-amd64: + name: Build AMD64 (Shared for GHCR + ECR) + runs-on: linux-x64-8-core + if: github.event_name == 'push' && github.ref == 'refs/heads/main' strategy: fail-fast: false matrix: include: - # AMD64 builds on x86 runners - dockerfile: ./docker/app.Dockerfile - image: ghcr.io/simstudioai/simstudio - platform: linux/amd64 - arch: amd64 - runner: linux-x64-8-core + ghcr_image: ghcr.io/simstudioai/simstudio + ecr_repo_secret: ECR_APP - dockerfile: ./docker/db.Dockerfile - image: ghcr.io/simstudioai/migrations - platform: linux/amd64 - arch: amd64 - runner: linux-x64-8-core + ghcr_image: ghcr.io/simstudioai/migrations + ecr_repo_secret: ECR_MIGRATIONS - dockerfile: ./docker/realtime.Dockerfile - image: ghcr.io/simstudioai/realtime - platform: linux/amd64 - arch: amd64 - runner: linux-x64-8-core - # ARM64 builds on native ARM64 runners - - dockerfile: ./docker/app.Dockerfile - image: ghcr.io/simstudioai/simstudio - platform: linux/arm64 - arch: arm64 - runner: linux-arm64-8-core - - dockerfile: ./docker/db.Dockerfile - image: ghcr.io/simstudioai/migrations - platform: linux/arm64 - arch: arm64 - runner: linux-arm64-8-core - - dockerfile: ./docker/realtime.Dockerfile - image: ghcr.io/simstudioai/realtime - platform: linux/arm64 - arch: arm64 - runner: linux-arm64-8-core - runs-on: ${{ matrix.runner }} - permissions: - contents: read - packages: write + ghcr_image: ghcr.io/simstudioai/realtime + ecr_repo_secret: ECR_REALTIME + outputs: + registry: ${{ steps.login-ecr.outputs.registry }} steps: - name: Checkout repository uses: actions/checkout@v4 - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }} + aws-region: ${{ secrets.AWS_REGION }} - - name: Log in to the Container registry - if: github.event_name != 'pull_request' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/staging') + - name: Login to Amazon ECR + id: login-ecr + uses: aws-actions/amazon-ecr-login@v2 + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Log in to GHCR uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Extract metadata (tags, labels) for Docker + - name: Set up Docker Buildx + uses: useblacksmith/setup-docker-builder@v1 + + - name: Generate tags + id: meta + run: | + ECR_REGISTRY="${{ steps.login-ecr.outputs.registry }}" + ECR_REPO="${{ secrets[matrix.ecr_repo_secret] }}" + GHCR_IMAGE="${{ matrix.ghcr_image }}" + + # ECR tags + ECR_IMAGE="${ECR_REGISTRY}/${ECR_REPO}:latest" + + # GHCR tags + GHCR_AMD64="${GHCR_IMAGE}:latest-amd64" + GHCR_SHA="${GHCR_IMAGE}:${{ github.sha }}-amd64" + + echo "ecr_image=${ECR_IMAGE}" >> $GITHUB_OUTPUT + echo "ghcr_tags=${GHCR_AMD64},${GHCR_SHA}" >> $GITHUB_OUTPUT + + - name: Build and push to both registries + uses: useblacksmith/build-push-action@v2 + with: + context: . + file: ${{ matrix.dockerfile }} + platforms: linux/amd64 + push: true + tags: | + ${{ steps.meta.outputs.ecr_image }} + ${{ steps.meta.outputs.ghcr_tags }} + provenance: false + sbom: false + + build-ghcr-arm64: + name: Build ARM64 (GHCR Only) + runs-on: linux-arm64-8-core + if: github.event_name == 'push' && github.ref == 'refs/heads/main' + strategy: + fail-fast: false + matrix: + include: + - dockerfile: ./docker/app.Dockerfile + image: ghcr.io/simstudioai/simstudio + - dockerfile: ./docker/db.Dockerfile + image: ghcr.io/simstudioai/migrations + - dockerfile: ./docker/realtime.Dockerfile + image: ghcr.io/simstudioai/realtime + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Log in to GHCR + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Set up Docker Buildx + uses: useblacksmith/setup-docker-builder@v1 + + - name: Extract metadata id: meta uses: docker/metadata-action@v5 with: images: ${{ matrix.image }} tags: | - type=raw,value=latest-${{ matrix.arch }},enable=${{ github.ref == 'refs/heads/main' }} - type=raw,value=staging-${{ matrix.arch }},enable=${{ github.ref == 'refs/heads/staging' }} - type=raw,value=staging-${{ github.sha }}-${{ matrix.arch }},enable=${{ github.ref == 'refs/heads/staging' }} - type=sha,format=long,suffix=-${{ matrix.arch }} + type=raw,value=latest-arm64 + type=sha,format=long,suffix=-arm64 - - name: Build and push Docker image - uses: docker/build-push-action@v6 + - name: Build and push ARM64 to GHCR + uses: useblacksmith/build-push-action@v2 with: context: . file: ${{ matrix.dockerfile }} - platforms: ${{ matrix.platform }} - push: ${{ github.event_name != 'pull_request' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/staging') }} + platforms: linux/arm64 + push: true tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - cache-from: type=gha,scope=build-v3 - cache-to: type=gha,mode=max,scope=build-v3 provenance: false sbom: false - create-manifests: - runs-on: ubuntu-latest - needs: build-and-push - if: github.event_name != 'pull_request' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/staging') + update-ecs-services: + name: Update ECS Services + needs: build-shared-amd64 + runs-on: blacksmith-4vcpu-ubuntu-2404 + if: github.event_name == 'push' && github.ref == 'refs/heads/main' + strategy: + fail-fast: false + matrix: + stack_type: [APP, CORE, MONITORING] + + steps: + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }} + aws-region: ${{ secrets.AWS_REGION }} + + - name: Login to Amazon ECR + id: login-ecr + uses: aws-actions/amazon-ecr-login@v2 + + - name: Determine stack and image details + id: stack + run: | + ECR_REGISTRY="${{ needs.build-shared-amd64.outputs.registry }}" + + # Map stack type to ECR repo + case "${{ matrix.stack_type }}" in + APP) + ECR_REPO="${{ secrets.ECR_APP }}" + ;; + CORE) + ECR_REPO="${{ secrets.ECR_MIGRATIONS }}" + ;; + MONITORING) + ECR_REPO="${{ secrets.ECR_REALTIME }}" + ;; + esac + + IMAGE_URI="${ECR_REGISTRY}/${ECR_REPO}:latest" + echo "image=$IMAGE_URI" >> $GITHUB_OUTPUT + + - name: Get stack name + id: stack-name + run: | + APP_STACK="${{ secrets.PROD_APP_STACK }}" + CORE_STACK="${{ secrets.PROD_CORE_STACK }}" + MONITORING_STACK="${{ secrets.PROD_MONITORING_STACK }}" + + case "${{ matrix.stack_type }}" in + APP) + STACK_NAME="$APP_STACK" + ;; + CORE) + STACK_NAME="$CORE_STACK" + ;; + MONITORING) + STACK_NAME="$MONITORING_STACK" + ;; + esac + + echo "name=$STACK_NAME" >> $GITHUB_OUTPUT + + - name: Get ECS services from stack + id: ecs-services + run: | + SERVICES=$(aws cloudformation describe-stack-resources \ + --stack-name "${{ steps.stack-name.outputs.name }}" \ + --query "StackResources[?ResourceType=='AWS::ECS::Service'].PhysicalResourceId" \ + --output text 2>/dev/null || echo "") + + if [ -z "$SERVICES" ]; then + echo "services=" >> $GITHUB_OUTPUT + else + echo "services=$SERVICES" >> $GITHUB_OUTPUT + fi + + - name: Update ECS services + if: steps.ecs-services.outputs.services != '' + run: | + SERVICES="${{ steps.ecs-services.outputs.services }}" + + for SERVICE_ARN in $SERVICES; do + CLUSTER_NAME=$(echo $SERVICE_ARN | cut -d'/' -f2) + SERVICE_NAME=$(echo $SERVICE_ARN | cut -d'/' -f3) + + TASK_DEF_ARN=$(aws ecs describe-services \ + --cluster "$CLUSTER_NAME" \ + --services "$SERVICE_NAME" \ + --query "services[0].taskDefinition" \ + --output text) + + TASK_DEF=$(aws ecs describe-task-definition \ + --task-definition "$TASK_DEF_ARN" \ + --query "taskDefinition") + + NEW_TASK_DEF=$(echo "$TASK_DEF" | jq --arg IMAGE "${{ steps.stack.outputs.image }}" \ + '.containerDefinitions |= map( + if .essential == true then + .image = $IMAGE + else . end + ) | + del(.taskDefinitionArn) | + del(.revision) | + del(.status) | + del(.requiresAttributes) | + del(.compatibilities) | + del(.registeredAt) | + del(.registeredBy)') + + NEW_TASK_ARN=$(aws ecs register-task-definition \ + --cli-input-json "$NEW_TASK_DEF" \ + --query "taskDefinition.taskDefinitionArn" \ + --output text) + + aws ecs update-service \ + --cluster "$CLUSTER_NAME" \ + --service "$SERVICE_NAME" \ + --task-definition "$NEW_TASK_ARN" \ + --force-new-deployment + done + + - name: Wait for service stability + if: steps.ecs-services.outputs.services != '' + run: | + SERVICES="${{ steps.ecs-services.outputs.services }}" + + for SERVICE_ARN in $SERVICES; do + CLUSTER_NAME=$(echo $SERVICE_ARN | cut -d'/' -f2) + SERVICE_NAME=$(echo $SERVICE_ARN | cut -d'/' -f3) + + ATTEMPTS=0 + MAX_ATTEMPTS=120 + while [ $ATTEMPTS -lt $MAX_ATTEMPTS ]; do + DEPLOYMENT_STATUS=$(aws ecs describe-services \ + --cluster "$CLUSTER_NAME" \ + --services "$SERVICE_NAME" \ + --query "services[0].deployments[?status=='PRIMARY'].rolloutState" \ + --output text) + + if [ "$DEPLOYMENT_STATUS" = "COMPLETED" ]; then + echo "✅ Service $SERVICE_NAME updated successfully!" + break + fi + + sleep 15 + ATTEMPTS=$((ATTEMPTS+1)) + done + done + + create-ghcr-manifests: + name: Create GHCR Manifests + runs-on: blacksmith-4vcpu-ubuntu-2404 + needs: [build-shared-amd64, build-ghcr-arm64] + if: github.event_name == 'push' && github.ref == 'refs/heads/main' strategy: matrix: include: @@ -106,52 +305,25 @@ jobs: packages: write steps: - - name: Log in to the Container registry + - name: Log in to GHCR uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Extract metadata for manifest - id: meta - uses: docker/metadata-action@v5 - with: - images: ${{ matrix.image }} - tags: | - type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }} - type=raw,value=staging,enable=${{ github.ref == 'refs/heads/staging' }} - type=sha,format=long - - name: Create and push manifest run: | - # Extract the tags from metadata (these are the final manifest tags we want) - MANIFEST_TAGS="${{ steps.meta.outputs.tags }}" + IMAGE_BASE="${{ matrix.image }}" - # Create manifest for each tag - for manifest_tag in $MANIFEST_TAGS; do - echo "Creating manifest for $manifest_tag" + # Create latest manifest + docker manifest create "${IMAGE_BASE}:latest" \ + "${IMAGE_BASE}:latest-amd64" \ + "${IMAGE_BASE}:latest-arm64" + docker manifest push "${IMAGE_BASE}:latest" - # The architecture-specific images have -amd64 and -arm64 suffixes - amd64_image="${manifest_tag}-amd64" - arm64_image="${manifest_tag}-arm64" - - echo "Looking for images: $amd64_image and $arm64_image" - - # Check if both architecture images exist - if docker manifest inspect "$amd64_image" >/dev/null 2>&1 && docker manifest inspect "$arm64_image" >/dev/null 2>&1; then - echo "Both images found, creating manifest..." - docker manifest create "$manifest_tag" \ - "$amd64_image" \ - "$arm64_image" - docker manifest push "$manifest_tag" - echo "Successfully created and pushed manifest for $manifest_tag" - else - echo "Error: One or both architecture images not found" - echo "Checking AMD64 image: $amd64_image" - docker manifest inspect "$amd64_image" || echo "AMD64 image not found" - echo "Checking ARM64 image: $arm64_image" - docker manifest inspect "$arm64_image" || echo "ARM64 image not found" - exit 1 - fi - done \ No newline at end of file + # Create SHA manifest + docker manifest create "${IMAGE_BASE}:${{ github.sha }}" \ + "${IMAGE_BASE}:${{ github.sha }}-amd64" \ + "${IMAGE_BASE}:${{ github.sha }}-arm64" + docker manifest push "${IMAGE_BASE}:${{ github.sha }}" \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 900915cba8..cf4888bd4c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,7 +13,7 @@ concurrency: jobs: test: name: Test and Build - runs-on: ubuntu-latest + runs-on: blacksmith-4vcpu-ubuntu-2404 steps: - name: Checkout code @@ -59,22 +59,23 @@ jobs: fail_ci_if_error: false verbose: true - # Call GHCR build workflow (runs in parallel with ECR) - build-ghcr: - name: Build GHCR Images + # Main branch: build (ECR + GHCR) + build: + name: Build (ECR + GHCR) needs: test - if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/staging') - uses: ./.github/workflows/build-ghcr-build.yml + if: github.event_name == 'push' && github.ref == 'refs/heads/main' + uses: ./.github/workflows/build.yml secrets: inherit permissions: contents: read packages: write + id-token: write - # Call ECR build workflow (runs in parallel with GHCR build) + # Staging branch: ECR only build-ecr-deploy: - name: Build ECR and Deploy + name: Build ECR and Deploy (Staging) needs: test - if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/staging') + if: github.event_name == 'push' && github.ref == 'refs/heads/staging' uses: ./.github/workflows/build-ecr.yml secrets: inherit permissions: @@ -89,23 +90,17 @@ jobs: uses: ./.github/workflows/trigger-deploy.yml secrets: inherit - # Push GHCR images after ECR/ECS deployment is complete - push-ghcr: - name: Push GHCR Images - needs: [build-ghcr, build-ecr-deploy] - if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/staging') - uses: ./.github/workflows/build-ghcr-push.yml - secrets: inherit - permissions: - contents: read - packages: write - - # Run database migrations (depends on GHCR push and trigger deployment) + # Run database migrations (depends on build completion and trigger deployment) migrations: name: Apply Database Migrations - needs: [push-ghcr, trigger-deploy] - runs-on: ubuntu-latest - if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/staging') + needs: [build-ecr-deploy, build, trigger-deploy] + runs-on: blacksmith-4vcpu-ubuntu-2404 + if: | + always() && + github.event_name == 'push' && + (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/staging') && + (needs.build-ecr-deploy.result == 'success' || needs.build.result == 'success') && + needs.trigger-deploy.result == 'success' steps: - name: Checkout code diff --git a/.github/workflows/docs-embeddings.yml b/.github/workflows/docs-embeddings.yml index 22b4adc05c..d61d866165 100644 --- a/.github/workflows/docs-embeddings.yml +++ b/.github/workflows/docs-embeddings.yml @@ -7,7 +7,7 @@ on: jobs: process-docs-embeddings: name: Process Documentation Embeddings - runs-on: ubuntu-latest + runs-on: blacksmith-4vcpu-ubuntu-2404 if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/staging' steps: diff --git a/.github/workflows/i18n.yml b/.github/workflows/i18n.yml index bbaffbce4c..5275b9444b 100644 --- a/.github/workflows/i18n.yml +++ b/.github/workflows/i18n.yml @@ -14,7 +14,7 @@ permissions: jobs: translate: - runs-on: ubuntu-latest + runs-on: blacksmith-4vcpu-ubuntu-2404 if: github.actor != 'github-actions[bot]' # Prevent infinite loops steps: @@ -104,7 +104,7 @@ jobs: verify-translations: needs: translate - runs-on: ubuntu-latest + runs-on: blacksmith-4vcpu-ubuntu-2404 if: always() # Run even if translation fails steps: diff --git a/.github/workflows/publish-cli.yml b/.github/workflows/publish-cli.yml index 41bce6a7b6..88209378c9 100644 --- a/.github/workflows/publish-cli.yml +++ b/.github/workflows/publish-cli.yml @@ -8,7 +8,7 @@ on: jobs: publish-npm: - runs-on: ubuntu-latest + runs-on: blacksmith-4vcpu-ubuntu-2404 steps: - name: Checkout repository uses: actions/checkout@v4 diff --git a/.github/workflows/publish-python-sdk.yml b/.github/workflows/publish-python-sdk.yml index 6892405de1..fdd208075a 100644 --- a/.github/workflows/publish-python-sdk.yml +++ b/.github/workflows/publish-python-sdk.yml @@ -8,7 +8,7 @@ on: jobs: publish-pypi: - runs-on: ubuntu-latest + runs-on: blacksmith-4vcpu-ubuntu-2404 steps: - name: Checkout repository uses: actions/checkout@v4 diff --git a/.github/workflows/publish-ts-sdk.yml b/.github/workflows/publish-ts-sdk.yml index 360f5aa20a..b1e733355e 100644 --- a/.github/workflows/publish-ts-sdk.yml +++ b/.github/workflows/publish-ts-sdk.yml @@ -8,7 +8,7 @@ on: jobs: publish-npm: - runs-on: ubuntu-latest + runs-on: blacksmith-4vcpu-ubuntu-2404 steps: - name: Checkout repository uses: actions/checkout@v4 diff --git a/.github/workflows/trigger-deploy.yml b/.github/workflows/trigger-deploy.yml index 40a7102c2a..9183903ea5 100644 --- a/.github/workflows/trigger-deploy.yml +++ b/.github/workflows/trigger-deploy.yml @@ -7,7 +7,7 @@ on: jobs: deploy: name: Trigger.dev Deploy - runs-on: ubuntu-latest + runs-on: blacksmith-4vcpu-ubuntu-2404 concurrency: group: trigger-deploy-${{ github.ref }} cancel-in-progress: false