人人都会AI编程

13.2 钩子自动化工作流搭建

更新时间:2026-06-28

hooks(钩子)是事件触发器的俗称。搭建自动化工作流的核心逻辑是:在特定事件发生时,自动执行预定脚本。以下是生产环境中最实用的三层钩子架构。

1. 本地层:代码提交前拦截(Git Hooks)

.git/hooks 目录下(或全局配置 git config --global core.hooksPath),最实用的是 pre-commit 钩子,防止脏代码进入仓库:

#!/bin/sh
# .git/hooks/pre-commit
echo "正在检查代码规范..."

# 仅检查本次修改的文件
STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep -E '\.(js|ts|vue|py)$')

if [ -z "$STAGED_FILES" ]; then exit 0; fi

# 运行 ESLint(前端)或 Black(Python)
echo "$STAGED_FILES" | xargs npx eslint --fix

# 如果有修改,阻止提交并提示
if ! git diff --cached --quiet; then
    echo "检测到自动修复,请重新 git add 并提交"
    exit 1
fi

关键配置:团队统一使用 Husky 管理钩子,避免每个人手动配置:

// package.json
{
  "husky": {
    "hooks": {
      "pre-commit": "lint-staged",
      "commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
    }
  }
}

2. 服务端层:代码推送后触发(Webhook)

当代码推送到 GitHub/GitLab 后,通过 Webhook 触发服务器动作。以 GitLab 自动部署为例:

服务器端脚本/opt/webhook/deploy.sh):

#!/bin/bash
DEPLOY_DIR="/var/www/project"
LOG_FILE="/var/log/deploy.log"

echo "$(date): 收到部署请求" >> $LOG_FILE

cd $DEPLOY_DIR
git pull origin main --ff-only >> $LOG_FILE 2>&1

# 仅当依赖文件变更时才重装
if git diff --name-only HEAD@{1} HEAD | grep -q "package.json"; then
    npm ci --production >> $LOG_FILE 2>&1
fi

pm2 reload app --update-env >> $LOG_FILE 2>&1

简易 Webhook 接收器(使用 Node.js 的 github-webhook-handler 或 Python 的 Flask):

# webhook_server.py
from flask import Flask, request
import hmac
import subprocess

app = Flask(__name__)

@app.route('/deploy', methods=['POST'])
def deploy():
    # 验证密钥(防止恶意触发)
    signature = request.headers.get('X-Hub-Signature-256')
    secret = b'your-webhook-secret'
    expected = 'sha256=' + hmac.new(secret, request.data, 'sha256').hexdigest()
    
    if not hmac.compare_digest(expected, signature):
        return 'Unauthorized', 401
    
    # 异步执行部署(避免请求超时)
    subprocess.Popen(['/opt/webhook/deploy.sh'])
    return 'Deploying', 200

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=9000)

3. CI/CD 层:流水线钩子(GitHub Actions/GitLab CI)

如果使用了 CI 平台,钩子表现为 Pipeline 的触发条件。最实用的模式是仅当特定文件变更时才运行对应任务

# .github/workflows/deploy.yml
name: Deploy
on:
  push:
    branches: [main]
    paths:        # 关键:只在以下文件变更时触发
      - 'src/**'
      - 'Dockerfile'
      - '.github/workflows/**'

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: 构建镜像
        run: docker build -t app:${{ github.sha }} .
      
      - name: 部署到测试环境
        if: github.ref == 'refs/heads/develop'
        run: kubectl set image deployment/test app=app:${{ github.sha }}
      
      - name: 部署到生产环境(带人工审批)
        if: github.ref == 'refs/heads/main'
        environment: production  # 利用 GitHub Environments 强制人工点确认
        run: kubectl set image deployment/prod app=app:${{ github.sha }}

4. 真实排坑指南

权限问题:钩子脚本常以 git 用户或 www-data 运行,需提前配置好 SSH 密钥或部署令牌(Deploy Token),切勿使用个人账号密码

并发冲突:多人同时推送可能触发并发部署。在脚本开头加锁:

exec 200>/var/lock/my_deploy_script.lock
flock -n 200 || { echo "另一个部署正在进行"; exit 1; }

日志追踪:钩子运行在非交互环境,务必重定向所有输出到日志文件,否则报错时你什么都看不到。

测试策略:先在本地用 git hook run pre-commit 或 Postman 模拟 Webhook 请求,确认无误后再部署到服务器。

小结

钩子工作流的本质是分层守门:本地钩子保代码质量,服务端钩子保部署及时,CI 钩子保流程规范。搭建时遵循最小权限原则(钩子只给必要的文件读写权限),并确保每个钩子都有日志输出,否则故障排查将是噩梦。