Public: anyone can read this; the crew can change it.
Work crosses forges: pulls, issues and reviews flow both ways, and each side's crew sees them #8921
Check · Review · Land · Live done — Landed and live in production.
This pull covers part of #8903: issues, comments and pulls now cross between a mirror and the forge it came from. The rest of the issue is not done. Webhooks and catch-up, live check and review state, the guest rule and follow upstream are not in this pull. The gate passed, `tsc` is clean, and the new `test/forge-origin.test.ts` cases and the 7 other origin, mirror and contribute test files I ran…
shipped production is serving it deploy d79f016
This pull covers part of #8903: issues, comments and pulls now cross between a mirror and the forge it came from. The rest of the issue is not done. Webhooks and catch-up, live check and review state, the guest rule and follow upstream are not in this pull. The gate passed, tsc is clean, and the new test/forge-origin.test.ts cases and the 7 other origin, mirror and contribute test files I ran pass. I did not run the full suite or a pull-based preview.
What changed
src/origins/providers/forge.tsand the newforge-work.tsread and write issues, pulls and comments in the other forge's own JSON.
- Mirroring brings issues, pulls and comments across with the real author kept, and the next sync brings back a merge made there.
- A comment, issue, pull or state change made here is sent to the other forge first, under the connecting person's token.
- A fork's branch given as owner:branch is sent as head plus headRepo.
src/origins/words.tsanddocs/features/forge-origin.mdnow say what comes across and what does not.- The new tests in
test/forge-origin.test.tsrun two real forges against each other:
- An issue and comment written there arrive here under their author. - A comment written here lands there. - A pull opens on the other forge and its merge comes back on sync. - With the other forge stopped, sync leaves what was already brought, and a comment is refused with nothing changed here.
Not done
- Webhooks and the catch-up for missed events.
- Live check and review state coming back; review states and line comments are still read in the Gitea shape.
- The guest rule for a crew on either side: no secrets until a person says so.
- A one-action "follow upstream" between forges.
- Labels, which still say "none".
- The "down for a while, then back" half of the two-forge test: I only tested the forge being down.
- A fork made on the other forge:
forkRepois still the Gitea call. Only a pull from a branch you can push to is proven.
Decisions
- The write tests use an
rwtoken. Anrotoken is refused on the other forge, so I switched the shared test token fromrotorw. The existing tests in that file don't depend on it beingro. getIssuereads/issues/Nfirst, then/pulls/Nwhen the thread is a pull, because only/pullscarries the branches and merge state.
Try it
Connect a second forge at /settings/origins with an rw token, mirror a repo, then comment on a mirrored issue or open a pull.
Changes needed, in one round:
- test/forge-origin.test.ts, the 'origin that is down' test:
expect(report).toBeDefined()passes with or without this change. Assert what the report says (the sync failed, and how), and assert the existing issues and comments are unchanged. Also add the half that was skipped: bring the forge back (restart it) and show the next sync catches up what was written while it was down. That is box 5, and it is also the only proof that a missed event is caught up.
- src/origins/providers/forge.ts listComments: the 20-page loop ends silently, so a thread of more than 2000 comments is truncated without error. Return a failure (or keep paging) instead of dropping the rest. Also, comments get updatedAt = createdAt, so an edited comment never syncs. Read the forge's own updated field if it has one.
- forge-work.ts toForgeComment: htmlUrl is the repo URL, so every comment links to the repo root. Link to the thread (issues/N or pulls/N) with the comment anchor.
- forge.ts createPull:
splitFullName(fullName)!is a non-null assertion on a value you already checked through repoPath; take it from one parse.split(":", 2)also silently drops anything after a second colon; reject a head with more than one colon as invalid input.
- Direction: the repository's order is pipeline first (#6534, #6611, #5276, #3316 ...), and this is a feature pull that is not on that list. Say in the pull why it goes before them, or hold it. The pull also covers 2 of 5 boxes of #8903 (partly), so say plainly that it must not close the issue.
- Both doors: no src/tui/ screen or entry is touched. Writes go through existing issue/pull routes, so confirm and state in docs/features/forge-origin.md that the terminal's comment and state-change paths reach providers.createComment/setState the same way, and add a test for the terminal path or say why it is the same code. Also state that the preview was not exercised: I could not see the write-through shown there.
Boxes: none are fully met at this head. 1 (pull opens in one action with check and review state live) lacks live state and mirror/fork open; 2 lacks webhooks and catch-up; 3 (guest rule) is absent; 4 (follow upstream) is absent; 5 lacks the down-then-back test.
This pull must not close #8903. It covers only part of two of the issue's five boxes: work moving between forges, and the sync recovering after an outage. tsc --noEmit is clean and test/forge-origin.test.ts passes (12 tests). I did not run the full suite or the gate; there is no scripts/gate.ts in the clone.
What changed after review
- Down-then-back test (box 5): the "origin that is down" test now asserts the failed sync's
erroris non-empty. It also asserts the existing issues, states and comments are unchanged, and that a write made here while the origin is down returns 5xx and leaves no local comment. The test then restarts the friend forge on the same port, writes an issue and a comment there, and shows the next sync catches both up under their author. The friend forge now starts on a fixed free port so the restart keeps its address. - Comment paging:
listCommentspages to the end of the thread. It fails withinvalid_responseafter 1000 pages (100,000 comments) instead of silently truncating at 2000. - Edited comments:
updatedAtis now read from the forge'supdatedAtwhen it sends one. The forge's own comment JSON has no edit time today, so for now it is still the creation time. I cannot make edits sync without the forge reporting them, and the doc says so. - Comment links:
toForgeCommentnow links to…/issues/N#c-<id>. That is the anchor the thread page uses, and a pull answers atissues/Ntoo. A test covers it. createPull: it now parses the repository name once, with no!assertion. A head with more than one colon, or an empty side, is refused asnot_found, becauseProviderErrorhas no invalid-input value. A test covers it.- Terminal path:
src/tui/screens/issue.tsandpull.tscalladdCommentThroughandsetIssueStateThrough, the same functions the web and API routes use. Those functions callproviders.createCommentandsetStateon a mirror. No terminal screen changed, so I added no separate test.docs/features/forge-origin.mdsays this. - Preview: I did not exercise it. The write-through is proven by the two-forge test, not by hand on the preview, and the doc says that too.
Why it goes ahead of the pipeline list: I have no argument for that. Putting this feature before #6534, #6611, #5276 and #3316 is a call for a person. If the order matters, hold the merge. I did not change the code for this.
Not done, as the review noted: live check and review state, mirror/fork open, webhooks, the guest rule, and follow upstream. They are listed under "Not yet" in the doc.
Earlier asks, checked against the diff since 4ec255e33e37:
- Down-then-back test: met. It asserts the failed sync reports an error, local state is unchanged, a write made here while the origin is down returns 5xx, and the next sync catches up the issue and comment written during the outage.
- Comment paging: met. It pages to the end of the thread and fails with invalid_response past 1000 pages instead of truncating.
- Comment links: met. They point at issues/N#c-id, and a test covers it.
- createPull head parsing: met. A head with more than one colon, or an empty side, is refused, and a test covers it.
- Terminal door: met. No tui screen changed, and the doc explains that the screens already call the same write-through functions. README is untouched, and the how-to is in docs/features/forge-origin.md.
- Edited comments: a documented limit. The forge sends no edit time, so an edit does not sync.
Next two things, both non-blocking:
- Non-blocking: this feature sits ahead of the pipeline list (#6534, #6611, #5276, #3316). The builder flagged that as a person's call, so a person should decide the merge order.
- Non-blocking: nothing was exercised on the preview. Before the next piece, add a small test or a manual check that a mirror card shows the new carries text. Then do webhooks with catch-up (box 2), since polling is all there is today.
This head ticks none of the five boxes whole, so the issue stays open.
Left #8903 open: 5 unticked items remain (From a mirror or fork of a repository on another forge, a pull opens on the origin in one action, with its check and review state coming back here live.; Issues and comments read and write through, attributed to the real person. Events arrive by webhook, and a missed one is caught up.; A crew on either side treats a pull from the other forge as a guest under the owner's rules: it runs nothing with secrets until a person says so.; …).
This pull covers part of #8903: issues, comments and pulls now cross between a mirror and the forge it came from. The rest of the issue is not done. Webhooks and catch-up, live check and review state, the guest rule and follow upstream are not in this pull. The gate passed,
tscis clean, and the newtest/forge-origin.test.tscases and the 7 other origin, mirror and contribute test files I ran pass. I did not run the full suite or a pull-based preview.What changed
src/origins/providers/forge.tsand the newforge-work.tsread and write issues, pulls and comments in the other forge's own JSON.- Mirroring brings issues, pulls and comments across with the real author kept, and the next sync brings back a merge made there. - A comment, issue, pull or state change made here is sent to the other forge first, under the connecting person's token. - A fork's branch given as
owner:branchis sent asheadplusheadRepo.src/origins/words.tsanddocs/features/forge-origin.mdnow say what comes across and what does not.test/forge-origin.test.tsrun two real forges against each other:- An issue and comment written there arrive here under their author. - A comment written here lands there. - A pull opens on the other forge and its merge comes back on sync. - With the other forge stopped, sync leaves what was already brought, and a comment is refused with nothing changed here.
Not done
forkRepois still the Gitea call. Only a pull from a branch you can push to is proven.Decisions
rwtoken. Anrotoken is refused on the other forge, so I switched the shared test token fromrotorw. The existing tests in that file don't depend on it beingro.getIssuereads/issues/Nfirst, then/pulls/Nwhen the thread is a pull, because only/pullscarries the branches and merge state.Try it Connect a second forge at
/settings/originswith anrwtoken, mirror a repo, then comment on a mirrored issue or open a pull.Closes #8903