mirror of
https://github.com/HamCQ/Handbook.git
synced 2026-10-02 04:47:21 +00:00
175 lines
7.0 KiB
YAML
175 lines
7.0 KiB
YAML
name: Build and Deploy VuePress
|
||
|
||
on:
|
||
push:
|
||
branches: [ main ]
|
||
workflow_dispatch:
|
||
|
||
jobs:
|
||
build-and-deploy:
|
||
runs-on: ubuntu-latest
|
||
|
||
steps:
|
||
- name: Checkout code
|
||
uses: actions/checkout@v4
|
||
with:
|
||
fetch-depth: 0
|
||
|
||
- name: Setup Node.js
|
||
uses: actions/setup-node@v4
|
||
with:
|
||
node-version: '20'
|
||
cache: 'yarn'
|
||
|
||
- name: Install dependencies
|
||
run: yarn install --frozen-lockfile
|
||
|
||
- name: Build VuePress site
|
||
run: yarn docs:build
|
||
|
||
- name: Get runner public IP
|
||
id: ip
|
||
run: echo "ipaddr=$(curl -s https://api.ipify.org)" >> $GITHUB_OUTPUT
|
||
|
||
- name: Add IP to Aliyun Security Group
|
||
env:
|
||
ALIYUN_ACCESS_KEY_ID: ${{ secrets.ALIYUN_ACCESS_KEY_ID }}
|
||
ALIYUN_ACCESS_KEY_SECRET: ${{ secrets.ALIYUN_ACCESS_KEY_SECRET }}
|
||
ALIYUN_REGION: ${{ secrets.ALIYUN_REGION }}
|
||
ALIYUN_SECURITY_GROUP_ID: ${{ secrets.ALIYUN_SECURITY_GROUP_ID }}
|
||
SERVER_SSH_PORT: ${{ secrets.SERVER_PORT }}
|
||
RUNNER_IP: ${{ steps.ip.outputs.ipaddr }}
|
||
run: |
|
||
pip install aliyun-python-sdk-core aliyun-python-sdk-ecs
|
||
python3 << 'EOF'
|
||
import os
|
||
import sys
|
||
from aliyunsdkcore.client import AcsClient
|
||
from aliyunsdkecs.request.v20140526 import AuthorizeSecurityGroupRequest
|
||
|
||
client = AcsClient(
|
||
os.environ['ALIYUN_ACCESS_KEY_ID'],
|
||
os.environ['ALIYUN_ACCESS_KEY_SECRET'],
|
||
os.environ['ALIYUN_REGION']
|
||
)
|
||
|
||
request = AuthorizeSecurityGroupRequest.AuthorizeSecurityGroupRequest()
|
||
request.set_SecurityGroupId(os.environ['ALIYUN_SECURITY_GROUP_ID'])
|
||
request.set_IpProtocol('tcp')
|
||
request.set_PortRange(f"{os.environ['SERVER_SSH_PORT']}/{os.environ['SERVER_SSH_PORT']}")
|
||
request.set_SourceCidrIp(f"{os.environ['RUNNER_IP']}/32")
|
||
request.set_Description('GitHub Actions temporary access')
|
||
|
||
try:
|
||
response = client.do_action_with_exception(request)
|
||
print(f"✓ Added {os.environ['RUNNER_IP']} to security group")
|
||
except Exception as e:
|
||
if 'InvalidPermission.Duplicate' in str(e):
|
||
print(f"✓ Rule already exists for {os.environ['RUNNER_IP']}")
|
||
else:
|
||
print(f"✗ Error: {e}")
|
||
sys.exit(1)
|
||
EOF
|
||
|
||
- name: Deploy to Aliyun Server
|
||
uses: appleboy/scp-action@v0.1.7
|
||
with:
|
||
host: ${{ secrets.SERVER_HOST }}
|
||
username: ${{ secrets.SERVER_USER }}
|
||
key: ${{ secrets.SERVER_SSH_KEY }}
|
||
port: ${{ secrets.SERVER_PORT }}
|
||
source: "docs/.vuepress/dist/*"
|
||
target: ${{ secrets.DEPLOY_PATH }}
|
||
strip_components: 3
|
||
overwrite: true
|
||
|
||
- name: Set Permissions
|
||
uses: appleboy/ssh-action@v1.0.3
|
||
with:
|
||
host: ${{ secrets.SERVER_HOST }}
|
||
username: ${{ secrets.SERVER_USER }}
|
||
key: ${{ secrets.SERVER_SSH_KEY }}
|
||
port: ${{ secrets.SERVER_PORT }}
|
||
script: |
|
||
# 先设置所有者(这样后续操作才有权限)
|
||
chown -R ${{ secrets.SERVER_USER }}:${{ secrets.SERVER_USER }} ${{ secrets.DEPLOY_PATH }}
|
||
# 目录权限:755 - 允许进入和列出
|
||
find ${{ secrets.DEPLOY_PATH }} -type d -exec chmod 755 {} \;
|
||
# 文件权限:644 - 只读
|
||
find ${{ secrets.DEPLOY_PATH }} -type f -exec chmod 644 {} \;
|
||
|
||
- name: Remove IP from Aliyun Security Group
|
||
if: always()
|
||
env:
|
||
ALIYUN_ACCESS_KEY_ID: ${{ secrets.ALIYUN_ACCESS_KEY_ID }}
|
||
ALIYUN_ACCESS_KEY_SECRET: ${{ secrets.ALIYUN_ACCESS_KEY_SECRET }}
|
||
ALIYUN_REGION: ${{ secrets.ALIYUN_REGION }}
|
||
ALIYUN_SECURITY_GROUP_ID: ${{ secrets.ALIYUN_SECURITY_GROUP_ID }}
|
||
SERVER_SSH_PORT: ${{ secrets.SERVER_PORT }}
|
||
RUNNER_IP: ${{ steps.ip.outputs.ipaddr }}
|
||
run: |
|
||
pip install aliyun-python-sdk-core aliyun-python-sdk-ecs
|
||
python3 << 'EOF'
|
||
import os
|
||
from aliyunsdkcore.client import AcsClient
|
||
from aliyunsdkecs.request.v20140526 import RevokeSecurityGroupRequest
|
||
|
||
client = AcsClient(
|
||
os.environ['ALIYUN_ACCESS_KEY_ID'],
|
||
os.environ['ALIYUN_ACCESS_KEY_SECRET'],
|
||
os.environ['ALIYUN_REGION']
|
||
)
|
||
|
||
request = RevokeSecurityGroupRequest.RevokeSecurityGroupRequest()
|
||
request.set_SecurityGroupId(os.environ['ALIYUN_SECURITY_GROUP_ID'])
|
||
request.set_IpProtocol('tcp')
|
||
request.set_PortRange(f"{os.environ['SERVER_SSH_PORT']}/{os.environ['SERVER_SSH_PORT']}")
|
||
request.set_SourceCidrIp(f"{os.environ['RUNNER_IP']}/32")
|
||
|
||
try:
|
||
response = client.do_action_with_exception(request)
|
||
print(f"✓ Removed {os.environ['RUNNER_IP']} from security group")
|
||
except Exception as e:
|
||
print(f"⚠ Warning: Failed to remove rule: {e}")
|
||
EOF
|
||
|
||
- name: Notify Success to WeChat
|
||
if: success()
|
||
env:
|
||
COMMIT_MSG: ${{ github.event.head_commit.message }}
|
||
run: |
|
||
curl "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=${{ secrets.WECHAT_WEBHOOK_KEY }}" \
|
||
-H 'Content-Type: application/json' \
|
||
-d "{
|
||
\"msgtype\": \"markdown\",
|
||
\"markdown\": {
|
||
\"content\": \"## ✅ 部署成功\n> 项目:**Handbook (VuePress)**\n> 分支:\\\`${{ github.ref_name }}\\\`\n> 提交者:${{ github.actor }}\n> 提交信息:${COMMIT_MSG}\n> 状态:已成功部署到生产环境\"
|
||
}
|
||
}"
|
||
|
||
- name: Get Job Logs
|
||
if: failure()
|
||
id: logs
|
||
run: |
|
||
ERROR_LOGS=$(cat $GITHUB_STEP_SUMMARY 2>/dev/null || echo "无法获取错误日志")
|
||
echo "logs<<EOF" >> $GITHUB_OUTPUT
|
||
echo "$ERROR_LOGS" >> $GITHUB_OUTPUT
|
||
echo "EOF" >> $GITHUB_OUTPUT
|
||
|
||
- name: Notify Failure to WeChat
|
||
if: failure()
|
||
env:
|
||
WORKFLOW_NAME: ${{ github.workflow }}
|
||
RUN_ID: ${{ github.run_id }}
|
||
JOB_NAME: ${{ github.job }}
|
||
run: |
|
||
FAILED_STEP=$(echo "${{ toJSON(job) }}" | jq -r '.steps[] | select(.conclusion=="failure") | .name' | head -1 || echo "未知步骤")
|
||
|
||
curl "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=${{ secrets.WECHAT_WEBHOOK_KEY }}" \
|
||
-H 'Content-Type: application/json' \
|
||
-d "{
|
||
\"msgtype\": \"markdown\",
|
||
\"markdown\": {
|
||
\"content\": \"## ❌ 部署失败\n> 项目:**Handbook (VuePress)**\n> 分支:\\\`${{ github.ref_name }}\\\`\n> 提交者:${{ github.actor }}\n> 提交信息:${{ github.event.head_commit.message }}\n> 失败步骤:${FAILED_STEP}\n> Run ID:${RUN_ID}\n\n查看完整日志请前往 GitHub Actions\"
|
||
}
|
||
}" |