Skip to content

feat(bin): add Gitea/Forgejo forge support for PR watch and merge - #3068

Open
chewbakartik wants to merge 14 commits into
kunchenguid:mainfrom
chewbakartik:fm/forgejo-forge-support
Open

feat(bin): add Gitea/Forgejo forge support for PR watch and merge#3068
chewbakartik wants to merge 14 commits into
kunchenguid:mainfrom
chewbakartik:fm/forgejo-forge-support

Conversation

@chewbakartik

@chewbakartik chewbakartik commented Aug 25, 2026

Copy link
Copy Markdown

Intent

Fix Greptile review findings 1 and 2 on the Gitea/Forgejo forge-support pull request #3068 in kunchenguid/firstmate (fork chewbakartik/firstmate, head branch fm/forgejo-forge-support), which blocked the Greptile Review check at 4/5 confidence. The change normalizes the tea login-vs-record endpoint comparison in both bin/fm-pr-merge.sh and the standalone byte-pinned bin/fm-pr-poll.sh: a login configured with its scheme's default port (https :443, http :80) now matches the validated portless PR URL that names the same endpoint, while any non-default port stays significant and never matches; the host is lowercased on both sides. The login-selection section of docs/forge-merge-watch.md is updated to describe endpoint identity, and regression tests cover a default-ported login matching in both the merge suite and the poll security suite. Greptile findings 3 through 7 (foreign --remote override rejection and the closed-list pagination walk) are already fixed in the base head 8f799af and were deliberately left untouched here. The pipeline must push only to the fork branch chewbakartik/firstmate:fm/forgejo-forge-support as a clean fast-forward and attach to the existing open PR #3068; it must not open a new pull request.

What Changed

  • bin/fm-pr-lib.sh parses https://<host>/<owner>/<repo>/pulls/<n> URLs into a new gitea provider identity (host validated with GitLab's arbitrary self-hosted-host rule, owner/repo with GitHub's fixed shape), and bin/fm-pr-check.sh refuses to arm a watch when tea is not on PATH.
  • bin/fm-pr-poll.sh (byte-static watcher) and bin/fm-pr-merge.sh read/merge Gitea/Forgejo pull requests through tea: the poll walks tea pulls list --state closed pages to find the recorded index, and the merge path resolves the one tea login whose endpoint matches the parsed host, calling tea pulls merge with --style squash by default. Both compare login endpoint to the validated host using endpoint identity — a login on its scheme's default port (https :443, http :80) matches the portless URL naming that endpoint, any non-default port stays distinct, and the host is lowercased on both sides.
  • bin/fm-pr-merge.sh extends its override rejection to --login/--remote (and, on Gitea/Forgejo only, the -r/-l short forms tea maps to --repo/--login) so the repository and login always come from the validated URL, not caller-supplied flags.
  • Renamed docs/gitlab-merge-watch.md to docs/forge-merge-watch.md, expanded to cover GitHub, GitLab, and Gitea/Forgejo (including the login endpoint-identity/default-port normalization), and updated README.md, docs/architecture.md, docs/scripts.md, and docs/documentation-audiences.json to match.
  • Added Gitea/Forgejo regression coverage to tests/fm-pr-check-security.test.sh and tests/fm-pr-merge.test.sh, including cases where a default-ported login matches a portless recorded URL.

Risk Assessment

✅ Low: The scoped fix (bin/fm-pr-merge.sh, bin/fm-pr-poll.sh, docs, tests) correctly implements endpoint-identity normalization — traced through default-port (443/80), non-default-port, and case-mismatch cases in both the extracted gitea_endpoint_identity helper and the standalone poll script's duplicated inline logic, both strip only an exact trailing ":443"/":80" suffix tied to the matching scheme so a non-default port is never falsely collapsed; the new tests exercise real behavior (poll/merge output) rather than source text, and the rest of the branch diff corresponds to already-decided or explicitly out-of-scope prior-round work (pagination budget removal, --remote rejection) per the recorded decisions and user intent.

