|
| 1 | +name: Deploy to OpenStack |
| 2 | + |
| 3 | +# Required GitHub Environment Secrets: |
| 4 | +# |
| 5 | +# Create two environments in GitHub: "production" and "staging" |
| 6 | +# Settings → Environments → New environment |
| 7 | +# |
| 8 | +# For each environment, add these secrets: |
| 9 | +# - SSH_HOST: OpenStack instance hostname or IP address |
| 10 | +# - SSH_USER: SSH username for the instance |
| 11 | +# - SSH_PRIVATE_KEY: Private SSH key for authentication |
| 12 | +# - SITE_URL: Site URL (for build) |
| 13 | +# - BACKEND_URL: Backend URL (for build) |
| 14 | +# - DEPLOY_PATH: (Optional) Deployment path (defaults to ~/processordb-website for prod, ~/processordb-website-staging for staging) |
| 15 | +# - PORT: (Optional, staging only) Port for staging app (defaults to 3001 for same instance, set to 3000 for separate instance) |
| 16 | + |
| 17 | +on: |
| 18 | + push: |
| 19 | + branches: |
| 20 | + - main |
| 21 | + - dev |
| 22 | + |
| 23 | +jobs: |
| 24 | + deploy: |
| 25 | + runs-on: ubuntu-latest |
| 26 | + |
| 27 | + # Determine environment based on branch |
| 28 | + environment: ${{ github.ref == 'refs/heads/main' && 'production' || 'staging' }} |
| 29 | + |
| 30 | + env: |
| 31 | + ENVIRONMENT: ${{ github.ref == 'refs/heads/main' && 'production' || 'staging' }} |
| 32 | + |
| 33 | + steps: |
| 34 | + - name: Checkout code |
| 35 | + uses: actions/checkout@v4 |
| 36 | + |
| 37 | + - name: Setup Node.js |
| 38 | + uses: actions/setup-node@v4 |
| 39 | + with: |
| 40 | + node-version: '20' |
| 41 | + cache: 'npm' |
| 42 | + |
| 43 | + - name: Install dependencies |
| 44 | + run: npm ci |
| 45 | + |
| 46 | + - name: Set environment variables |
| 47 | + id: env |
| 48 | + run: | |
| 49 | + if [ "${{ github.ref }}" == "refs/heads/main" ]; then |
| 50 | + echo "SSH_HOST=${{ secrets.SSH_HOST }}" >> $GITHUB_ENV |
| 51 | + echo "SSH_USER=${{ secrets.SSH_USER }}" >> $GITHUB_ENV |
| 52 | + echo "SSH_PRIVATE_KEY=${{ secrets.SSH_PRIVATE_KEY }}" >> $GITHUB_ENV |
| 53 | + echo "SITE_URL=${{ secrets.SITE_URL }}" >> $GITHUB_ENV |
| 54 | + echo "BACKEND_URL=${{ secrets.BACKEND_URL }}" >> $GITHUB_ENV |
| 55 | + echo "DEPLOY_PATH=${{ secrets.DEPLOY_PATH || '~/processordb-website' }}" >> $GITHUB_ENV |
| 56 | + echo "PM2_APP_NAME=ProcessorDB-website" >> $GITHUB_ENV |
| 57 | + echo "PM2_PORT=3000" >> $GITHUB_ENV |
| 58 | + echo "ECOSYSTEM_FILE=ecosystem.config.js" >> $GITHUB_ENV |
| 59 | + else |
| 60 | + # For staging, use port from secret or default to 3001 (same instance) or 3000 (separate) |
| 61 | + # If using same instance as production, use 3001. If separate instance, use 3000. |
| 62 | + # You can override by setting PORT secret in staging environment |
| 63 | + DEPLOY_PATH="${{ secrets.DEPLOY_PATH || '~/processordb-website-staging' }}" |
| 64 | + STAGING_PORT="${{ secrets.PORT || '3001' }}" |
| 65 | + |
| 66 | + echo "SSH_HOST=${{ secrets.SSH_HOST }}" >> $GITHUB_ENV |
| 67 | + echo "SSH_USER=${{ secrets.SSH_USER }}" >> $GITHUB_ENV |
| 68 | + echo "SSH_PRIVATE_KEY=${{ secrets.SSH_PRIVATE_KEY }}" >> $GITHUB_ENV |
| 69 | + echo "SITE_URL=${{ secrets.SITE_URL }}" >> $GITHUB_ENV |
| 70 | + echo "BACKEND_URL=${{ secrets.BACKEND_URL }}" >> $GITHUB_ENV |
| 71 | + echo "DEPLOY_PATH=$DEPLOY_PATH" >> $GITHUB_ENV |
| 72 | + echo "PM2_APP_NAME=ProcessorDB-website-staging" >> $GITHUB_ENV |
| 73 | + echo "PM2_PORT=$STAGING_PORT" >> $GITHUB_ENV |
| 74 | + echo "ECOSYSTEM_FILE=ecosystem.staging.config.js" >> $GITHUB_ENV |
| 75 | + fi |
| 76 | +
|
| 77 | + - name: Build application |
| 78 | + run: npm run build |
| 79 | + env: |
| 80 | + SITE_URL: ${{ env.SITE_URL }} |
| 81 | + BACKEND_URL: ${{ env.BACKEND_URL }} |
| 82 | + |
| 83 | + - name: Create staging ecosystem config |
| 84 | + if: github.ref != 'refs/heads/main' |
| 85 | + run: | |
| 86 | + PM2_PORT="${{ env.PM2_PORT }}" |
| 87 | + cat > ecosystem.staging.config.js << EOF |
| 88 | + module.exports = { |
| 89 | + apps : [{ |
| 90 | + name: "ProcessorDB-website-staging", |
| 91 | + port: "$PM2_PORT", |
| 92 | + exec_mode: "cluster", |
| 93 | + instances: "max", |
| 94 | + script: "./.output/server/index.mjs" |
| 95 | + }] |
| 96 | + } |
| 97 | + EOF |
| 98 | +
|
| 99 | + - name: Create deployment archive |
| 100 | + run: | |
| 101 | + FILES=".output ecosystem.config.js package.json package-lock.json public server nuxt.config.ts" |
| 102 | + if [ -f "ecosystem.staging.config.js" ]; then |
| 103 | + FILES="$FILES ecosystem.staging.config.js" |
| 104 | + fi |
| 105 | + tar -czf deploy.tar.gz $FILES |
| 106 | +
|
| 107 | + - name: Setup SSH |
| 108 | + uses: webfactory/[email protected] |
| 109 | + with: |
| 110 | + ssh-private-key: ${{ env.SSH_PRIVATE_KEY }} |
| 111 | + |
| 112 | + - name: Add server to known hosts |
| 113 | + run: | |
| 114 | + mkdir -p ~/.ssh |
| 115 | + ssh-keyscan -H ${{ env.SSH_HOST }} >> ~/.ssh/known_hosts |
| 116 | +
|
| 117 | + - name: Deploy to ${{ env.ENVIRONMENT }} |
| 118 | + run: | |
| 119 | + DEPLOY_PATH="${{ env.DEPLOY_PATH }}" |
| 120 | + PM2_APP_NAME="${{ env.PM2_APP_NAME }}" |
| 121 | + ECOSYSTEM_FILE="${{ env.ECOSYSTEM_FILE }}" |
| 122 | + |
| 123 | + # Copy files to server |
| 124 | + scp -r deploy.tar.gz ${{ env.SSH_USER }}@${{ env.SSH_HOST }}:$DEPLOY_PATH/ |
| 125 | + |
| 126 | + # SSH into server and deploy |
| 127 | + ssh ${{ env.SSH_USER }}@${{ env.SSH_HOST }} "bash -s" << EOF |
| 128 | + set -e |
| 129 | + cd $DEPLOY_PATH |
| 130 | + |
| 131 | + # Extract deployment files |
| 132 | + tar -xzf deploy.tar.gz |
| 133 | + |
| 134 | + # Install/update dependencies |
| 135 | + source ~/.nvm/nvm.sh |
| 136 | + npm ci --production |
| 137 | + |
| 138 | + # Use staging ecosystem config if it exists, otherwise use production |
| 139 | + if [ -f "$ECOSYSTEM_FILE" ]; then |
| 140 | + PM2_CONFIG="$ECOSYSTEM_FILE" |
| 141 | + else |
| 142 | + PM2_CONFIG="ecosystem.config.js" |
| 143 | + fi |
| 144 | + |
| 145 | + # Restart PM2 application |
| 146 | + pm2 restart $PM2_APP_NAME || pm2 start $PM2_CONFIG |
| 147 | + |
| 148 | + # Save PM2 process list for auto-restart on reboot |
| 149 | + pm2 save --force |
| 150 | + |
| 151 | + # Clean up |
| 152 | + rm -f deploy.tar.gz |
| 153 | + |
| 154 | + echo "Deployment to ${{ env.ENVIRONMENT }} completed successfully" |
| 155 | + EOF |
| 156 | +
|
| 157 | + - name: Cleanup |
| 158 | + if: always() |
| 159 | + run: rm -f deploy.tar.gz |
0 commit comments