PR #451 (来自 fork aeoform/openless, head ref 也叫 beta) 触发 @claude 时, claude-code-action 执行 `git fetch origin pull/451/head:beta` 把 PR head 拉到本地 beta 分支,但此时 worktree 正 checkout 在 refs/heads/beta, git 拒绝 fetch 到已 checkout 的分支: fatal: refusing to fetch into branch 'refs/heads/beta' checked out at ... Action failed with error: Command failed: git fetch origin --depth=20 pull/451/head:beta 修复: 在 actions/checkout 后立即 git checkout --detach,释放 refs/heads/<default-branch> 这个本地分支名,让 action 自己 fetch 不撞名. 仅在 fork head ref == base ref name 的 corner case 才会触发问题, detach 对其他场景无副作用. 失败 run: https://github.com/Open-Less/openless/actions/runs/25978532215 Co-authored-by: baiqing <lbx12309@icloud.com>
81 lines
3.8 KiB
YAML
81 lines
3.8 KiB
YAML
name: Claude Code
|
||
|
||
# 触发策略:
|
||
# - 默认不主动 review;任何 PR 打开 / 同步都不会自动调用模型,避免烧 OAuth token 额度。
|
||
# - 评论 / review / issue 中出现 `@claude` 才触发,且发起者必须是 Open-Less 组织成员(OWNER 或 MEMBER)。
|
||
# - 模型默认 claude-sonnet-4-6(量大、成本低);评论里写 `--opus` 或包含 `claude-opus`
|
||
# 字样会切到 claude-opus-4-7(用于需要更深推理的任务)。
|
||
|
||
on:
|
||
issue_comment:
|
||
types: [created]
|
||
pull_request_review_comment:
|
||
types: [created]
|
||
issues:
|
||
types: [opened, assigned]
|
||
pull_request_review:
|
||
types: [submitted]
|
||
|
||
jobs:
|
||
claude:
|
||
# 双重门禁:(1) 内容含 @claude (2) 触发者是 OWNER 或 MEMBER(Open-Less 组织成员)。
|
||
# 注:仓库已转入 Open-Less 组织后,author_association 对人类用户最高只会是 MEMBER,
|
||
# OWNER 此时只对个人账号下的同名仓库有效,这里保留是为了兼容仓库再次个人持有的情形。
|
||
if: |
|
||
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude') && contains(fromJson('["OWNER","MEMBER"]'), github.event.comment.author_association)) ||
|
||
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude') && contains(fromJson('["OWNER","MEMBER"]'), github.event.comment.author_association)) ||
|
||
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude') && contains(fromJson('["OWNER","MEMBER"]'), github.event.review.author_association)) ||
|
||
(github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')) && contains(fromJson('["OWNER","MEMBER"]'), github.event.issue.author_association))
|
||
runs-on: ubuntu-latest
|
||
permissions:
|
||
contents: read
|
||
pull-requests: read
|
||
issues: read
|
||
id-token: write
|
||
actions: read # Required for Claude to read CI results on PRs
|
||
steps:
|
||
- name: Checkout repository
|
||
uses: actions/checkout@v4
|
||
with:
|
||
fetch-depth: 1
|
||
|
||
# Detach HEAD 释放 refs/heads/<default-branch> 这个本地分支名。
|
||
# 背景:claude-code-action 在 fork PR 上会执行
|
||
# git fetch origin pull/<n>/head:<head-ref-name>
|
||
# 把 PR head 拉到与 fork 端 head 同名的本地分支。当 fork PR 的 head ref
|
||
# 与本仓库 base / 默认分支同名(例如 fork 也是 beta → beta)时,
|
||
# 上面那条 fetch 会撞上"当前已 checkout 的分支"而失败:
|
||
# fatal: refusing to fetch into branch 'refs/heads/beta' checked out at ...
|
||
# 提前 detach 让本地分支名可以被 action 重新使用。
|
||
- name: Detach HEAD to free local branch ref
|
||
run: git checkout --detach
|
||
|
||
- name: Pick model (default sonnet, opt-in opus)
|
||
id: pick_model
|
||
env:
|
||
COMMENT_BODY: ${{ github.event.comment.body }}
|
||
REVIEW_BODY: ${{ github.event.review.body }}
|
||
ISSUE_BODY: ${{ github.event.issue.body }}
|
||
ISSUE_TITLE: ${{ github.event.issue.title }}
|
||
run: |
|
||
set -eu
|
||
body="${COMMENT_BODY}${REVIEW_BODY}${ISSUE_BODY}${ISSUE_TITLE}"
|
||
if [[ "$body" == *"--opus"* ]] || [[ "$body" == *"claude-opus"* ]]; then
|
||
echo "model=claude-opus-4-7" >> "$GITHUB_OUTPUT"
|
||
else
|
||
echo "model=claude-sonnet-4-6" >> "$GITHUB_OUTPUT"
|
||
fi
|
||
|
||
- name: Run Claude Code
|
||
id: claude
|
||
uses: anthropics/claude-code-action@v1
|
||
with:
|
||
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
||
|
||
# 让 Claude 能看 CI 结果
|
||
additional_permissions: |
|
||
actions: read
|
||
|
||
# 模型策略:默认 sonnet,评论里 --opus 才升级到 opus
|
||
claude_args: '--model ${{ steps.pick_model.outputs.model }}'
|