Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
1034252
changed the username of the images from the docker-compose.deploy file.
tgillysuit Nov 20, 2025
6a177d3
did an audit fix on the package-lcok
tgillysuit Nov 22, 2025
9f1e72b
docker-compose deploy file had to be chagned with my username for the…
tgillysuit Nov 22, 2025
207db98
Adding a couple files (depoly and test) of the github workflows. test…
tgillysuit Nov 22, 2025
4ab73c1
finsihed the test and deploy files.
tgillysuit Nov 23, 2025
489a41c
Test workflows after fixing permissions
tgillysuit Nov 23, 2025
657ba70
Test workflows after fixing permissions
tgillysuit Nov 23, 2025
1c678b7
Pushing some workflow fixes.
RMarx1456 Nov 24, 2025
75a5434
Trying to fix cypress.
RMarx1456 Nov 24, 2025
e90babd
Fixed minor typo in workflow.
RMarx1456 Nov 24, 2025
7f2f69c
Still fixing.
RMarx1456 Nov 24, 2025
bc6d005
Reverted.
RMarx1456 Nov 24, 2025
b625de7
Revert "Pushing some workflow fixes."
RMarx1456 Nov 24, 2025
f64ee2d
Bringing back old test.
RMarx1456 Nov 24, 2025
993e40e
errror merging...test.
tgillysuit Nov 24, 2025
822cc53
Merge branch 'main' of https://github.com/tgillysuit/Pixel-to-Pattern
tgillysuit Nov 24, 2025
4f51617
Adding cypress?
RMarx1456 Nov 24, 2025
9822f9b
Merge branch 'main' of https://github.com/tgillysuit/Pixel-to-Pattern
tgillysuit Nov 24, 2025
136c3fa
chanced an env variable name for the secret
tgillysuit Nov 24, 2025
165deef
Updated Secrets inside of the deploy.yml file....testing
tgillysuit Nov 24, 2025
585cab6
Test deployment again..
tgillysuit Nov 24, 2025
5d7a694
Exiting ssh so handshake doesn't break and thus, result in failure fo…
RMarx1456 Nov 24, 2025
f47dff4
Merge branch 'main' of https://github.com/tgillysuit/Pixel-to-Pattern…
RMarx1456 Nov 24, 2025
d6edfea
Added EOF? Not sure if this works.
RMarx1456 Nov 24, 2025
bf80b80
Testing again for the 1,000,000th time
tgillysuit Nov 24, 2025
35b2981
Test deployment again..
tgillysuit Nov 24, 2025
9dc57b6
Edited the README for proper Secret inputs wuth steps on how to add.
tgillysuit Nov 24, 2025
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
220 changes: 220 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
# Deploy Pipeline
name: Automated Deployment

on:
push:
branches:
- main

# Ensure only one deployment runs at a time
concurrency:
group: deployment
cancel-in-progress: false

env:
REGISTRY: ghcr.io
BACKEND_IMAGE: ghcr.io/${{ github.repository_owner }}/pixel-to-pattern-backend
FRONTEND_IMAGE: ghcr.io/${{ github.repository_owner }}/pixel-to-pattern-frontend

jobs:

# Build and Push Docker Images to GHCR
build-and-push:
name: Build and Push Docker Images
runs-on: ubuntu-latest
permissions:
contents: read
packages: write

outputs:
backend_image: ${{ steps.meta-backend.outputs.tags }}
frontend_image: ${{ steps.meta-frontend.outputs.tags }}

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

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

- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GHCR_TOKEN }}

# Backend Image
- name: Extract metadata for backend
id: meta-backend
uses: docker/metadata-action@v5
with:
images: ${{ env.BACKEND_IMAGE }}
tags: |
type=raw,value=latest
type=sha,prefix=

