You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Filed after driving git-cli against a self-hosted Gitea remote (git.stonefish.tech, Gitea Actions) this session. Four defects were observed in run list / run show / pr show / run watch output. While researching the source to cite line numbers, I found that two of the four (#2 and #3 below) are already fixed on master (commit b3a47fc, closing issue #140, 2026-08-29) — the session that observed them was running the installed plugin cache at git-tools 2.2.1, which predates that fix (master is now at 2.2.2). I'm still recording them here with what I found, since the fix's status doesn't line up cleanly with the open issue tracker (see note under #2). The other two (#1 and #4) appear to still be present on current master — I read the relevant code and describe what it does below.
All four were observed against git-cli run show 2941 (and runs 2918, 2915), git-cli pr show 60, and git-cli run watch --branch feature-lock-acquire-discards-ssh-error --interval 30.
Defect 1 — run list / run show always report duration: null and started_at: "" (open)
Observed on completed, successful runs. Example: git-cli run show 2941 on a finished run returned "started_at": "", "duration": null. Same for runs 2918 and 2915, all status: success.
Impact: no way to tell how long a run took, or how long an in-progress run has been going — so "slow but healthy" is indistinguishable from "hung" without leaving the tool.
Source (verified): neither run list nor run show compute these fields — both pass the Gitea REST response through with no fallback derivation:
run:show, Gitea branch — plugins-claude/git-tools/scripts/git-cli:1029-1030 (same expression, fed from tea api repos/{owner}/{repo}/actions/runs/$run_id at line 980):
Both sites source from the raw Gitea REST payload (repos/{owner}/{repo}/actions/runs...) and just try .run_started_at, then .created, then give up to ""/null — there's no computation from any other timestamp the payload might carry (e.g. created_at/updated_at), and no live-duration estimate for in-progress runs.
Unverified: I did not independently dump the raw tea api repos/{owner}/{repo}/actions/runs/<id> JSON for this Gitea instance, so I can't confirm whether the underlying fields (run_started_at, created, duration) are genuinely absent/blank in Gitea's response, or whether Gitea uses different field names (e.g. created_at) that the script isn't checking. Either way, the script-level behavior — blind pass-through with no fallback — is confirmed by the source above.
Defect 2 — run watch --branch NAME cannot correlate pull_request runs (fixed on master, but see note)
git-cli run watch --branch feature-lock-acquire-discards-ssh-error --interval 30 returned:
status: no-workflow
duration: 120s
CI workflow runs exist but none correlate to branch '...' after 120s
even though a run for that branch's head SHA existed and was in_progress at that moment.
Cause (observed in run list output, not verified independently against Gitea docs): Gitea reports "branch": "" for event: "pull_request" runs — only push runs carry a branch name. Correlating on head_sha works reliably; that's the workaround used this session.
Status: this is already fixed on master. Commit b3a47fc (2026-08-29, closes #140) added a head_sha-based fallback correlator (_runs_for_branch, plugins-claude/git-tools/scripts/git-cli:1104-1118) that run watch now calls instead of filtering on branch name alone (call sites at lines 1204 and 1389). The comment at lines 1086-1091 describes exactly this failure mode. The installed plugin cache used this session (2.2.1) predates that fix.
Note for triage: issue #134 ("run watch --branch misses PR-gate runs") describes this same root cause and is still open, even though #140's fix (already on master) appears to cover it. I'm not closing anything myself — just flagging the mismatch so it doesn't get re-discovered as a fresh bug.
Defect 3 — pr show <N> returns contradictory merge fields (fixed on master)
git-cli pr show 60 on a merged PR returned "state": "merged" together with "merged": false. The PR was genuinely merged (confirmed independently: git ls-remote origin master showed the PR's head SHA as master's tip). A caller trusting the merged boolean would conclude the opposite of the truth.
Status: already fixed on master by the same commit b3a47fc (closes #140). pr:show's Gitea branch previously sourced from tea pr list, whose JSON omits merged/merged_at entirely (see removed code in the diff between the installed 2.2.1 cache and current master, formerly around what's now plugins-claude/git-tools/scripts/git-cli:589-651). The current code instead fetches tea api repos/{owner}/{repo}/pulls/${num} directly and derives state from .merged so the two fields can't disagree — plugins-claude/git-tools/scripts/git-cli:631-648, notably:
Again, the installed 2.2.1 cache predates this fix.
Defect 4 — run list always returns "workflow": "" (open)
Every row in run list --limit 50 had an empty workflow field, so there's no way to tell the PR-gate workflow from the release workflow in the listing. This matters where different workflows have very different meanings — e.g. ci.yaml running unit tests only vs. release.yaml running VM-backed integration suites — and telling them apart from the listing alone is impossible.
Source (verified expression, unverified against raw payload): both run:list and run:show's Gitea branches select the workflow name as:
jq's // only falls through on null/false, not on an empty string. If Gitea's run payload returns .name as "" (rather than null), this expression never reaches the .workflow_id fallback, and the result is always "" — consistent with what was observed.
Unverified: I did not dump the raw Gitea payload to confirm whether .name comes back as an empty string vs. null, or whether .workflow_id is itself populated on this instance. The jq semantics above are confirmed; which of the two payload shapes is actually occurring is not.
Impact
Defect 1: no timing signal for CI runs — can't distinguish "slow but healthy" from "hung."
Defect 4: no way to tell which workflow a run belongs to from run list, on repos where that distinction matters (e.g. unit-test-only CI vs. release/integration CI).
For Feature/issue driven workflow git tools #4: treat empty string the same as null when falling back to .workflow_id (e.g. (.name // empty) // (.workflow_id // empty) // ""), and/or confirm what Gitea actually populates in .name vs .workflow_id for this Gitea version.
Whether either of these is right depends on what the raw Gitea API payload actually contains, which I wasn't able to verify from within this repo.
Summary
Filed after driving
git-cliagainst a self-hosted Gitea remote (git.stonefish.tech, Gitea Actions) this session. Four defects were observed inrun list/run show/pr show/run watchoutput. While researching the source to cite line numbers, I found that two of the four (#2 and #3 below) are already fixed onmaster(commitb3a47fc, closing issue #140, 2026-08-29) — the session that observed them was running the installed plugin cache atgit-tools 2.2.1, which predates that fix (masteris now at2.2.2). I'm still recording them here with what I found, since the fix's status doesn't line up cleanly with the open issue tracker (see note under #2). The other two (#1 and #4) appear to still be present on currentmaster— I read the relevant code and describe what it does below.All four were observed against
git-cli run show 2941(and runs 2918, 2915),git-cli pr show 60, andgit-cli run watch --branch feature-lock-acquire-discards-ssh-error --interval 30.Defect 1 —
run list/run showalways reportduration: nullandstarted_at: ""(open)Observed on completed, successful runs. Example:
git-cli run show 2941on a finished run returned"started_at": "", "duration": null. Same for runs 2918 and 2915, allstatus: success.Impact: no way to tell how long a run took, or how long an in-progress run has been going — so "slow but healthy" is indistinguishable from "hung" without leaving the tool.
Source (verified): neither
run listnorrun showcompute these fields — both pass the Gitea REST response through with no fallback derivation:run:list, Gitea branch —plugins-claude/git-tools/scripts/git-cli:954-955:run:show, Gitea branch —plugins-claude/git-tools/scripts/git-cli:1029-1030(same expression, fed fromtea api repos/{owner}/{repo}/actions/runs/$run_idat line 980):Both sites source from the raw Gitea REST payload (
repos/{owner}/{repo}/actions/runs...) and just try.run_started_at, then.created, then give up to""/null— there's no computation from any other timestamp the payload might carry (e.g.created_at/updated_at), and no live-duration estimate for in-progress runs.Unverified: I did not independently dump the raw
tea api repos/{owner}/{repo}/actions/runs/<id>JSON for this Gitea instance, so I can't confirm whether the underlying fields (run_started_at,created,duration) are genuinely absent/blank in Gitea's response, or whether Gitea uses different field names (e.g.created_at) that the script isn't checking. Either way, the script-level behavior — blind pass-through with no fallback — is confirmed by the source above.Defect 2 —
run watch --branch NAMEcannot correlatepull_requestruns (fixed on master, but see note)git-cli run watch --branch feature-lock-acquire-discards-ssh-error --interval 30returned:even though a run for that branch's head SHA existed and was
in_progressat that moment.Cause (observed in
run listoutput, not verified independently against Gitea docs): Gitea reports"branch": ""forevent: "pull_request"runs — onlypushruns carry a branch name. Correlating onhead_shaworks reliably; that's the workaround used this session.Status: this is already fixed on
master. Commitb3a47fc(2026-08-29, closes #140) added ahead_sha-based fallback correlator (_runs_for_branch,plugins-claude/git-tools/scripts/git-cli:1104-1118) thatrun watchnow calls instead of filtering on branch name alone (call sites at lines 1204 and 1389). The comment at lines 1086-1091 describes exactly this failure mode. The installed plugin cache used this session (2.2.1) predates that fix.Note for triage: issue #134 ("
run watch --branchmisses PR-gate runs") describes this same root cause and is still open, even though #140's fix (already on master) appears to cover it. I'm not closing anything myself — just flagging the mismatch so it doesn't get re-discovered as a fresh bug.Defect 3 —
pr show <N>returns contradictory merge fields (fixed on master)git-cli pr show 60on a merged PR returned"state": "merged"together with"merged": false. The PR was genuinely merged (confirmed independently:git ls-remote origin mastershowed the PR's head SHA as master's tip). A caller trusting themergedboolean would conclude the opposite of the truth.Status: already fixed on
masterby the same commitb3a47fc(closes #140).pr:show's Gitea branch previously sourced fromtea pr list, whose JSON omitsmerged/merged_atentirely (see removed code in the diff between the installed2.2.1cache and currentmaster, formerly around what's nowplugins-claude/git-tools/scripts/git-cli:589-651). The current code instead fetchestea api repos/{owner}/{repo}/pulls/${num}directly and derivesstatefrom.mergedso the two fields can't disagree —plugins-claude/git-tools/scripts/git-cli:631-648, notably:Again, the installed
2.2.1cache predates this fix.Defect 4 —
run listalways returns"workflow": ""(open)Every row in
run list --limit 50had an emptyworkflowfield, so there's no way to tell the PR-gate workflow from the release workflow in the listing. This matters where different workflows have very different meanings — e.g.ci.yamlrunning unit tests only vs.release.yamlrunning VM-backed integration suites — and telling them apart from the listing alone is impossible.Source (verified expression, unverified against raw payload): both
run:listandrun:show's Gitea branches select the workflow name as:run:list—plugins-claude/git-tools/scripts/git-cli:950:workflow: (.name // .workflow_id // ""),run:show—plugins-claude/git-tools/scripts/git-cli:1026:workflow: (.name // .workflow_id // ""),jq's
//only falls through onnull/false, not on an empty string. If Gitea's run payload returns.nameas""(rather thannull), this expression never reaches the.workflow_idfallback, and the result is always""— consistent with what was observed.Unverified: I did not dump the raw Gitea payload to confirm whether
.namecomes back as an empty string vs.null, or whether.workflow_idis itself populated on this instance. The jq semantics above are confirmed; which of the two payload shapes is actually occurring is not.Impact
run list, on repos where that distinction matters (e.g. unit-test-only CI vs. release/integration CI).run watch --branchmisses PR-gate runs (pull_request event has empty branch) #134 — already fixed onmaster(2.2.2); the observed failures were against a stale installed plugin cache (2.2.1).Suggested direction
Not prescribing an implementation — a few directions that seem plausible for #1 and #4, for whoever picks this up to weigh:
durationfrom whatever start/end timestamps the payload does carry (or fromstarted_at→now for in-progress runs), rather than only passing through a.durationfield that may not exist in Gitea's response.nullwhen falling back to.workflow_id(e.g.(.name // empty) // (.workflow_id // empty) // ""), and/or confirm what Gitea actually populates in.namevs.workflow_idfor this Gitea version.Whether either of these is right depends on what the raw Gitea API payload actually contains, which I wasn't able to verify from within this repo.
Environment
git-toolsversion observed:2.2.1(installed plugin cache) — currentmasteris2.2.2teaCLI used by the script for the Gitea path🤖 Filed via
git-cli issue createper session instructions.