Skip to content

[TASK] Document Forgejo and Gitea webhook support - #526

Draft
CybotTM wants to merge 1 commit into
TYPO3-Documentation:mainfrom
CybotTM:feat/document-forgejo-webhook
Draft

[TASK] Document Forgejo and Gitea webhook support#526
CybotTM wants to merge 1 commit into
TYPO3-Documentation:mainfrom
CybotTM:feat/document-forgejo-webhook

Conversation

@CybotTM

@CybotTM CybotTM commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Draft — do not merge yet. This documents behaviour that is not deployed. It depends on TYPO3GmbH/site-intercept#305, which adds Forgejo/Gitea support to the documentation hook. Please merge this only once that change is released, otherwise this page promises something that still fails in production. I will mark it ready for review then.

Why

The Webhook page currently lists GitHub, Bitbucket and GitLab as the supported hosts, and the "Foreign setups" section tells everyone else to create a mirror on a supported platform. That is what a Forgejo user ran into on Slack, which led to TYPO3GmbH/site-intercept#304 and then to the implementation in TYPO3GmbH/site-intercept#305.

What changed

  • Webhook.rst — new "Forgejo and Gitea" setup section next to the existing ones, the host list in the intro extended, and the "Foreign setups" paragraph rewritten. It also states that self-hosted instances work on any domain, with the domain approved once together with the repository.
  • WritingDocForExtension/Index.rst, FAQ.rst, RenderingDocs/Index.rst — three enumerations that named the hosts individually now link to the webhook page instead, so the list lives in exactly one place. The one in the rendering chapter was already incomplete before this change: it named only GitHub and GitLab and omitted Bitbucket.

Two things worth a maintainer's opinion

No screenshots. Every sibling section has a figure per step under Documentation/_Images/webhook/<host>/; the new section is text only, because I have no Forgejo instance to capture them from. Happy to add them if someone supplies the images — the original reporter runs an instance and may be willing.

The note about "Test Delivery". Forgejo has no ping event; its Test Delivery button sends a synthetic push whose commit lists no changed files, so intercept accepts it and answers "no documentation changes" without rendering anything. The button therefore reports success while nothing happens, which is confusing enough to warrant the note. This is from Forgejo's source (routers/web/repo/setting/webhook.go), not from an assumption.

Verification

make test-docs renders cleanly: 92 files, no warnings or errors. Both new cross-references resolve to real links in the rendered output. I compared the render against the unmodified branch to confirm this change adds no new unresolved references.

Intercept gained support for Forgejo and Gitea push webhooks, so those
hosts no longer need a mirror on another platform. Self-hosted instances
work on any domain, the domain is approved once by the Documentation
Team along with the repository.

Add a setup section for them next to the existing ones, extend the list
of supported hosts and rewrite the "Foreign setups" paragraph, which
until now told those users to build a mirror.

Two enumerations elsewhere named the supported hosts individually and
would have gone stale again with the next host. They now link to the
webhook page instead. One of them, in the rendering chapter, was
already incomplete, it omitted Bitbucket.

The new section has no screenshots yet, unlike its siblings.

Signed-off-by: Sebastian Mendel <github@sebastianmendel.de>
andreaskienast pushed a commit to TYPO3GmbH/site-intercept that referenced this pull request Aug 22, 2026
…305)

Fixes #304

Forgejo and Gitea send `X-GitHub-Event` as a compatibility header
alongside their own, so their pushes were handled as Github pushes and
the composer.json was looked up on `raw.githubusercontent.com`. For the
repository in the issue that is a 404 where
`git.codemacher.de/…/raw/branch/main/composer.json` returns 200.

This routes their push events before the Github check and resolves the
composer.json against `repository.html_url`, so instances on any domain
work.

**Two things touch the shared Github path, please look at these:** a
body that is valid json but not an object now returns 422 instead of
raising a `TypeError` (500), and a truncated commit list now renders
instead of being dropped as "no documentation changes". Both are
explained below.

`t3g:test` (192 tests), `t3g:phpstan`, `t3g:cgl`, `npm ci` and `npm run
build` pass. The functional suite needs the private
`t3g/lib-test-helper` and could not be run here.

