Skip to content

fix(git-tools): correlate Gitea PR merge state and CI runs (#140) - #184

Merged
st0nefish-ci[bot] merged 2 commits into
masterfrom
fix/gitea-pr-show-and-run-watch-correlation
Aug 29, 2026
Merged

fix(git-tools): correlate Gitea PR merge state and CI runs (#140)#184
st0nefish-ci[bot] merged 2 commits into
masterfrom
fix/gitea-pr-show-and-run-watch-correlation

Conversation

@St0nefish

Copy link
Copy Markdown
Owner

Closes #140.

Summary

Two Gitea-only defects made git-cli report the wrong thing, plus a fork-bomb landmine in the test mocks that the first fix exposed.

1. pr show reported merged PRs as open

The Gitea path sourced from tea pr list, whose JSON omits the merged boolean and merged_at timestamp entirely — tea only encodes merge state into the state string. A merged PR came back merged:false and callers treated it as still open.

Fetches the PR detail via tea api repos/{owner}/{repo}/pulls/<n> instead, mirroring the existing run:show/run:list pattern, and derives state from merged so it matches the GitHub path. merged_at is now emitted on both platforms so the shape is identical.

2. run watch timed out into no-workflow when CI had actually run

Gitea leaves head_branch empty on pull_request-triggered runs, so run list --branch correlates nothing. Resolves the branch head SHA up front and falls back to head_sha correlation when the branch-filtered lookup is empty.

GitHub is unaffected — its server-side --branch filter populates the first call, so the SHA path is never taken. The two GitHub-only call sites (statusCheckRollup) are deliberately left alone.

3. Test mocks fork-bombed on any unmatched git subcommand

Every suite that PATH-injects a fake git fell through to command git "$@". command bypasses functions and aliases but not PATH lookup, and the mock's directory is prepended to PATH — so the mock re-executed itself, unbounded.

Latent since the mocks were written, because nothing had ever called git with a subcommand other than remote get-url origin. The rev-parse call in fix 2 was the first, and it took out a whole terminal: 56,311 processes in one cgroup scope against a pids.max of 114,647, after which every fork in that terminal failed.

Fixed at all 11 fallbacks across 9 suites by stripping the mock's own directory from PATH before delegating:

*) PATH=${PATH#"${0%/*}":}; exec git "$@" ;;

Without this, CI itself would fork-bomb on the rev-parse call, so it is a prerequisite for fix 2 rather than a follow-up.

Test plan

  • bash tests/test.sh32 suites, 0 failed; previously hung indefinitely
  • tests/session/test-ci-poll.sh — 38/38 (this is the suite that bombed)
  • New regression suites: test-pr-show-gitea.sh (4), test-run-watch-gitea.sh (2)
  • All git-cli suites: 43 tests, 0 failures
  • Mock behaviour verified directly: matched cases still return mock values, unmatched delegate to real git and terminate, git rev-parse origin/<missing> returns git's own error instead of recursing
  • validate-frontmatter.sh 103/0; utils/sync.sh --check no drift

Versions

git-tools 2.2.1 → 2.2.2, session 4.5.0 → 4.5.1 (both vendor git-cli).

St0nefish and others added 2 commits August 29, 2026 16:54
Two Gitea-only defects made `pr show` and `run watch` report the wrong
thing. Both fixes were written against an older git-cli and never landed;
this rebases them onto current master, which has since gained the
progress-aware idle-timeout handling that the original branch predated.

- `pr show` on Gitea sourced from `tea pr list`, whose JSON omits the
  `merged` boolean and `merged_at` timestamp entirely, so a merged PR
  reported merged:false and callers treated it as still open. Fetch the PR
  detail via `tea api repos/{owner}/{repo}/pulls/<n>` instead, mirroring the
  existing run:show/run:list pattern, and derive `state` from `merged` so it
  matches the GitHub path
- Emit `merged_at` on the GitHub path too, so both platforms return the
  same shape
- `run watch` timed out into status:no-workflow on Gitea even when CI ran:
  Gitea leaves head_branch empty on pull_request-triggered runs, so
  `run list --branch` correlates nothing. Resolve the branch head SHA up
  front and fall back to head_sha correlation when the branch-filtered
  lookup comes back empty. GitHub is unaffected — its server-side --branch
  filter populates the first call, so the SHA path is never taken
- Add regression suites for both (6 tests, mock git/tea via PATH injection)
- Bump git-tools 2.2.1 -> 2.2.2 and session 4.5.0 -> 4.5.1 for the
  vendored git-cli

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EddJxaTMXyj7o4ndrqfCxa
Every test that PATH-injects a fake `git` fell through unmatched
subcommands to `command git "$@"`. `command` bypasses functions and
aliases but NOT PATH lookup, and the mock's own directory is prepended to
PATH — so the mock re-executed itself, recursing without bound.

This was latent for as long as the mocks have existed: nothing ever called
git with a subcommand other than `remote get-url origin`. The `run watch`
head-SHA fix in the preceding commit calls `git rev-parse`, which made
every affected suite spawn processes until the terminal's cgroup pids
controller started rejecting forks. Observed at 56,311 processes in one
scope against a pids.max of 114,647, which takes down the whole terminal,
not just the test run.

Delegate to the real git by stripping the mock's own directory from PATH
first, so `exec git` resolves past it:

  *) PATH=${PATH#"${0%/*}":}; exec git "$@" ;;

- Fix all 11 fallbacks across 9 suites
- `exec` rather than a nested call, so the mock does not linger as a parent
- Verified: matched cases still return mock values; unmatched delegate to
  real git and terminate; `git rev-parse origin/<missing>` now returns
  git's own error instead of recursing

tests/test.sh: 32 suites, 0 failed — previously it hung indefinitely.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EddJxaTMXyj7o4ndrqfCxa
Copilot AI lite review requested due to automatic review settings August 29, 2026 21:13
@St0nefish St0nefish self-assigned this Aug 29, 2026
@st0nefish-ci
st0nefish-ci Bot enabled auto-merge August 29, 2026 21:13

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The fixes directly address the reported Gitea defects and are backed by targeted regression tests plus a hardened mock setup to prevent recursive git execution.

Pull request overview

This PR fixes two Gitea-specific correctness bugs in git-cli (PR merge-state reporting and CI run correlation in run watch) and hardens the test harness to prevent recursive git mock execution (fork-bomb) when unmocked subcommands are invoked.

Changes:

  • Fix pr show on Gitea to fetch PR details via tea api .../pulls/<n> and emit consistent merge fields (merged, merged_at, derived state), matching the GitHub path’s semantics.
  • Fix run watch --branch on Gitea by resolving the branch head SHA and falling back to head_sha correlation when branch-based correlation yields no runs.
  • Update git mocks across test suites to safely delegate unmatched subcommands to real git (avoid PATH-based self-recursion), and add Gitea regression tests for both defects.
File summaries
File Description
utils/git-cli Gitea pr show now uses REST detail for reliable merge fields; Gitea run watch gains head-SHA fallback correlation.
tests/session/test-pr-wait.sh Fix git mock fallback to avoid recursive execution when delegating to real git.
tests/session/test-pr-auto-merge-status.sh Fix git mock fallback to avoid recursive execution when delegating to real git.
tests/session/test-ci-poll.sh Fix git mock fallback(s) to avoid recursive execution when delegating to real git.
tests/git-cli/test-run-watch-gitea.sh Add regression coverage for Gitea run watch head-SHA fallback correlation.
tests/git-cli/test-run-show.sh Fix git mock fallback to avoid recursive execution when delegating to real git.
tests/git-cli/test-pr-show-gitea.sh Add regression coverage for Gitea pr show REST merge fields + guard against tea pr list usage.
tests/git-cli/test-pr-create.sh Fix git mock fallback to avoid recursive execution when delegating to real git.
tests/git-cli/test-issue-write-json.sh Fix git mock fallback(s) to avoid recursive execution when delegating to real git.
tests/git-cli/test-body-args.sh Fix git mock fallback to avoid recursive execution when delegating to real git.
plugins-copilot/session/.claude-plugin/plugin.json Bump session plugin version to ship the vendored git-cli fix.
plugins-copilot/git-tools/.claude-plugin/plugin.json Bump git-tools plugin version to ship the vendored git-cli fix.
plugins-claude/session/scripts/git-cli Vendored git-cli copy updated to include the Gitea fixes.
plugins-claude/session/.claude-plugin/plugin.json Bump session plugin version to ship the vendored git-cli fix.
plugins-claude/git-tools/scripts/git-cli Vendored git-cli copy updated to include the Gitea fixes.
plugins-claude/git-tools/.claude-plugin/plugin.json Bump git-tools plugin version to ship the vendored git-cli fix.
Review details
  • Files reviewed: 16/16 changed files
  • Comments generated: 0
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@st0nefish-ci
st0nefish-ci Bot merged commit 912f304 into master Aug 29, 2026
7 checks passed
@st0nefish-ci
st0nefish-ci Bot deleted the fix/gitea-pr-show-and-run-watch-correlation branch August 29, 2026 21:16
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.

git-cli: PR merge-status and run-watch branch correlation unreliable on Gitea

2 participants