156 lines
5.6 KiB
YAML
156 lines
5.6 KiB
YAML
name: Deploy SiliconPin
|
|
on:
|
|
push:
|
|
branches: [ main ] # Change this to match your main branch name if different
|
|
workflow_dispatch: # Allows manual workflow runs
|
|
|
|
jobs:
|
|
build-and-deploy:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Setup Node.js
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version: '20'
|
|
|
|
- name: Cache Yarn dependencies
|
|
uses: actions/cache@v4
|
|
with:
|
|
path: |
|
|
~/.cache/yarn
|
|
node_modules
|
|
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-yarn-
|
|
|
|
- name: Install dependencies
|
|
run: yarn install --frozen-lockfile
|
|
|
|
- name: Create .env file
|
|
run: |
|
|
echo "Creating .env file with secrets..."
|
|
echo "MONGODB_URI=${{ secrets.MONGODB_URI }}" > .env
|
|
echo "REDIS_URL=${{ secrets.REDIS_URL }}" >> .env
|
|
echo "SESSION_SECRET=${{ secrets.SESSION_SECRET }}" >> .env
|
|
echo "JWT_SECRET=${{ secrets.JWT_SECRET }}" >> .env
|
|
echo "JWT_REFRESH_SECRET=${{ secrets.JWT_REFRESH_SECRET }}" >> .env
|
|
echo "GOOGLE_CLIENT_ID=${{ secrets.GOOGLE_CLIENT_ID }}" >> .env
|
|
echo "GOOGLE_CLIENT_SECRET=${{ secrets.GOOGLE_CLIENT_SECRET }}" >> .env
|
|
echo "GOOGLE_REDIRECT_URI=${{ secrets.GOOGLE_REDIRECT_URI }}" >> .env
|
|
echo "NEXT_PUBLIC_APP_URL=${{ secrets.NEXT_PUBLIC_APP_URL }}" >> .env
|
|
echo "NODE_ENV=production" >> .env
|
|
|
|
- name: Set up Docker Buildx
|
|
uses: docker/setup-buildx-action@v3
|
|
|
|
- name: Build Docker image
|
|
uses: docker/build-push-action@v5
|
|
with:
|
|
context: .
|
|
push: false
|
|
tags: siliconpin:latest
|
|
cache-from: type=gha
|
|
cache-to: type=gha,mode=max
|
|
outputs: type=docker,dest=/tmp/siliconpin-image.tar
|
|
|
|
- name: Load Docker image
|
|
run: docker load -i /tmp/siliconpin-image.tar
|
|
|
|
- name: Set up SSH
|
|
uses: shimataro/ssh-key-action@v2
|
|
with:
|
|
key: ${{ secrets.SSH_PRIVATE_KEY }}
|
|
known_hosts: 'just-a-placeholder'
|
|
|
|
- name: Add remote host to known hosts
|
|
run: |
|
|
mkdir -p ~/.ssh
|
|
echo "Adding ${{ secrets.SSH_HOST }} to known hosts..."
|
|
ssh-keyscan -H ${{ secrets.SSH_HOST }} >> ~/.ssh/known_hosts
|
|
chmod 600 ~/.ssh/known_hosts
|
|
|
|
- name: Compress Docker image
|
|
run: |
|
|
echo "Compressing Docker image..."
|
|
gzip /tmp/siliconpin-image.tar
|
|
mv /tmp/siliconpin-image.tar.gz siliconpin-image.tar.gz
|
|
|
|
- name: Transfer Docker image to server
|
|
run: |
|
|
echo "Transferring Docker image to server..."
|
|
scp -o StrictHostKeyChecking=no siliconpin-image.tar.gz ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }}:/root/services/siliconpin-image.tar.gz
|
|
scp -o StrictHostKeyChecking=no docker-compose.yml ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }}:/root/services/siliconpin/docker-compose.yml
|
|
|
|
- name: Deploy to production
|
|
run: |
|
|
ssh -o StrictHostKeyChecking=no ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }} << 'EOF'
|
|
# Force using bash instead of fish
|
|
bash -c '
|
|
# Navigate to the services directory
|
|
cd /root/services/
|
|
|
|
# Create siliconpin directory if it doesn not exist
|
|
mkdir -p siliconpin
|
|
cd siliconpin
|
|
|
|
# Stop the current container
|
|
docker compose down || true
|
|
|
|
# Load the new Docker image
|
|
echo "Loading Docker image..."
|
|
docker load < /root/services/siliconpin-image.tar.gz
|
|
|
|
# Remove the transferred image file
|
|
rm -f /root/services/siliconpin-image.tar.gz
|
|
|
|
# Start the container using the new image
|
|
echo "Starting container..."
|
|
docker compose up -d
|
|
|
|
# Wait for container to be fully running
|
|
echo "Waiting for container to be ready..."
|
|
attempt=1
|
|
max_attempts=30
|
|
|
|
until [ $attempt -gt $max_attempts ] || docker container inspect siliconpin --format="{{.State.Running}}" 2>/dev/null | grep -q "true"; do
|
|
echo "Attempt $attempt/$max_attempts: Container not ready yet, waiting..."
|
|
sleep 2
|
|
attempt=$((attempt+1))
|
|
done
|
|
|
|
if [ $attempt -gt $max_attempts ]; then
|
|
echo "Container failed to start properly within time limit!"
|
|
docker compose logs
|
|
exit 1
|
|
fi
|
|
|
|
# Further verification of application health
|
|
echo "Verifying application health..."
|
|
timeout=120
|
|
start_time=$(date +%s)
|
|
end_time=$((start_time + timeout))
|
|
while [ $(date +%s) -lt $end_time ]; do
|
|
if curl -s http://localhost:4023/ > /dev/null; then
|
|
echo "Application is responding!"
|
|
break
|
|
fi
|
|
echo "Waiting for application to respond..."
|
|
sleep 10
|
|
done
|
|
|
|
if ! curl -s http://localhost:4023/ > /dev/null; then
|
|
echo "Application failed to respond within timeout!"
|
|
docker compose logs
|
|
exit 1
|
|
fi
|
|
|
|
# Clean up is already done above
|
|
|
|
# Verify deployment
|
|
echo "Deployment successful! Container is running and application is responding."
|
|
docker ps | grep siliconpin
|
|
'
|
|
EOF |