mirror of
https://github.com/l0ng-ai/tty7.git
synced 2026-09-22 08:02:24 +00:00
The fork job never checked where the head branch lived. It was written as the fork path and reads like one, but `pull_request_target` fires on every pull request, so labelling one of ours landed there too -- silently, and with the weaker review: no plugin, no whole-repo context, read-only tools. #389 got that instead of the review it should have had. Also corrects the `labeled` comment in claude-code-review.yml, which promised exactly the case that cannot work. A `pull_request` workflow is read from the PR's merge ref, and GitHub recomputes that on a push and not otherwise, so a PR whose last push predates the file has a merge ref without it and no label can summon it. Pushing fixes it, and also triggers synchronize by itself -- which is why the empty commit worked and the label looked broken. Co-authored-by: l0ng-ai <24760907+l0ng-ai@users.noreply.github.com>
85 lines
4.9 KiB
YAML
85 lines
4.9 KiB
YAML
name: Claude Code Review
|
|
|
|
# Automated PR review, run on our own Actions minutes rather than the managed
|
|
# Code Review service (that one is Team/Enterprise only, and bills per review).
|
|
# A run reads the diff in the context of the whole checkout and posts what it
|
|
# found back onto the PR; findings are advisory and never gate a merge, so the
|
|
# required checks on main stay exactly `rustfmt` and the three
|
|
# `build & test (<target>)` jobs.
|
|
#
|
|
# Setup, both steps one-time and both outside this file:
|
|
# 1. Install the Claude GitHub App on l0ng-ai/tty7 -> https://github.com/apps/claude
|
|
# 2. Add the repo secret CLAUDE_CODE_OAUTH_TOKEN, from `claude setup-token`
|
|
# locally. That token bills against the Claude subscription instead of a
|
|
# separate API bill. To use an API key instead, swap the input below for
|
|
# `anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}`.
|
|
# `/install-github-app` inside a local claude session does both for you.
|
|
|
|
on:
|
|
pull_request:
|
|
# `labeled` is the manual re-run: reopening a PR fires `reopened`, not
|
|
# `opened`, and a PR that predates this file has no run to restart from the
|
|
# Actions tab. Applying the label needs write access, so the same label
|
|
# doubles as the approval gate in claude-review-fork.yml.
|
|
#
|
|
# It does not reach the PRs that need it most, and the reason is worth
|
|
# knowing before you conclude the label is broken. A `pull_request` workflow
|
|
# is read from the PR's merge ref, which GitHub recomputes on a push and not
|
|
# otherwise. A PR whose last push predates this file therefore has a merge
|
|
# ref that does not contain it, and no label will summon a workflow that,
|
|
# from that ref's point of view, does not exist. Push to the branch and the
|
|
# merge ref catches up -- though by then the push has triggered
|
|
# `synchronize` anyway, which is why the empty-commit trick works and the
|
|
# label appears not to. `claude-review-fork.yml` is exempt: a
|
|
# `pull_request_target` workflow is read from the base branch.
|
|
types: [opened, synchronize, labeled]
|
|
|
|
# Same reasoning as ci.yml: a superseded review is dead weight, and unlike a
|
|
# build its output would be actively misleading — comments describing a diff
|
|
# that no longer exists.
|
|
concurrency:
|
|
group: ${{ github.workflow }}-${{ github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
jobs:
|
|
review:
|
|
name: claude review
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 30
|
|
# First clause: tty7 is public, and GitHub withholds secrets from fork-PR
|
|
# runs, so the action would fail its auth step rather than skip. Gate on the
|
|
# head repo so a fork PR simply doesn't queue a job.
|
|
# Second clause: every label, not just ours, fires `labeled` -- without it,
|
|
# tagging a PR `bug` would spend a review.
|
|
if: >-
|
|
github.event.pull_request.head.repo.full_name == github.repository &&
|
|
(github.event.action != 'labeled' || github.event.label.name == 'claude-review')
|
|
permissions:
|
|
contents: read
|
|
pull-requests: write # post the review comment
|
|
issues: write # the action's tracking comment lives on the issue timeline
|
|
id-token: write # required for the action's GitHub App auth
|
|
actions: read # let the review see whether CI passed
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
with:
|
|
# A shallow clone has no merge base, and the review's first move is
|
|
# `git diff main...HEAD`.
|
|
fetch-depth: 0
|
|
|
|
- uses: anthropics/claude-code-action@v1
|
|
with:
|
|
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
|
# The same multi-agent review plugin the managed service runs.
|
|
plugin_marketplaces: "https://github.com/anthropics/claude-code.git"
|
|
plugins: "code-review@claude-code-plugins"
|
|
prompt: "/code-review:code-review ${{ github.repository }}/pull/${{ github.event.pull_request.number }}"
|
|
# Without this the findings only reach the workflow run log.
|
|
track_progress: true
|
|
# The rules a general-purpose reviewer cannot know. Everything CI
|
|
# already enforces (rustfmt, the host-boundary grep, clippy) is
|
|
# deliberately absent: a second opinion on a check that already
|
|
# failed is noise.
|
|
claude_args: |
|
|
--append-system-prompt "This is tty7, a Rust terminal workspace app (GPUI). Repo-specific review rules, in addition to the usual correctness review: (1) Anything that changes the wire format between the app and tty7-server must bump the control/protocol dialect in RemoteProtocol::of_this_build and stay readable to an older peer, or say why a hard break is correct. (2) Rendering and layout live in src/ui; a workspace path there may belong to a remote machine, so filesystem and git access must go through the Host trait. (3) User-visible strings live in src/ui/i18n/{en,zh,ja}.rs and all three must gain the key together. (4) Do not comment on formatting, import order, or anything rustfmt and clippy already decide."
|