Skip to content

πŸ› fix: resolve semantic-release pre-commit hook conflicts in CI/CD #6

πŸ› fix: resolve semantic-release pre-commit hook conflicts in CI/CD

πŸ› fix: resolve semantic-release pre-commit hook conflicts in CI/CD #6

Workflow file for this run

name: πŸš€ CI/CD Pipeline
on:
push:
branches: [main]
pull_request:
branches: [main]
workflow_dispatch:
permissions:
contents: write
issues: write
pull-requests: write
id-token: write
jobs:
# Test & Lint both client and server
test-and-lint:
name: πŸ§ͺ Test & Lint
runs-on: ubuntu-latest
strategy:
matrix:
package: [client, server]
steps:
- name: πŸ“₯ Checkout
uses: actions/checkout@v3
- name: πŸ“¦ Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '20'
cache: 'npm'
cache-dependency-path: '${{ matrix.package }}/package-lock.json'
- name: πŸ“₯ Install Dependencies
run: |
cd ${{ matrix.package }}
npm ci --include=optional || npm ci --omit=optional || (rm -rf node_modules package-lock.json && npm install --omit=optional)
- name: πŸ” Lint
run: |
cd ${{ matrix.package }}
npm run lint
- name: πŸ§ͺ Test
run: |
cd ${{ matrix.package }}
npm run test:ci || npm run test:coverage || npm run test
- name: πŸ“Š Upload Coverage
uses: codecov/codecov-action@v3
if: matrix.package == 'server'
with:
files: ./server/coverage/lcov.info
flags: ${{ matrix.package }}
name: ${{ matrix.package }}-coverage
fail_ci_if_error: false
# Build applications (only on main branch)
build:
name: πŸ—οΈ Build
runs-on: ubuntu-latest
needs: test-and-lint
if: github.ref == 'refs/heads/main'
strategy:
matrix:
package: [client, server]
steps:
- name: πŸ“₯ Checkout
uses: actions/checkout@v3
- name: πŸ“¦ Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '20'
cache: 'npm'
cache-dependency-path: '${{ matrix.package }}/package-lock.json'
- name: πŸ“₯ Install Dependencies
run: |
cd ${{ matrix.package }}
npm ci --include=optional || npm ci --omit=optional || (rm -rf node_modules package-lock.json && npm install --omit=optional)
- name: πŸ”¨ Build Version Info
env:
BUILD_NUMBER: ${{ github.run_number }}
NODE_ENV: production
run: |
cd ${{ matrix.package }}
npm run build:version
- name: πŸ—οΈ Build Client
if: matrix.package == 'client'
env:
NODE_ENV: production
EXPO_PUBLIC_SUPABASE_URL: ${{ secrets.EXPO_PUBLIC_SUPABASE_URL }}
EXPO_PUBLIC_SUPABASE_ANON_KEY: ${{ secrets.EXPO_PUBLIC_SUPABASE_ANON_KEY }}
run: |
cd client
npm run build:web
- name: πŸ—οΈ Build Server
if: matrix.package == 'server'
run: |
cd server
npm run build
- name: πŸ“€ Upload Build Artifacts
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.package }}-build
path: |
${{ matrix.package }}/dist
${{ matrix.package }}/web/dist
${{ matrix.package }}/package.json
${{ matrix.package }}/package-lock.json
retention-days: 30
# Release with semantic versioning (only on main)
release:
name: πŸ”– Release
runs-on: ubuntu-latest
needs: build
if: github.ref == 'refs/heads/main'
permissions:
contents: write
issues: write
pull-requests: write
id-token: write
outputs:
new-release-published: ${{ steps.semantic.outputs.new-release-published }}
new-release-version: ${{ steps.semantic.outputs.new-release-version }}
steps:
- name: πŸ“₯ Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
persist-credentials: false
- name: πŸ“¦ Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '20'
cache: 'npm'
- name: πŸ“₯ Install Dependencies
run: npm ci
- name: πŸ”§ Configure Git
run: |
git config --global user.name "github-actions[bot]"
git config --global user.email "github-actions[bot]@users.noreply.github.com"
git remote set-url origin https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git
- name: πŸ”– Semantic Release
id: semantic
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GIT_AUTHOR_NAME: github-actions[bot]
GIT_AUTHOR_EMAIL: github-actions[bot]@users.noreply.github.com
GIT_COMMITTER_NAME: github-actions[bot]
GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com
run: npm run release
# Deploy to AWS (only if new release)
deploy:
name: πŸš€ Deploy
runs-on: ubuntu-latest
needs: release
if: needs.release.outputs.new-release-published == 'true'
environment: production
steps:
- name: πŸ“₯ Checkout
uses: actions/checkout@v3
- name: πŸ“₯ Download Build Artifacts
uses: actions/download-artifact@v4
with:
path: ./artifacts
- name: πŸ”§ Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v2
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ secrets.AWS_REGION }}
# Deploy Client to S3
- name: 🌐 Deploy Client to S3
run: |
if [ -d "./artifacts/client-build/web/dist" ]; then
aws s3 sync ./artifacts/client-build/web/dist/ s3://${{ secrets.S3_BUCKET }} --delete
echo "βœ… Client deployed to S3"
else
echo "❌ Client build not found"
fi
# Deploy Server to EC2
- name: πŸ“¦ Build Server Docker Image
run: |
cd server
npm ci --include=optional || npm ci --omit=optional || (rm -rf node_modules package-lock.json && npm install --omit=optional)
docker build -t lab1-todoapp-server:${{ needs.release.outputs.new-release-version }} --target production .
docker save lab1-todoapp-server:${{ needs.release.outputs.new-release-version }} | gzip > lab1-todoapp-server.tar.gz
- name: πŸš€ Deploy Server to EC2
uses: appleboy/[email protected]
with:
host: ${{ secrets.EC2_HOST }}
username: ${{ secrets.EC2_USER }}
key: ${{ secrets.EC2_PRIVATE_KEY }}
source: "server/lab1-todoapp-server.tar.gz"
target: "/home/ubuntu/"
- name: πŸ”„ Update Server on EC2
uses: appleboy/[email protected]
with:
host: ${{ secrets.EC2_HOST }}
username: ${{ secrets.EC2_USER }}
key: ${{ secrets.EC2_PRIVATE_KEY }}
script: |
# Load new image
cd /home/ubuntu
sudo docker load < server/lab1-todoapp-server.tar.gz
# Stop and remove old container
sudo docker stop lab1-todoapp-server || true
sudo docker rm lab1-todoapp-server || true
# Run new container
sudo docker run -d \
--name lab1-todoapp-server \
--restart unless-stopped \
-p 80:3000 \
-e NODE_ENV=production \
-e PORT=3000 \
-e SUPABASE_DB_URL="${{ secrets.SUPABASE_DB_URL }}" \
-e SUPABASE_KEY="${{ secrets.SUPABASE_KEY }}" \
-e SUPABASE_URL="${{ secrets.SUPABASE_URL }}" \
-e ALLOWED_ORIGINS="http://56.228.14.41,https://lab1.warteamx.com,http://lab1-todoapp.s3-website.eu-north-1.amazonaws.com" \
lab1-todoapp-server:${{ needs.release.outputs.new-release-version }}
# Clean up old images
sudo docker image prune -f
- name: βœ… Deployment Summary
run: |
echo "πŸŽ‰ Deployment completed for version ${{ needs.release.outputs.new-release-version }}"
echo "🌐 Client: http://${{ secrets.S3_BUCKET }}.s3-website.eu-north-1.amazonaws.com"
echo "πŸ–₯️ Server: http://${{ secrets.EC2_HOST }}/api"
- name: πŸ” Health Check
run: |
sleep 30
if curl -f http://${{ secrets.EC2_HOST }}/api/health; then
echo "βœ… Server health check passed"
else
echo "❌ Server health check failed"
exit 1
fi