CC-CR Examen de code unifié

Compétence de révision de code unifiée combinant la détection automatique par lots et les modes CR interactifs, avec intégration GitLab et Feishu.

Spar Skills Guide Bot
DeveloppementIntermédiaire
1026/07/2026
Claude Code
#code-review#gitlab#automation#batch-detection#interactive-review

Recommandé pour


name: cc-cr description: > 统一 CR skill,整合批量自动检测(原 cr-monitor)和交互式单次 CR(原 gitlab-cr)两种能力。 TRIGGER when: - 用户消息包含"cr自动检测" → 自动检测模式(批量扫描所有配置项目) - 用户提供 GitLab URL(含 /-/merge_requests/ 或 /-/tags) → 交互式 CR 模式 - 用户说"做cr"、"review MR"、"帮我cr"、"cr检查"等(不含"自动检测") → 交互式 CR 模式 - 用户说"cc-cr setup"、"cr配置"、"配置cr"、"setup" → 配置向导 DO NOT TRIGGER when: 用户仅在询问关于 CR 的问题,没有执行 CR 的意图 argument-hint: "setup | cr自动检测 | <GitLab URL>" allowed-tools: [Bash, Read, Write, Edit, Grep, AskUserQuestion]

CC-CR — 统一代码审查

模式判断

根据用户输入确定执行模式和飞书推送目标:

| 输入特征 | 执行模式 | 飞书目标 | |---------|---------|---------| | 包含"setup"/"cr配置"/"配置cr" | 配置向导模式 | — | | 包含"cr自动检测" | 自动检测模式 | personal(默认) | | 包含"cr自动检测" + "推给群" / "发群" / "通知群" | 自动检测模式 | group | | 包含 GitLab URL | 交互式 CR 模式 | — | | 包含"做cr"/"review"/"帮我cr"/"cr检查"但无 URL | 交互式 CR 模式 | — |

