summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHa Thach <[email protected]>2026-06-02 10:18:06 +0700
committerGitHub <[email protected]>2026-06-02 10:18:06 +0700
commit8e0f2bd1c7b234282e0a98b6069780cff21cabe9 (patch)
treebfee68ede8f40a8425d1c925f37bea3a231e7b05
parentbbdb41995de6510b837ad239933e1823ca175314 (diff)
parent044cd06f87117afa541d8cc743fcc9ef2bdc8089 (diff)
Merge pull request #3662 from hathach/update-claude
Update claude
-rw-r--r--.claude/skills/hil/SKILL.md66
-rw-r--r--.github/workflows/claude-code-review.yml26
-rw-r--r--.github/workflows/claude.yml26
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: