name: ๐ŸŒธ ็ง‹็ง‹ๆœๅŠกๅ™จ ยท ้ƒจ็ฝฒ # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• # ็ง‹็ง‹(ไน‹ไน‹)ๆœๅŠกๅ™จ้ƒจ็ฝฒๅทฅไฝœๆต # ็ผ–ๅท: ZZ-WF-็ง‹็ง‹้ƒจ็ฝฒ # ๅฎˆๆŠค: ้“ธๆธŠ ยท ICE-GL-ZY001 # ็‰ˆๆƒ: ๅ›ฝไฝœ็™ปๅญ—-2026-A-00037559 # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• # # ๆœๅŠกๅ™จ: ZZ ๆœๅŠกๅ™จ # ๅฏ†้’ฅ: ZZ_SERVER_KEY / ZZ_SERVER_HOST / ZZ_SERVER_USER / ZZ_SERVER_PATH # LLM: ZZ_LLM_API_KEY / ZZ_LLM_BASE_URL on: workflow_dispatch: inputs: action: description: '้ƒจ็ฝฒๅŠจไฝœ' required: true default: 'deploy' type: choice options: - deploy - health-check concurrency: group: qiuqiu-server-deploy cancel-in-progress: false permissions: contents: read jobs: # โ•โ•โ• ยง1 ้ƒจ็ฝฒๅบ”็”จ โ•โ•โ• deploy: name: ๐Ÿš€ ้ƒจ็ฝฒ็ง‹็ง‹ๆœๅŠก if: github.event.inputs.action == 'deploy' runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: ๐Ÿ” ้…็ฝฎSSHๅฏ†้’ฅ env: SSH_KEY: ${{ secrets.ZZ_SERVER_KEY }} run: | mkdir -p ~/.ssh echo "$SSH_KEY" > ~/.ssh/id_zz chmod 600 ~/.ssh/id_zz if ! head -1 ~/.ssh/id_zz | grep -q "BEGIN"; then echo "โŒ SSHๅฏ†้’ฅๆ ผๅผๅผ‚ๅธธ" exit 1 fi echo "โœ… SSHๅฏ†้’ฅๆ ผๅผๆญฃ็กฎ" ssh-keyscan -H ${{ secrets.ZZ_SERVER_HOST }} >> ~/.ssh/known_hosts 2>/dev/null cat > ~/.ssh/config << EOF Host zz-server HostName ${{ secrets.ZZ_SERVER_HOST }} User ${{ secrets.ZZ_SERVER_USER }} IdentityFile ~/.ssh/id_zz StrictHostKeyChecking accept-new BatchMode yes ConnectTimeout 30 EOF chmod 600 ~/.ssh/config - name: ๐Ÿ” SSH่ฟžๆŽฅๆต‹่ฏ• run: | ssh zz-server 'echo "โœ… SSH่ฟžๆŽฅๆˆๅŠŸ ยท $(hostname) ยท $(date)"' - name: ๐Ÿ“ฆ ๅŒๆญฅๅบ”็”จไปฃ็  run: | ZZ_PATH="${{ secrets.ZZ_SERVER_PATH }}" echo "๐Ÿ“ฆ ้ƒจ็ฝฒ็›ฎๆ ‡: ${ZZ_PATH}" ssh zz-server "mkdir -p ${ZZ_PATH}/app" rsync -avz --delete \ -e "ssh -F ~/.ssh/config" \ server/app/ \ zz-server:${ZZ_PATH}/app/ - name: โš™๏ธ ๅ†™ๅ…ฅ LLM ็Žฏๅขƒ้…็ฝฎ run: | ZZ_PATH="${{ secrets.ZZ_SERVER_PATH }}" ssh zz-server "cat > ${ZZ_PATH}/app/.env << 'ENVEOF' LLM_API_KEY=${{ secrets.ZZ_LLM_API_KEY }} LLM_BASE_URL=${{ secrets.ZZ_LLM_BASE_URL }} ENVEOF chmod 600 ${ZZ_PATH}/app/.env" - name: ๐Ÿ“ฅ ๅฎ‰่ฃ…ไพ่ต– & ้‡ๅฏ run: | ZZ_PATH="${{ secrets.ZZ_SERVER_PATH }}" COMMIT_SHA="${{ github.sha }}" ssh zz-server << DEPLOY_CMD set -e cd ${ZZ_PATH}/app if [ ! -f server.js ]; then echo "โŒ ้”™่ฏฏ: server.js ไธๅญ˜ๅœจ" exit 1 fi npm install --production 2>&1 pm2 delete qiuqiu 2>/dev/null || true pm2 start server.js --name qiuqiu pm2 save sleep 3 curl -sf http://localhost:3000/api/health && echo "โœ… ็ง‹็ง‹ๆœๅŠกๅทฒไธŠ็บฟ" || echo "โŒ ็ง‹็ง‹ๆœๅŠกๅฏๅŠจๅคฑ่ดฅ" DEPLOY_CMD - name: ๐Ÿงน ๆธ…็†SSHๅฏ†้’ฅ if: always() run: rm -f ~/.ssh/id_zz ~/.ssh/config # โ•โ•โ• ยง2 ๅฅๅบทๆฃ€ๆŸฅ โ•โ•โ• health-check: name: ๐Ÿ’š ็ง‹็ง‹ๆœๅŠกๅฅๅบทๆฃ€ๆŸฅ if: github.event.inputs.action == 'health-check' runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: ๐Ÿ” ้…็ฝฎSSHๅฏ†้’ฅ env: SSH_KEY: ${{ secrets.ZZ_SERVER_KEY }} run: | mkdir -p ~/.ssh echo "$SSH_KEY" > ~/.ssh/id_zz chmod 600 ~/.ssh/id_zz ssh-keyscan -H ${{ secrets.ZZ_SERVER_HOST }} >> ~/.ssh/known_hosts 2>/dev/null cat > ~/.ssh/config << EOF Host zz-server HostName ${{ secrets.ZZ_SERVER_HOST }} User ${{ secrets.ZZ_SERVER_USER }} IdentityFile ~/.ssh/id_zz StrictHostKeyChecking accept-new BatchMode yes ConnectTimeout 30 EOF chmod 600 ~/.ssh/config - name: ๐Ÿ’š ๆ‰ง่กŒๅฅๅบทๆฃ€ๆŸฅ run: | ssh zz-server << 'HEALTH_CMD' echo "โ•โ•โ• ็ง‹็ง‹ๆœๅŠกๅ™จๅฅๅบทๆŠฅๅ‘Š โ•โ•โ•" echo "" echo "ยง1 ็ณป็ปŸ็Šถๆ€:" uptime echo "" echo "ยง2 ็ฃ็›˜ไฝฟ็”จ:" df -h / echo "" echo "ยง3 ๅ†…ๅญ˜ไฝฟ็”จ:" free -m echo "" echo "ยง4 PM2 ่ฟ›็จ‹:" pm2 list 2>/dev/null || echo "PM2 ๆœช่ฟ่กŒ" echo "" echo "ยง5 ๅบ”็”จๅฅๅบท:" curl -sf http://localhost:3000/api/health | jq . 2>/dev/null || echo "ๅบ”็”จๆœชๅ“ๅบ”" HEALTH_CMD - name: ๐Ÿงน ๆธ…็†SSHๅฏ†้’ฅ if: always() run: rm -f ~/.ssh/id_zz ~/.ssh/config