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
199 changes: 199 additions & 0 deletions .github/workflows/ci-cd.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
name: CI/CD Pipeline with Tests and Docker

on:
push:
branches: [ main, sullivantuft-branch ]
pull_request:
branches: [ main ]
workflow_dispatch:

jobs:
# Backend testing job
test-backend:
runs-on: ubuntu-latest

defaults:
run:
working-directory: backend

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

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
cache: 'npm'
cache-dependency-path: backend/package-lock.json

- name: Install dependencies
run: npm ci

- name: Run Jest tests with coverage
run: npm run test:ci
env:
SUPABASE_URL: ${{ secrets.SUPABASE_URL }}
SUPABASE_KEY: ${{ secrets.SUPABASE_KEY }}
PORT: ${{ secrets.PORT }}

- name: Upload backend coverage reports
uses: codecov/codecov-action@v4
with:
files: ./backend/coverage/lcov.info
flags: backend
name: backend-coverage
fail_ci_if_error: false

# Frontend testing job
test-frontend:
runs-on: ubuntu-latest

defaults:
run:
working-directory: frontend

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

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
cache: 'npm'
cache-dependency-path: frontend/package-lock.json

- name: Install dependencies
run: npm ci

- name: Run Jest tests with coverage
run: npm test
env:
CI: true

- name: Upload frontend coverage reports
uses: codecov/codecov-action@v4
with:
files: ./frontend/coverage/lcov.info
flags: frontend
name: frontend-coverage
fail_ci_if_error: false

# Build and push Docker images
build-and-push:
runs-on: ubuntu-latest
needs: [test-backend, test-frontend]
if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/sullivantuft-branch')

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

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

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

- name: Extract metadata for frontend
id: meta-frontend
uses: docker/metadata-action@v5
with:
images: shawnjensen/devops-group-c-fall2025-frontend
tags: |
type=ref,event=branch
type=sha,prefix={{branch}}-
type=raw,value=latest,enable={{is_default_branch}}

- name: Build and push frontend Docker image
uses: docker/build-push-action@v5
with:
context: ./frontend
file: ./frontend/Dockerfile
push: true
tags: ${{ steps.meta-frontend.outputs.tags }}
labels: ${{ steps.meta-frontend.outputs.labels }}
cache-from: type=registry,ref=shawnjensen/devops-group-c-fall2025-frontend:buildcache
cache-to: type=registry,ref=shawnjensen/devops-group-c-fall2025-frontend:buildcache,mode=max

- name: Extract metadata for backend
id: meta-backend
uses: docker/metadata-action@v5
with:
images: shawnjensen/devops-group-c-fall2025-backend
tags: |
type=ref,event=branch
type=sha,prefix={{branch}}-
type=raw,value=latest,enable={{is_default_branch}}

- name: Build and push backend Docker image
uses: docker/build-push-action@v5
with:
context: ./backend
file: ./backend/Dockerfile
push: true
tags: ${{ steps.meta-backend.outputs.tags }}
labels: ${{ steps.meta-backend.outputs.labels }}
cache-from: type=registry,ref=shawnjensen/devops-group-c-fall2025-backend:buildcache
cache-to: type=registry,ref=shawnjensen/devops-group-c-fall2025-backend:buildcache,mode=max

# Deploy to AWS EC2 (optional, triggered manually or after successful build)
deploy-to-ec2:
runs-on: ubuntu-latest
needs: [build-and-push]
if: github.event_name == 'push' && github.ref == 'refs/heads/main'

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 }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-session-token: ${{ secrets.AWS_SESSION_TOKEN }}
aws-region: us-west-2

- name: Deploy to EC2 via SSH
uses: appleboy/ssh-action@v1.0.0
with:
host: ${{ secrets.EC2_HOST }}
username: ${{ secrets.EC2_USERNAME }}
key: ${{ secrets.EC2_SSH_KEY }}
script: |
# Pull latest images
docker pull shawnjensen/devops-group-c-fall2025-frontend:latest
docker pull shawnjensen/devops-group-c-fall2025-backend:latest

# Stop and remove old containers
docker stop frontend backend || true
docker rm frontend backend || true

# Run new containers
docker run -d \
--name backend \
-p 5000:5000 \
-e SUPABASE_URL=${{ secrets.SUPABASE_URL }} \
-e SUPABASE_KEY=${{ secrets.SUPABASE_KEY }} \
-e PORT=${{ secrets.PORT }} \
shawnjensen/devops-group-c-fall2025-backend:latest

