added deployment workflow #1
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Deploy to OpenStack | |
| # Required GitHub Environment Secrets: | |
| # | |
| # Create two environments in GitHub: "production" and "staging" | |
| # Settings → Environments → New environment | |
| # | |
| # For each environment, add these secrets: | |
| # - SSH_HOST: OpenStack instance hostname or IP address | |
| # - SSH_USER: SSH username for the instance | |
| # - SSH_PRIVATE_KEY: Private SSH key for authentication | |
| # - SITE_URL: Site URL (for build) | |
| # - BACKEND_URL: Backend URL (for build) | |
| # - DEPLOY_PATH: (Optional) Deployment path (defaults to ~/processordb-website for prod, ~/processordb-website-staging for staging) | |
| # - PORT: (Optional, staging only) Port for staging app (defaults to 3001 for same instance, set to 3000 for separate instance) | |
| on: | |
| push: | |
| branches: | |
| - main | |
| - dev | |
| jobs: | |
| deploy: | |
| runs-on: ubuntu-latest | |
| # Determine environment based on branch | |
| environment: ${{ github.ref == 'refs/heads/main' && 'production' || 'staging' }} | |
| env: | |
| ENVIRONMENT: ${{ github.ref == 'refs/heads/main' && 'production' || 'staging' }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '20' | |
| cache: 'npm' | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Set environment variables | |
| id: env | |
| run: | | |
| if [ "${{ github.ref }}" == "refs/heads/main" ]; then | |
| echo "SSH_HOST=${{ secrets.SSH_HOST }}" >> $GITHUB_ENV | |
| echo "SSH_USER=${{ secrets.SSH_USER }}" >> $GITHUB_ENV | |
| echo "SSH_PRIVATE_KEY=${{ secrets.SSH_PRIVATE_KEY }}" >> $GITHUB_ENV | |
| echo "SITE_URL=${{ secrets.SITE_URL }}" >> $GITHUB_ENV | |
| echo "BACKEND_URL=${{ secrets.BACKEND_URL }}" >> $GITHUB_ENV | |
| echo "DEPLOY_PATH=${{ secrets.DEPLOY_PATH || '~/processordb-website' }}" >> $GITHUB_ENV | |
| echo "PM2_APP_NAME=ProcessorDB-website" >> $GITHUB_ENV | |
| echo "PM2_PORT=3000" >> $GITHUB_ENV | |
| echo "ECOSYSTEM_FILE=ecosystem.config.js" >> $GITHUB_ENV | |
| else | |
| # For staging, use port from secret or default to 3001 (same instance) or 3000 (separate) | |
| # If using same instance as production, use 3001. If separate instance, use 3000. | |
| # You can override by setting PORT secret in staging environment | |
| DEPLOY_PATH="${{ secrets.DEPLOY_PATH || '~/processordb-website-staging' }}" | |
| STAGING_PORT="${{ secrets.PORT || '3001' }}" | |
| echo "SSH_HOST=${{ secrets.SSH_HOST }}" >> $GITHUB_ENV | |
| echo "SSH_USER=${{ secrets.SSH_USER }}" >> $GITHUB_ENV | |
| echo "SSH_PRIVATE_KEY=${{ secrets.SSH_PRIVATE_KEY }}" >> $GITHUB_ENV | |
| echo "SITE_URL=${{ secrets.SITE_URL }}" >> $GITHUB_ENV | |
| echo "BACKEND_URL=${{ secrets.BACKEND_URL }}" >> $GITHUB_ENV | |
| echo "DEPLOY_PATH=$DEPLOY_PATH" >> $GITHUB_ENV | |
| echo "PM2_APP_NAME=ProcessorDB-website-staging" >> $GITHUB_ENV | |
| echo "PM2_PORT=$STAGING_PORT" >> $GITHUB_ENV | |
| echo "ECOSYSTEM_FILE=ecosystem.staging.config.js" >> $GITHUB_ENV | |
| fi | |
| - name: Build application | |
| run: npm run build | |
| env: | |
| SITE_URL: ${{ env.SITE_URL }} | |
| BACKEND_URL: ${{ env.BACKEND_URL }} | |
| - name: Create staging ecosystem config | |
| if: github.ref != 'refs/heads/main' | |
| run: | | |
| PM2_PORT="${{ env.PM2_PORT }}" | |
| cat > ecosystem.staging.config.js << EOF | |
| module.exports = { | |
| apps : [{ | |
| name: "ProcessorDB-website-staging", | |
| port: "$PM2_PORT", | |
| exec_mode: "cluster", | |
| instances: "max", | |
| script: "./.output/server/index.mjs" | |
| }] | |
| } | |
| EOF | |
| - name: Create deployment archive | |
| run: | | |
| FILES=".output ecosystem.config.js package.json package-lock.json public server nuxt.config.ts" | |
| if [ -f "ecosystem.staging.config.js" ]; then | |
| FILES="$FILES ecosystem.staging.config.js" | |
| fi | |
| tar -czf deploy.tar.gz $FILES | |
| - name: Setup SSH | |
| uses: webfactory/[email protected] | |
| with: | |
| ssh-private-key: ${{ env.SSH_PRIVATE_KEY }} | |
| - name: Add server to known hosts | |
| run: | | |
| mkdir -p ~/.ssh | |
| ssh-keyscan -H ${{ env.SSH_HOST }} >> ~/.ssh/known_hosts | |
| - name: Deploy to ${{ env.ENVIRONMENT }} | |
| run: | | |
| DEPLOY_PATH="${{ env.DEPLOY_PATH }}" | |
| PM2_APP_NAME="${{ env.PM2_APP_NAME }}" | |
| ECOSYSTEM_FILE="${{ env.ECOSYSTEM_FILE }}" | |
| # Copy files to server | |
| scp -r deploy.tar.gz ${{ env.SSH_USER }}@${{ env.SSH_HOST }}:$DEPLOY_PATH/ | |
| # SSH into server and deploy | |
| ssh ${{ env.SSH_USER }}@${{ env.SSH_HOST }} "bash -s" << EOF | |
| set -e | |
| cd $DEPLOY_PATH | |
| # Extract deployment files | |
| tar -xzf deploy.tar.gz | |
| # Install/update dependencies | |
| source ~/.nvm/nvm.sh | |
| npm ci --production | |
| # Use staging ecosystem config if it exists, otherwise use production | |
| if [ -f "$ECOSYSTEM_FILE" ]; then | |
| PM2_CONFIG="$ECOSYSTEM_FILE" | |
| else | |
| PM2_CONFIG="ecosystem.config.js" | |
| fi | |
| # Restart PM2 application | |
| pm2 restart $PM2_APP_NAME || pm2 start $PM2_CONFIG | |
| # Save PM2 process list for auto-restart on reboot | |
| pm2 save --force | |
| # Clean up | |
| rm -f deploy.tar.gz | |
| echo "Deployment to ${{ env.ENVIRONMENT }} completed successfully" | |
| EOF | |
| - name: Cleanup | |
| if: always() | |
| run: rm -f deploy.tar.gz |