Testing

The fix normalizes tea login-vs-record endpoint comparison (stripping default ports https:443/http:80, lowercasing host) in both bin/fm-pr-merge.sh and bin/fm-pr-poll.sh. Its own added regression tests (one in tests/fm-pr-merge.test.sh, one in tests/fm-pr-check-security.test.sh) exercise exactly the CLI-facing behavior end-to-end — a default-ported tea login now resolves and drives a real merge (tea pulls merge invoked, pr= recorded) and a real poll match (poll reports 'merged') for a portless PR URL. Ran the full merge test file (44/44 pass) and, since the full 200KB security suite exceeded a reasonable local runtime, ran a targeted invocation of just its two relevant cases (both pass). To rule out these being trivially-passing tests, I checked out the pre-fix versions of both scripts and reran the same two new tests: both failed with the exact symptom the intent describes (default-ported login rejected/ambiguous), proving the tests are real regression coverage, then restored the fixed scripts leaving the worktree clean. No test or environment issues found; no findings to report.

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

🔧 **Rebase** - 3 issues found → auto-fixed ✅
  • ⚠️ bin/fm-pr-merge.sh - merge conflict rebasing onto origin/main
  • ⚠️ docs/architecture.md - merge conflict rebasing onto origin/main
  • ⚠️ tests/fm-pr-merge.test.sh - merge conflict rebasing onto origin/main

🔧 Fix applied.
✅ Re-checked - no issues remain.

✅ **Review** - passed

✅ No issues found.

✅ **Test** - passed

✅ No issues found.

  • bash tests/fm-pr-merge.test.sh (all 44 cases pass, including new test_gitea_default_port_login_matches)
  • Focused re-run of tests/fm-pr-check-security.test.sh restricted to test_gitea_login_port_mismatch and test_gitea_default_port_login_matches (both pass)
  • Regression proof: swapped bin/fm-pr-merge.sh and bin/fm-pr-poll.sh back to the pre-fix parent commit (12bfaef) content and re-ran the two new tests — both failed as expected ('did not match a login configured with its https default port' / 'could not resolve exactly one tea login for forge.example'), then restored the fixed scripts and confirmed a clean worktree
✅ **Document** - passed

✅ No issues found.

🔧 **Lint** - 1 issue found → auto-fixed (2) ✅
  • ⚠️ linter found issues (exit code 1)

🔧 Fix: {"summary": "no code lint fixes needed; install actionlint to unblock lint check"}
1 warning still open:

  • ⚠️ linter found issues (exit code 1)

🔧 Fix: Install actionlint to $HOME/.local/bin to unblock lint check
✅ Re-checked - no issues remain.

✅ **Push** - passed

✅ No issues found.

@greptile-apps

greptile-apps Bot commented Aug 25, 2026

Copy link
Copy Markdown

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Reviews (10): Last reviewed commit: "no-mistakes: apply CI fixes" | Re-trigger Greptile

Comment thread bin/fm-pr-merge.sh Outdated
Comment thread bin/fm-pr-poll.sh Outdated
Comment thread bin/fm-pr-poll.sh Outdated
Comment thread bin/fm-pr-poll.sh Outdated
Comment thread bin/fm-pr-merge.sh
@chewbakartik chewbakartik changed the title feat(pr): add Gitea/Forgejo as a fully-supported forge feat(bin): add Gitea/Forgejo pull request support to forge merge/watch scripts Aug 25, 2026
Comment thread bin/fm-pr-poll.sh
Comment thread bin/fm-pr-merge.sh Outdated
Comment thread bin/fm-pr-merge.sh Outdated
@kunchenguid

Copy link
Copy Markdown
Owner

Speaking as Kun's firstmate:

Full diff reviewed at 8f799af5ed10d5a137bd1ba9a57523b1e37834b5 against main 9a01dea3995c7f80ff4890d6f77142bba32d4ba3. Class: opt-in. Fork workflows for this HEAD are approved.

