mirror of
https://github.com/simstudioai/sim.git
synced 2026-04-06 03:00:16 -04:00
improvement(ci): ensure atomicity in trigger deploys, improve overall ci organization (#1477)
* improvement(chat): deployed chat no longer uses subdomains, uses sim.ai/chat/[identifier]
* improvement(ci): ensure atomicity in trigger deploys, improve overall ci organization
* Revert "improvement(chat): deployed chat no longer uses subdomains, uses sim.ai/chat/[identifier]"
This reverts commit c68c052601.
---------
Co-authored-by: waleed <waleed>
This commit is contained in:
262
.github/workflows/build-ecr.yml
vendored
262
.github/workflows/build-ecr.yml
vendored
@@ -1,262 +0,0 @@
|
||||
name: Build and Push to ECR
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
id-token: write
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build-and-push-ecr:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- dockerfile: ./docker/app.Dockerfile
|
||||
ecr_repo_secret: ECR_APP
|
||||
service_type: app
|
||||
- dockerfile: ./docker/db.Dockerfile
|
||||
ecr_repo_secret: ECR_MIGRATIONS
|
||||
service_type: core
|
||||
- dockerfile: ./docker/realtime.Dockerfile
|
||||
ecr_repo_secret: ECR_REALTIME
|
||||
service_type: monitoring
|
||||
runs-on: blacksmith-4vcpu-ubuntu-2404
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Configure AWS credentials
|
||||
uses: aws-actions/configure-aws-credentials@v4
|
||||
with:
|
||||
role-to-assume: ${{ github.ref == 'refs/heads/main' && secrets.AWS_ROLE_TO_ASSUME || secrets.STAGING_AWS_ROLE_TO_ASSUME }}
|
||||
aws-region: ${{ github.ref == 'refs/heads/main' && secrets.AWS_REGION || secrets.STAGING_AWS_REGION }}
|
||||
|
||||
- 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: Set up Docker Buildx
|
||||
uses: useblacksmith/setup-docker-builder@v1
|
||||
|
||||
- name: Generate image tags
|
||||
id: meta
|
||||
run: |
|
||||
ECR_REGISTRY="${{ steps.login-ecr.outputs.registry }}"
|
||||
ECR_REPO="${{ secrets[matrix.ecr_repo_secret] }}"
|
||||
|
||||
# Simple tagging: :latest for main, :staging for staging
|
||||
if [ "${{ github.ref }}" = "refs/heads/main" ]; then
|
||||
TAG="latest"
|
||||
else
|
||||
TAG="staging"
|
||||
fi
|
||||
|
||||
FULL_IMAGE="${ECR_REGISTRY}/${ECR_REPO}:${TAG}"
|
||||
|
||||
echo "tag=$TAG" >> $GITHUB_OUTPUT
|
||||
echo "full_image=$FULL_IMAGE" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Build and push Docker image
|
||||
uses: useblacksmith/build-push-action@v2
|
||||
with:
|
||||
context: .
|
||||
file: ${{ matrix.dockerfile }}
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.full_image }}
|
||||
platforms: linux/amd64
|
||||
provenance: false
|
||||
sbom: false
|
||||
|
||||
update-ecs-services:
|
||||
needs: build-and-push-ecr
|
||||
runs-on: blacksmith-4vcpu-ubuntu-2404
|
||||
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: ${{ github.ref == 'refs/heads/main' && secrets.AWS_ROLE_TO_ASSUME || secrets.STAGING_AWS_ROLE_TO_ASSUME }}
|
||||
aws-region: ${{ github.ref == 'refs/heads/main' && secrets.AWS_REGION || secrets.STAGING_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="${{ steps.login-ecr.outputs.registry }}"
|
||||
|
||||
# Determine tag based on environment
|
||||
if [ "${{ github.ref }}" = "refs/heads/main" ]; then
|
||||
TAG="latest"
|
||||
else
|
||||
TAG="staging"
|
||||
fi
|
||||
|
||||
# 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
|
||||
|
||||
# Full image URI with simple tag
|
||||
IMAGE_URI="${ECR_REGISTRY}/${ECR_REPO}:${TAG}"
|
||||
|
||||
echo "image=$IMAGE_URI" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Get stack name
|
||||
id: stack-name
|
||||
run: |
|
||||
# Use conditional expressions to get stack name based on branch and type
|
||||
APP_STACK="${{ github.ref == 'refs/heads/main' && secrets.PROD_APP_STACK || secrets.STAGING_APP_STACK }}"
|
||||
CORE_STACK="${{ github.ref == 'refs/heads/main' && secrets.PROD_CORE_STACK || secrets.STAGING_CORE_STACK }}"
|
||||
MONITORING_STACK="${{ github.ref == 'refs/heads/main' && secrets.PROD_MONITORING_STACK || secrets.STAGING_MONITORING_STACK }}"
|
||||
|
||||
# Select the appropriate stack based on matrix type
|
||||
case "${{ matrix.stack_type }}" in
|
||||
APP)
|
||||
STACK_NAME="$APP_STACK"
|
||||
;;
|
||||
CORE)
|
||||
STACK_NAME="$CORE_STACK"
|
||||
;;
|
||||
MONITORING)
|
||||
STACK_NAME="$MONITORING_STACK"
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "Updating stack: $STACK_NAME"
|
||||
echo "name=$STACK_NAME" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Get ECS services from stack
|
||||
id: ecs-services
|
||||
run: |
|
||||
# Get all ECS services from the stack
|
||||
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 "No ECS services found in stack ${{ steps.stack-name.outputs.name }}"
|
||||
echo "services=" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "Found services: $SERVICES"
|
||||
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
|
||||
echo "Updating service: $SERVICE_ARN"
|
||||
|
||||
# Extract cluster name from service ARN
|
||||
CLUSTER_NAME=$(echo $SERVICE_ARN | cut -d'/' -f2)
|
||||
SERVICE_NAME=$(echo $SERVICE_ARN | cut -d'/' -f3)
|
||||
|
||||
# Get the current task definition
|
||||
TASK_DEF_ARN=$(aws ecs describe-services \
|
||||
--cluster "$CLUSTER_NAME" \
|
||||
--services "$SERVICE_NAME" \
|
||||
--query "services[0].taskDefinition" \
|
||||
--output text)
|
||||
|
||||
# Get the task definition details
|
||||
TASK_DEF=$(aws ecs describe-task-definition \
|
||||
--task-definition "$TASK_DEF_ARN" \
|
||||
--query "taskDefinition")
|
||||
|
||||
# Update the image in the task definition
|
||||
# For Ubuntu ECS, container definitions may have multiple containers
|
||||
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)')
|
||||
|
||||
# Register new task definition
|
||||
NEW_TASK_ARN=$(aws ecs register-task-definition \
|
||||
--cli-input-json "$NEW_TASK_DEF" \
|
||||
--query "taskDefinition.taskDefinitionArn" \
|
||||
--output text)
|
||||
|
||||
echo "Registered new task definition: $NEW_TASK_ARN"
|
||||
|
||||
# Update service with new task definition
|
||||
aws ecs update-service \
|
||||
--cluster "$CLUSTER_NAME" \
|
||||
--service "$SERVICE_NAME" \
|
||||
--task-definition "$NEW_TASK_ARN" \
|
||||
--force-new-deployment
|
||||
|
||||
echo "Service update initiated for $SERVICE_NAME"
|
||||
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)
|
||||
|
||||
echo "Waiting for service $SERVICE_NAME to stabilize..."
|
||||
|
||||
# Wait up to 30 minutes for service to stabilize
|
||||
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
|
||||
|
||||
echo "Deployment status: $DEPLOYMENT_STATUS (attempt $((ATTEMPTS+1))/$MAX_ATTEMPTS)"
|
||||
sleep 15
|
||||
ATTEMPTS=$((ATTEMPTS+1))
|
||||
done
|
||||
|
||||
if [ $ATTEMPTS -eq $MAX_ATTEMPTS ]; then
|
||||
echo "⚠️ Service $SERVICE_NAME did not stabilize within timeout"
|
||||
fi
|
||||
done
|
||||
329
.github/workflows/build.yml
vendored
329
.github/workflows/build.yml
vendored
@@ -1,329 +0,0 @@
|
||||
name: Unified Build and Push
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
id-token: write
|
||||
|
||||
jobs:
|
||||
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:
|
||||
- dockerfile: ./docker/app.Dockerfile
|
||||
ghcr_image: ghcr.io/simstudioai/simstudio
|
||||
ecr_repo_secret: ECR_APP
|
||||
- dockerfile: ./docker/db.Dockerfile
|
||||
ghcr_image: ghcr.io/simstudioai/migrations
|
||||
ecr_repo_secret: ECR_MIGRATIONS
|
||||
- dockerfile: ./docker/realtime.Dockerfile
|
||||
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: 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: 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: 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-arm64
|
||||
type=sha,format=long,suffix=-arm64
|
||||
|
||||
- name: Build and push ARM64 to GHCR
|
||||
uses: useblacksmith/build-push-action@v2
|
||||
with:
|
||||
context: .
|
||||
file: ${{ matrix.dockerfile }}
|
||||
platforms: linux/arm64
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
provenance: false
|
||||
sbom: false
|
||||
|
||||
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:
|
||||
- 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 GHCR
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Create and push manifest
|
||||
run: |
|
||||
IMAGE_BASE="${{ matrix.image }}"
|
||||
|
||||
# Create latest manifest
|
||||
docker manifest create "${IMAGE_BASE}:latest" \
|
||||
"${IMAGE_BASE}:latest-amd64" \
|
||||
"${IMAGE_BASE}:latest-arm64"
|
||||
docker manifest push "${IMAGE_BASE}:latest"
|
||||
|
||||
# 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 }}"
|
||||
109
.github/workflows/ci.yml
vendored
109
.github/workflows/ci.yml
vendored
@@ -11,81 +11,27 @@ concurrency:
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
test:
|
||||
test-build:
|
||||
name: Test and Build
|
||||
runs-on: blacksmith-4vcpu-ubuntu-2404
|
||||
uses: ./.github/workflows/test-build.yml
|
||||
secrets: inherit
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: latest
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: latest
|
||||
|
||||
- name: Install dependencies
|
||||
run: bun install --frozen-lockfile
|
||||
|
||||
- name: Run tests with coverage
|
||||
env:
|
||||
NODE_OPTIONS: '--no-warnings'
|
||||
NEXT_PUBLIC_APP_URL: 'https://www.sim.ai'
|
||||
DATABASE_URL: 'postgresql://postgres:postgres@localhost:5432/simstudio'
|
||||
ENCRYPTION_KEY: '7cf672e460e430c1fba707575c2b0e2ad5a99dddf9b7b7e3b5646e630861db1c' # dummy key for CI only
|
||||
run: bun run test
|
||||
|
||||
- name: Build application
|
||||
env:
|
||||
NODE_OPTIONS: '--no-warnings'
|
||||
NEXT_PUBLIC_APP_URL: 'https://www.sim.ai'
|
||||
DATABASE_URL: 'postgresql://postgres:postgres@localhost:5432/simstudio'
|
||||
STRIPE_SECRET_KEY: 'dummy_key_for_ci_only'
|
||||
STRIPE_WEBHOOK_SECRET: 'dummy_secret_for_ci_only'
|
||||
RESEND_API_KEY: 'dummy_key_for_ci_only'
|
||||
AWS_REGION: 'us-west-2'
|
||||
ENCRYPTION_KEY: '7cf672e460e430c1fba707575c2b0e2ad5a99dddf9b7b7e3b5646e630861db1c' # dummy key for CI only
|
||||
run: bun run build
|
||||
|
||||
- name: Upload coverage to Codecov
|
||||
uses: codecov/codecov-action@v5
|
||||
with:
|
||||
directory: ./apps/sim/coverage
|
||||
fail_ci_if_error: false
|
||||
verbose: true
|
||||
|
||||
# Main branch: build (ECR + GHCR)
|
||||
build:
|
||||
name: Build (ECR + GHCR)
|
||||
needs: test
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
||||
uses: ./.github/workflows/build.yml
|
||||
# Build and push images (ECR for staging, ECR + GHCR for main)
|
||||
build-images:
|
||||
name: Build Images
|
||||
needs: test-build
|
||||
if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/staging')
|
||||
uses: ./.github/workflows/images.yml
|
||||
secrets: inherit
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
id-token: write
|
||||
|
||||
# Staging branch: ECR only
|
||||
build-ecr-deploy:
|
||||
name: Build ECR and Deploy (Staging)
|
||||
needs: test
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/staging'
|
||||
uses: ./.github/workflows/build-ecr.yml
|
||||
secrets: inherit
|
||||
permissions:
|
||||
id-token: write
|
||||
contents: read
|
||||
|
||||
# Call Trigger.dev deploy workflow (runs in parallel)
|
||||
# Deploy Trigger.dev with skip-promotion (after builds complete to ensure atomicity)
|
||||
trigger-deploy:
|
||||
name: Deploy Trigger.dev
|
||||
needs: test
|
||||
needs: build-images
|
||||
if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/staging')
|
||||
uses: ./.github/workflows/trigger-deploy.yml
|
||||
secrets: inherit
|
||||
@@ -93,37 +39,28 @@ jobs:
|
||||
# Run database migrations (depends on build completion and trigger deployment)
|
||||
migrations:
|
||||
name: Apply Database Migrations
|
||||
needs: [build-ecr-deploy, build, trigger-deploy]
|
||||
runs-on: blacksmith-4vcpu-ubuntu-2404
|
||||
needs: [build-images, trigger-deploy]
|
||||
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.build-images.result == 'success' &&
|
||||
needs.trigger-deploy.result == 'success'
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
uses: ./.github/workflows/migrations.yml
|
||||
secrets: inherit
|
||||
|
||||
- name: Setup Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: latest
|
||||
|
||||
- name: Install dependencies
|
||||
run: bun install
|
||||
|
||||
- name: Apply migrations
|
||||
working-directory: ./packages/db
|
||||
env:
|
||||
DATABASE_URL: ${{ github.ref == 'refs/heads/main' && secrets.DATABASE_URL || secrets.STAGING_DATABASE_URL }}
|
||||
run: bunx drizzle-kit migrate --config=./drizzle.config.ts
|
||||
# Promote Trigger.dev deployment after ECS completes
|
||||
trigger-promote:
|
||||
name: Promote Trigger.dev
|
||||
needs: migrations
|
||||
if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/staging')
|
||||
uses: ./.github/workflows/trigger-promote.yml
|
||||
secrets: inherit
|
||||
|
||||
# Process docs embeddings if needed
|
||||
process-docs:
|
||||
name: Process Docs
|
||||
needs: migrations
|
||||
needs: trigger-promote
|
||||
if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/staging')
|
||||
uses: ./.github/workflows/docs-embeddings.yml
|
||||
secrets: inherit
|
||||
|
||||
184
.github/workflows/images.yml
vendored
Normal file
184
.github/workflows/images.yml
vendored
Normal file
@@ -0,0 +1,184 @@
|
||||
name: Build and Push Images
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
id-token: write
|
||||
|
||||
jobs:
|
||||
build-amd64:
|
||||
name: Build AMD64
|
||||
runs-on: blacksmith-4vcpu-ubuntu-2404
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- dockerfile: ./docker/app.Dockerfile
|
||||
ghcr_image: ghcr.io/simstudioai/simstudio
|
||||
ecr_repo_secret: ECR_APP
|
||||
- dockerfile: ./docker/db.Dockerfile
|
||||
ghcr_image: ghcr.io/simstudioai/migrations
|
||||
ecr_repo_secret: ECR_MIGRATIONS
|
||||
- dockerfile: ./docker/realtime.Dockerfile
|
||||
ghcr_image: ghcr.io/simstudioai/realtime
|
||||
ecr_repo_secret: ECR_REALTIME
|
||||
outputs:
|
||||
registry: ${{ steps.login-ecr.outputs.registry }}
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Configure AWS credentials
|
||||
uses: aws-actions/configure-aws-credentials@v4
|
||||
with:
|
||||
role-to-assume: ${{ github.ref == 'refs/heads/main' && secrets.AWS_ROLE_TO_ASSUME || secrets.STAGING_AWS_ROLE_TO_ASSUME }}
|
||||
aws-region: ${{ github.ref == 'refs/heads/main' && secrets.AWS_REGION || secrets.STAGING_AWS_REGION }}
|
||||
|
||||
- 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: Login to GHCR
|
||||
if: github.ref == 'refs/heads/main'
|
||||
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: 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 (always build for ECR)
|
||||
if [ "${{ github.ref }}" = "refs/heads/main" ]; then
|
||||
ECR_TAG="latest"
|
||||
else
|
||||
ECR_TAG="staging"
|
||||
fi
|
||||
ECR_IMAGE="${ECR_REGISTRY}/${ECR_REPO}:${ECR_TAG}"
|
||||
|
||||
# Build tags list
|
||||
TAGS="${ECR_IMAGE}"
|
||||
|
||||
# Add GHCR tags only for main branch
|
||||
if [ "${{ github.ref }}" = "refs/heads/main" ]; then
|
||||
GHCR_AMD64="${GHCR_IMAGE}:latest-amd64"
|
||||
GHCR_SHA="${GHCR_IMAGE}:${{ github.sha }}-amd64"
|
||||
TAGS="${TAGS},$GHCR_AMD64,$GHCR_SHA"
|
||||
fi
|
||||
|
||||
echo "tags=${TAGS}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Build and push images
|
||||
uses: useblacksmith/build-push-action@v2
|
||||
with:
|
||||
context: .
|
||||
file: ${{ matrix.dockerfile }}
|
||||
platforms: linux/amd64
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
provenance: false
|
||||
sbom: false
|
||||
|
||||
build-ghcr-arm64:
|
||||
name: Build ARM64 (GHCR Only)
|
||||
runs-on: linux-arm64-8-core
|
||||
if: 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 code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Login 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: Generate ARM64 tags
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ matrix.image }}
|
||||
tags: |
|
||||
type=raw,value=latest-arm64
|
||||
type=sha,format=long,suffix=-arm64
|
||||
|
||||
- name: Build and push ARM64 to GHCR
|
||||
uses: useblacksmith/build-push-action@v2
|
||||
with:
|
||||
context: .
|
||||
file: ${{ matrix.dockerfile }}
|
||||
platforms: linux/arm64
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
provenance: false
|
||||
sbom: false
|
||||
|
||||
create-ghcr-manifests:
|
||||
name: Create GHCR Manifests
|
||||
runs-on: blacksmith-4vcpu-ubuntu-2404
|
||||
needs: [build-amd64, build-ghcr-arm64]
|
||||
if: github.ref == 'refs/heads/main'
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- image: ghcr.io/simstudioai/simstudio
|
||||
- image: ghcr.io/simstudioai/migrations
|
||||
- image: ghcr.io/simstudioai/realtime
|
||||
|
||||
steps:
|
||||
- name: Login to GHCR
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Create and push manifests
|
||||
run: |
|
||||
IMAGE_BASE="${{ matrix.image }}"
|
||||
|
||||
# Create latest manifest
|
||||
docker manifest create "${IMAGE_BASE}:latest" \
|
||||
"${IMAGE_BASE}:latest-amd64" \
|
||||
"${IMAGE_BASE}:latest-arm64"
|
||||
docker manifest push "${IMAGE_BASE}:latest"
|
||||
|
||||
# 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 }}"
|
||||
28
.github/workflows/migrations.yml
vendored
Normal file
28
.github/workflows/migrations.yml
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
name: Database Migrations
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
migrate:
|
||||
name: Apply Database Migrations
|
||||
runs-on: blacksmith-4vcpu-ubuntu-2404
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: latest
|
||||
|
||||
- name: Install dependencies
|
||||
run: bun install
|
||||
|
||||
- name: Apply migrations
|
||||
working-directory: ./packages/db
|
||||
env:
|
||||
DATABASE_URL: ${{ github.ref == 'refs/heads/main' && secrets.DATABASE_URL || secrets.STAGING_DATABASE_URL }}
|
||||
run: bunx drizzle-kit migrate --config=./drizzle.config.ts
|
||||
54
.github/workflows/test-build.yml
vendored
Normal file
54
.github/workflows/test-build.yml
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
name: Test and Build
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
test-build:
|
||||
name: Test and Build
|
||||
runs-on: blacksmith-4vcpu-ubuntu-2404
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: latest
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: latest
|
||||
|
||||
- name: Install dependencies
|
||||
run: bun install --frozen-lockfile
|
||||
|
||||
- name: Run tests with coverage
|
||||
env:
|
||||
NODE_OPTIONS: '--no-warnings'
|
||||
NEXT_PUBLIC_APP_URL: 'https://www.sim.ai'
|
||||
DATABASE_URL: 'postgresql://postgres:postgres@localhost:5432/simstudio'
|
||||
ENCRYPTION_KEY: '7cf672e460e430c1fba707575c2b0e2ad5a99dddf9b7b7e3b5646e630861db1c' # dummy key for CI only
|
||||
run: bun run test
|
||||
|
||||
- name: Build application
|
||||
env:
|
||||
NODE_OPTIONS: '--no-warnings'
|
||||
NEXT_PUBLIC_APP_URL: 'https://www.sim.ai'
|
||||
DATABASE_URL: 'postgresql://postgres:postgres@localhost:5432/simstudio'
|
||||
STRIPE_SECRET_KEY: 'dummy_key_for_ci_only'
|
||||
STRIPE_WEBHOOK_SECRET: 'dummy_secret_for_ci_only'
|
||||
RESEND_API_KEY: 'dummy_key_for_ci_only'
|
||||
AWS_REGION: 'us-west-2'
|
||||
ENCRYPTION_KEY: '7cf672e460e430c1fba707575c2b0e2ad5a99dddf9b7b7e3b5646e630861db1c' # dummy key for CI only
|
||||
run: bun run build
|
||||
|
||||
- name: Upload coverage to Codecov
|
||||
uses: codecov/codecov-action@v5
|
||||
with:
|
||||
directory: ./apps/sim/coverage
|
||||
fail_ci_if_error: false
|
||||
verbose: true
|
||||
18
.github/workflows/trigger-deploy.yml
vendored
18
.github/workflows/trigger-deploy.yml
vendored
@@ -6,21 +6,22 @@ on:
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
name: Trigger.dev Deploy
|
||||
name: Deploy to Trigger.dev
|
||||
runs-on: blacksmith-4vcpu-ubuntu-2404
|
||||
concurrency:
|
||||
group: trigger-deploy-${{ github.ref }}
|
||||
cancel-in-progress: false
|
||||
env:
|
||||
TRIGGER_ACCESS_TOKEN: ${{ secrets.TRIGGER_ACCESS_TOKEN }}
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node.js
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 'lts/*'
|
||||
node-version: latest
|
||||
|
||||
- name: Setup Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
@@ -30,13 +31,12 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: bun install
|
||||
|
||||
- name: Deploy to Staging
|
||||
- name: Deploy to Trigger.dev (Staging)
|
||||
if: github.ref == 'refs/heads/staging'
|
||||
working-directory: ./apps/sim
|
||||
run: npx --yes trigger.dev@4.0.4 deploy -e staging
|
||||
run: npx --yes trigger.dev@4.0.4 deploy -e staging --skip-promotion
|
||||
|
||||
- name: Deploy to Production
|
||||
- name: Deploy to Trigger.dev (Production)
|
||||
if: github.ref == 'refs/heads/main'
|
||||
working-directory: ./apps/sim
|
||||
run: npx --yes trigger.dev@4.0.4 deploy
|
||||
|
||||
run: npx --yes trigger.dev@4.0.4 deploy --skip-promotion
|
||||
42
.github/workflows/trigger-promote.yml
vendored
Normal file
42
.github/workflows/trigger-promote.yml
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
name: Trigger.dev Promote
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
promote:
|
||||
name: Promote Trigger.dev
|
||||
runs-on: blacksmith-4vcpu-ubuntu-2404
|
||||
concurrency:
|
||||
group: trigger-promote-${{ github.ref }}
|
||||
cancel-in-progress: false
|
||||
env:
|
||||
TRIGGER_ACCESS_TOKEN: ${{ secrets.TRIGGER_ACCESS_TOKEN }}
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: latest
|
||||
|
||||
- name: Setup Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: latest
|
||||
|
||||
- name: Install dependencies
|
||||
run: bun install
|
||||
|
||||
- name: Promote Trigger.dev (Staging)
|
||||
if: github.ref == 'refs/heads/staging'
|
||||
working-directory: ./apps/sim
|
||||
run: npx --yes trigger.dev@4.0.4 deploy promote --latest -e staging
|
||||
|
||||
- name: Promote Trigger.dev (Production)
|
||||
if: github.ref == 'refs/heads/main'
|
||||
working-directory: ./apps/sim
|
||||
run: npx --yes trigger.dev@4.0.4 deploy promote --latest
|
||||
Reference in New Issue
Block a user