- name: Build and push backend image
uses: docker/build-push-action@v5
with:
context: ./server
push: true
tags: ${{ steps.meta-backend.outputs.tags }}
labels: ${{ steps.meta-backend.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max

# Frontend Image
- name: Extract metadata for frontend
id: meta-frontend
uses: docker/metadata-action@v5
with:
images: ${{ env.FRONTEND_IMAGE }}
tags: |
type=raw,value=latest
type=sha,prefix=

- name: Build and push frontend image
uses: docker/build-push-action@v5
with:
context: ./client
push: true
tags: ${{ steps.meta-frontend.outputs.tags }}
labels: ${{ steps.meta-frontend.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max

# Deploy to VM
deploy:
name: Deploy to VM
runs-on: ubuntu-latest
needs: build-and-push
environment: production

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

- name: Deploy to VM via SSH
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ secrets.VM_HOST }}
username: ${{ secrets.VM_USERNAME }}
password: ${{ secrets.VM_PASSWORD }}
port: ${{ secrets.VM_SSH_PORT || 22 }}
script: |
set -e

echo "--- Starting deployment ---"
echo "Timestamp: $(date)"

# Navigate to project directory
cd ${{ secrets.VM_PROJECT_PATH }}

# Log in to GHCR
echo ${{ secrets.GHCR_TOKEN }} | docker login ghcr.io -u ${{ github.repository_owner }} --password-stdin

# Pull latest images
echo "--- Pulling latest images ---"
docker compose -f docker-compose.deploy.yml pull

# Stop current containers gracefully
echo "--- Stopping current containers ---"
docker compose -f docker-compose.deploy.yml down --timeout 30

# Start new containers
echo "--- Starting new containers ---"
docker compose -f docker-compose.deploy.yml up -d

# Clean up old images
echo "--- Cleaning up old images ---"
docker image prune -f

echo "--- Deployment complete ---"

- name: Verify deployment
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ secrets.VM_HOST }}
username: ${{ secrets.VM_USERNAME }}
password: ${{ secrets.VM_PASSWORD }}
port: ${{ secrets.VM_SSH_PORT || 22 }}
script: |
set -e

echo "--- Verifying deployment ---"

# Wait for containers to be ready
sleep 10

# Check if containers are running
cd ${{ secrets.VM_PROJECT_PATH }}

echo "--- Container status ---"
docker compose -f docker-compose.deploy.yml ps

# Check container health
RUNNING_CONTAINERS=$(docker compose -f docker-compose.deploy.yml ps --status running -q | wc -l)
EXPECTED_CONTAINERS=$(docker compose -f docker-compose.deploy.yml config --services | wc -l)

echo "Running containers: $RUNNING_CONTAINERS"
echo "Expected containers: $EXPECTED_CONTAINERS"

if [ "$RUNNING_CONTAINERS" -lt "$EXPECTED_CONTAINERS" ]; then
echo "ERROR: Not all containers are running!"
docker compose -f docker-compose.deploy.yml logs --tail=50
exit 1
fi

# Health check - verify frontend is responding
echo "--- Health check ---"
if curl -sSf http://localhost:3001 > /dev/null 2>&1; then
echo "PASSED! Frontend is responding"
else
echo "FAILED! Frontend health check failed (may still be starting)"
fi

# Check if backend container is running (no endpoint check)
if docker compose -f docker-compose.deploy.yml ps backend | grep -q "Up"; then
echo "PASSED! Backend container is running"
else
echo "FAILED! Backend container is not running!"
exit 1
fi

echo "--- Deployment verified successfully ---"

- name: Deployment summary
run: |
echo "## Deployment Summary" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "PASSED! **Deployment completed successfully**" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "- **Branch:** ${{ github.ref_name }}" >> $GITHUB_STEP_SUMMARY
echo "- **Commit:** ${{ github.sha }}" >> $GITHUB_STEP_SUMMARY
echo "- **Triggered by:** ${{ github.actor }}" >> $GITHUB_STEP_SUMMARY
echo "- **Time:** $(date -u '+%Y-%m-%d %H:%M:%S UTC')" >> $GITHUB_STEP_SUMMARY


# Rollback on Failure
rollback:
name: Rollback on Failure
runs-on: ubuntu-latest
needs: deploy
if: failure()

steps:
- name: Notify about failed deployment
run: |
echo "## FAILED! Deployment Failed" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "The deployment to production has failed." >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Manual intervention may be required.**" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "To rollback manually:" >> $GITHUB_STEP_SUMMARY
echo "1. SSH into the VM" >> $GITHUB_STEP_SUMMARY
echo "2. Navigate to the project directory" >> $GITHUB_STEP_SUMMARY
echo "3. Run: \`docker compose -f docker-compose.deploy.yml down\`" >> $GITHUB_STEP_SUMMARY
echo "4. Pull the previous working image tag" >> $GITHUB_STEP_SUMMARY
echo "5. Run: \`docker compose -f docker-compose.deploy.yml up -d\`" >> $GITHUB_STEP_SUMMARY
175 changes: 175 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
# Testing Pipeline

name: Automated Testing Pipeline

