Skip to content

Commit be4ba6b

Browse files
committed
Prepared CICD folder for A2 submission
1 parent 924412c commit be4ba6b

File tree

5 files changed

+355
-0
lines changed

5 files changed

+355
-0
lines changed

CICD/README.md

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
# CSCC01 Assignment 2 - CI/CD Submission (Team: Microsofties)
2+
3+
This folder contains the Dockerfiles, CI/CD workflows, integration test scripts, and documentation required for Assignment 2.
4+
5+
---
6+
7+
## What This Project Does
8+
9+
This project automates the CI/CD pipeline for a full-stack web application using:
10+
11+
- **GitHub Actions** for continuous integration and deployment
12+
- **Docker & Docker Hub** for containerization and versioning
13+
- **Render** for live deployment of frontend and backend containers
14+
15+
---
16+
17+
## Folder Structure
18+
19+
CICD/
20+
21+
├── backend/
22+
23+
│ └── Dockerfile
24+
25+
├── frontend/
26+
27+
│ └── Dockerfile
28+
29+
├── scripts/
30+
31+
│ └── integration-test.sh
32+
33+
├── workflows/
34+
35+
│ └── ci-cd.yml
36+
37+
├── README.md
38+
39+
└── Report.pdf
40+
41+
---
42+
43+
## CI/CD Workflow
44+
45+
On every push to `main`, GitHub Actions will:
46+
47+
1. Run **unit tests** for both frontend and backend using Jest
48+
2. Build and tag Docker images (`latest` and versioned)
49+
3. Push images to Docker Hub
50+
4. Trigger **Render deploy hooks** for both frontend and backend
51+
5. Wait for services to go live
52+
6. Run **integration tests** by hitting live endpoints via `curl`
53+
54+
---
55+
56+
## Integration Tests
57+
58+
The integration tests (`scripts/integration-test.sh`) validate the deployed containers by:
59+
60+
- Hitting the backend health check at `/api/health`
61+
- Hitting a key backend API route `/api/water-data`
62+
- Checking that the frontend root (`/`) returns a response
63+
64+
---
65+
66+
## Environment Variables (Set in Render)
67+
68+
**Backend:**
69+
70+
- `MONGODB_URI` → MongoDB Atlas connection string
71+
- `JWT_SECRET` → Secret key for token generation
72+
73+
**Frontend:**
74+
75+
- `REACT_APP_API_URL` → URL of deployed backend (e.g., `https://glow-backend-v4-0-0.onrender.com`)
76+
77+
---
78+
79+
## Manual Test Commands (Optional)
80+
81+
From project root:
82+
83+
```bash
84+
# Run backend locally
85+
cd backend
86+
npm install
87+
npm test
88+
89+
# Run frontend locally
90+
cd frontend
91+
npm install
92+
npm test
93+
94+
# Run integration test against deployed services
95+
bash CICD/scripts/integration-test.sh

CICD/Report.pdf

108 KB
Binary file not shown.

CICD/backend/Dockerfile

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Use the official Node.js runtime as the base image
2+
FROM node:18-alpine
3+
4+
# Set the working directory inside the container
5+
WORKDIR /app
6+
7+
# Copy package.json and package-lock.json (if available)
8+
COPY package*.json ./
9+
10+
# Install dependencies
11+
RUN npm ci --only=production
12+
13+
# Copy the rest of the application code
14+
COPY . .
15+
16+
# Create a non-root user to run the application
17+
RUN addgroup -g 1001 -S nodejs
18+
RUN adduser -S backend -u 1001
19+
20+
# Change ownership of the app directory to the nodejs user
21+
RUN chown -R backend:nodejs /app
22+
USER backend
23+
24+
# Expose the port the app runs on
25+
EXPOSE 5000
26+
27+
# Define the command to run the application
28+
CMD ["npm", "start"]

CICD/frontend/Dockerfile

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Use the official Node.js runtime as the base image
2+
FROM node:18-alpine
3+
4+
# Set the working directory inside the container
5+
WORKDIR /app
6+
7+
# Copy package.json and package-lock.json (if available)
8+
COPY package*.json ./
9+
10+
# Install dependencies
11+
RUN npm ci --only=production
12+
13+
# Copy the rest of the application code
14+
COPY . .
15+
16+
# Build the Next.js application
17+
RUN npm run build
18+
19+
# Create a non-root user to run the application
20+
RUN addgroup -g 1001 -S nodejs
21+
RUN adduser -S frontend -u 1001
22+
23+
# Change ownership of the app directory to the nodejs user
24+
RUN chown -R frontend:nodejs /app
25+
USER frontend
26+
27+
# Expose the port the app runs on
28+
EXPOSE 3000
29+
30+
# Define the command to run the application
31+
CMD ["npm", "start"]
Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
name: Build and Push Docker Images
2+
3+
on:
4+
push:
5+
branches: [ main, master ]
6+
pull_request:
7+
branches: [ main, master ]
8+
9+
env:
10+
DOCKER_HUB_USERNAME: ${{ secrets.DOCKER_HUB_USERNAME }}
11+
12+
jobs:
13+
test-backend:
14+
runs-on: ubuntu-latest
15+
16+
steps:
17+
- name: Checkout code
18+
uses: actions/checkout@v4
19+
20+
- name: Set up Node.js
21+
uses: actions/setup-node@v4
22+
with:
23+
node-version: '18'
24+
cache: 'npm'
25+
cache-dependency-path: backend/package-lock.json
26+
27+
- name: Install backend dependencies
28+
run: |
29+
cd backend
30+
npm ci
31+
32+
- name: Run backend tests
33+
run: |
34+
cd backend
35+
npm test
36+
env:
37+
NODE_ENV: test
38+
JWT_SECRET: test_jwt_secret
39+
MONGODB_URI: mongodb://localhost:27017/glow_test
40+
41+
- name: Upload backend test results
42+
uses: actions/upload-artifact@v4
43+
if: always()
44+
with:
45+
name: backend-test-results
46+
path: backend/coverage/
47+
48+
test-frontend:
49+
runs-on: ubuntu-latest
50+
51+
steps:
52+
- name: Checkout code
53+
uses: actions/checkout@v4
54+
55+
- name: Set up Node.js
56+
uses: actions/setup-node@v4
57+
with:
58+
node-version: '18'
59+
cache: 'npm'
60+
cache-dependency-path: frontend/package-lock.json
61+
62+
- name: Install frontend dependencies
63+
run: |
64+
cd frontend
65+
npm ci
66+
67+
- name: Run frontend tests
68+
run: |
69+
cd frontend
70+
npm test -- --coverage --watchAll=false
71+
env:
72+
NEXT_PUBLIC_API_URL: http://localhost:5000/api
73+
CI: true
74+
75+
- name: Upload frontend test results
76+
uses: actions/upload-artifact@v4
77+
if: always()
78+
with:
79+
name: frontend-test-results
80+
path: frontend/coverage/
81+
82+
build-backend:
83+
runs-on: ubuntu-latest
84+
needs: [test-backend]
85+
86+
steps:
87+
- name: Checkout code
88+
uses: actions/checkout@v4
89+
90+
- name: Set up Docker Buildx
91+
uses: docker/setup-buildx-action@v3
92+
93+
- name: Log in to Docker Hub
94+
uses: docker/login-action@v3
95+
with:
96+
username: ${{ secrets.DOCKER_HUB_USERNAME }}
97+
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
98+
99+
- name: Extract metadata for backend
100+
id: meta-backend
101+
uses: docker/metadata-action@v5
102+
with:
103+
images: ${{ env.DOCKER_HUB_USERNAME }}/glow-backend
104+
tags: |
105+
type=ref,event=branch
106+
type=ref,event=pr
107+
type=sha,prefix=commit-
108+
type=raw,value=latest,enable={{is_default_branch}}
109+
110+
- name: Build and push backend Docker image
111+
uses: docker/build-push-action@v5
112+
with:
113+
context: ./backend
114+
file: ./backend/Dockerfile
115+
push: true
116+
tags: ${{ steps.meta-backend.outputs.tags }}
117+
labels: ${{ steps.meta-backend.outputs.labels }}
118+
cache-from: type=gha
119+
cache-to: type=gha,mode=max
120+
121+
- name: Trigger backend redeploy on Render
122+
if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master'
123+
run: |
124+
curl -X POST "${{ secrets.RENDER_BACKEND_DEPLOY_HOOK }}"
125+
env:
126+
RENDER_BACKEND_DEPLOY_HOOK: ${{ secrets.RENDER_BACKEND_DEPLOY_HOOK }}
127+
128+
build-frontend:
129+
runs-on: ubuntu-latest
130+
needs: [test-frontend]
131+
132+
steps:
133+
- name: Checkout code
134+
uses: actions/checkout@v4
135+
136+
- name: Set up Docker Buildx
137+
uses: docker/setup-buildx-action@v3
138+
139+
- name: Log in to Docker Hub
140+
uses: docker/login-action@v3
141+
with:
142+
username: ${{ secrets.DOCKER_HUB_USERNAME }}
143+
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
144+
145+
- name: Extract metadata for frontend
146+
id: meta-frontend
147+
uses: docker/metadata-action@v5
148+
with:
149+
images: ${{ env.DOCKER_HUB_USERNAME }}/glow-frontend
150+
tags: |
151+
type=ref,event=branch
152+
type=ref,event=pr
153+
type=sha,prefix=commit-
154+
type=raw,value=latest,enable={{is_default_branch}}
155+
156+
- name: Build and push frontend Docker image
157+
uses: docker/build-push-action@v5
158+
with:
159+
context: ./frontend
160+
file: ./frontend/Dockerfile
161+
push: true
162+
build-args: |
163+
NEXT_PUBLIC_API_URL=https://glow-backend-v4-0-0.onrender.com/api
164+
tags: ${{ steps.meta-frontend.outputs.tags }}
165+
labels: ${{ steps.meta-frontend.outputs.labels }}
166+
cache-from: type=gha
167+
cache-to: type=gha,mode=max
168+
169+
- name: Trigger frontend redeploy on Render
170+
if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master'
171+
run: |
172+
curl -X POST "${{ secrets.RENDER_FRONTEND_DEPLOY_HOOK }}"
173+
env:
174+
RENDER_FRONTEND_DEPLOY_HOOK: ${{ secrets.RENDER_FRONTEND_DEPLOY_HOOK }}
175+
176+
integration-tests:
177+
runs-on: ubuntu-latest
178+
needs: [build-backend, build-frontend]
179+
if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master'
180+
181+
steps:
182+
- name: Checkout code
183+
uses: actions/checkout@v4
184+
185+
- name: Wait for deployments to complete
186+
run: |
187+
echo "⏳ Waiting for Render deployments to complete..."
188+
sleep 120 # Wait 2 minutes for deployments
189+
190+
- name: Make integration test script executable
191+
run: chmod +x CICD/scripts/integration-test.sh
192+
193+
- name: Run integration tests
194+
run: |
195+
echo "🔄 Running integration tests..."
196+
CICD/scripts/integration-test.sh
197+
198+
- name: Integration tests passed
199+
run: |
200+
echo "✅ All integration tests passed successfully!"
201+
echo "🚀 Deployment pipeline completed successfully!"

0 commit comments

Comments
 (0)