feat: Forgejo API mock server for CI smoke tests #123
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
The
smoke-initCI pipeline was removed because it spun up a real Forgejo instance inside the Woodpecker CI container, which never started within the 5-minute timeout (Forgejo takes >60s in Docker-in-LXD, often hangs entirely).The test itself (
tests/smoke-init.sh) is valuable — it validates the fulldisinto initflow. We need to restore it with a mock Forgejo API instead of a real instance.What to build
A Python HTTP mock server (
tests/mock-forgejo.py) that implements the 15 Forgejo API endpoints thatdisinto initcalls. The mock stores state in-memory (dicts), responds instantly, and validates that init sends correct requests.Endpoints to implement
Based on the Forgejo v11.0 Swagger spec (Gitea 1.22.0 compatible):
1.
GET /api/v1/version{"version": "11.0.0-mock"}2.
POST /api/v1/admin/users{"id": N, "login": "username", "email": "...", "is_admin": false, ...}usersdict keyed by username3.
PATCH /api/v1/admin/users/{username}users[username]in-memory4.
GET /api/v1/users/{username}{"message": "user does not exist"}if not inusersdict5.
POST /api/v1/users/{username}/tokens{"id": N, "name": "token-name", "sha1": "<generated-hex-40>", "scopes": ["all"]}sha256(username + name)[:40]tokensdict6.
GET /api/v1/repos/{owner}/{repo}{"id": N, "full_name": "owner/repo", "name": "repo", "owner": {"login": "owner"}, "empty": false, "default_branch": "main", ...}reposdict7.
POST /api/v1/orgs{"id": N, "username": "org-name", ...}orgsdict8.
POST /api/v1/orgs/{org}/reposreposdict keyed by"{org}/{name}"9.
POST /api/v1/user/reposreposdict keyed by"{authenticated_user}/{name}"10.
PUT /api/v1/repos/{owner}/{repo}/collaborators/{collaborator}collaborators[owner/repo]set11.
GET /api/v1/repos/{owner}/{repo}/labels?limit=50[{"id": N, "name": "backlog", "color": "#hex"}, ...]12.
POST /api/v1/repos/{owner}/{repo}/labelslabels[owner/repo]list13.
POST /api/v1/repos/{owner}/{repo}/branch_protectionsprotections[owner/repo]dict14.
GET /api/v1/user/applications/oauth2[](empty — no existing OAuth2 apps)15.
POST /api/v1/user/applications/oauth2{"id": N, "name": "woodpecker-ci", "client_id": "<uuid>", "client_secret": "<hex>"}Server implementation
Auth handling
The mock should:
Authorization: token <any>for token auth (don't validate the token value — init generates tokens dynamically)Authorization: Basic <base64>for basic auth — decode and check username exists in users dictAffected files
tests/mock-forgejo.py(new — ~150-200 lines)Acceptance criteria
/mock/shutdownDependencies
None — standalone component.