Merge pull request #447 from lisafast/fix/auto-deploy #83
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Deploy to AWS App Runner | |
| on: | |
| workflow_dispatch: | |
| push: | |
| branches: | |
| - main | |
| permissions: | |
| contents: read | |
| id-token: write | |
| jobs: | |
| deploy: | |
| runs-on: ubuntu-latest | |
| env: | |
| AWS_REGION: ${{ secrets.AWS_REGION }} | |
| AWS_ASSUME_ROLE_ARN: ${{ secrets.AWS_ASSUME_ROLE_ARN }} | |
| APP_RUNNER_SERVICE_ARN: ${{ secrets.APP_RUNNER_SERVICE_ARN }} | |
| ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} | |
| OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} | |
| GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }} | |
| GOOGLE_SEARCH_ENGINE_ID: ${{ secrets.GOOGLE_SEARCH_ENGINE_ID }} | |
| DOCDB_URI: ${{ secrets.DOCDB_URI }} | |
| JWT_SECRET_KEY: ${{ secrets.JWT_SECRET_KEY }} | |
| NODE_ENV: ${{ secrets.NODE_ENV }} | |
| steps: | |
| - name: Configure AWS credentials via OIDC | |
| uses: aws-actions/configure-aws-credentials@v2 | |
| with: | |
| role-to-assume: ${{ env.AWS_ASSUME_ROLE_ARN }} | |
| aws-region: ${{ env.AWS_REGION }} | |
| - name: Write update-input.json | |
| run: | | |
| cat > update-input.json <<-EOF | |
| { | |
| "ServiceArn": "${{ env.APP_RUNNER_SERVICE_ARN }}", | |
| "SourceConfiguration": { | |
| "CodeRepository": { | |
| "RepositoryUrl": "https://github.com/${{ github.repository }}", | |
| "SourceCodeVersion": { | |
| "Type": "BRANCH", | |
| "Value": "main" | |
| }, | |
| "CodeConfiguration": { | |
| "ConfigurationSource": "API", | |
| "CodeConfigurationValues": { | |
| "Runtime": "NODEJS_22", | |
| "BuildCommand": "npm install && npm run build", | |
| "StartCommand": "npm run start-server", | |
| "RuntimeEnvironmentVariables": { | |
| "DEPLOY_RUN_ID": "${{ github.run_id }}", | |
| "ANTHROPIC_API_KEY": "${{ env.ANTHROPIC_API_KEY }}", | |
| "OPENAI_API_KEY": "${{ env.OPENAI_API_KEY }}", | |
| "GOOGLE_API_KEY": "${{ env.GOOGLE_API_KEY }}", | |
| "GOOGLE_SEARCH_ENGINE_ID": "${{ env.GOOGLE_SEARCH_ENGINE_ID }}", | |
| "DOCDB_URI": "${{ env.DOCDB_URI }}", | |
| "JWT_SECRET_KEY": "${{ env.JWT_SECRET_KEY }}", | |
| "NODE_ENV": "${{ env.NODE_ENV }}" | |
| } | |
| } | |
| } | |
| } | |
| }, | |
| "InstanceConfiguration": { "Cpu": "512", "Memory": "1024" }, | |
| "HealthCheckConfiguration": { | |
| "Protocol": "HTTP", | |
| "Path": "/health", | |
| "Interval": 20, | |
| "Timeout": 15, | |
| "HealthyThreshold": 1, | |
| "UnhealthyThreshold": 10 | |
| } | |
| } | |
| EOF | |
| - name: Wait up to 4h for idle | |
| run: | | |
| echo "Waiting for App Runner to be idle..." | |
| for i in {1..240}; do | |
| STATUS=$(aws apprunner describe-service \ | |
| --service-arn "${{ env.APP_RUNNER_SERVICE_ARN }}" \ | |
| --region ${{ env.AWS_REGION }} \ | |
| --query 'Service.OperationSummary.Status' --output text) | |
| [[ "$STATUS" != "IN_PROGRESS" ]] && break | |
| sleep 60 | |
| done | |
| - name: Update service (retries) | |
| run: | | |
| set -e | |
| for i in {1..10}; do | |
| if aws apprunner update-service --cli-input-json file://update-input.json --region ${{ env.AWS_REGION }}; then | |
| echo "✅ update-service succeeded" | |
| break | |
| else | |
| echo "🔁 Retrying in 60s..." | |
| sleep 60 | |
| fi | |
| done | |
| - name: Wait up to 4h for RUNNING (force if not deploying) | |
| run: | | |
| echo "Waiting for service RUNNING or IN_PROGRESS..." | |
| for i in {1..240}; do | |
| STATE=$(aws apprunner describe-service \ | |
| --service-arn "${{ env.APP_RUNNER_SERVICE_ARN }}" \ | |
| --region ${{ env.AWS_REGION }} \ | |
| --query 'Service.Status' --output text) | |
| OP_STATUS=$(aws apprunner describe-service \ | |
| --service-arn "${{ env.APP_RUNNER_SERVICE_ARN }}" \ | |
| --region ${{ env.AWS_REGION }} \ | |
| --query 'Service.OperationSummary.Status' --output text) | |
| if [[ "$STATE" == "RUNNING" ]]; then | |
| if [[ "$OP_STATUS" != "IN_PROGRESS" ]]; then | |
| echo "⚠️ No deployment in progress, forcing deployment..." | |
| aws apprunner start-deployment \ | |
| --service-arn "${{ env.APP_RUNNER_SERVICE_ARN }}" \ | |
| --region ${{ env.AWS_REGION }} | |
| sleep 10 | |
| else | |
| echo "🟢 Service is RUNNING and deployment is in progress." | |
| exit 0 | |
| fi | |
| elif [[ "$STATE" == "FAILED" ]]; then | |
| echo "❌ Deployment FAILED!" | |
| exit 1 | |
| else | |
| echo "⏳ Service state: $STATE, operation: $OP_STATUS. Waiting..." | |
| fi | |
| sleep 60 | |
| done | |
| echo "❌ Timed out"; exit 1 | |
| - name: Output App Runner URL | |
| run: | | |
| URL=$(aws apprunner describe-service \ | |
| --service-arn "${{ env.APP_RUNNER_SERVICE_ARN }}" \ | |
| --region ${{ env.AWS_REGION }} \ | |
| --query 'Service.ServiceUrl' --output text) | |
| echo "✅ App Runner URL: $URL" |