@@ -160,13 +160,14 @@ Mode: \`${DEPLOY_MODE}\`
160160By : \`${{ github.actor }}\`"
161161
162162 # ---------------------------------------------------------------------------
163- # Job 2: Deploy to VPS — SSH into VPS and run deploy.sh
163+ # Job 2: Deploy to VPS — pull latest main, restart service, health check
164164 # Only triggers after quality gates pass on a valid PR merge to main.
165165 # ---------------------------------------------------------------------------
166166 deploy :
167167 name : Deploy to VPS
168168 runs-on : ubuntu-latest
169169 needs : quality-gates
170+ environment : Production
170171 if : needs.quality-gates.result == 'success'
171172
172173 env :
@@ -175,7 +176,7 @@ By: \`${{ github.actor }}\`"
175176 steps :
176177 - uses : actions/checkout@v4
177178
178- - name : Install sshpass (password SSH fallback)
179+ - name : Install sshpass (password fallback)
179180 run : sudo apt-get install -y sshpass
180181
181182 - name : Setup SSH
@@ -185,9 +186,12 @@ By: \`${{ github.actor }}\`"
185186 run : |
186187 mkdir -p ~/.ssh
187188 chmod 700 ~/.ssh
189+
188190 printf '%s\n' "$SERVER_KEY" > ~/.ssh/deploy_key
189191 chmod 600 ~/.ssh/deploy_key
192+
190193 ssh-keyscan -H "$SERVER_HOST" >> ~/.ssh/known_hosts
194+
191195 cat >> ~/.ssh/config <<EOF
192196 Host deploy_target
193197 HostName $SERVER_HOST
@@ -197,13 +201,27 @@ By: \`${{ github.actor }}\`"
197201 ConnectTimeout 15
198202 EOF
199203
204+ - name : Notify — deploy job started
205+ env :
206+ BOT_TOKEN : ${{ secrets.BOT_TOKEN }}
207+ run : |
208+ chmod +x scripts/notify-telegram.sh
209+ ./scripts/notify-telegram.sh "🚀 *Deploy Job Started*
210+ Repo : \`${{ github.repository }}\`
211+ Branch : \`${{ github.ref_name }}\`
212+ Commit : \`${{ needs.quality-gates.outputs.commit_hash }}\`
213+ Version : \`${{ needs.quality-gates.outputs.version }}\`
214+ Actor : \`${{ github.actor }}\`"
215+
200216 - name : Save pre-deploy SHA
201217 id : pre
202218 run : |
203219 SHA=$(ssh deploy_target "cd /var/www/html/Runewager && git rev-parse HEAD || echo none")
204220 echo "sha=$SHA" >> "$GITHUB_OUTPUT"
205221
206222 - name : Pre-deploy health snapshot
223+ env :
224+ BOT_TOKEN : ${{ secrets.BOT_TOKEN }}
207225 run : |
208226 ssh deploy_target "
209227 set -e
@@ -221,49 +239,87 @@ By: \`${{ github.actor }}\`"
221239 echo 'Checking memory/disk...'
222240 free -m || true
223241 df -h . || true
224-
225- echo 'Checking disk free threshold...'
226- FREE_KB=\$(df . | awk 'NR==2 {print \$4}')
227- FREE_MB=\$((FREE_KB / 1024))
228- if [ \"\$FREE_MB\" -lt 100 ]; then
229- echo 'WARNING: Less than 100MB free disk space (' \$FREE_MB 'MB). Proceeding with caution.'
230- else
231- echo \"✅ Disk: \${FREE_MB}MB free\"
232- fi
233242 "
234243
235- - name : Deploy via deploy.sh (with password fallback)
244+ chmod +x scripts/notify-telegram.sh
245+ ./scripts/notify-telegram.sh "📋 *Pre-Deploy Health Snapshot*
246+ Path : \`/var/www/html/Runewager\`
247+ Commit (pre) : \`${{ steps.pre.outputs.sha }}\`"
248+
249+ - name : Deploy via deploy.sh (key first, then password fallback)
236250 env :
237251 SERVER_HOST : ${{ secrets.SERVER_HOST }}
238252 SERVER_USER : ${{ secrets.SERVER_USER }}
253+ BOT_TOKEN : ${{ secrets.BOT_TOKEN }}
239254 run : |
240- DEPLOY_CMD="bash /var/www/html/Runewager/deploy.sh github"
255+ chmod +x scripts/notify-telegram.sh
256+
257+ DEPLOY_CMD='
258+ set -e
259+ cd /var/www/html/Runewager
260+
261+ echo "Pulling latest main..."
262+ git fetch origin main
263+ git reset --hard origin/main
264+
265+ echo "Ensuring .env exists and is preserved..."
266+ if [ ! -f .env ]; then
267+ echo "ERROR: .env missing on VPS" >&2
268+ exit 1
269+ fi
270+
271+ echo "Stopping systemd service (if running)..."
272+ sudo systemctl stop runewager.service || true
273+
274+ echo "Killing any stray Node/bot processes..."
275+ pkill -f "Runewager" || true
276+ pkill -f "index.js" || true
277+ pkill -f "node" || true
278+
279+ echo "Installing production dependencies..."
280+ npm ci --omit=dev
281+
282+ echo "Starting systemd service cleanly..."
283+ sudo systemctl daemon-reload || true
284+ sudo systemctl start runewager.service
285+
286+ echo "Checking systemd status..."
287+ sudo systemctl is-active --quiet runewager.service
288+ '
289+
290+ ./scripts/notify-telegram.sh "🔑 *Deploy Phase — SSH Key Attempt*
291+ Host : \`${SERVER_HOST}\`"
241292
242- # First attempt: SSH with key
243293 if ssh deploy_target "$DEPLOY_CMD"; then
244294 echo "✅ Deployed via SSH key"
295+ ./scripts/notify-telegram.sh "✅ *Deploy Succeeded via SSH Key*
296+ Host : \`${SERVER_HOST}\`"
245297 else
246- echo "⚠️ SSH key attempt failed — waiting 120 seconds before password retry…"
298+ echo "⚠️ SSH key failed — waiting 120 seconds before password retry..."
299+ ./scripts/notify-telegram.sh "⚠️ *SSH Key Failed — Waiting 2 Minutes Before Password Fallback*
300+ Host : \`${SERVER_HOST}\`"
247301 sleep 120
248302
249- # Second attempt: password fallback via sshpass
250303 if sshpass -p "$DEPLOY_PASS" ssh \
251304 -o StrictHostKeyChecking=no \
252305 -o ConnectTimeout=15 \
253306 " ${SERVER_USER}@${SERVER_HOST}" " $DEPLOY_CMD" ; then
254307 echo "✅ Deployed via password fallback"
308+ ./scripts/notify-telegram.sh "✅ *Deploy Succeeded via Password Fallback*
309+ Host : \`${SERVER_HOST}\`"
255310 else
256- echo "❌ Both SSH attempts failed — sending admin alert"
257- chmod +x scripts/notify-telegram.sh
258- ./scripts/notify-telegram.sh "❌ Deploy failed — SSH could not connect to VPS after key + password retry. Manual intervention required."
311+ echo "❌ Both SSH attempts failed"
312+ ./scripts/notify-telegram.sh "❌ *Deploy Failed — SSH Key + Password Fallback Both Failed*
313+ Host : \`${SERVER_HOST}\`
314+ Action required : manual SSH + service check."
259315 exit 1
260316 fi
261317 fi
262318
263319 - name : Download deploy report from VPS
264320 if : always()
265321 run : |
266- ssh deploy_target "cat /tmp/deploy-report.txt 2>/dev/null || echo 'No deploy report file found on server .'" \
322+ ssh deploy_target "cat /tmp/deploy-report.txt 2>/dev/null || echo 'No deploy report file found.'" \
267323 > /tmp/deploy-report.txt || echo 'No deploy report available.' > /tmp/deploy-report.txt
268324
269325 - name : Upload deploy report as artifact
@@ -275,35 +331,48 @@ By: \`${{ github.actor }}\`"
275331 if-no-files-found : ignore
276332 retention-days : 7
277333
278- - name : Notify success
334+ - name : Post-deploy health check (30s delay)
279335 if : success()
280336 env :
281337 BOT_TOKEN : ${{ secrets.BOT_TOKEN }}
282338 run : |
283339 chmod +x scripts/notify-telegram.sh
284- ./scripts/notify-telegram.sh "✅ *Deploy Successful*
285- Commit : \`${{ needs.quality-gates.outputs.commit_hash }}\`
286- Version : \`${{ needs.quality-gates.outputs.version }}\`
287- Time : \`${{ needs.quality-gates.outputs.deploy_time }}\`"
340+ ./scripts/notify-telegram.sh "⏳ *Post-Deploy Health Check in 30s*"
341+ sleep 30
342+
343+ HEALTH_STATUS="FAIL"
344+ if ssh deploy_target "curl -fsS http://127.0.0.1:3000/health" >/dev/null 2>&1; then
345+ HEALTH_STATUS="OK"
346+ fi
347+
348+ ./scripts/notify-telegram.sh "📡 *Post-Deploy Health Check*
349+ Status : \`${HEALTH_STATUS}\`
350+ Commit : \`${{ needs.quality-gates.outputs.commit_hash }}\`"
288351
289352 - name : Rollback on failure
290353 if : failure()
291354 env :
292355 BOT_TOKEN : ${{ secrets.BOT_TOKEN }}
293356 run : |
294357 PRE="${{ steps.pre.outputs.sha }}"
295-
296358 chmod +x scripts/notify-telegram.sh
297- ./scripts/notify-telegram.sh "❌ *Deploy Failed — Rolling Back*
298- Previous SHA : \`${PRE}\`
299- Reason : Deployment failed — see GitHub Actions logs for full stack trace. "
359+
360+ ./scripts/notify-telegram.sh "❌ *Deploy Failed — Starting Rollback*
361+ Previous SHA : \`${PRE}\` "
300362
301363 ssh deploy_target "
302364 cd /var/www/html/Runewager
303365 if [ \"$PRE\" != \"none\" ] && [ -n \"$PRE\" ]; then
304- git reset --hard $PRE
366+ git reset --hard \" $PRE\"
305367 npm ci --omit=dev || true
306- systemctl restart runewager.service || bash prod-run.sh restart || true
368+
369+ sudo systemctl stop runewager.service || true
370+ pkill -f \"Runewager\" || true
371+ pkill -f \"index.js\" || true
372+ pkill -f \"node\" || true
373+
374+ sudo systemctl daemon-reload || true
375+ sudo systemctl start runewager.service || true
307376 else
308377 echo 'No previous SHA recorded, skipping git rollback'
309378 fi
@@ -321,7 +390,6 @@ Restored to: \`${PRE}\`"
321390 COMMIT="${{ needs.quality-gates.outputs.commit_hash }}"
322391 VERSION="${{ needs.quality-gates.outputs.version }}"
323392 TIME="${{ needs.quality-gates.outputs.deploy_time }}"
324- DURATION="${{ needs.quality-gates.outputs.duration_seconds }}"
325393
326394 REPORT_BODY=$(cat /tmp/deploy-report.txt 2>/dev/null || echo "No deploy report available.")
327395
@@ -331,7 +399,6 @@ Status: ✅ Success
331399Commit : \`$COMMIT\`
332400Version : \`$VERSION\`
333401Time : \`$TIME\`
334- Duration : \`${DURATION}s\`
335402
336403$REPORT_BODY"
337404 else
@@ -340,31 +407,13 @@ Status: ❌ Failure
340407Commit : \`$COMMIT\`
341408Version : \`$VERSION\`
342409Time : \`$TIME\`
343- Duration : \`${DURATION}s\`
344- Reason : Deployment failed — see GitHub Actions logs.
345410
346411$REPORT_BODY"
347412 fi
348413
349414 chmod +x scripts/notify-telegram.sh
350415 ./scripts/notify-telegram.sh "$MSG"
351416
352- - name : Post-deploy health check (30s delay)
353- if : success()
354- env :
355- BOT_TOKEN : ${{ secrets.BOT_TOKEN }}
356- run : |
357- echo "Waiting 30 seconds before post-deploy health check..."
358- sleep 30
359- HEALTH_STATUS="FAIL"
360- if ssh deploy_target "curl -fsS http://127.0.0.1:3000/health" >/dev/null 2>&1; then
361- HEALTH_STATUS="OK"
362- fi
363- chmod +x scripts/notify-telegram.sh
364- ./scripts/notify-telegram.sh "📡 *Post-Deploy Health Check (30s)*
365- Status : \`${HEALTH_STATUS}\`
366- Commit : \`${{ needs.quality-gates.outputs.commit_hash }}\`"
367-
368417 # ---------------------------------------------------------------------------
369418 # Job 3: Dry-run report (only when dry_run=true)
370419 # ---------------------------------------------------------------------------
0 commit comments