Skip to content

πŸ› fix(server): fix server ci version on healthcheck #41

πŸ› fix(server): fix server ci version on healthcheck

πŸ› fix(server): fix server ci version on healthcheck #41

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 }}
rm -f package-lock.json
npm install --package-lock-only
npm ci
- 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@v4
with:
files: ./${{ matrix.package }}/coverage/lcov.info
flags: ${{ matrix.package }}
name: ${{ matrix.package }}-coverage
token: ${{ secrets.CODECOV_TOKEN }}
fail_ci_if_error: false
# Release with semantic versioning (only on main branch)
release:
name: πŸ”– Release
runs-on: ubuntu-latest
needs: test-and-lint
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
SEMANTIC_RELEASE: true
run: |
npm run release > semantic-release-output.txt 2>&1
cat semantic-release-output.txt
# Check if a new release was published
if grep -q "Published release" semantic-release-output.txt; then
echo "new-release-published=true" >> $GITHUB_OUTPUT
# Extract version from the output
VERSION=$(grep "Published release" semantic-release-output.txt | sed -n 's/.*Published release \([0-9.]*\).*/\1/p')
echo "new-release-version=$VERSION" >> $GITHUB_OUTPUT
echo "βœ… New release published: $VERSION"
else
echo "new-release-published=false" >> $GITHUB_OUTPUT
echo "No new release published"
fi
# Build applications (only if new release was published)
build:
name: πŸ—οΈ Build
runs-on: ubuntu-latest
needs: release
if: needs.release.outputs.new-release-published == 'true'
strategy:
matrix:
package: [client, server]
steps:
- name: πŸ“₯ Checkout
uses: actions/checkout@v3
with:
ref: ${{ github.ref }} # Ensure we get the latest commit with updated version
- 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: Get package versions
run: |
echo "client_version=$(jq -r .version client/package.json)" >> $GITHUB_OUTPUT
echo "server_version=$(jq -r .version server/package.json)" >> $GITHUB_OUTPUT
id: set_versions
- name: πŸ”¨ Build Version Info
env:
BUILD_NUMBER: ${{ github.run_number }}
NODE_ENV: production
# Use the released version (should match package.json after semantic-release)
APP_VERSION: ${{ needs.release.outputs.new-release-version }}
SERVER_VERSION: ${{ needs.release.outputs.new-release-version }}
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 }}
EXPO_PUBLIC_API_URL: http://56.228.14.41
EXPO_PUBLIC_APP_VERSION: ${{ needs.release.outputs.new-release-version }}
EXPO_PUBLIC_BUILD_NUMBER: ${{ github.run_number }}
EXPO_PUBLIC_BUILD_DATE: ${{ github.event.head_commit.timestamp }}
EXPO_PUBLIC_COMMIT_HASH: ${{ github.sha }}
EXPO_PUBLIC_BUILD_ENV: production
run: |
cd client
echo "\n--- VERSION INFO ---"
echo "Released Version: ${{ needs.release.outputs.new-release-version }}"
echo "Package.json Version: $(jq -r .version package.json)"
echo "\n--- ENVIRONMENT VARIABLES ---"
printenv | grep -E "(EXPO_PUBLIC_|NODE_ENV)" | sort
echo "\n--- constants/version.ts (before build-version) ---"
cat constants/version.ts || echo "File not found"
npm run build:version
echo "\n--- constants/version.ts (after build-version) ---"
cat constants/version.ts
npm run build
- name: πŸ—οΈ Build Server
if: matrix.package == 'server'
env:
NODE_ENV: production
SERVER_VERSION: ${{ needs.release.outputs.new-release-version }}
BUILD_NUMBER: ${{ github.run_number }}
BUILD_DATE: ${{ github.event.head_commit.timestamp }}
COMMIT_HASH: ${{ github.sha }}
run: |
cd server
echo "\n--- VERSION INFO ---"
echo "Released Version: ${{ needs.release.outputs.new-release-version }}"
echo "Package.json Version: $(jq -r .version package.json)"
echo "\n--- ENVIRONMENT VARIABLES ---"
printenv | grep -E "(SERVER_VERSION|BUILD_|NODE_ENV)" | sort
echo "\n--- src/common/config/version.ts (before build-version) ---"
cat src/common/config/version.ts || echo "File not found"
npm run build:version
echo "\n--- src/common/config/version.ts (after build-version) ---"
cat src/common/config/version.ts
npm run build
- name: πŸ“€ Upload Build Artifacts
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.package }}-build-${{ needs.release.outputs.new-release-version }}
path: |
${{ matrix.package }}/dist
${{ matrix.package }}/web/dist
${{ matrix.package }}/package.json
${{ matrix.package }}/package-lock.json
retention-days: 30
# Deploy to AWS (only if new release was published)
deploy:
name: οΏ½ Deploy
runs-on: ubuntu-latest
needs: [release, build]
if: needs.release.outputs.new-release-published == 'true'
environment: production
steps:
- name: πŸ“₯ Checkout
uses: actions/checkout@v3
with:
ref: ${{ github.ref }} # Ensure we get the latest commit
- 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-${{ needs.release.outputs.new-release-version }}/web/dist" ]; then
aws s3 sync "./artifacts/client-build-${{ needs.release.outputs.new-release-version }}/web/dist/" s3://${{ secrets.S3_BUCKET }} --delete --cache-control "no-cache, no-store, must-revalidate"
echo "βœ… Client deployed to S3 with version ${{ needs.release.outputs.new-release-version }}"
else
echo "❌ Client build not found for version ${{ needs.release.outputs.new-release-version }}"
ls -la ./artifacts/ || echo "No artifacts directory"
fi
# Deploy Server to EC2
- name: οΏ½ Build Server Docker Image
run: |
# Copy server build artifacts to server directory
if [ -d "./artifacts/server-build-${{ needs.release.outputs.new-release-version }}/dist" ]; then
cp -r "./artifacts/server-build-${{ needs.release.outputs.new-release-version }}/dist" server/
echo "βœ… Server build artifacts copied"
else
echo "❌ Server build artifacts not found"
ls -la ./artifacts/
exit 1
fi
cd server
# Update package-lock.json to fix npm ci sync issues
rm -f package-lock.json
npm install --package-lock-only
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 with versioned tag
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 (keep latest 3 versions)
sudo docker image prune -f
sudo docker images lab1-todoapp-server --format "table {{.Repository}}\t{{.Tag}}\t{{.ID}}" | tail -n +2 | head -n -3 | awk '{print $3}' | xargs -r sudo docker rmi || echo "No old images to remove"
- name: βœ… Deployment Summary
run: |
echo "πŸŽ‰ Deployment completed for version ${{ needs.release.outputs.new-release-version }}"
echo "πŸ“¦ Released Version: ${{ needs.release.outputs.new-release-version }}"
echo "πŸ—οΈ Build Number: ${{ github.run_number }}"
echo "🌐 Client: http://${{ secrets.S3_BUCKET }}.s3-website.eu-north-1.amazonaws.com"
echo "πŸ–₯️ Server: http://${{ secrets.EC2_HOST }}/api"
echo "πŸ” Health endpoint: http://${{ secrets.EC2_HOST }}/api/health"
- name: πŸ” Health Check
run: |
echo "⏳ Waiting 30 seconds for server to start..."
sleep 30
echo "πŸ” Checking server health..."
if curl -f -s http://${{ secrets.EC2_HOST }}/api/health; then
echo "βœ… Server health check passed"
echo "πŸ” Checking version endpoint..."
curl -s http://${{ secrets.EC2_HOST }}/api/version || echo "Version endpoint not available"
else
echo "❌ Server health check failed"
echo "πŸ“‹ Checking server logs..."
exit 1
fi