Skip to content

bridge: add todo.sr.ht (SourceHut) bridge - #1499

Open
mcepl wants to merge 15 commits into
git-bug:trunkfrom
openSUSE-Python:todosrht
Open

mcepl wants to merge 15 commits into
git-bug:trunkfrom
openSUSE-Python:todosrht

Conversation

@mcepl

@mcepl mcepl commented Nov 29, 2025 •

Copy link
Copy Markdown
Contributor

Adds a bridge for SourceHut's issue tracker, todo.sr.ht, using its GraphQL API. The first version was written with heavy AI assistance. I have since reviewed it, fixed what review and live testing found, and tested it against a real tracker. Reviews from people who know Go and the git-bug internals better than I do are very welcome.

Fixes: #1024

What it does

  • git bug bridge new --target=todosrht --url=https://todo.sr.ht/~owner/tracker --login=USER configures the bridge. It verifies the token by looking up the tracker.
  • Pull imports tickets with their comments, status changes and label changes. Assignment and mention events become warnings, because git-bug has no equivalent.
  • Push creates tickets and exports comments, status changes, title and body edits, and label changes. Missing labels are created on the tracker. Edits to comments other than the ticket body are skipped, because the API cannot edit them.
  • Both directions are idempotent. Operation metadata records SourceHut IDs, so repeated syncs do not duplicate events. Pulling a ticket that was first pushed from git-bug reuses the existing local bug.

Commits

  1. test(repository): makes the mock repository storage safe for concurrent access.
  2. bridge/todosrht: vendors the todo.sr.ht GraphQL schema (schema.graphqls). Tests validate every query and mutation against it.
  3. bridge/todosrht: adds the GraphQL client.
  4. bridge/todosrht: adds configuration, import, export and bridge registration.
  5. test(bridge/todosrht): adds mock-based tests, schema validation, and HTTP tests for request paths and redirects.
  6. docs: adds the usage guide, command help, man pages and the design notes.

Security

  • Base URLs must use HTTPS. Plain HTTP is allowed only for loopback hosts, for local testing.
  • The client refuses cross-origin redirects, so the bearer token is never re-sent to another host.
  • GIT_BUG_DEBUG=1 dumps requests and responses with the token redacted, and truncates response bodies.
  • Response size is capped at 32 MiB.

Testing

  • go test ./... passes.
  • I tested it live against https://todo.sr.ht/~mcepl/git-bug-bridge-testing. That covered configuration, import of a ticket created on SourceHut, and export of a new bug, a comment, adding and removing a label, and closing the ticket. I also imported a comment added with hut. Repeated pulls and pushes made no further changes, and hut confirmed the ticket state.

Known limitations

  • The live test did not cover title or body edits, reopening, or a tracker owned by someone other than the token holder.
  • A SourceHut personal access token cannot be restricted to one tracker. The documented grant (todo.sr.ht/PROFILE:RO todo.sr.ht/EVENTS:RO todo.sr.ht/TRACKERS:RW todo.sr.ht/TICKETS:RW) reaches every tracker the account can access.
  • Push ignores since and scans all local bugs. Metadata prevents duplicate exports, but push time grows with the number of bugs.
  • Queries for an owner-qualified tracker (~owner/name) are built by rewriting the me { ... } query templates. Schema tests cover the result, but separate templates would be clearer.
  • TrackerExists now only wraps GetTracker, and client_test.go tests only the mock client. Both could be removed.

RetriggerView in GreptileConfidence Score: 5/5

The latest changes appear safe to merge, with all five numbered previous findings addressed.

Summary

Adds a SourceHut bridge with configuration, GraphQL requests, ticket import/export, and usage guides.

  • git-bug pulls SourceHut tickets and pushes local changes.
  • The bridge connects to a chosen SourceHut tracker with server-specific credentials.
  • Mock repository storage stays safe during concurrent tests.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  A[SourceHut tracker] -->|Pull tickets and events| B[Local bugs]
  B -->|Push pending operations| A
  B --> C[Saved IDs and remote content]
  C -->|Skip completed work| B
  C -->|Protect pending local edits| B
Loading

Reviews (9) · Last reviewed commit: "bridge/todosrht: preserve sync ordering ..." · Reviewed by Greptile

@mcepl
mcepl marked this pull request as draft November 29, 2025 23:28
@mcepl
mcepl force-pushed the todosrht branch 9 times, most recently from 8c0d156 to e76ef40 Compare December 5, 2025 00:07
@sudoforge sudoforge mentioned this pull request Dec 6, 2025
@mcepl
mcepl force-pushed the todosrht branch 2 times, most recently from 032a598 to 45b5005 Compare January 28, 2026 00:15
@jimdigriz