Documentation follow-up, held as a draft until this is released:
TYPO3-Documentation/TYPO3CMS-Guide-HowToDocument#526

---

<details>
<summary><b>Details</b> — verification against a real instance, the two
behaviour changes, known limitations, and how to reproduce</summary>

### Verified against a real Forgejo instance

Not only against the source: I ran Forgejo 12.0.4 locally, pointed a
webhook at a recorder and replayed the captured deliveries through the
actual `WebHookService`.

| push | what the delivery contains |
|---|---|
| branch with a `Documentation/` change | `X-Forgejo-Event`,
`X-GitHub-Event`, `X-Gitea-Event`, `X-Gogs-Event` all `push` |
| tag | `ref: refs/tags/…`, `commits: []` |
| tag deletion | regular push, `after` = 40 zeros, **no `deleted`
property** |
| branch deletion | no push event at all, only a `delete` event |
| 20 commits | **`commits: 15`, `total_commits: 20`** |

Replaying those captures against `develop` shows what users get today:
every url points at `raw.githubusercontent.com`, the tag deletion is
accepted as a render trigger, and the 20-commit push is dropped. With
this branch the urls point at the instance and resolve
(`/raw/branch/main/composer.json` and `/raw/tag/2.0.0/composer.json`
both 200). The fixtures here were checked field by field against those
real payloads — that is what added the missing `head_commit` and
corrected `compare_url` on the deleted-tag fixture.

To reproduce, no Forgejo account needed:

```bash
docker run -d --name fj --network host \
  -e FORGEJO__security__INSTALL_LOCK=true \
  -e FORGEJO__server__ROOT_URL=http://localhost:3000/ \
  -e FORGEJO__webhook__ALLOWED_HOST_LIST='*' \
  -e FORGEJO__database__DB_TYPE=sqlite3 codeberg.org/forgejo/forgejo:12
docker exec -u git fj forgejo admin user create --username tester \
  --password 'TestPass123!' --email t@example.com --admin --must-change-password=false
```

Then create a repository, point a `push` webhook at any request bin, and
push. I deliberately did not add this as an automated test: the project
has no container in its test path at all — the functional suite runs
against file-based SQLite and the CI workflow has no `services:` section
— so adding one for a single provider would be infrastructure out of
proportion to the change.

### The two changes on the shared Github path

**Non-object json body.** The shared payload handling is typed, so
without a guard a body like `123` raises a `TypeError` and answers 500
where it used to answer 422. It is now rejected as an unsupported
request. On `develop` this was `InvalidWebHookPayloadException` /
`HOOK_INVALID_PAYLOAD`; it is now `UnsupportedWebHookRequestException` /
`UNSUPPORTED_HOOK`, same http status. Say the word if you would rather
keep the old classification.

**Truncated commit list.** Senders cap the list — Forgejo at 15, Gitea
at 5 — while `total_commits` keeps the real number, so a documentation
change in a dropped commit would never render and could not be
recovered. A truncated list therefore no longer counts as "nothing to
render". Github payloads carry no `total_commits` and are unaffected.

I verified every other existing path is byte-identical to `develop` by
running a payload matrix (Github
branch/tag/rst/form-encoded/ping/broken-json/malformed-commits, GitLab,
both Bitbucket variants) against both revisions and diffing.

### Known limitations, so they are not mistaken for oversights

Deleting a *branch* on Forgejo sends no push event, only a `delete`
event, which falls through to `UNSUPPORTED_HOOK` (422) rather than the
`BRANCH_DELETED` (404) a Github deletion produces.

`RepositoryUrlUtility` still matches only the three cloud hosts, so
`RenderOtherBranchesFromNewDocsCommand` cannot resolve a composer.json
for a Forgejo repository. The webhook path is unaffected.

`SERVICE_NAMES` is deliberately not extended: it only feeds the manual
wizard's dropdown, and that path resolves urls via
`RepositoryUrlUtility` — a Forgejo entry there would build a
Bitbucket-shaped url.

Merging this does not by itself make the reporter's instance work:
`assertUrlToComposerFileIsSafe()` still requires an admin to approve the
domain.

</details>

Signed-off-by: Sebastian Mendel <github@sebastianmendel.de>
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.

1 participant