Not merge-ready:

  • the current login/URL model rejects valid explicitly-default-port endpoints such as https://host:443/... (the URL parser cannot carry a port, while login matching preserves it), so valid Gitea/Forgejo configurations cannot poll or merge;
  • no matching no-mistakes-pipeline-attestation:v1 exists for this HEAD;
  • repository CI is only now starting after workflow approval.

Overlap check: #3044 currently implements fleet-wide GitHub conflict detection, not Gitea merge/watch, but it also changes bin/fm-pr-lib.sh, related tests, and docs in a very large moving branch. This PR remains on the standing overlap hold so the two branches are not landed blindly.

The correctness and attestation blockers are waiting on the author. The overlap hold is a captain/maintainer integration decision and is not waiting on the author.

Extends the PR watch-and-merge pipeline with a third provider, tagged
"gitea", at parity with GitHub: URL recognition for the
https://<host>/<owner>/<repo>/pulls/<n> shape, merge-poll status via tea,
and autonomous merge via tea pulls merge. Forgejo is a protocol-compatible
fork of Gitea and shares the tea CLI, so one implementation covers both;
tea is used over Forgejo's own fj CLI per the captain's own manual testing.
GitLab remains watch-only, unchanged, since no owner/repository pair can
address its arbitrary-depth namespace.

tea addresses a self-hosted instance through a configured login rather
than through the URL, so both the poll and the merge path resolve the
login whose own host matches the validated record's host, refusing
silently (poll) or loudly (merge) on any ambiguity or absence. tea has no
head-commit field in any output format, so a Gitea/Forgejo task records no
pr_head=, mirroring GitLab's existing precedent.

Renames docs/gitlab-merge-watch.md to docs/forge-merge-watch.md, keeping
the GitLab evidence intact and adding a Gitea/Forgejo section built from
read-only verification against a real self-hosted instance; no live
arm-and-merge cycle against a real pull request was exercised, so the
captain should smoke-test that path before relying on it unattended.
The autonomous merge path has since been smoke-tested live against a
real Gitea/Forgejo pull request and passed on the first attempt with
no code changes required; update the disclosure to reflect that.
caller_has_github_merge_method only matched the long-form
--squash/--merge/--rebase/--method flags, so a caller-supplied -r
(gh's own --rebase shorthand) was not recognized as an explicit
merge method: fm-pr-merge.sh still added the default --squash,
producing a command with both --squash and -r, which gh rejects as
conflicting methods. Recognize -m/-r/-s alongside the long forms, and
correct the existing regression test's expected invocation.
Greptile findings 1 and 2 on PR kunchenguid#3068 are two sides of one
normalization. The login-vs-record comparison kept every port, so a
login configured with its scheme's default port (https://...:443,
http://...:80) could never match the validated portless record that
names the same endpoint, so merging or watching a PR on such a login
silently refused.

Endpoint identity now strips the scheme's default port (https :443,
http :80) from both sides of the comparison and lowercases the host,
while any other port is kept, which is the guarantee finding 1
requires: a validated Gitea/Forgejo PR URL never carries a port and
names the default-port endpoint, a default-ported login is that same
endpoint, and a non-default-ported login names a different endpoint
and never matches.

Both copies of the contract change: bin/fm-pr-merge.sh (the merge
path, through gitea_endpoint_identity) and bin/fm-pr-poll.sh (the
standalone poll's inline matching, which cannot source shared code).
The login-selection section of docs/forge-merge-watch.md is updated
to describe endpoint identity, and regression tests cover a
default-ported login matching in both the merge suite and the poll
security suite.
@chewbakartik
chewbakartik force-pushed the fm/forgejo-forge-support branch from 8f799af to 52cada3 Compare August 27, 2026 11:02
@chewbakartik chewbakartik changed the title feat(bin): add Gitea/Forgejo pull request support to forge merge/watch scripts feat(bin): add Gitea/Forgejo forge support for PR watch and merge Aug 27, 2026
Comment thread bin/fm-pr-merge.sh
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.

2 participants