From 554fe668dc0bd08cb4b2fd570314ea5430b18ee1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 7 Mar 2026 09:09:13 +0000 Subject: [PATCH] =?UTF-8?q?feat:=20add=20CD=20workflow=20deploy-to-server.?= =?UTF-8?q?yml=20(=E5=B7=A5=E5=8D=95=20YM-CD-20260307-001)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Job 1 (validate): HLI contract check + module fingerprint check - Job 2 (deploy): rsync docs/ to server via SSH with safety checks - Job 3 (notify): Push deployment record to Notion changelog - Trigger: push to main (excludes non-frontend paths) - Requires: DEPLOY_HOST, DEPLOY_USER, DEPLOY_KEY, DEPLOY_PATH secrets Co-authored-by: qinfendebingshuo <207279273+qinfendebingshuo@users.noreply.github.com> --- .github/workflows/deploy-to-server.yml | 200 +++++++++++++++++++++++++ 1 file changed, 200 insertions(+) create mode 100644 .github/workflows/deploy-to-server.yml diff --git a/.github/workflows/deploy-to-server.yml b/.github/workflows/deploy-to-server.yml new file mode 100644 index 00000000..1f05b654 --- /dev/null +++ b/.github/workflows/deploy-to-server.yml @@ -0,0 +1,200 @@ +name: "๐Ÿš€ ้“ธๆธŠ CD ยท ่‡ชๅŠจ้ƒจ็ฝฒๅˆฐ guanghulab.com" + +# โ”โ”โ” ๅทฅๅ• YM-CD-20260307-001 โ”โ”โ” +# push ๅˆฐ main โ†’ ๆ ก้ชŒ โ†’ rsync ๅŒๆญฅๅˆฐๆœๅŠกๅ™จ โ†’ Notion ้ƒจ็ฝฒ้€š็Ÿฅ +# +# ๅฟ…้œ€ GitHub Secrets๏ผˆไป“ๅบ“ Settings โ†’ Secrets โ†’ Actions๏ผ‰: +# DEPLOY_HOST โ€” ๆœๅŠกๅ™จ IP +# DEPLOY_USER โ€” SSH ็”จๆˆทๅ +# DEPLOY_KEY โ€” SSH ็ง้’ฅ๏ผˆๅฎŒๆ•ด PEM ๅ†…ๅฎน๏ผ‰ +# DEPLOY_PATH โ€” Nginx ็ฝ‘็ซ™ๆ น็›ฎๅฝ•๏ผˆๅฆ‚ /usr/share/nginx/html๏ผ‰ +# +# ๅฏ้€‰ Secrets๏ผˆๅทฒๆœ‰ๅˆ™่‡ชๅŠจๅฏ็”จ Notion ้€š็Ÿฅ๏ผ‰: +# NOTION_TOKEN โ€” Notion ้›†ๆˆ token +# CHANGES_DB_ID โ€” Notion ๅ˜ๆ›ดๆ—ฅๅฟ—ๆ•ฐๆฎๅบ“ ID๏ผˆๆœ‰ๅ†…็ฝฎ้ป˜่ฎคๅ€ผ๏ผ‰ + +on: + push: + branches: [main] + paths-ignore: + - '.github/persona-brain/**' + - 'broadcasts-outbox/**' + - 'syslog-inbox/**' + - 'syslog-processed/**' + - 'signal-log/**' + - 'dev-nodes/**' + + workflow_dispatch: + +permissions: + contents: read + +jobs: + + # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• + # Job 1: ้ƒจ็ฝฒๅ‰ๆ ก้ชŒ + # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• + validate: + name: "๐Ÿ” ้ƒจ็ฝฒๅ‰ๆ ก้ชŒ" + runs-on: ubuntu-latest + steps: + - name: ๐Ÿ“ฅ ๆฃ€ๅ‡บไปฃ็  + uses: actions/checkout@v4 + + - name: ๐ŸŸข ้…็ฝฎ Node.js + uses: actions/setup-node@v4 + with: + node-version: "20" + + - name: ๐Ÿ“ฆ ๅฎ‰่ฃ…ไพ่ต–๏ผˆๅฆ‚้œ€่ฆ๏ผ‰ + run: | + if [ -f "package-lock.json" ] && grep -q '"glob"' package.json; then + npm ci --ignore-scripts || npm install --ignore-scripts || echo "โš ๏ธ ไพ่ต–ๅฎ‰่ฃ…ๅคฑ่ดฅ๏ผŒ็ปง็ปญๆ‰ง่กŒ" + fi + + - name: ๐Ÿ” HLI ๅฅ‘็บฆๆ ก้ชŒ + run: | + if [ -f "scripts/contract-check.js" ]; then + echo "๐Ÿ” ๆ‰ง่กŒ HLI ๅฅ‘็บฆๆ ก้ชŒ..." + node scripts/contract-check.js + else + echo "โญ๏ธ scripts/contract-check.js ไธๅญ˜ๅœจ๏ผŒ่ทณ่ฟ‡ HLI ๆ ก้ชŒ" + fi + + - name: ๐Ÿ“‹ ๆจกๅ—ๆŒ‡็บนๆฃ€ๆŸฅ + run: | + if [ -f "scripts/zhuyuan-module-protocol.js" ]; then + echo "๐Ÿ” ๆ‰ง่กŒๆจกๅ—ๆŒ‡็บนๆฃ€ๆŸฅ..." + node scripts/zhuyuan-module-protocol.js status + else + echo "โญ๏ธ scripts/zhuyuan-module-protocol.js ไธๅญ˜ๅœจ๏ผŒ่ทณ่ฟ‡ๆจกๅ—ๆฃ€ๆŸฅ" + fi + + - name: โœ… ๆ ก้ชŒๆฑ‡ๆ€ป + run: | + echo "### โœ… ้ƒจ็ฝฒๅ‰ๆ ก้ชŒ้€š่ฟ‡" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "- HLI ๅฅ‘็บฆๆ ก้ชŒ: โœ…" >> $GITHUB_STEP_SUMMARY + echo "- ๆจกๅ—ๆŒ‡็บนๆฃ€ๆŸฅ: โœ…" >> $GITHUB_STEP_SUMMARY + echo "- ๆไบค: \`${{ github.sha }}\`" >> $GITHUB_STEP_SUMMARY + + # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• + # Job 2: rsync ๅŒๆญฅๅˆฐๆœๅŠกๅ™จ + # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• + deploy: + name: "๐Ÿš€ ้ƒจ็ฝฒๅˆฐๆœๅŠกๅ™จ" + needs: validate + runs-on: ubuntu-latest + steps: + - name: ๐Ÿ“ฅ ๆฃ€ๅ‡บไปฃ็  + uses: actions/checkout@v4 + + - name: ๐Ÿ”‘ ้…็ฝฎ SSH ่ฟžๆŽฅ + run: | + mkdir -p ~/.ssh + echo "${{ secrets.DEPLOY_KEY }}" > ~/.ssh/deploy_key + chmod 600 ~/.ssh/deploy_key + ssh-keyscan -H ${{ secrets.DEPLOY_HOST }} >> ~/.ssh/known_hosts 2>/dev/null + + - name: ๐Ÿ”’ ้ƒจ็ฝฒๅ‰ๅฎ‰ๅ…จๆฃ€ๆŸฅ + run: | + if [ ! -f "docs/index.html" ]; then + echo "โŒ docs/index.html ไธๅญ˜ๅœจ๏ผŒไธญๆญข้ƒจ็ฝฒไปฅ้˜ฒๆธ…็ฉบ็”Ÿไบง็Žฏๅขƒ" + exit 1 + fi + FILE_COUNT=$(find docs/ -type f | wc -l) + if [ "$FILE_COUNT" -lt 2 ]; then + echo "โŒ docs/ ็›ฎๅฝ•ๆ–‡ไปถๆ•ฐๅผ‚ๅธธ๏ผˆไป… ${FILE_COUNT} ไธช๏ผ‰๏ผŒไธญๆญข้ƒจ็ฝฒ" + exit 1 + fi + echo "โœ… docs/ ็›ฎๅฝ•ๅŒ…ๅซ ${FILE_COUNT} ไธชๆ–‡ไปถ๏ผŒๅฎ‰ๅ…จๆฃ€ๆŸฅ้€š่ฟ‡" + + - name: ๐Ÿš€ rsync ๅŒๆญฅๅˆฐๆœๅŠกๅ™จ + run: | + echo "๐Ÿ“ก ๅผ€ๅง‹ๅŒๆญฅๅˆฐ ${{ secrets.DEPLOY_HOST }}:${{ secrets.DEPLOY_PATH }}" + + rsync -avz --delete-after \ + --exclude '.git' \ + --exclude '.github' \ + --exclude 'node_modules' \ + --exclude 'scripts' \ + --exclude 'syslog-inbox' \ + --exclude 'syslog-processed' \ + --exclude 'signal-log' \ + --exclude 'dev-nodes' \ + --exclude 'broadcasts-outbox' \ + --exclude 'backend-integration' \ + --exclude 'tests' \ + --exclude 'src' \ + --exclude 'cost-control' \ + --exclude 'notion-push' \ + --exclude 'multi-persona' \ + --exclude 'status-board' \ + --exclude 'reports' \ + --exclude 'guanghulab-main' \ + --exclude 'package*.json' \ + --exclude 'tsconfig.json' \ + --exclude 'next.config.ts' \ + --exclude 'postcss.config.mjs' \ + --exclude 'jest.smoke.config.js' \ + --exclude 'ecosystem.config.js' \ + --exclude '.gitignore' \ + --exclude 'CNAME' \ + -e "ssh -i ~/.ssh/deploy_key" \ + docs/ \ + ${{ secrets.DEPLOY_USER }}@${{ secrets.DEPLOY_HOST }}:${{ secrets.DEPLOY_PATH }}/ + + echo "โœ… ๅŒๆญฅๅฎŒๆˆ" + + - name: ๐Ÿ” ้ชŒ่ฏ้ƒจ็ฝฒ + run: | + ssh -i ~/.ssh/deploy_key \ + ${{ secrets.DEPLOY_USER }}@${{ secrets.DEPLOY_HOST }} \ + "echo 'โœ… ๆœๅŠกๅ™จ่ฟžๆŽฅๆญฃๅธธ' && ls -la ${{ secrets.DEPLOY_PATH }}/ | head -20" + + - name: ๐Ÿ“ ้ƒจ็ฝฒๆฑ‡ๆ€ป + run: | + echo "### ๐Ÿš€ ้ƒจ็ฝฒๅฎŒๆˆ" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "- ็›ฎๆ ‡: \`${{ secrets.DEPLOY_HOST }}:${{ secrets.DEPLOY_PATH }}\`" >> $GITHUB_STEP_SUMMARY + echo "- ๆไบค: \`${{ github.sha }}\`" >> $GITHUB_STEP_SUMMARY + echo "- ๆ—ถ้—ด: $(TZ=Asia/Shanghai date '+%Y-%m-%d %H:%M CST')" >> $GITHUB_STEP_SUMMARY + + # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• + # Job 3: Notion ้ƒจ็ฝฒ้€š็Ÿฅ + # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• + notify: + name: "๐Ÿ“ก ้ƒจ็ฝฒ้€š็Ÿฅ โ†’ Notion" + needs: deploy + runs-on: ubuntu-latest + if: success() + steps: + - name: ๐Ÿ“ฅ ๆฃ€ๅ‡บไปฃ็  + uses: actions/checkout@v4 + with: + fetch-depth: 2 + + - name: ๐ŸŸข ้…็ฝฎ Node.js + uses: actions/setup-node@v4 + with: + node-version: "20" + + - name: ๐Ÿ“ก ๆŽจ้€้ƒจ็ฝฒ่ฎฐๅฝ•ๅˆฐ Notion + env: + NOTION_TOKEN: ${{ secrets.NOTION_TOKEN }} + CHANGES_DB_ID: ${{ secrets.CHANGES_DB_ID }} + EVENT_TYPE: commit + COMMIT_SHA: ${{ github.sha }} + COMMIT_MSG: "[CD ้ƒจ็ฝฒ] ${{ github.event.head_commit.message }}" + COMMITTER: ${{ github.event.head_commit.author.name || github.actor }} + COMMIT_TIMESTAMP: ${{ github.event.head_commit.timestamp }} + BRANCH: ${{ github.ref_name }} + run: | + CHANGED=$(git diff --name-only HEAD~1 HEAD 2>/dev/null || true) + export CHANGED_FILES="$CHANGED" + if [ -f "scripts/notion-bridge.js" ]; then + node scripts/notion-bridge.js changes + echo "โœ… Notion ้ƒจ็ฝฒ้€š็Ÿฅๅทฒๅ‘้€" + else + echo "โญ๏ธ scripts/notion-bridge.js ไธๅญ˜ๅœจ๏ผŒ่ทณ่ฟ‡ Notion ้€š็Ÿฅ" + fi