Skip to content

fix(git-tools): repair Gitea repo info and issue list author - #173

Open
calcorum wants to merge 1 commit into
St0nefish:masterfrom
calcorum:fix/git-cli-gitea-issue-author-and-repo-info
Open

fix(git-tools): repair Gitea repo info and issue list author#173
calcorum wants to merge 1 commit into
St0nefish:masterfrom
calcorum:fix/git-cli-gitea-issue-author-and-repo-info

Conversation

@calcorum

@calcorum calcorum commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator

Summary

Three defects on the Gitea path of git-cli, all the same root cause as #133: the code asks tea for a shape it does not emit. All three fail silently — empty output or an empty string, never an error — which is why they survived.

Found while using the git-tools plugin against a self-hosted Gitea instance.

1. repo info returns nothing on Gitea

It filtered tea repos list --output json with select(.full_name == $slug). That command emits only {owner, name, type, ssh}:

$ tea repos list --output json | jq -c '.[0]'
{"owner":"cal","name":"agency-agents","type":"mirror","ssh":"ssh://git@…/cal/agency-agents.git"}

So the select dropped every row. The trailing 2>/dev/null || echo "{}" then swallowed the evidence, leaving an empty result and exit 0.

A jq-only fix isn't possible: tea repos list --fields offers description,forks,id,name,owner,stars,ssh,updated,url,permission,type — no full_name, no default_branch, no visibility — and it is paginated at 30/page, so a filter would miss any repo past the first page regardless.

Fixed by fetching the repo directly via tea api repos/{owner}/{repo}, which returns all the required fields. This is the same shape #133 introduced for run show.

2. The remote slug kept its .git suffix

sed -E 's|.*[:/]([^/]+/[^/]+?)(\.git)?$|\1|'

This relies on +? being lazy. POSIX ERE has no lazy quantifiers, so [^/]+ matched greedily, (\.git)? matched empty, and the result was owner/repo.git:

$ echo 'git@host:owner/repo.git' | sed -E 's|.*[:/]([^/]+/[^/]+?)(\.git)?$|\1|'
owner/repo.git

Masked before this change rather than latent — the select failed on .full_name first, so a wrong slug never got the chance to surface. Two independent bugs hiding each other. Fatal once the slug is interpolated into an API path. Now stripped in its own expression.

3. issue list always reports author: ""

The --fields request omitted author while the normalizer reads .author. tea emits only the fields named, so it was always the empty fallback:

$ tea issues list --fields "index,title,state,author" --output json | jq -c '.[0]'
{"index":"10","title":"…","state":"open","author":"cal"}

issue show is unaffected — it uses tea issues <N>, which emits user, and the code already reads .user. That path was correct and is unchanged.

Testing

New suite tests/git-cli/test-gitea-repo-info-issue-author.sh, 8 cases, following the mock-PATH pattern from test-run-show.sh:

  • repo info emits a populated normalized object (name, owner, description, default_branch, visibility, url, stars, forks)
  • regression guard: tea repos list is never invoked (sentinel)
  • slug resolves to repos/owner/repo across all four remote URL forms — ssh://…:2222/…, git@host:…, https://…/….git, and no-suffix
  • issue list requests author in --fields and reports a non-empty author

The tea mock honours --fields the way tea does (emitting only the named fields), so case 4 genuinely fails if the field is dropped again.

All 8 fail against the pre-change code and pass after.

Also run locally:

  • bash tests/test.sh — no new failures. permission-manager/test-classify fails with 9 cases, but it fails identically on a pristine origin/master worktree; pre-existing and unrelated.
  • bash .github/scripts/validate-plugins.sh — 300 checks, 0 failures (includes vendored-drift and version-sync)
  • bash .github/scripts/validate-frontmatter.sh — 103 checks, 0 failures

CI's shellcheck --severity=error job covers the changed scripts; no executable line differs from the reviewed diff.

Also verified against a live Gitea instance (tea 0.14.1), old code vs new, on real repos with git@host:owner/repo.git remotes:

  • repo info — old printed nothing and exited 0; new returns the populated object (name, owner, description, default_branch, visibility, url, stars, forks).
  • issue list — old reported author: "" for every issue; new reports the real login.
  • slug parsing — checked directly across all four remote URL forms; the old expression left owner/repo.git on the three .git-suffixed ones, the new one strips it.

