4.6 KiB · text History 1294137

gg — command-line client

Speaks /api/mobile/v1, the same surface the Android app in ../android uses. The two are kept in step deliberately: a capability that exists on the phone exists here, and a field that changes shape breaks both at once rather than drifting apart.

cargo build --release   # target/release/gg
cargo test

Signing in

Mint a token on the web under Settings → API tokens with the Mobile app bundle ticked, then either paste the pairing URI the QR encodes:

gg login 'gitgud://pair?base=https://forge.example.com&token=ggp_…'

or give the two fields:

gg login --url https://forge.example.com        # prompts for the token, unechoed
gg login --url https://forge.example.com --token-stdin < token.txt

Credentials land in ~/.config/gitgud/config.toml, mode 0600. GITGUD_URL and GITGUD_TOKEN override the file; --url and --token override both.

Which repository

Commands that need one take --repo owner/name. Without it, the git remote of the current directory is used when it points at this forge — so inside a checkout, gg ci list just works. gg login --default-repo owner/name sets a fallback for everywhere else.

Commands

gg whoami                        who the token belongs to, and its scopes
gg repos [--sort pushed|name|ci] repositories this token can reach
gg repo [owner/name]             counts, permissions, latest run

gg ci list [--limit N]           recent workflow runs
gg ci show [N] [--steps]         one run: jobs, steps, artifacts
gg ci logs [N] [--job JOB]       a job's logs, grouped by step
gg ci rerun N [--job JOB]        re-queue a run, or one job of it
gg ci cancel N                   cancel a queued or running run
gg ci watch [N]                  poll until it settles; exits non-zero on failure

gg issues list [--state open|closed|all] [--search TEXT]
gg issue show N [--no-comments]
gg issue comment N --body TEXT   (or --body-file PATH, or piped stdin)
gg issue close|reopen N

gg pulls list [--state open|closed|merged|all]
gg pull show N
gg pull comment N --body TEXT
gg pull review N --state approve|request-changes|comment [--body TEXT]
gg pull merge N [--message TEXT] [--override-rules]

gg wiki list | gg wiki show SLUG
gg packages list | gg package show FORMAT NAME | gg package usage FORMAT

gg dashboard [--refresh SECS]    interactive CI dashboard

--json on any command prints the server’s response verbatim instead of a table, which is the intended way to script against it.

Dashboard

gg dashboard opens runs, jobs and logs over one repository.

j/k, ↑/↓   move          Enter  open the run / the job's logs
Tab        switch pane   l      logs for the selected job
r          refresh now   Esc    back a level
R          re-run        C      cancel
q          quit

Write actions are capitalized so neither is a neighbour of a navigation key — re-running someone else’s release because you reached for r is not a recoverable mistake.

Packaging

CI builds a .deb and an .rpm on every push to master and publishes both to this forge’s own registries — gg installs from the same place the server package does:

# Debian / Ubuntu (trixie, forky)
sudo apt install gg

# Fedora / RHEL / openSUSE
sudo dnf install gg

The workflow prints the repository lines to add first; see the cli job in .forgejo/workflows/build.yml.

Both packages come from metadata in Cargo.toml, and both build by hand — a packaging bug should be reproducible without pushing a commit:

cargo deb            # target/debian/gg_<version>_<arch>.deb
cargo generate-rpm   # target/generate-rpm/gg-<version>-<release>.<arch>.rpm

cli/Dockerfile is what CI drives. It compiles the crate twice, once on Debian trixie and once on EL9, because a Rust binary is linked against the glibc of whatever built it — one binary packaged for both families would install cleanly and then die with version GLIBC_2.41 not found. It also runs cargo fmt --check, cargo clippy -D warnings and cargo test on the way past, so a failing tree produces no package.

docker buildx build --target packages \
  --output type=local,dest=./cli-dist --file cli/Dockerfile .

The build context is the repository root, not cli/: the copyright file in both packages is the repo’s LICENSE.md.

Layout

path what
src/cli.rs the clap command tree
src/api/ HTTP client and the wire types, mirroring the server’s JSON module
src/commands/ one module per noun, plus repo inference and body input
src/output.rs colour, the CI status vocabulary, tables, relative times
src/tui/ the dashboard