docker run -d \
--name frontend \
-p 80:80 \
-e REACT_APP_BACKEND_URL=http://localhost:5000 \
shawnjensen/devops-group-c-fall2025-frontend:latest

# Clean up old images
docker image prune -af

- name: Verify deployment
run: |
echo "Deployment completed successfully!"
echo "Frontend should be available at: http://${{ secrets.EC2_HOST }}"
echo "Backend should be available at: http://${{ secrets.EC2_HOST }}:5000"
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,5 @@ Thumbs.db

# Logs
*.log

TESTING.md
138 changes: 138 additions & 0 deletions backend/coverage/clover.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
<?xml version="1.0" encoding="UTF-8"?>
<coverage generated="1765570211017" clover="3.2.0">
<project timestamp="1765570211017" name="All files">
<metrics statements="108" coveredstatements="107" conditionals="30" coveredconditionals="28" methods="17" coveredmethods="16" elements="155" coveredelements="151" complexity="0" loc="108" ncloc="108" packages="2" files="6" classes="6"/>
<package name="backend">
<metrics statements="20" coveredstatements="19" conditionals="4" coveredconditionals="2" methods="1" coveredmethods="0"/>
<file name="server.js" path="C:\Users\Sullivan\Documents\itm350final\devops-group-c-fall2025\backend\server.js">
<metrics statements="20" coveredstatements="19" conditionals="4" coveredconditionals="2" methods="1" coveredmethods="0"/>
<line num="1" count="1" type="stmt"/>
<line num="2" count="1" type="stmt"/>
<line num="3" count="1" type="stmt"/>
<line num="5" count="1" type="stmt"/>
<line num="6" count="1" type="stmt"/>
<line num="7" count="1" type="stmt"/>
<line num="10" count="1" type="stmt"/>
<line num="11" count="1" type="stmt"/>
<line num="17" count="1" type="stmt"/>
<line num="18" count="1" type="stmt"/>
<line num="19" count="1" type="stmt"/>
<line num="20" count="1" type="stmt"/>
<line num="22" count="1" type="stmt"/>
<line num="23" count="1" type="stmt"/>
<line num="24" count="1" type="stmt"/>
<line num="25" count="1" type="stmt"/>
<line num="27" count="1" type="cond" truecount="1" falsecount="1"/>
<line num="29" count="1" type="cond" truecount="1" falsecount="1"/>
<line num="30" count="0" type="stmt"/>
<line num="33" count="1" type="stmt"/>
</file>
</package>
<package name="backend.routes">
<metrics statements="88" coveredstatements="88" conditionals="26" coveredconditionals="26" methods="16" coveredmethods="16"/>
<file name="activity.js" path="C:\Users\Sullivan\Documents\itm350final\devops-group-c-fall2025\backend\routes\activity.js">
<metrics statements="14" coveredstatements="14" conditionals="4" coveredconditionals="4" methods="3" coveredmethods="3"/>
<line num="1" count="2" type="stmt"/>
<line num="3" count="2" type="stmt"/>
<line num="4" count="4" type="stmt"/>
<line num="7" count="4" type="stmt"/>
<line num="8" count="2" type="stmt"/>
<line num="9" count="2" type="stmt"/>
<line num="15" count="2" type="cond" truecount="2" falsecount="0"/>
<line num="16" count="1" type="stmt"/>
<line num="20" count="4" type="stmt"/>
<line num="21" count="2" type="stmt"/>
<line num="22" count="2" type="stmt"/>
<line num="27" count="2" type="cond" truecount="2" falsecount="0"/>
<line num="28" count="1" type="stmt"/>
<line num="31" count="4" type="stmt"/>
</file>
<file name="auth.js" path="C:\Users\Sullivan\Documents\itm350final\devops-group-c-fall2025\backend\routes\auth.js">
<metrics statements="18" coveredstatements="18" conditionals="4" coveredconditionals="4" methods="3" coveredmethods="3"/>
<line num="1" count="2" type="stmt"/>
<line num="3" count="2" type="stmt"/>
<line num="4" count="6" type="stmt"/>
<line num="7" count="6" type="stmt"/>
<line num="8" count="3" type="stmt"/>
<line num="9" count="3" type="stmt"/>
<line num="10" count="3" type="stmt"/>
<line num="15" count="2" type="cond" truecount="2" falsecount="0"/>
<line num="16" count="1" type="stmt"/>
<line num="18" count="1" type="stmt"/>
<line num="23" count="6" type="stmt"/>
<line num="24" count="3" type="stmt"/>
<line num="25" count="3" type="stmt"/>
<line num="26" count="3" type="stmt"/>
<line num="30" count="2" type="cond" truecount="2" falsecount="0"/>
<line num="31" count="1" type="stmt"/>
<line num="33" count="1" type="stmt"/>
<line num="37" count="6" type="stmt"/>
</file>
<file name="boards.js" path="C:\Users\Sullivan\Documents\itm350final\devops-group-c-fall2025\backend\routes\boards.js">
<metrics statements="22" coveredstatements="22" conditionals="8" coveredconditionals="8" methods="3" coveredmethods="3"/>
<line num="1" count="2" type="stmt"/>
<line num="3" count="2" type="stmt"/>
<line num="4" count="8" type="stmt"/>
<line num="7" count="8" type="stmt"/>
<line num="8" count="3" type="stmt"/>
<line num="10" count="3" type="stmt"/>
<line num="11" count="3" type="stmt"/>
<line num="17" count="2" type="cond" truecount="2" falsecount="0"/>
<line num="18" count="1" type="stmt"/>
<line num="21" count="1" type="stmt"/>
<line num="23" count="1" type="stmt"/>
<line num="28" count="8" type="stmt"/>
<line num="29" count="5" type="stmt"/>
<line num="31" count="5" type="cond" truecount="4" falsecount="0"/>
<line num="32" count="2" type="stmt"/>
<line num="35" count="3" type="stmt"/>
<line num="36" count="3" type="stmt"/>
<line num="41" count="2" type="cond" truecount="2" falsecount="0"/>
<line num="42" count="1" type="stmt"/>
<line num="45" count="1" type="stmt"/>
<line num="47" count="1" type="stmt"/>
<line num="51" count="8" type="stmt"/>
</file>
<file name="cards.js" path="C:\Users\Sullivan\Documents\itm350final\devops-group-c-fall2025\backend\routes\cards.js">
<metrics statements="20" coveredstatements="20" conditionals="6" coveredconditionals="6" methods="4" coveredmethods="4"/>
<line num="1" count="2" type="stmt"/>
<line num="3" count="2" type="stmt"/>
<line num="4" count="6" type="stmt"/>
<line num="7" count="6" type="stmt"/>
<line num="8" count="2" type="stmt"/>
<line num="9" count="2" type="stmt"/>
<line num="15" count="2" type="cond" truecount="2" falsecount="0"/>
<line num="16" count="1" type="stmt"/>
<line num="20" count="6" type="stmt"/>
<line num="21" count="2" type="stmt"/>
<line num="22" count="2" type="stmt"/>
<line num="27" count="2" type="cond" truecount="2" falsecount="0"/>
<line num="28" count="1" type="stmt"/>
<line num="32" count="6" type="stmt"/>
<line num="33" count="2" type="stmt"/>
<line num="34" count="2" type="stmt"/>
<line num="36" count="2" type="stmt"/>
<line num="42" count="2" type="cond" truecount="2" falsecount="0"/>
<line num="43" count="1" type="stmt"/>
<line num="46" count="6" type="stmt"/>
</file>
<file name="lists.js" path="C:\Users\Sullivan\Documents\itm350final\devops-group-c-fall2025\backend\routes\lists.js">
<metrics statements="14" coveredstatements="14" conditionals="4" coveredconditionals="4" methods="3" coveredmethods="3"/>
<line num="1" count="2" type="stmt"/>
<line num="3" count="2" type="stmt"/>
<line num="4" count="4" type="stmt"/>
<line num="7" count="4" type="stmt"/>
<line num="8" count="2" type="stmt"/>
<line num="9" count="2" type="stmt"/>
<line num="15" count="2" type="cond" truecount="2" falsecount="0"/>
<line num="16" count="1" type="stmt"/>
<line num="20" count="4" type="stmt"/>
<line num="21" count="2" type="stmt"/>
<line num="22" count="2" type="stmt"/>
<line num="27" count="2" type="cond" truecount="2" falsecount="0"/>
<line num="28" count="1" type="stmt"/>
<line num="31" count="4" type="stmt"/>
</file>
</package>
</project>
</coverage>
Loading
Loading