Skip to content

Agentic Patrol

Agentic Patrol #14

name: Agentic Patrol
on:
schedule:
# 每 4 小时巡查一次
- cron: '7 */4 * * *'
workflow_dispatch:
env:
NOTO_SANS_URL: https://github.com/notofonts/noto-cjk/releases/download/Sans2.004/03_NotoSansCJK-OTC.zip
NOTO_SERIF_URL: https://github.com/notofonts/noto-cjk/releases/download/Serif2.002/04_NotoSerifCJKOTC.zip
permissions:
contents: write
issues: write
pull-requests: write
jobs:
patrol:
runs-on: ubuntu-latest
env:
diffext: .diff
diffexe: git diff --no-index --text --
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
token: ${{ secrets.PAT_TOKEN || github.token }}
- name: Configure git
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git config core.hooksPath .githooks
- name: Install TeX Live
timeout-minutes: 30
uses: TeX-Live/setup-texlive-action@v4
with:
package-file: .github/tl_packages
repository: https://ctan.math.illinois.edu/systems/texlive/tlnet
update-all-packages: true
- name: Install Noto fonts
run: |
curl -LO ${{ env.NOTO_SANS_URL }}
curl -LO ${{ env.NOTO_SERIF_URL }}
for f in *OTC.zip; do unzip -ojd /usr/share/fonts/truetype "$f" "*.ttc"; done
fc-cache -f
- name: Install Claude Code CLI
id: setup_claude
run: |
CLAUDE_INSTALL_DIR="$RUNNER_TEMP/claude-code"
rm -rf "$CLAUDE_INSTALL_DIR"
npm install --prefix "$CLAUDE_INSTALL_DIR" @anthropic-ai/claude-code@2.1.80
CLAUDE_CODE_PATH="$CLAUDE_INSTALL_DIR/node_modules/.bin/claude"
echo "path=$CLAUDE_CODE_PATH" >> $GITHUB_OUTPUT
"$CLAUDE_CODE_PATH" --version
- name: Run Patrol
id: patrol
timeout-minutes: 60
# claude-code-action v0.0.19 (pinned by commit hash)
uses: anthropics/claude-code-action@e7b588b6eaa5263c2e7c6c7b34a29e190d32ee68
env:
ANTHROPIC_BASE_URL: ${{ secrets.ANTHROPIC_BASE_URL }}
DISABLE_AUTOUPDATER: "1"
with:
github_token: ${{ secrets.PAT_TOKEN || github.token }}
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
path_to_claude_code_executable: ${{ steps.setup_claude.outputs.path }}
prompt: |
仓库: ${{ github.repository }}
仓库 URL: https://github.com/${{ github.repository }}
使用 `patrol` skill 执行仓库定期巡查。
本环境已安装完整 TeX Live 和 Noto CJK 字体,可运行 l3build check/save 等命令。
l3build 测试所需环境变量已配置(diffext=.diff, diffexe="git diff --no-index --text --")。
claude_args: |
--model opus --allowedTools "Bash,Read,Write,Edit,Glob,Grep,Task,TodoWrite,Agent,Skill"
--json-schema '{"type":"object","properties":{"description":{"type":"string","description":"巡查结果摘要"},"ci_status":{"type":"string","enum":["pass","fail","unknown"],"description":"CI 整体状态"},"issues_processed":{"type":"integer","description":"处理的 Issue 数"},"prs_created":{"type":"integer","description":"创建的 PR 数"},"actions_taken":{"type":"array","items":{"type":"string"},"description":"本次巡查采取的操作"}},"required":["description","ci_status","issues_processed"]}'
- name: Output Result
if: always()
env:
STRUCTURED_OUTPUT: ${{ steps.patrol.outputs.structured_output }}
run: |
echo "## Patrol Result" >> $GITHUB_STEP_SUMMARY
echo '```json' >> $GITHUB_STEP_SUMMARY
echo "$STRUCTURED_OUTPUT" >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
- name: Parse Patrol Output
if: always()
id: parse
env:
STRUCTURED_OUTPUT: ${{ steps.patrol.outputs.structured_output }}
JOB_STATUS: ${{ job.status }}
run: |
if [ -n "$STRUCTURED_OUTPUT" ] && [ "$STRUCTURED_OUTPUT" != "null" ]; then
DESCRIPTION=$(echo "$STRUCTURED_OUTPUT" | jq -r '.description // "巡查完成"')
CI_STATUS=$(echo "$STRUCTURED_OUTPUT" | jq -r '.ci_status // "unknown"')
ISSUES=$(echo "$STRUCTURED_OUTPUT" | jq -r '.issues_processed // 0')
PRS=$(echo "$STRUCTURED_OUTPUT" | jq -r '.prs_created // 0')
case "$CI_STATUS" in
"fail") STATUS="error" ;;
"pass") STATUS="success" ;;
*) STATUS="info" ;;
esac
TITLE="巡查: CI ${CI_STATUS}, ${ISSUES} issues, ${PRS} PRs"
else
TITLE="巡查完成"
DESCRIPTION="未能获取结构化输出"
STATUS="warning"
ISSUES=0
PRS=0
CI_STATUS="unknown"
fi
if [ "$JOB_STATUS" != "success" ]; then
STATUS="warning"
DESCRIPTION="GitHub Action 执行失败"
fi
echo "status=${STATUS}" >> $GITHUB_OUTPUT
echo "title=${TITLE}" >> $GITHUB_OUTPUT
{
echo 'description<<EOF'
echo "**${{ github.repository }}**"
echo "${DESCRIPTION}"
echo 'EOF'
} >> $GITHUB_OUTPUT
# 判断是否需要通知(有实质操作时才通知)
if [ "$ISSUES" -gt 0 ] || [ "$PRS" -gt 0 ] || [ "$CI_STATUS" = "fail" ] || [ "$STATUS" = "warning" ]; then
echo "should_notify=true" >> $GITHUB_OUTPUT
else
echo "should_notify=false" >> $GITHUB_OUTPUT
fi
- name: Checkout Action
if: always() && steps.parse.outputs.should_notify == 'true'
uses: actions/checkout@v6
with:
repository: Lightspeed-Intelligence/agentic-workflow-template
ref: main
token: ${{ secrets.PAT_TOKEN || github.token }}
path: .agentic-actions
sparse-checkout: .github/actions
sparse-checkout-cone-mode: false
- name: Notify Feishu
if: always() && steps.parse.outputs.should_notify == 'true'
uses: ./.agentic-actions/.github/actions/feishu-notify
with:
webhook_token: ${{ secrets.FEISHU_WEBHOOK_TOKEN }}
title: ${{ steps.parse.outputs.title }}
description: ${{ steps.parse.outputs.description }}
link_text: "🔗 查看运行"
link_url: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
status: ${{ steps.parse.outputs.status }}