blob: 4bcab913661da4c6c14dacfa5cbca8e16b7cc64f [file]
.. _module-pw_ghish-project-integration:
================
Project adoption
================
.. pigweed-module-subpage::
:name: pw_ghish
While ``pw_ghish`` provides the ``./gh`` CLI for Pigweed contributors, its
underlying engine (``gh-ish``) can be used with any project hosted on Gerrit
and LUCI.
This guide explains how to integrate ``gh-ish`` into a repository, build and
distribute the binary, configure project profiles, set up authentication, and
inspect CI builds.
--------------------------------
Building and distributing gh-ish
--------------------------------
``gh-ish`` is written in standard Go without external C library dependencies.
It can be built and distributed using Bazel, Go toolchains, or pre-built binary
packages.
Building with Bazel
===================
If your project uses Bazel, compile the binary target directly:
.. code-block:: console
$ bazelisk build //pw_ghish:gh-ish
The compiled executable is placed in ``bazel-bin/pw_ghish/gh-ish_/gh-ish``.
Building with standard Go
=========================
You can compile and install ``gh-ish`` using the Go toolchain:
.. code-block:: console
# Compile binary from source:
$ go build -o gh-ish ./pw_ghish/cmd/main.go
# Or install directly into $GOPATH/bin:
$ go install pigweed.dev/pw_ghish/cmd@latest
Distributing via CIPD or package managers
=========================================
For large multi-repo projects (such as Fuchsia or Chromium), ``gh-ish`` can be
packaged as a CIPD (Chrome Infrastructure Package Deployer) package or added to
host toolchains so developers and CI bots have it pre-installed on their
``$PATH``.
-----------------------------
Creating a repository wrapper
-----------------------------
Rather than requiring every developer and AI coding agent to manually install
and update a global binary, we strongly recommend placing a lightweight wrapper
script named ``gh`` at the root of your repository (e.g. ``./gh``).
Why use a repository wrapper?
=============================
1. **Zero-setup onboarding**: New contributors and AI agents can immediately run
``./gh pr list`` or ``./gh pr status`` without prior installation steps.
2. **Commit-pinned consistency**: The wrapper automatically builds or downloads
the exact version of the tool tied to the repository's current commit,
eliminating "works on my machine" version skew.
3. **Transparent caching**: The wrapper can build the binary once per commit and
cache it in a local output directory (e.g. ``out/gh/``), providing instant
sub-second execution on subsequent runs.
4. **Agent muscle memory**: AI coding agents frequently check for a ``./gh``
executable or default to GitHub CLI commands. Providing ``./gh`` allows
agents to interact with the repository without custom instructions.
Example wrapper implementation
==============================
Here is an example wrapper script that builds and caches the binary:
.. code-block:: bash
#!/usr/bin/env bash
set -euo pipefail
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
CACHE_DIR="${REPO_ROOT}/out/gh"
COMMIT_HASH="$(git -C "${REPO_ROOT}" rev-parse HEAD 2>/dev/null || echo "latest")"
CACHED_BIN="${CACHE_DIR}/gh-ish-${COMMIT_HASH}"
if [[ ! -x "${CACHED_BIN}" ]]; then
mkdir -p "${CACHE_DIR}"
# Build using Bazel or Go:
bazelisk build --noshow_progress //pw_ghish:gh-ish
cp -f "${REPO_ROOT}/bazel-bin/pw_ghish/gh-ish_/gh-ish" "${CACHED_BIN}"
chmod +x "${CACHED_BIN}"
fi
exec "${CACHED_BIN}" "$@"
----------------------------
Project Profile Architecture
----------------------------
Every Gerrit project has unique review conventions: differing label names
(such as ``Code-Review`` vs. ``Commit-Queue`` vs. ``Auto-Submit``), varying
presubmit gates, and dedicated LUCI build buckets.
``pw_ghish`` abstracts these differences through **Project Profiles**.
Built-in profiles
=================
``pw_ghish`` includes built-in profiles for common Google open-source projects:
.. list-table::
:header-rows: 1
* - Profile
- Gerrit Host Match
- Commit-Queue
- Code-Review
- Try Bucket
* - **pigweed**
- ``pigweed-review.googlesource.com``
- ``Commit-Queue+2``
- ``Code-Review+2``
- ``pigweed/try``
* - **fuchsia**
- ``fuchsia-review.googlesource.com``
- ``Commit-Queue+2``
- ``Code-Review+2``
- ``fuchsia/try``
* - **generic**
- *(fallback)*
- *(none)*
- ``Code-Review+2``
- *(custom)*
Auto-submit labels (such as ``Pigweed-Auto-Submit`` or ``Auto-Submit``) do not
need to be configured in a profile: ``--auto`` queries Gerrit for the change's
or project's labels and votes the matching auto-submit label automatically.
Automatic profile detection
===========================
``pw_ghish`` automatically selects the appropriate profile by inspecting:
1. The Git remote URL (e.g. ``origin``) for the repository.
2. The Gerrit review host hostname.
3. The Git config setting ``ghish.profile``.
Explicit profile override
=========================
You can force a specific profile on any command using the ``--profile`` flag:
.. code-block:: console
$ gh-ish pr list --profile fuchsia
$ gh-ish pr status --profile pigweed
Profile names are strictly validated. Passing an invalid profile name halts with
an error listing all available profiles.
Adding a new project profile
============================
To add a profile for your project, implement the ``ProjectProfile`` interface in
``pw_ghish/profile.go`` (or embed ``genericProfile`` for default behavior) and
register it with ``RegisterProfile``:
.. code-block:: go
type myProjectProfile struct {
genericProfile
}
func (p *myProjectProfile) Name() string {
return "myproject"
}
func (p *myProjectProfile) DefaultGerritHost() string {
return "https://myproject-review.googlesource.com/a"
}
func (p *myProjectProfile) CQLabel() (LabelVote, bool) {
return LabelVote{Name: "Commit-Queue", Value: 2}, true
}
func (p *myProjectProfile) BuildbucketProject() string {
return "myproject"
}
func init() {
RegisterProfile(&myProjectProfile{})
}
Add a test case in ``pw_ghish/profile_test.go`` verifying detection and behavior.
-----------------------------------
Authentication and Credential Setup
-----------------------------------
``pw_ghish`` supports multiple authentication strategies, from standard open-source
cookie and token files to automated CI bot credentials and Google-internal
developer workstations.
Credential discovery order
==========================
When communicating with Gerrit REST APIs, ``pw_ghish`` searches for credentials in
the following order:
1. **Explicit Environment Token**:
Reads bearer or personal access tokens from the ``GERRIT_TOKEN`` environment
variable. Recommended for automated CI pipelines and bots.
.. code-block:: console
$ export GERRIT_TOKEN="your-http-access-token"
2. **Git Cookies** (``.gitcookies``):
Parses Netscape-formatted cookie jars at ``~/.gitcookies`` or the path
specified by ``git config http.cookiefile``. This is the standard mechanism
used by Git-on-Borg and Google Open Source Gerrit hosts.
To generate cookies for a Google-hosted Gerrit server:
* Visit the Gerrit web UI (e.g. ``https://your-host-review.googlesource.com``).
* Click your user avatar and select **Settings** -> **HTTP Credentials**.
* Click **Generate Password** and copy the provided command into your terminal.
3. **Netrc** (``.netrc``):
Parses machine entries in ``~/.netrc`` matching the target Gerrit hostname.
4. **Internal Workstation Transport**:
When running on Google-internal developer workstations, ``pw_ghish``
automatically integrates with local authentication helpers without requiring
manual configuration.
5. **Anonymous Read Fallback**:
If no credentials are found, public read operations (such as ``pr view``,
``pr list``, ``pr diff``, and ``pr checks``) fall back to unauthenticated
access on public Gerrit hosts. Write operations (such as ``pr push``,
``pr comment``, or ``pr merge``) report an actionable authentication error.
Forcing authentication method
=============================
In automated environments or debugging sessions, you can strictly enforce a
specific authentication backend using the ``GH_ISH_AUTH_METHOD`` environment
variable:
.. code-block:: console
$ export GH_ISH_AUTH_METHOD=cookies # Strictly require .gitcookies
$ export GH_ISH_AUTH_METHOD=token # Strictly require GERRIT_TOKEN
$ export GH_ISH_AUTH_METHOD=none # Force anonymous access
$ export GH_ISH_AUTH_METHOD=gob-curl # Force workstation helper transport
If the requested authentication method cannot be satisfied (e.g. missing cookie
file or missing token), ``pw_ghish`` immediately halts with a descriptive error
rather than silently falling back to anonymous access.
-----------------------------------
LUCI CI and Buildbucket Integration
-----------------------------------
Projects using LUCI (such as Chromium, Fuchsia, Pigweed, and Android) can use
Buildbucket integration for check inspection and reruns:
pRPC checks querying
====================
``pw_ghish pr checks`` queries ``cr-buildbucket.appspot.com`` via pRPC to fetch
builder statuses, durations, and build URLs.
Terminal log inspection
=======================
``gh-ish run view --log-failed`` queries Buildbucket step summaries and step
log URLs to retrieve the tail of failed build steps in the terminal:
.. code-block:: console
# Inspect step execution tree for a specific builder:
$ gh-ish run view -j myproject-linux-dbg
# Print failure summaries and step log snippets for failed builders:
$ gh-ish run view --log-failed
Builder reruns
==============
``gh-ish run rerun`` automatically constructs and executes ``bb add`` commands
targeting your profile's try bucket:
.. code-block:: console
# Rerun all failed builders on the current change:
$ gh-ish run rerun --failed
# Rerun a specific builder:
$ gh-ish run rerun -j myproject-linux-dbg
# Preview the generated bb command without executing:
$ gh-ish run rerun --failed --dry-run