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