Notes for the reviewer

  • Edited utils/git-cli and re-ran utils/sync.sh; vendored copies for git-tools and session are in the same commit.
  • Bumped git-tools 2.2.1 → 2.2.2 and session 4.5.0 → 4.5.1 (both vendor git-cli), claude and copilot manifests together.
  • Deliberate behaviour change: repo info on Gitea now surfaces errors instead of swallowing them, because it routes through cli_json rather than … 2>/dev/null || echo "{}". This aligns it with the rest of the file rather than departing from it:
    • Every data-returning subcommand goes through cli_json, which dies on a non-zero exit with the CLI's stderr — all 23 call sites, covering issue list/show, issue comment, pr list/show, pr comment, and run list/show.
    • Scope of that, precisely: cli_json catches process failure (network, auth, a missing tea). It does not catch API-level errors, because tea api prints {"message":"not found",…} and still exits 0 — a 404 therefore yields a null-filled object rather than an error. That is not new here: run show behaves identically, and has since git-cli: run show broken on Gitea — tea ignores --output json, jq parse error #133. Worth a follow-up across all tea api call sites, but out of scope for this fix.
    • repo info's own GitHub arm, three lines above the Gitea arm, already used cli_json. Before this change the two platform branches of one subcommand disagreed about whether a fetch failure is an error: on GitHub it aborted, on Gitea it printed nothing and exited 0.
    • The 2>/dev/null || <fallback> sites elsewhere are a different layer — the ship/wait loops, which soften the results of git-cli's own already-cli_json'd subcommands. That's intentional and documented at _ci_status: "Every API call is guarded so a probe failure degrades to none and never aborts the wait loop." "No CI run yet for this branch" is a legitimate state during a poll, not an error.
    • The only other || echo fallbacks are repo:default-branch's || echo "main" (tail of a git-local resolution chain, no API call) and that _ci_status probe. The old repo info line was the sole primitive-layer swallow in the file.

Three defects on the Gitea path of `git-cli`, all the same root cause as
St0nefish#133: the code asked `tea` for a shape it does not emit, and the failures
were silent rather than loud.

`repo info` returned nothing at all on Gitea. It filtered `tea repos list
--output json` with `select(.full_name == $slug)`, but that command emits
only {owner,name,type,ssh} — the select dropped every row, and the
trailing `2>/dev/null || echo "{}"` swallowed the evidence, so it exited 0
with empty output. `tea repos list` is also paginated (30/page) and cannot
report `default_branch` under any `--fields` combination, so no jq fix
was possible; it now fetches the repo directly via `tea api
repos/{owner}/{repo}`, matching the shape St0nefish#133 introduced for `run show`.

The slug feeding that call was itself broken. `([^/]+/[^/]+?)(\.git)?$`
relies on a lazy quantifier, and POSIX ERE has none — `+?` matched
greedily, `(\.git)?` matched empty, and the slug kept its `.git` suffix.
Latent before (the result was discarded either way), fatal once it
reaches the API.

`issue list` always reported `author: ""`. The `--fields` request omitted
`author` while the normalizer read `.author`; tea emits only the fields
named, so it was always the empty fallback. `issue show` uses a different
tea command that emits `user`, which the code already reads — that path
was correct and is unchanged.

- repo:info (gitea) — fetch via `tea api repos/{owner}/{repo}`; read
  `.owner.login` (object) rather than `.owner` (string in the old shape)
- repo:info (gitea) — strip `.git` in a separate sed expression
- issue:list (gitea) — add `author` to the requested `--fields`
- add tests/git-cli/test-gitea-repo-info-issue-author.sh (8 cases; all 8
  fail against the previous code, covering all four remote URL forms)
- bump git-tools 2.2.1 → 2.2.2 and session 4.5.0 → 4.5.1 (both vendor
  git-cli), and re-run utils/sync.sh

Note a deliberate behaviour change: `repo info` on Gitea now reports
errors instead of swallowing them, since it routes through `cli_json`.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant