Skip to content

Add development standards documentation #2

Add development standards documentation

Add development standards documentation #2

Workflow file for this run

# Deployment Pipeline
# Deploys to AWS App Runner (backend) and S3/CloudFront (frontend)
name: Deploy
on:
push:
branches: [main]
workflow_dispatch:
inputs:
environment:
description: 'Environment to deploy to'
required: true
default: 'preprod'
type: choice
options:
- preprod
- prod
env:
AWS_REGION: us-east-1
jobs:
test:
name: Run Tests
uses: ./.github/workflows/ci.yml
deploy-preprod:
name: Deploy to Pre-Production
runs-on: ubuntu-latest
needs: test
if: (github.event_name == 'push' && github.ref == 'refs/heads/main') || (github.event_name == 'workflow_dispatch' && github.event.inputs.environment == 'preprod')
environment:
name: preprod
url: https://app.preprod.yourdomain.com
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID_PREPROD }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY_PREPROD }}
aws-region: ${{ env.AWS_REGION }}
- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build and push backend image
uses: docker/build-push-action@v6
with:
context: ./backend
push: true
platforms: linux/amd64
tags: |
${{ steps.login-ecr.outputs.registry }}/${{ secrets.ECR_REPOSITORY_PREPROD }}:latest
${{ steps.login-ecr.outputs.registry }}/${{ secrets.ECR_REPOSITORY_PREPROD }}:${{ github.sha }}
build-args: |
GIT_SHA=${{ github.sha }}
BUILD_TIMESTAMP=${{ github.event.head_commit.timestamp || github.event.repository.updated_at }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
cache-dependency-path: frontend/package-lock.json
- name: Build frontend
run: |
cd frontend
npm ci
VITE_API_URL=https://api.preprod.yourdomain.com \
VITE_COGNITO_USER_POOL_ID=${{ secrets.COGNITO_USER_POOL_ID_PREPROD }} \
VITE_COGNITO_CLIENT_ID=${{ secrets.COGNITO_CLIENT_ID_PREPROD }} \
VITE_COGNITO_DOMAIN=${{ secrets.COGNITO_DOMAIN_PREPROD }} \
VITE_COGNITO_REGION=us-east-1 \
npm run build
- name: Deploy frontend to S3
run: |
aws s3 sync frontend/dist s3://${{ secrets.S3_BUCKET_PREPROD }} \
--delete \
--cache-control "public, max-age=31536000, immutable" \
--exclude "index.html" \
--exclude "*.json"
aws s3 cp frontend/dist/index.html s3://${{ secrets.S3_BUCKET_PREPROD }}/index.html \
--cache-control "no-cache, no-store, must-revalidate"
- name: Invalidate CloudFront cache
run: |
aws cloudfront create-invalidation \
--distribution-id ${{ secrets.CLOUDFRONT_DISTRIBUTION_ID_PREPROD }} \
--paths "/*"
- name: Trigger App Runner deployment
run: |
aws apprunner start-deployment --service-arn ${{ secrets.APPRUNNER_SERVICE_ARN_PREPROD }} || true
- name: Wait for deployment and verify
run: |
echo "Waiting for deployment..."
EXPECTED_SHA="${{ github.sha }}"
for i in {1..60}; do
HEALTH=$(curl -sf https://api.preprod.yourdomain.com/api/health 2>/dev/null || echo '{}')
DEPLOYED_SHA=$(echo $HEALTH | jq -r '.git_sha // "unknown"')
echo "Attempt $i/60: Deployed=$DEPLOYED_SHA, Expected=$EXPECTED_SHA"
if [ "$DEPLOYED_SHA" = "$EXPECTED_SHA" ]; then
echo "Deployment verified!"
exit 0
fi
sleep 10
done
echo "Deployment verification failed"
exit 1
deploy-prod:
name: Deploy to Production
runs-on: ubuntu-latest
needs: test
if: github.event_name == 'workflow_dispatch' && github.event.inputs.environment == 'prod'
environment:
name: production
url: https://app.yourdomain.com
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID_PROD }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY_PROD }}
aws-region: ${{ env.AWS_REGION }}
- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build and push backend image
uses: docker/build-push-action@v6
with:
context: ./backend
push: true
platforms: linux/amd64
tags: |
${{ steps.login-ecr.outputs.registry }}/${{ secrets.ECR_REPOSITORY_PROD }}:latest
${{ steps.login-ecr.outputs.registry }}/${{ secrets.ECR_REPOSITORY_PROD }}:${{ github.sha }}
build-args: |
GIT_SHA=${{ github.sha }}
BUILD_TIMESTAMP=${{ github.event.head_commit.timestamp || github.event.repository.updated_at }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
cache-dependency-path: frontend/package-lock.json
- name: Build frontend
run: |
cd frontend
npm ci
VITE_API_URL=https://api.yourdomain.com \
VITE_COGNITO_USER_POOL_ID=${{ secrets.COGNITO_USER_POOL_ID_PROD }} \
VITE_COGNITO_CLIENT_ID=${{ secrets.COGNITO_CLIENT_ID_PROD }} \
VITE_COGNITO_DOMAIN=${{ secrets.COGNITO_DOMAIN_PROD }} \
VITE_COGNITO_REGION=us-east-1 \
npm run build
- name: Deploy frontend to S3
run: |
aws s3 sync frontend/dist s3://${{ secrets.S3_BUCKET_PROD }} \
--delete \
--cache-control "public, max-age=31536000, immutable" \
--exclude "index.html" \
--exclude "*.json"
aws s3 cp frontend/dist/index.html s3://${{ secrets.S3_BUCKET_PROD }}/index.html \
--cache-control "no-cache, no-store, must-revalidate"
- name: Invalidate CloudFront cache
run: |
aws cloudfront create-invalidation \
--distribution-id ${{ secrets.CLOUDFRONT_DISTRIBUTION_ID_PROD }} \
--paths "/*"
- name: Trigger App Runner deployment
run: |
aws apprunner start-deployment --service-arn ${{ secrets.APPRUNNER_SERVICE_ARN_PROD }} || true
- name: Verify deployment
run: |
echo "Waiting for production deployment..."
EXPECTED_SHA="${{ github.sha }}"
for i in {1..60}; do
HEALTH=$(curl -sf https://api.yourdomain.com/api/health 2>/dev/null || echo '{}')
DEPLOYED_SHA=$(echo $HEALTH | jq -r '.git_sha // "unknown"')
if [ "$DEPLOYED_SHA" = "$EXPECTED_SHA" ]; then
echo "Production deployment verified!"
exit 0
fi
sleep 10
done
exit 1