飞书目标判断规则(自动检测模式):

  • 默认推送个人(personal
  • 用户输入包含"推给群"、"发群"、"通知群"、"发给群"等词汇时,使用 group

模式 S:配置向导(setup)

AskUserQuestion 逐步收集配置,最终写入 SCRIPT_DIR/cr_config.json,全程在 Claude Code session 内完成,无需终端交互。

SCRIPT_DIR = ~/.claude/skills/cc-cr

前置检查

先运行依赖检查:

for cmd in jq curl python3 perl git; do
  command -v "$cmd" &>/dev/null && echo "✓ $cmd" || echo "✗ $cmd (缺失)"
done
command -v claude &>/dev/null && echo "✓ claude" || echo "✗ claude (缺失,需要安装: https://claude.ai/download)"

输出检查结果。如有缺失,列出安装命令(brew install jq 等),并询问是否继续。

cr_config.json 已存在,用 AskUserQuestion 询问:是否覆盖现有配置? 选"是"继续(先执行备份),选"否"退出。

选"是"时,先备份并明确告知用户备份文件完整路径

BACKUP_FILE="${SCRIPT_DIR}/cr_config.json.bak.$(date +%Y%m%d_%H%M%S)"
cp "${SCRIPT_DIR}/cr_config.json" "$BACKUP_FILE"
echo "已备份到:$BACKUP_FILE"

备份后立即用 Read 读取现有配置,将各字段值保存为变量,作为后续步骤的默认值:

# 读取现有配置用于后续默认值
EXISTING_GITLAB_URL=$(jq -r '.gitlab_base_url // ""' "${SCRIPT_DIR}/cr_config.json")
EXISTING_TOKEN=$(jq -r '.gitlab_token // ""' "${SCRIPT_DIR}/cr_config.json")
EXISTING_LOCAL_PATH=$(jq -r '.local_base_path // ""' "${SCRIPT_DIR}/cr_config.json")
EXISTING_RELEASE_BRANCH=$(jq -r '.release_branch // "release"' "${SCRIPT_DIR}/cr_config.json")
EXISTING_NOTIFY_NO_CHANGE=$(jq -r '.notify_no_change // "false"' "${SCRIPT_DIR}/cr_config.json")
EXISTING_RECIPIENTS=$(jq -r '.feishu_recipients // [] | join(",")' "${SCRIPT_DIR}/cr_config.json")

Step 1:GitLab 配置

AskUserQuestion 依次收集(每次一个问题):

1. GitLab 实例地址

选项:

  • EXISTING_GITLAB_URL 非空,第一个选项显示现有值(标注"当前配置")
  • 第二个选项为"其他地址(Other 输入)"

2. GitLab Personal Access Token

根据 EXISTING_TOKEN 是否非空,提供不同选项:

  • 若现有 token 非空:
    • 选项1:保留现有 token(显示末尾 4 位,如 ****yuj
    • 选项2:使用环境变量 GITLAB_TOKEN(留空)
    • 选项3:重新输入(Other 填写)
  • 若现有 token 为空:
    • 选项1:使用环境变量 GITLAB_TOKEN
    • 选项2:手动输入(Other 填写)

3. 本地代码库根目录

选项:

  • EXISTING_LOCAL_PATH 非空,第一个选项显示现有值(标注"当前配置")
  • 其他常见路径作为备选(如 ~/projects~/workspace
  • Other 自由输入

4. Release 分支名

选项:

  • release(当前配置)release(默认)
  • main
  • Other 自由输入

Step 2:飞书配置(可选)

先执行自动检测,再根据结果决定问什么:

# 检查 ~/.claude-to-im/config.env 是否已有飞书凭证
CTI_CONFIG="$HOME/.claude-to-im/config.env"
HAS_CTI_FEISHU=false
if [[ -f "$CTI_CONFIG" ]]; then
  grep -q "CTI_FEISHU_APP_ID=" "$CTI_CONFIG" && grep -q "CTI_FEISHU_APP_SECRET=" "$CTI_CONFIG" && HAS_CTI_FEISHU=true
fi

AskUserQuestion 询问:是否配置飞书推送?

  • 若选"是",根据 HAS_CTI_FEISHU 值决定后续:

    • HAS_CTI_FEISHU=true:提示"已检测到 claude-to-im 飞书配置,App ID/Secret 将自动继承,无需重复填写",直接跳到接收人配置
    • HAS_CTI_FEISHU=false:继续收集:
      1. 飞书应用 App ID(格式 cli_xxxxxxxxx
      2. 飞书应用 App Secret
      3. 飞书域名(默认 https://open.feishu.cn,私有化部署时修改)

    无论哪种情况,都询问飞书推送接收人 ID

    • EXISTING_RECIPIENTS 非空,第一个选项显示现有值(标注"当前配置")
    • 说明:ou_ 开头=个人,oc_ 开头=群,多个用英文逗号分隔
    • Other 自由输入
  • 若选"否",跳过飞书配置(recipients 为空数组,app_id/secret 为空)。

Step 3:notify_no_change

AskUserQuestion 询问:无版本变化时是否推送飞书通知?

选项:

  • false — 不推送(推荐):安静模式,只有真正有变化时才通知
  • true — 也推送:每次检测都推一条"无变化"通知

Step 4:监控项目配置

先检查是否已有项目配置:

  • 若已有项目,展示现有项目列表,用 AskUserQuestion 询问:
    • 选项1:保留现有项目
    • 选项2:追加新项目
    • 选项3:删除指定项目
    • 选项4:清空,重新配置

选"保留":跳过,直接进入 Step 5。

选"追加":循环用 AskUserQuestion 收集新项目,每轮两个问题:

  1. GitLab 项目路径(格式 group/project-name;选"完成添加"结束)
  2. 检测模式mr(合并请求,默认)或 tag(版本标签)

选"删除指定项目":用 AskUserQuestion 展示当前所有项目,multiSelect: true,让用户勾选要删除的项目,未勾选的保留。每个选项格式为 group/project-name(mode)。删除后展示剩余项目列表确认。

选"清空重新配置":从空列表开始,循环添加(同"追加"流程)。

至少需要保留一个项目。

Step 5:汇总确认 & 写入

展示完整配置摘要(Token 和 Secret 只显示最后 4 位),用 AskUserQuestion 确认:确认写入配置?

确认后:

mkdir -p "${SCRIPT_DIR}/logs" "${SCRIPT_DIR}/cache" "${SCRIPT_DIR}/tmp"

Write 将配置写入 ${SCRIPT_DIR}/cr_config.json(JSON 格式,参照 cr_config.json.example 结构)。

写入完成后输出提示:

  • "配置完成!现在可以在 Claude Code 中说:cr自动检测"
  • 若飞书凭证来自 claude-to-im 继承,提示确认 ~/.claude-to-im/config.env 中凭证有效
  • 若飞书凭证直接配置,提醒检查 App ID/Secret 和接收人 ID 是否正确

重要:CC 独白(每次 CR 必须遵守)

每次交互式 CR 报告的最后(总结表格和总体评价之后),必须附上独白,没有例外。规则:

  • 格式:**CC 内心OS:** ...(加粗前缀 + 普通文本,不要用 blockquote > 或斜体 *,飞书不支持)
  • 内容:结合本次变更特点(文件数、改动类型、commit message 质量、代码风格)幽默吐槽或感悟
  • 风格:深夜写代码的内心 OS、程序员自嘲、代码拟人化比喻、生活化类比
  • 要求:够毒、够搞笑、够扎心
  • 长度:2-4 句话
  • 每次要有新意,禁止重复

模式 A:自动检测模式

批量轮询所有配置项目,有版本变化才执行 CR,结果发飞书卡片。

Step 1:前台运行脚本

根据模式判断结果确定 FEISHU_TARGETpersonalgroup),然后执行:

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

# 默认推个人
bash "${SCRIPT_DIR}/cr_monitor.sh" 2>&1

# 推群(用户输入含"推给群"/"发群"/"通知群"等词时)
bash "${SCRIPT_DIR}/cr_monitor.sh" --feishu-target group 2>&1

直接前台执行(不加 &),等待完成。

Step 2:汇总输出

脚本结束后,读取各项目 log:${SCRIPT_DIR}/logs/cr_<project-name>.log

输出一条简洁结论:

  • 有变化的项目:<project-name> CR完成
  • 无变化项目:合并为一句 其它项目未发现版本变化

不输出版本号、问题摘要或其他多余信息。

注意

  • 配置文件:${SCRIPT_DIR}/cr_config.json
  • 各项目 log:${SCRIPT_DIR}/logs/cr_<project-name>.log
  • 版本 cache:${SCRIPT_DIR}/cache/
  • GitLab token 来自环境变量 GITLAB_TOKEN,或 cr_config.jsongitlab_token 字段

模式 B:交互式 CR 模式

支持三种 URL 格式,全部自动处理无需手动干预:

  • MR URLhttps://<host>/<group>/<project>/-/merge_requests/<iid> → MR CR
  • Tags 列表 URLhttps://<host>/<group>/<project>/-/tags → 取最新两个 tag 对比
  • 指定 Tag URLhttps://<host>/<group>/<project>/-/tags/<tag-name> → 以该 tag 为 new_tag,自动查找前一个 tag 作为 old_tag

Step 1:解析 URL,确定参数

从 URL 提取 project path(格式:<group>/<project>)和模式。

  • MR 模式:提取 MR IID(URL 中最后的数字)
  • Tags 模式:
    • URL 末尾是 /tags/<tag-name>:提取 new_tag=<tag-name>,old_tag 由 cr_run.sh 自动查找
    • URL 末尾是 /tags(列表页):不传 new_tag,cr_run.sh 自动取最新两个 tag

Step 2:调用 cr_run.sh

SCRIPT_DIR="$HOME/.claude/skills/cc-cr"

# MR 模式(--no-feishu:交互式模式下报告直接输出到 session)
bash "${SCRIPT_DIR}/cr_run.sh" \
  --mode mr \
  --project-path "<group>/<project>" \
  --iid <iid> \
  --no-feishu

# Tags 模式 - 指定 tag(cr_run.sh 自动查找 old_tag)
bash "${SCRIPT_DIR}/cr_run.sh" \
  --mode tag \
  --project-path "<group>/<project>" \
  --new-tag "<tag-name>" \
  --no-feishu

# Tags 模式 - 列表页(cr_run.sh 自动取最新两个 tag)
bash "${SCRIPT_DIR}/cr_run.sh" \
  --mode tag \
  --project-path "<group>/<project>" \
  --no-feishu

cr_run.sh 会完成:tag 自动解析 → 调用 Claude 子进程执行 CR → 写报告文件 → 更新 cache(交互式模式跳过飞书推送)。
标准输出最后一行格式:CR_REPORT_READY:/path/to/report.md

Step 3:读取报告,输出到当前 session

从 Step 2 输出中提取报告路径(CR_REPORT_READY: 后的内容),然后:

# 解析报告路径
REPORT_FILE=$(上一步输出 | grep '^CR_REPORT_READY:' | cut -d: -f2-)

Read $REPORT_FILE,将完整 CR 报告内容输出到当前 session 供用户查看。


Review 关注点(按优先级)

  1. 正确性:逻辑错误、边界条件、NPE/空指针、并发安全
  2. 安全性:注入风险、敏感信息泄露、权限校验
  3. 可靠性:异常处理、降级策略、超时设置、资源泄露
  4. 数据一致性:状态机完整性、事务边界、缓存一致性
  5. 可读性:命名、注释代码(不应提交)、过度复杂的逻辑
  6. 性能:N+1 查询、不必要的循环、内存分配
  7. 可维护性:硬编码、重复代码、过时注释、魔法数字
  8. 提交规范:commit message 质量、是否包含无关变更

Java / Spring Boot 专项

  • Bean 生命周期和作用域
  • 事务传播行为
  • 线程安全(特别是 @Value 注入的共享状态)
  • Stream API 的惰性求值陷阱
  • Optional 的正确使用

Go 专项

  • error 是否被正确处理(不要 _ 掉)
  • goroutine 泄露
  • channel 死锁
  • defer 的执行时机

注意事项

  • 对代码保持敬意,CR 是为了让代码更好,不是为了挑刺
  • 区分"必须修"和"建议修",不要把小问题升级成严重问题
  • 发现亮点也要表扬
  • MR 超过 500 行 diff,先给整体架构评审,再深入细节
  • 注释代码、commit message 质量归为"小问题",不要过度强调
  • CC 独白是灵魂,不是可选项,每次必须有
Skills similaires