Copy link
Copy Markdown

I seem to be unable to get this code to work.

git bug bridge push default reports:

exported 0 issues with default bridge

git bug bridge pull default reports:

import error on entity 60a687b649533bf0e0511d8f3573a062370fe2cf277f02425add5e4dbee4323f: failed to get events for ticket 1: failed to fetch events: GraphQL request failed with status 422: 422 Unprocessable Entity
imported 0 issues and 0 identities with default bridge

@mcepl
mcepl force-pushed the todosrht branch 2 times, most recently from 8a1bebe to 0d216d6 Compare September 13, 2026 20:53
@mcepl

mcepl commented Sep 13, 2026

Copy link
Copy Markdown
Contributor Author

Still broken? I have rebased this branch on the top of trunk.

Otherwise, I really don’t want to work on this PR any more. Given the sharp anti-AI stance of SourceHut, I am moving elsewhere. Anybody, feel free, to take this PR over.

@mcepl
mcepl force-pushed the todosrht branch 2 times, most recently from d146faa to beae5b8 Compare September 24, 2026 09:29
@mcepl
mcepl force-pushed the todosrht branch 2 times, most recently from 6ca8f2d to d656db0 Compare October 4, 2026 21:48
@mcepl mcepl changed the title feat(bridge): add SourceHut todo bridge implementation bridge: add todo.sr.ht (SourceHut) bridge Oct 4, 2026
@mcepl
mcepl marked this pull request as ready for review October 4, 2026 21:52
Comment thread bridge/todosrht/export.go Outdated
Comment thread bridge/todosrht/import.go Outdated
Comment thread bridge/todosrht/import.go
Comment thread bridge/todosrht/client.go Outdated
Comment thread bridge/todosrht/client.go
Comment thread bridge/todosrht/config.go
Comment thread bridge/todosrht/import.go Outdated
Comment thread bridge/todosrht/import.go Outdated
Comment thread doc/usage/todosrht.md Outdated
Comment thread doc/design/todosrht-implementation-plan.md Outdated
Comment thread bridge/todosrht/export.go Outdated
Comment thread bridge/todosrht/import.go Outdated
Comment thread bridge/todosrht/import.go
Comment thread bridge/todosrht/import.go Outdated
Comment thread bridge/todosrht/export.go Outdated
Comment thread bridge/todosrht/import.go Outdated
@jimdigriz

Copy link
Copy Markdown

As a SourceHut user looking to move from GitHub, I see here:

When I flagged this code did not work I had already tried rebasing before you did so yourself and recommend I retry. That sort of hints you do not use this code day-to-day and had not tried your rebasing effort which makes me somewhat twitchy about using it.

What do you recommend SourceHut users do here? Besides I suspect that community is unlikely to receive well a majority LLM written bridge :)

For me, I am going to write my own bridge.

@mcepl

mcepl commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor Author

As a SourceHut user looking to move from GitHub, I see here:
What do you recommend SourceHut users do here? Besides I suspect that community is unlikely to receive well a majority LLM written bridge :)

For me, I am going to write my own bridge.

Yes, I am leaving Sourcehut (partially because of their LLM policy, but mostly because my users just seem to irrationally hate email and I have much better feedback on web-based forge; and of course, there are other reasons as well), and yes I expect to really use daily Gitea/Forgejo so #1628 is much more relevant to me. Mostly, I wanted to make this as a kind of farewell letter to Sourcehut, and I hate to leave an unfinished business behind.

Concerning the quality of coding: I am not a native Golang programmer, so I cannot really evaluate how good the best models are writing it, but with Python (and C to some extent), which are languages are used every day for my work, it seems to me that the latest models (Opus 5.5 and ChatGPT 5+ ones) are on the same level or better than what I could write by hand, much much better than they were just a year ago when I started to write this PR.

What should Sourcehut users do? Well, I would hope they could take this branch, and take it further and maintain it. I believe that there is a lot of work and testing I did (completely manually, it is a way more than me blindly pressing Enter to pi), which is better that it is done rather than not. Writing it all over again just because you write it seems like an unnecessary exercise in time-wasting. But, of course, it is your time and you can do whatever you want to do with it, and it is mainly @MichaelMure ’s project and it is his decision what to do with git-bug.

