diff options
| author | Ha Thach <[email protected]> | 2026-06-02 10:18:06 +0700 |
|---|---|---|
| committer | GitHub <[email protected]> | 2026-06-02 10:18:06 +0700 |
| commit | 8e0f2bd1c7b234282e0a98b6069780cff21cabe9 (patch) | |
| tree | bfee68ede8f40a8425d1c925f37bea3a231e7b05 | |
| parent | bbdb41995de6510b837ad239933e1823ca175314 (diff) | |
| parent | 044cd06f87117afa541d8cc743fcc9ef2bdc8089 (diff) | |
Merge pull request #3662 from hathach/update-claude
Update claude
| -rw-r--r-- | .claude/skills/hil/SKILL.md | 66 | ||||
| -rw-r--r-- | .github/workflows/claude-code-review.yml | 26 | ||||
| -rw-r--r-- | .github/workflows/claude.yml | 26 |
3 files changed, 71 insertions, 47 deletions
diff --git a/.claude/skills/hil/SKILL.md b/.claude/skills/hil/SKILL.md index 1f3d7d072..a7a916907 100644 --- a/.claude/skills/hil/SKILL.md +++ b/.claude/skills/hil/SKILL.md @@ -1,66 +1,64 @@ --- name: hil -description: Use when running TinyUSB Hardware-in-the-Loop (HIL) tests on physical boards, debugging HIL failures, or copying firmware to the ci.lan test rig. Covers local execution and remote execution over SSH, config selection, and debugging tips. +description: Use when running TinyUSB Hardware-in-the-Loop (HIL) tests on physical boards, debugging HIL failures, or copying firmware to the ci.lan test rig. Covers per-host config selection (htpc uses local.json, ci uses tinyusb.json), local execution on either htpc or ci, remote execution over SSH from htpc, and debugging tips. --- # Hardware-in-the-Loop (HIL) Testing -Run TinyUSB HIL tests against real boards. Two execution modes — **local** (boards attached to this machine) and **remote** (boards attached to `ci.lan`, reached over SSH). Default to **local** unless the user specifies `remote`. Do not auto-detect. +Run TinyUSB HIL tests on real boards. **Run `hostname` first** — it tells you which host you are on, which determines the default config and whether remote mode is possible. -## Prerequisites +| Host | Local config | Remote (SSH → ci.lan)? | +|------|--------------|------------------------| +| `htpc` (dev PC) | `test/hil/local.json` | yes (large pool, `test/hil/tinyusb.json`) | +| `ci` (the rig) | `test/hil/tinyusb.json` (large pool) | no — can't SSH to htpc, and boards are already local | -- Examples must already be built for the target board(s). See AGENTS.md "Build" → "All examples for a board", which produces `examples/cmake-build-<board>/`. -- `-B examples` tells `hil_test.py` that `examples/` is the parent folder containing the per-board build outputs. +Default to **local**. Use **remote** only when on `htpc` and the user says `remote`/`ci.lan`. Never attempt remote on `ci`. -## Choosing arguments +## Prerequisites -Infer from the user's request: +Examples must be built for the target board(s) — see AGENTS.md "Build" → "All examples for a board" (produces `examples/cmake-build-<board>/`). `-B examples` points `hil_test.py` at that parent folder. -- **Mode:** `local` (default) or `remote`. Only switch to `remote` if the user explicitly says so or names `ci.lan`. -- **Board:** if the user names a specific board, pass `-b BOARD_NAME`. Otherwise omit `-b` to run all boards in the config. -- **Pass-through flags:** `-v` (verbose), `-r N` (retry count), etc. — pass through unchanged. +## Arguments -Config file follows from mode: -- **Local** → `test/hil/local.json` (user-supplied; not tracked in repo — describes boards attached locally) -- **Remote** → `test/hil/tinyusb.json` (tracked; describes the `ci.lan` test rig) +- **Board:** `-b BOARD_NAME` for one board; omit to run all boards in the config. +- **Pass-through:** `-v`, `-r N`, etc. forwarded unchanged. -If `local.json` is missing, fall back to `tinyusb.json` only when explicitly told to; otherwise stop and ask the user to supply one. +If `local.json` is missing on `htpc`, ask the user to supply one (only fall back to `tinyusb.json` if told to). ## Local execution -Boards attached to this machine: +Set `CONFIG` from `hostname` first (`test/hil/local.json` on htpc, `test/hil/tinyusb.json` on ci): ```bash -# Specific board: -python3 test/hil/hil_test.py -b BOARD_NAME -B examples test/hil/local.json $EXTRA_ARGS -# All boards in the config (no -b): -python3 test/hil/hil_test.py -B examples test/hil/local.json $EXTRA_ARGS +CONFIG=test/hil/local.json # on ci use: CONFIG=test/hil/tinyusb.json + +# All boards in the config: +python3 test/hil/hil_test.py -B examples "$CONFIG" + +# A single board (replace stm32f723disco): +python3 test/hil/hil_test.py -b stm32f723disco -B examples "$CONFIG" ``` -## Remote execution (ci.lan) +Append pass-through flags (`-v`, `-r 1`, …) to either command as needed. -Use `test/hil/hil_ci.sh` — it handles dir setup, scp of test scripts, rsync of firmware artifacts (`.elf` / `.bin` / `.hex` only), and running `hil_test.py` on `ci.lan`: +## Remote execution (htpc → ci.lan only) + +`test/hil/hil_ci.sh` handles dir setup, scp of test scripts, rsync of firmware (`.elf`/`.bin`/`.hex`), and runs `hil_test.py` on `ci.lan` with `tinyusb.json`: ```bash -# Specific board: -bash test/hil/hil_ci.sh -b raspberry_pi_pico2 -# All boards in tinyusb.json: +# All boards: bash test/hil/hil_ci.sh -# Pass-through extra args (any non -b flag is forwarded to hil_test.py): + +# A single board, with pass-through flags: bash test/hil/hil_ci.sh -b raspberry_pi_pico2 -t host/cdc_msc_hid -r 1 ``` -Overrides via env vars: `REMOTE=ci.lan`, `REMOTE_DIR=/tmp/tinyusb-hil`, `CONFIG=test/hil/tinyusb.json`. - -The script fails fast if the build dir or repo layout is missing. +Env overrides: `REMOTE`, `REMOTE_DIR`, `CONFIG`. Fails fast if the build dir/repo layout is missing. ## Timing -HIL runs take 2-5 minutes. Use a timeout of at least 20 minutes (600000 ms). NEVER cancel early. +Runs take 2-5 min. Use a timeout ≥ 20 min (1200000 ms). NEVER cancel early. -## Reporting results +## Reporting -After the test completes: -- Show the test output to the user. -- Summarize pass/fail per board. -- On failure, suggest re-running with `-v` for verbose output. If `-v` isn't enough, temporarily add debug prints to `test/hil/hil_test.py` to pinpoint the issue. +Show the output, summarize pass/fail per board. On failure, retry with `-v`; if that's not enough, add temporary debug prints to `hil_test.py`. diff --git a/.github/workflows/claude-code-review.yml b/.github/workflows/claude-code-review.yml index 43144bb5e..4a0e4639b 100644 --- a/.github/workflows/claude-code-review.yml +++ b/.github/workflows/claude-code-review.yml @@ -1,18 +1,29 @@ name: Claude Code Review on: - pull_request_target: - types: [opened, synchronize, ready_for_review, reopened] + pull_request: + # opened/reopened/ready_for_review -> first auto review + # synchronize -> auto re-review on new pushes + # + # NOTE: pull_request (not _target) means fork PRs get a read-only GITHUB_TOKEN + # and NO repository secrets (CLAUDE_CODE_OAUTH_TOKEN), so they cannot be + # auto-reviewed. The job condition below skips them cleanly -> use @claude on + # those. Same-repo branches (yours or write-access contributors) auto-review. + types: [opened, synchronize, reopened, ready_for_review] jobs: claude-review: - if: false + # Skip drafts, and skip fork PRs (no secrets -> would only fail noisily) + if: > + github.event.pull_request.draft == false && + github.event.pull_request.head.repo.full_name == github.repository runs-on: ubuntu-latest permissions: contents: read pull-requests: write - issues: read + issues: write # use_sticky_comment posts/updates a PR comment via the issues API id-token: write + actions: read # Required for Claude to read CI results on PRs steps: - name: Checkout repository @@ -25,8 +36,13 @@ jobs: uses: anthropics/claude-code-action@v1 with: claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} + # Pairs with the actions: read permission so Claude can read CI results + additional_permissions: | + actions: read 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 }}' + # Reuse one comment instead of posting a new one each push + use_sticky_comment: true + claude_args: '--max-turns 20' # See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md - # or https://code.claude.com/docs/en/cli-reference for available options diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml index 50f449949..bf7a401e4 100644 --- a/.github/workflows/claude.yml +++ b/.github/workflows/claude.yml @@ -6,22 +6,32 @@ on: pull_request_review_comment: types: [created] issues: - types: [opened, assigned] + # only "opened" — an issue's author_association gates the summon below; + # "assigned" would gate on the issue author, not the assigner, so a + # maintainer assigning an outsider's issue would be wrongly skipped. + types: [opened] pull_request_review: types: [submitted] jobs: claude: + # Only trusted actors (repo owner/member/collaborator) may summon @claude, so the + # write-scoped token and OAuth secret are never issued for an outside contributor's + # comment on this public repo. Defense-in-depth on top of the action's own check. if: | - (github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) || - (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) || - (github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) || - (github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude'))) + (github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude') && + contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.comment.author_association)) || + (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude') && + contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.comment.author_association)) || + (github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude') && + contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), 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", "COLLABORATOR"]'), github.event.issue.author_association)) runs-on: ubuntu-latest permissions: - contents: read - pull-requests: read - issues: read + contents: write # allow Claude to push commits/branches when asked + pull-requests: write # allow Claude to comment on / update PRs + issues: write # allow Claude to comment on / update issues id-token: write actions: read # Required for Claude to read CI results on PRs steps: |
