Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
161 changes: 161 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
name: Build and Test

on:
push:
branches: [ main, develop, 'feature/**' ]
pull_request:
branches: [ main, develop ]

jobs:
backend-build:
name: Backend Build & Test
runs-on: ubuntu-latest

strategy:
matrix:
node-version: [18.x, 20.x]

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}

- name: Install dependencies
working-directory: ./backend
run: npm install

- name: Run linter
working-directory: ./backend
run: npm run lint --if-present

- name: Run tests
working-directory: ./backend
run: npm test --if-present

- name: Build
working-directory: ./backend
run: npm run build --if-present

- name: Upload coverage reports
if: matrix.node-version == '18.x'
uses: codecov/codecov-action@v3
with:
directory: ./backend/coverage
flags: backend

backend-docker:
name: Backend Docker Build
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Build Docker image
uses: docker/build-push-action@v5
with:
context: ./backend
push: false
tags: cloudkeep-backend:latest
cache-from: type=gha
cache-to: type=gha,mode=max

frontend-build:
name: Frontend Build & Test
runs-on: ubuntu-latest

strategy:
matrix:
node-version: [18.x, 20.x]

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}

- name: Install dependencies
working-directory: ./frontend
run: npm install

- name: Run linter
working-directory: ./frontend
run: npm run lint --if-present

- name: Run tests
working-directory: ./frontend
run: npm test --if-present
env:
CI: true

- name: Build
working-directory: ./frontend
run: npm run build
env:
CI: true

- name: Upload build artifacts
if: matrix.node-version == '18.x'
uses: actions/upload-artifact@v3
with:
name: frontend-build
path: frontend/build
retention-days: 7

- name: Upload coverage reports
if: matrix.node-version == '18.x'
uses: codecov/codecov-action@v3
with:
directory: ./frontend/coverage
flags: frontend

frontend-docker:
name: Frontend Docker Build
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Build Docker image
uses: docker/build-push-action@v5
with:
context: ./frontend
push: false
tags: cloudkeep-frontend:latest
cache-from: type=gha
cache-to: type=gha,mode=max

security-scan:
name: Security Scan
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
scan-type: 'fs'
scan-ref: '.'
format: 'sarif'
output: 'trivy-results.sarif'

- name: Upload Trivy results to GitHub Security
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: 'trivy-results.sarif'
183 changes: 183 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
name: Deploy

on:
push:
branches:
- main
- develop
workflow_dispatch:
inputs:
environment:
description: 'Environment to deploy to'
required: true
type: choice
options:
- dev
- staging
- production

env:
AWS_REGION: us-east-1

jobs:
determine-environment:
name: Determine Environment
runs-on: ubuntu-latest
outputs:
environment: ${{ steps.set-env.outputs.environment }}
steps:
- name: Set environment
id: set-env
run: |
if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
echo "environment=${{ inputs.environment }}" >> $GITHUB_OUTPUT
elif [ "${{ github.ref }}" == "refs/heads/main" ]; then
echo "environment=production" >> $GITHUB_OUTPUT
elif [ "${{ github.ref }}" == "refs/heads/develop" ]; then
echo "environment=staging" >> $GITHUB_OUTPUT
else
echo "environment=dev" >> $GITHUB_OUTPUT
fi

deploy-backend:
name: Deploy Backend
runs-on: ubuntu-latest
needs: determine-environment
environment: ${{ needs.determine-environment.outputs.environment }}

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18.x'

- name: Install dependencies
working-directory: ./backend
run: npm install

- name: Install Serverless Framework
run: npm install -g serverless

- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ env.AWS_REGION }}

- name: Deploy to AWS Lambda
working-directory: ./backend
run: |
serverless deploy --stage ${{ needs.determine-environment.outputs.environment }} --region ${{ env.AWS_REGION }}

- name: Get deployment outputs
id: outputs
working-directory: ./backend
run: |
API_URL=$(serverless info --stage ${{ needs.determine-environment.outputs.environment }} --region ${{ env.AWS_REGION }} | grep "endpoint:" | awk '{print $2}')
echo "api_url=$API_URL" >> $GITHUB_OUTPUT

- name: Store API URL
run: |
echo "Backend API URL: ${{ steps.outputs.outputs.api_url }}"

deploy-frontend:
name: Deploy Frontend
runs-on: ubuntu-latest
needs: [determine-environment, deploy-backend]
environment: ${{ needs.determine-environment.outputs.environment }}

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18.x'

- name: Install dependencies
working-directory: ./frontend
run: npm install

- name: Build frontend
working-directory: ./frontend
run: npm run build
env:
CI: true
REACT_APP_API_URL: ${{ needs.deploy-backend.outputs.api_url }}
REACT_APP_STAGE: ${{ needs.determine-environment.outputs.environment }}

- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ env.AWS_REGION }}

- name: Deploy to S3
working-directory: ./frontend
run: |
aws s3 sync build/ s3://cloudkeep-frontend-${{ needs.determine-environment.outputs.environment }} --delete

- name: Invalidate CloudFront cache
if: needs.determine-environment.outputs.environment == 'production'
run: |
aws cloudfront create-invalidation --distribution-id ${{ secrets.CLOUDFRONT_DISTRIBUTION_ID }} --paths "/*"

deploy-docker:
name: Deploy Docker Images
runs-on: ubuntu-latest
needs: determine-environment
if: needs.determine-environment.outputs.environment == 'production'

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}

- name: Build and push backend image
uses: docker/build-push-action@v5
with:
context: ./backend
push: true
tags: |
${{ secrets.DOCKER_USERNAME }}/cloudkeep-backend:latest
${{ secrets.DOCKER_USERNAME }}/cloudkeep-backend:${{ github.sha }}
cache-from: type=gha
cache-to: type=gha,mode=max

- name: Build and push frontend image
uses: docker/build-push-action@v5
with:
context: ./frontend
push: true
tags: |
${{ secrets.DOCKER_USERNAME }}/cloudkeep-frontend:latest
${{ secrets.DOCKER_USERNAME }}/cloudkeep-frontend:${{ github.sha }}
cache-from: type=gha
cache-to: type=gha,mode=max

notify:
name: Notify Deployment Status
runs-on: ubuntu-latest
needs: [determine-environment, deploy-backend, deploy-frontend]
if: always()

steps:
- name: Send notification
run: |
echo "Deployment to ${{ needs.determine-environment.outputs.environment }} completed"
echo "Backend: ${{ needs.deploy-backend.result }}"
echo "Frontend: ${{ needs.deploy-frontend.result }}"
Loading
Loading