--- name: ghish description: >- Use the ./gh CLI (gh-ish) for all Gerrit code reviews (CLs, pwrev), LUCI Buildbucket CI checks and tryjobs, Buganizer issues (b/, pwbug.dev), and pushing changes using GitHub CLI syntax. --- # `gh-ish` (`./gh`): Gerrit, Buildbucket & Buganizer CLI Pigweed provides `./gh` (a cached repository wrapper around `//pw_ghish:gh-ish`), exposing Gerrit code reviews (`./gh pr`), LUCI Buildbucket CI checks (`./gh pr checks`, `./gh run`), Google Issue Tracker / Buganizer (`./gh issue`), and worktree pools (`./gh wt`) through standard GitHub CLI (`gh`) syntax. This skill is the single source of truth for Gerrit, Buildbucket, and Buganizer workflows in Pigweed, completely replacing legacy raw `git push`, manual `curl` commands, `search_builds.py`, and `.gitcookies` scripts. ## Quick Command Reference All commands run via `./gh ` (or root aliases `./gh view`, `./gh diff`, `./gh push`, `./gh checks`, `./gh status`, `./gh worktree`): ### 1. Change Targeting & Inspection Subcommands accepting `[]` support: - **Omitted argument**: Automatically resolves the active change on the current Git branch. - **Change number**: `472267` or with patchset `472267/3`. - **Gerrit URL**: `https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/472267` (or `/+/472267/3`). Automatically routes to the Gerrit host in the URL even when invoked from a different repository. - **Shortlink**: `pwrev/472267`, `pwrev.dev/472267`, `pwrev.dev/i/472267` (internal review), `fxrev/472267`, `fxrev.dev/472267`, `fxr/472267`, `fxrev.dev/i/472267`, `fxr/i/472267`, `ag/472267`, `aosp/472267`, `crrev.com/c/472267`, `crrev.com/i/472267` (and `go/` or `goto.google.com/` forms), plus any custom prefixes configured in `.ghish.toml` (`[gerrit.shortlinks]`) or `git config ghish.gerrit.shortlink.`. Automatically resolves the corresponding Gerrit host. - **Branch name**: `my-feature`, `cl/472267`, `change-472267` (resolves via branch commit `Change-Id` or `branch..gerrit-change-id` config). Commands: - **`./gh pr view []`**: View change metadata (patchset, owner, reviewers, attention set, status, labels). Defaults to active change on current branch. - `-c, --comments`: Display all file and inline comment threads (including your unpublished `[DRAFT]` comments, `[PS]` patchset numbers, and `[resolved]` / `[unresolved]` thread states) indented by file and line number, or `Comments: None` when empty. - `--json `: Output structured JSON (e.g. `number,title,state,author,files,reviewers,comments,drafts`). Unknown fields are strictly rejected. - `--json bug,bugs`: Read back the linked bugs — the Gerrit counterpart to GitHub's `closingIssuesReferences`. `bug` is a flat `"b/123456, b/789"` string; `bugs` is `[{"id": "b/123456", "closes": true}]`, where `closes` distinguishes a `Fixed:` trailer (closes the bug on submit) from a `Bug:` trailer (links only). Use this to verify a `./gh issue create --amend` or `Bug:`/`Fixed:` commit trailer update, and to check whether a bug is already linked before adding one. - **`./gh pr diff [[/]]`**: View unified patch diff. - **`./gh pr checkout [[/]]`**: Fetch and check out change branch or specific patchset locally at `FETCH_HEAD`. ### 2. Push & Edit - **`./gh pr create`**: Push local commit(s) to Gerrit as a **new** change. - *Safety Guard*: Fails with a clear error and URL if the change already exists (use `pr push` to update existing changes). - *Stack Guard*: Halts if pushing multiple commits unless `--stack` is specified. - *Submodule Guard*: Enforces `gerrit.submodule_policy` (`"allow"`, `"warn-unpushed"`, `"require-pushed"`, or `"forbid-manual-rolls"`, plus automatic detection of Gerrit's `No-Submodule-Changes` submit requirement) before `git push`. - *Multi-Remote & Default Branch*: Automatically resolves non-`origin` remotes (`gerrit.remote` in `.ghish.toml`, `branch..remote`, `goog`, `aosp`, `partner`) and default branches (`gerrit.default_branch`, tracked upstream merge branch, `refs/remotes//HEAD`, `main`). - Flags: `-r, --reviewer `, `--owner`, `-c, --cc `, `--auto`, `--trigger [1|2]` (alias `--cq [1|2]`; defaults to `+1` dry run on `Commit-Queue` or `Presubmit-Ready`; `2` submits), `-d, --draft` (WIP), `-B, --base `, `--stack`, `--publish`, `-o, --push-option `, `--no-verify`. - **`./gh pr push`** (aliases: `./gh push`, `./gh pr upload`): Push local commit(s) to Gerrit to upload a **new patchset** on an existing change. - *Branch Memory*: Automatically queries Gerrit by `Change-Id` to discover the CL's target branch (e.g. sandbox branch), guaranteeing updates land on the right branch. - *Stack & Submodule Guards*: Enforces stack and submodule safety checks before pushing. - Supports `--ready` (remove WIP) and all `create` flags (including `--owner` and `-r @owners`). - *Smart Fallback*: If pushed with `--trigger` / `--cq` or metadata on an already up-to-date commit, `pr push` automatically applies updates via the Gerrit API instead of failing. - **`./gh pr ready [] [--owner] [-r ] [-m ] [-u|--undo]`**: Mark a change ready for review (or back to WIP with `--undo`), optionally assigning reviewers or resolving module code owners via `--owner` / `-r @owners`. - **`./gh pr edit []`**: Edit Gerrit CL metadata: - Trigger presubmit / CQ dry run: `./gh pr edit --trigger` (alias `--cq`; or `--trigger 2` / `--cq 2` to submit, `--trigger 0` / `--cq 0` to remove vote; also supports `--add-label =`). - Update reviewers/assignees: `./gh pr edit --add-reviewer user@google.com` (pass `--add-owner` or `--add-reviewer @owners` to automatically assign module code owners; also supports `--remove-reviewer`, `--add-assignee`, `--remove-assignee`). - Update the attention set: `./gh pr edit --remove-attention me` (`--add-attention `, `--remove-attention `). Unlike `--remove-assignee`, this leaves the user as a reviewer. - Set or remove topic/hashtags: `./gh pr edit --topic ` (`--remove-topic`, `--add-hashtag`, `--remove-hashtag`). Rejects `--topic` and `-o topic=...` before pushing if the project sets `Topics-Not-Supported` or `forbid_topics = true` in `.ghish.toml`. - *Commit-Message Edits (`b/567763970`)*: Unlike GitHub (where PR titles and descriptions live in the server database), Gerrit stores the CL description inside the Git commit message of each patchset. Commit-message flags (`--title`, `--body`, `--message`, `--bug`, `--fixed`) are disabled in `gh pr edit` and redirect to local surgical commit-message editing: 1. `git log -1 --format=%B HEAD > "$(git rev-parse --git-dir)/COMMIT_EDITMSG_TMP"` 2. Surgically edit `"$(git rev-parse --git-dir)/COMMIT_EDITMSG_TMP"` (preserving `Change-Id:`) 3. `git commit --amend --only -F "$(git rev-parse --git-dir)/COMMIT_EDITMSG_TMP" && ./gh pr push` ### 3. Review & Comment - **`./gh pr comment [] --path [--line ] -m `** (or `-b `): Post a file-level or inline comment (auto-threads onto any existing thread at `` or `:` across patchsets, keeping unrelated drafts private via `Drafts: KEEP`). - `--resolved`: Mark thread as resolved (requires `--path`, and `--line` for inline threads). - `--draft`: Create or update an unpublished draft comment visible only to you. If an unpublished draft already exists at that target, `--draft` updates it in place (preserving `Side` and character `Range`). If multiple drafts exist at the same location across different patchsets, disambiguate with `--patchset ` or `/`. - `--delete-draft`: Delete an unpublished draft comment at `--path [--line ]` (or omit `--path` for a change-level draft). - **`./gh pr comment [] -m [--draft]`**: Post or stage a change-level comment (`-F ` reads from file). - **`./gh pr review [] [--approve | --request-changes] [--trigger [1|2] | --cq [1|2]] [--publish] [-m ]`**: Submit review (`--approve` dynamically votes the change's maximum allowed `Code-Review` score, e.g. `+2` or `+1`; `--request-changes` votes `Code-Review-1`; `--publish` batch-publishes all staged draft comments across revisions; without `--publish`, pending drafts are kept private). For full review criteria, see [`.agents/skills/code_review/SKILL.md`](../code_review/SKILL.md). ### 4. Monitor & Rerun CI / Buildbucket & Busytown Checks - **`./gh pr checks [[/]]`**: Query remote LUCI Buildbucket checks, Android Busytown / TreeHugger presubmit targets (`treetop~presubmittasks` / `ci.android.com`), and Gerrit automated submit requirements / verification labels (`./pw presubmit` runs local host validation). - `-w, --watch`: Monitor checks until all blocking checks finish. - `--fail-fast`: Exit immediately upon the first blocking failure (implies `--watch`). - `--log-failed`: Automatically display failure reports and log snippets on exit (default: `true`). - `-e, --experimental`: Include non-blocking experimental checks in output. - `--all`: Include child subbuilds hidden by `ci.hide_tag_filters` in `.ghish.toml`. - **Exit codes**: `0` = all blocking checks passed, `8` = checks still running, `1` = blocking check failed, canceled, or no checks reported. Branch on the exit code; never scrape the table. - *Equivalent Patchsets*: Builds from earlier code-equivalent patchsets (`TRIVIAL_REBASE`, `TRIVIAL_REBASE_WITH_MESSAGE_UPDATE`, `NO_CODE_CHANGE`, `NO_CHANGE`, `MERGE_FIRST_PARENT_UPDATE`) are automatically included and labeled `(from patchset )`. - *Gerrit UI Check Count Note*: `./gh pr checks` returns top-level Buildbucket builders (e.g. ~72), whereas the Gerrit UI "Checks" tab (~132) also counts individual `pw_presubmit` sub-steps and static analyzers (AyeAye, SLSA). - **`./gh run view [] [-j|--job ] [--target ] [--log-failed] [--log] [--all] [-v] [--json]`**: Inspect failed builders, LogDog or Busytown `build.log` / AnTS failure snippets (`--log-failed`), or the hierarchical step tree (`-j [/][/]`). For direct Busytown build inspection, pass `P/` or `P --target `. - **`./gh run rerun [] [--failed | -j ] [--dry-run]`**: Rerun all failed builders or a specific builder via `bb add` on Buildbucket (using each build's recorded `//` and skipping child subbuilds tagged with `skip-retry-in-gerrit:subbuild`) or via `treetop~runaction` / `Presubmit-Ready+1` on Android Busytown / TreeHugger changes. - **`./gh run list [] [--all]`** & **`./gh run watch []`**. ### 5. Listing, Merging & Status - **`./gh pr list [--limit 30] [--state open|merged|closed|all] [--all-projects] [--json ]`**: Automatically scopes to `project:` when run inside a Git checkout; pass `--all-projects` to list across all projects on the Gerrit host. - **`./gh pr merge [] [--auto] [--trigger | --cq]`**: Submit change to target branch. Prefer `--auto` (auto-submit upon approval) or `--trigger` (alias `--cq`; `Commit-Queue+2` or `Autosubmit+1` + `Presubmit-Ready+1`) over bare `pr merge`. - **`./gh pr status [--all]`**: Focused dashboard of current branch (including inline `[PS]` previews for up to 2 unresolved threads and standalone `[DRAFT]` comments), CLs created by you, and incoming reviews (scoped to last 30 days unless `--all` is passed). - **`./gh sense [] [--json] [--status] [--fleet]`** (aliases: `./gh pr sense`, `./gh wt sense`): Fast parallel context sensor for autonomous workflows (`/crank`). Inspects local Git state, manual & `./gh wt` worktrees (including whether `` bug/CL is already tracked in another slot), active/target Gerrit CL comments & drafts, Buildbucket CI checks, and optional `.ghish.toml` oncall status in `<500ms`, classifying the recommended next-step modality. ### 6. Buganizer Issue Management (`./gh issue`) - **`./gh issue status`** & **`./gh issue list [--assignee @me|] [--state open|closed|all] [--label priority:P1|type:BUG|component:|hotlist:] [--search ""]`**. - **`./gh issue view [|] [--comments] [--json ]`**: View issue (resolves `Bug:`/`Fixed:`/`Fixes:`/`Closes:` trailer from `HEAD` if `` is omitted). - **`./gh issue develop [--checkout | -w|--worktree]`**: Create feature branch or allocate an isolated warm worktree slot (`./gh wt use --issue `). - **`./gh issue create -t "" -b "<body>" [-C <component-id>] [--amend | --commit]`**: Create a Buganizer issue (`--amend` appends `Bug: b/<new-id>` or configured `issue.trailer_format` to `HEAD` using `git commit --amend --only`). Resolves component ID via `-C`/`-l component:<id>` -> `[issue.path_components]` -> nearest `OWNERS` (`# COMPONENT:` / `# Buganizer component:`) -> `issue.default_component` -> `ghish.componentid` -> profile default. - **`./gh issue comment [<id>] -m "<text>"`**, **`./gh issue edit [<id>]`**, **`./gh issue close [<id>]`**, **`./gh issue reopen [<id>]`**. ### 7. Where `gh` Habits Break Use the long form for `--auto` (`-a` is `--assignee`), `--publish` (`-p` is `--project`), `--force` (`-f` is `--fill`), `--trigger`/`--cq` (`-t` is `--title`/`--template`, `-q` is `--jq`), `--target` on `run view` (`-t` is `--template`), `--all-projects` on `pr list` (`-a` is `--assignee`), and `--message` on `pr merge` (`-m` is `--merge`). | You type | Real `gh` | Here | |---|---|---| | `pr list -a` | assignee | queries Gerrit `reviewer:` — Gerrit dropped assignees in 3.8. | | `pr list -l` | issue label | a Gerrit **vote** predicate, e.g. `Code-Review+2`. | | `run list/view --json` | a field list | a boolean; it takes no fields. `pr view --json` does take fields. | | `--json state` | `OPEN`/`CLOSED`/`MERGED` | Gerrit's `NEW`/`MERGED`/`ABANDONED`. | | `pr review --request-changes` | blocks the PR | votes `Code-Review-1`, which is **advisory**. `Code-Review-2` is the veto. | | `pr comment --draft` | (n/a) | an unpublished draft **comment** nobody else can see — not a WIP change. | | `issue -l/--label` | free-form text | Buganizer priority/type/hotlist (`P0`–`P4`, `bug`, `feature`, `task`, `hotlist:<id>`). | --- ## Key Agent Workflows ### Workflow 1: Addressing Review Feedback & Drafts 1. **Fetch & review comments and drafts**: `./gh pr view <id> --comments` (or `./gh pr status`) 2. **Apply fixes & verify locally**: `./pw presubmit --mode auto --base origin/main` 3. **Upload updated patchset**: `git commit -a --amend --no-edit && ./gh pr push` 4. **Reply & resolve threads** (add `--draft` to stage privately for human review, or `--delete-draft` to remove a private steering draft): `./gh pr comment <id> --path <file> --line <line> -m "Fixed." --resolved [--draft]` 5. **Publish staged drafts (when ready)**: `./gh pr review <id> --publish` (or `./gh pr push --publish`) ### Workflow 2: CI Triage & Targeted Retry 1. **Check or watch status**: `./gh pr checks <id>` or run `./gh pr checks <id> --watch --fail-fast` as a **background command** (never poll in an agent loop!). 2. **Inspect failure logs**: `./gh run view <id> --log-failed` (or `./gh run view <id> -j <builder>`). 3. **Rerun failed builders**: `./gh run rerun <id> --failed` (or `-j <builder>`). 4. **Full CQ dry run**: `./gh pr edit <id> --cq`. --- ## Critical Rules for AI Agents 1. **NEVER use raw `git push`**: Always use `./gh pr push` (or `./gh push`) to update existing changes with new patchsets, and `./gh pr create` to create new changes. 2. **Use `--draft` for Private Notes**: Intermediate or preparatory review comments should use `--draft` so they remain private to you until ready. 3. **Resolve Threads Explicitly**: When fixing an issue raised by a reviewer, always reply with `--resolved --path <file> [--line <line>]`. 4. **Authentication is Automatic**: Never use manual `curl -sb ~/.gitcookies` or `gob-curl`; `./gh` handles corp (`gob-curl`) and `.gitcookies` auth automatically. 5. **Never Ignore Command Failures or Exit Codes**: Invalid inputs fail fast with non-zero exit codes. Always inspect stderr and address reported errors. 6. **Preserve `Change-Id` and Commit Trailers**: Preserve `Change-Id` footers when editing, amending, squashing, or rebasing commits. Gerrit uses these to link git commits to Change Lists. If multiple commits are combined, ensure ONLY the `Change-Id` from the earliest commit in the series is retained in the final commit message. To edit a commit message, dump it to a file (`git log -1 --format=%B HEAD > "$(git rev-parse --git-dir)/COMMIT_EDITMSG_TMP"`), edit the file surgically while keeping `Change-Id:` intact, and apply with `git commit --amend --only -F "$(git rev-parse --git-dir)/COMMIT_EDITMSG_TMP"`. 7. **Link Bugs With Trailers, Never `Fixes #N` or Fabricated Bug IDs**: GitHub's `Fixes #456` does **nothing** on Gerrit. Use `Bug: b/456` or `Fixed: b/456` trailers in the commit message (or `./gh issue create --amend`), and verify with `./gh pr view <id> --json bug,bugs`. **NEVER invent, guess, or placeholder-fill a `Bug:` or `Fixed:` issue number** — omit the trailer entirely if no real issue ID was provided or created. 8. **Submit Changes, Not Patchsets**: Use `./gh pr merge <id> --cq` (or `--auto`) without `/<patchset>` suffixes. 9. **NEVER Poll CI in an Agent Loop**: Run `./gh pr checks --watch --fail-fast` as a background command and stop calling tools until notified.