chore: cập nhật cấu trúc mã và cải tiến xử lý webhook GHN #404
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: CI/CD Pipeline Optimized | |
| on: | |
| push: | |
| branches: [main, master] | |
| workflow_dispatch: | |
| inputs: | |
| manual_rollback: | |
| description: 'Commit SHA hoặc tag để rollback' | |
| required: false | |
| permissions: | |
| contents: write | |
| jobs: | |
| deploy: | |
| name: Deploy to Production | |
| runs-on: ubuntu-latest | |
| if: ${{ github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && !github.event.inputs.manual_rollback) }} | |
| steps: | |
| - name: Record Job Start Time | |
| id: start_time | |
| run: echo "timestamp_utc=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_OUTPUT | |
| - name: Setup SSH agent | |
| uses: webfactory/ssh-agent@v0.9.0 | |
| with: | |
| ssh-private-key: ${{ secrets.VPS_SSH_KEY }} | |
| - name: Add VPS host to known_hosts | |
| run: | | |
| mkdir -p ~/.ssh | |
| ssh-keyscan -H ${{ secrets.VPS_HOST }} >> ~/.ssh/known_hosts | |
| - name: Deploy via SSH & Get Server status | |
| id: ssh_deploy | |
| run: | | |
| ssh -o StrictHostKeyChecking=no ${{ secrets.VPS_USERNAME }}@${{ secrets.VPS_HOST }} << 'EOF' | |
| set -euo pipefail | |
| export NVM_DIR="$HOME/.nvm" | |
| [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" | |
| cd ${{ secrets.VPS_PATH }} | |
| git fetch origin master && git reset --hard origin/master | |
| npm ci | |
| npm run build | |
| pm2 startOrReload ecosystem.config.js --env production | |
| sleep 5 | |
| pm2 status > /tmp/pm2_status.txt | |
| STATUS=$(pm2 jlist | jq -r '.[] | select(.name == "server-shopsifu") | .pm2_env.status') | |
| [ "$STATUS" = "online" ] || exit 2 | |
| EOF | |
| continue-on-error: true | |
| - name: Collect PM2 status | |
| if: always() | |
| id: pm2_status | |
| run: | | |
| PM2_CONSOLE_OUTPUT=$(ssh -o StrictHostKeyChecking=no ${{ secrets.VPS_USERNAME }}@${{ secrets.VPS_HOST }} 'cat /tmp/pm2_status.txt' || echo "Không thể lấy trạng thái PM2.") | |
| echo "pm2_console_output<<EOF" >> $GITHUB_OUTPUT | |
| echo "$PM2_CONSOLE_OUTPUT" >> $GITHUB_OUTPUT | |
| echo "EOF" >> $GITHUB_OUTPUT | |
| - name: Get Commit Info | |
| id: commit_info | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - run: | | |
| COMMIT_MESSAGE=$(git log -1 --pretty=%B) | |
| echo "commit_message<<EOF" >> $GITHUB_OUTPUT | |
| echo "$COMMIT_MESSAGE" >> $GITHUB_OUTPUT | |
| echo "EOF" >> $GITHUB_OUTPUT | |
| id: get_commit_message | |
| - name: Send Discord Notification | |
| if: always() | |
| env: | |
| DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }} | |
| STATUS: ${{ job.status }} | |
| BRANCH: ${{ github.ref_name }} | |
| COMMIT: ${{ github.sha }} | |
| ACTOR: ${{ github.actor }} | |
| REPO: ${{ github.repository }} | |
| RUN_ID: ${{ github.run_id }} | |
| PM2_STATUS_OUTPUT: ${{ steps.pm2_status.outputs.pm2_console_output }} | |
| COMMIT_MESSAGE: ${{ steps.get_commit_message.outputs.commit_message }} | |
| JOB_STARTED_AT: ${{ steps.start_time.outputs.timestamp_utc }} | |
| run: | | |
| sudo apt-get update && sudo apt-get install -y jq | |
| COLOR=$([ "$STATUS" = "success" ] && echo 3066993 || echo 15158332) | |
| ICON=$([ "$STATUS" = "success" ] && echo "✅" || echo "❌") | |
| STARTED_AT_EPOCH=$(date -d "$JOB_STARTED_AT" +%s) | |
| JSON_PAYLOAD=$(jq -n \ | |
| --arg status "$STATUS" \ | |
| --arg icon "$ICON" \ | |
| --arg branch "$BRANCH" \ | |
| --arg commit_short "$(echo $COMMIT | cut -c1-7)" \ | |
| --arg commit_full "$COMMIT" \ | |
| --arg commit_message "$COMMIT_MESSAGE" \ | |
| --arg repo "$REPO" \ | |
| --arg actor "$ACTOR" \ | |
| --arg pm2_status "${PM2_STATUS_OUTPUT:0:1800}" \ | |
| --arg run_id "$RUN_ID" \ | |
| --arg color "$COLOR" \ | |
| --arg started_at "$STARTED_AT_EPOCH" \ | |
| '{ | |
| embeds: [{ | |
| title: "🚀 SERVER - Thông báo triển khai ✨", | |
| color: ($color | tonumber), | |
| fields: [ | |
| { name: "Trạng thái", value: "\($icon) \($status | ascii_upcase)", inline: true }, | |
| { name: "Nhánh", value: "`\($branch)`", inline: true }, | |
| { name: "Người thực hiện", value: "`\($actor)`", inline: true }, | |
| { name: "Commit", value: "[`\($commit_short)`](https://github.com/\($repo)/commit/\($commit_full))", inline: false }, | |
| { name: "Nội dung Commit", value: "```\n\($commit_message)\n```", inline: false }, | |
| { name: "Thời gian", value: "<t:\($started_at):R>", inline: true } | |
| ], | |
| description: "**Trạng thái PM2 trên server:**\n```ansi\n\($pm2_status)\n```", | |
| url: "https://github.com/\($repo)/actions/runs/\($run_id)", | |
| "timestamp": (now | strftime("%Y-%m-%dT%H:%M:%SZ")) | |
| }] | |
| }') | |
| curl -s -H "Content-Type: application/json" -X POST -d "$JSON_PAYLOAD" "$DISCORD_WEBHOOK" || echo "Lỗi gửi thông báo Discord" | |
| # Các job rollback vẫn được giữ lại để đảm bảo an toàn | |
| rollback-auto: | |
| name: Automatic Rollback | |
| needs: deploy | |
| runs-on: ubuntu-latest | |
| if: failure() | |
| steps: | |
| - name: Rollback to previous commit | |
| run: | | |
| ssh -o StrictHostKeyChecking=no ${{ secrets.VPS_USERNAME }}@${{ secrets.VPS_HOST }} << 'EOF' | |
| set -euo pipefail | |
| export NVM_DIR="$HOME/.nvm" | |
| [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" | |
| cd ${{ secrets.VPS_PATH }} | |
| git fetch origin master && git reset --hard HEAD~1 | |
| npm ci | |
| npm run build | |
| pm2 startOrReload ecosystem.config.js --env production | |
| EOF | |
| manual-rollback: | |
| name: Manual Rollback | |
| if: github.event_name == 'workflow_dispatch' && github.event.inputs.manual_rollback | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Re-deploy to VPS | |
| run: | | |
| ssh -o StrictHostKeyChecking=no ${{ secrets.VPS_USERNAME }}@${{ secrets.VPS_HOST }} << 'EOF' | |
| set -euo pipefail | |
| export NVM_DIR="$HOME/.nvm" | |
| [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" | |
| cd ${{ secrets.VPS_PATH }} | |
| git fetch --all | |
| git reset --hard ${{ github.event.inputs.manual_rollback }} | |
| npm ci | |
| npm run build | |
| pm2 startOrReload ecosystem.config.js --env production | |
| EOF |