on:
push:
branches: [ main, dev ]
pull_request:
branches: [ main, dev ]



jobs:
# BACKEND TESTS
backend-unit-tests:
name: Backend Unit tests
runs-on: ubuntu-latest

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

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

- name: Build Test Containers
run: docker compose -f docker-compose.test.yml build --no-cache backend-unit-tests

- name: Run backend unit tests
run: |
docker compose -f docker-compose.test.yml up backend-unit-tests \
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not familiar with this command syntax, what are the additional arguments after docker compose up?

--abort-on-container-exit \
--exit-code-from backend-unit-tests

- name: Cleanup
if: always()
run: docker compose -f docker-compose.test.yml down -v

# FRONTEND TESTS
frontend-unit-tests:
name: Frontend Unit tests
runs-on: ubuntu-latest

steps:
- name: Check repo
uses: actions/checkout@v4

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

- name: Build test containers (if needed)
run: docker compose -f docker-compose.test.yml build --no-cache db-test backend-integration

- name: Run integration tests
run: |
docker compose -f docker-compose.test.yml up db-test backend-integration \
--abort-on-container-exit \
--exit-code-from backend-integration

- name: Cleanup
if: always()
run: docker compose -f docker-compose.test.yml down -v

# E2E Tests (Cypress)
e2e-tests:
name: End-to-End Tests (Cypress)
runs-on: ubuntu-latest

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

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

- name: Create .env file for Docker compose
run: |
cat << EOF > .env
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These .env values should probably be stored in secrets just in case.

DB_USER=test_user
DB_PASSWORD=test_password
DB_HOST=db
DB_DATABASE=pixel_to_pattern_test
DB_PORT=3306
SERVER_PORT=3000
EOF

- name: Start app stack
run: |
docker compose up -d --build
# Wait for services to be healthy
echo "Waiting for services to start..."
sleep 30

- name: Check service health
run: |
docker compose ps
# Verify frontend is accessible
curl --retry 10 --retry-delay 5 --retry-connrefused http://localhost:3001 || true

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '24'
cache: 'npm'

- name: Install dependencies
run: |
npm install cypress
npm run cypress:run
env:
CYPRESS_BASE_URL: http://localhost:3001

- name: Upload Cypress screenshots on failure
uses: actions/upload-artifact@v4
if: failure()
with:
name: cypress-screenshots
path: cypress/screenshots
retention-days: 7

- name: Upload Cypress videos
uses: actions/upload-artifact@v4
if: always()
with:
name: cypress-videos
path: cypress/videos
retention-days: 7

- name: Cleanup
if: always()
run: docker compose down -v

# TEST SUMMARY
test-summary:
name: Test Summary
runs-on: ubuntu-latest
needs: [backend-unit-tests, frontend-unit-tests, e2e-tests]

steps:
- name: Display test results
run: |
echo "## Test Results Summary" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY

if [ "${{ needs.backend-unit-tests.result }}" == "success" ]; then
echo "PASSED! Backend Unit Tests: Passed" >> $GITHUB_STEP_SUMMARY
else
echo "FAILED! Backend Unit Tests: ${{ needs.backend-unit-tests.result }}" >> $GITHUB_STEP_SUMMARY
fi

if [ "${{ needs.frontend-unit-tests.result }}" == "success" ]; then
echo "PASSED! Frontend Unit Tests: Passed" >> $GITHUB_STEP_SUMMARY
else
echo "FAILED! Frontend Unit Tests: ${{ needs.frontend-unit-tests.result }}" >> $GITHUB_STEP_SUMMARY
fi

if [ "${{ needs.integration-tests.result }}" == "success" ]; then
echo "PASSED! Integration Tests: Passed" >> $GITHUB_STEP_SUMMARY
else
echo "FAILED! Integration Tests: ${{ needs.integration-tests.result }}" >> $GITHUB_STEP_SUMMARY
fi

if [ "${{ needs.e2e-tests.result }}" == "success" ]; then
echo "PASSED! E2E Tests: Passed" >> $GITHUB_STEP_SUMMARY
else
echo "FAILED! E2E Tests: ${{ needs.e2e-tests.result }}" >> $GITHUB_STEP_SUMMARY
fi

- name: Fail if any tests failed
if: |
needs.backend-unit-tests.result == 'failure' ||
needs.frontend-unit-tests.result == 'failure' ||
needs.integration-tests.result == 'failure' ||
needs.e2e-tests.result == 'failure'
run: exit 1
Loading