Comment thread bridge/todosrht/config.go
Comment thread bridge/todosrht/export.go Outdated
Comment thread bridge/todosrht/import.go Outdated
Comment thread bridge/todosrht/export.go Outdated
Comment thread bridge/todosrht/remote_state.go
Comment thread bridge/todosrht/export.go
mcepl added 14 commits October 23, 2026 00:04
Add a Billy-backed test storage implementation and protect mock repository state against concurrent access. Keep test infrastructure separate from the new bridge so reviewers can assess the storage change independently.
Record the API schema beside the bridge so client queries, mutations, and response types can be reviewed against the service contract without relying on an external copy.
Add authenticated HTTP transport, GraphQL request and response types, pagination queries, and ticket, event, and label mutations. Keep the protocol client separate from bridge synchronization and configuration.
Register the bridge, resolve tracker credentials, import remote tickets and events, and export local operations. Combine the mutually dependent importer and exporter so the bridge can compile as one implementation commit.
Provide mock GraphQL methods and tests for the client, configuration, debug transport, importer, and exporter. Fold compilation repairs into the tests rather than leaving later fixes to earlier test commits.
Document tracker URL, login, token, and bridge usage in help and reference pages. Include the design plan with the user-facing guide.
… handling

Address feedback from code review on the todo.sr.ht bridge:

- Require verified tracker and base URL metadata before accepting
  creation metadata ticket IDs on export, preventing operations on
  unverified bugs from modifying tickets on the configured tracker.
- Track imported event operations with change-level IDs to prevent
  ErrMultipleMatch on repeat pulls of events containing multiple changes.
- Reconcile remote edits to ticket title and body during import when
  reusing existing bugs.
- Support explicit null body in UpdateTicketInput to allow clearing
  ticket descriptions on SourceHut without losing edits.
- Make label export idempotent by checking remote ticket labels before
  adding or removing them.
- Ensure credentials added without base URL metadata can be used to
  initialize the bridge, and tag selected credentials with base URL.
- Isolate user identities by instance base URL to avoid collisions
  across multiple SourceHut instances.
- Align ValidParams and error messages with the --project flag.
- Establish chronological order for imported events across pages.
- Silence repetitive warnings for unsupported assignment and mention events.
- Surface server GraphQL error details on non-200 HTTP responses and clean
  unused variables when querying the authenticated user.
- Document label color limitations and replace the obsolete roadmap
  in the design documentation.
Scope ticket queries, tracker mappings and credentials to their owner and instance. Preserve pending local edits, record remote content checkpoints, and stop import/export from replaying state changes out of order. Keep ambiguous comments separate and avoid attributing unknown editors to ticket submitters. Add regression coverage and regenerate the add-token documentation.
Compare checkpoints, remote content and local snapshots in the same cleaned form, including legacy baselines. Skip unsupported ordinary-comment edits before credential lookup, while preserving the ordered stop for supported changes. Add regressions for false conflicts, continued event import and credential-free skips.
Pass the command context through configuration, identity and bug
resolution, commits, export metadata, and remote-state
checkpoints. Configuration now uses the same context for
authenticated requests instead of a placeholder context, so
cancellation reaches those requests.

Update regression tests for the context-aware cache API. Commit
created bugs before resolving or exporting them, and persist the
initial imported issue before testing a later remote edit. Trunk
no longer commits bug creation implicitly, so these fixtures
otherwise test empty repositories rather than synchronization.

Refs: git-bug#1499
Comment thread bridge/todosrht/export.go Outdated
Comment thread bridge/todosrht/import.go
Comment thread commands/bridge/bridge_auth_addtoken.go
Comment thread bridge/todosrht/import.go Outdated
Comment thread bridge/todosrht/client.go
Record every label mutation event as it succeeds, including
partial exports, so a later pull cannot replay earlier additions
over an exported removal. Persist event markers before attempting
the next mutation and test the add/add/remove sequence across a
failed request and retry.

Mark pending title and body edits as superseded when
reconciliation accepts a newer remote value. This prevents
whitespace-only edits and edit/revert sequences from overwriting
that remote value on the next push.

Reject assigning an already-mapped SourceHut server/login pair to
a second local identity before changing metadata or storing its
token. Unsupported event markers now use a synchronization
identity, allowing pulls without a current local user to continue
past warnings.

Restore the HTTP redirect hop limit alongside the cross-origin
token protection. Add regression tests for each reported failure,
including repeat imports, credential-side-effect checks, and
same-origin redirect loops.

Refs: git-bug#1499

This branch has not been deployed

No deployments
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.

Sourcehut Support

2 participants