The wiki package uses forgejo-sdk methods that don't exist in the released SDK (v2.0.0), causing builds to fail when compiling all subpackages (go build ./...). Add //go:build wiki tag to exclude the wiki package from default builds. This fixes Nix buildGoModule without requiring subPackages workarounds. Closes #47
308 lines
10 KiB
Markdown
308 lines
10 KiB
Markdown
# Wiki Support Implementation Plan for forgejo-mcp
|
|
|
|
## Summary
|
|
|
|
Complete wiki support in forgejo-mcp requires wiki API methods in the upstream forgejo-sdk. This plan outlines the upstream contribution strategy and downstream integration.
|
|
|
|
## Current State
|
|
|
|
**forgejo-mcp** (`operation/wiki/wiki.go`) defines 3 wiki tools but uses SDK methods that don't exist:
|
|
|
|
- `ListWikiPages()`, `CreateWikiPage()`, `EditWikiPage()` - undefined
|
|
- `CreateWikiPageOption`, `EditWikiPageOption` - undefined
|
|
- **Build fails** with undefined method errors
|
|
|
|
**forgejo-sdk v2.0.0-v2.2.0** has no wiki page API methods.
|
|
|
|
## Target State
|
|
|
|
### forgejo-sdk (upstream)
|
|
|
|
Add wiki page methods matching the Forgejo/Gitea API:
|
|
|
|
- `ListWikiPages(owner, repo string, opts ListWikiPagesOptions) ([]*WikiPageMeta, *Response, error)`
|
|
- `GetWikiPage(owner, repo, pageName string) (*WikiPage, *Response, error)`
|
|
- `GetWikiPageRevisions(owner, repo, pageName string, opts ListOptions) ([]*WikiCommit, *Response, error)`
|
|
- `CreateWikiPage(owner, repo string, opt CreateWikiPageOption) (*WikiPage, *Response, error)`
|
|
- `EditWikiPage(owner, repo, pageName string, opt EditWikiPageOption) (*WikiPage, *Response, error)`
|
|
- `DeleteWikiPage(owner, repo, pageName string) (*Response, error)`
|
|
|
|
### forgejo-mcp (downstream)
|
|
|
|
Once SDK is updated, complete wiki support with 6 tools:
|
|
|
|
| Tool | Description |
|
|
|------|-------------|
|
|
| `list_wiki_pages` | List all wiki pages in a repository |
|
|
| `get_wiki_page` | Get a wiki page content and metadata |
|
|
| `get_wiki_revisions` | Get revisions history of a wiki page |
|
|
| `create_wiki_page` | Create a new wiki page |
|
|
| `update_wiki_page` | Update an existing wiki page |
|
|
| `delete_wiki_page` | Delete a wiki page |
|
|
|
|
---
|
|
|
|
## Part 1: Upstream Contribution to forgejo-sdk
|
|
|
|
### Repository
|
|
|
|
- **URL**: <https://codeberg.org/mvdkleijn/forgejo-sdk>
|
|
- **Branch**: `main`
|
|
|
|
### Files to Create/Modify
|
|
|
|
#### 1. `forgejo/wiki.go` (NEW FILE)
|
|
|
|
```go
|
|
// Copyright 2024 The Forgejo Authors. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package forgejo
|
|
|
|
import (
|
|
"fmt"
|
|
"net/url"
|
|
"time"
|
|
)
|
|
|
|
// WikiPage represents a wiki page
|
|
type WikiPage struct {
|
|
Title string `json:"title"`
|
|
PageName string `json:"page_name"`
|
|
SubURL string `json:"sub_url"`
|
|
Content string `json:"content_base64"` // base64 encoded
|
|
CommitSHA string `json:"commit_sha"`
|
|
Sidebar string `json:"sidebar"`
|
|
Footer string `json:"footer"`
|
|
LastCommit *WikiCommit `json:"last_commit,omitempty"`
|
|
}
|
|
|
|
// WikiPageMeta represents wiki page metadata (for list operations)
|
|
type WikiPageMeta struct {
|
|
Title string `json:"title"`
|
|
PageName string `json:"page_name"`
|
|
SubURL string `json:"sub_url"`
|
|
LastCommit *WikiCommit `json:"last_commit,omitempty"`
|
|
}
|
|
|
|
// WikiCommit represents a wiki commit
|
|
type WikiCommit struct {
|
|
SHA string `json:"sha"`
|
|
Author *WikiAuthor `json:"author"`
|
|
Committer *WikiCommitter `json:"committer"`
|
|
Message string `json:"message"`
|
|
}
|
|
|
|
// WikiAuthor represents a wiki commit author
|
|
type WikiAuthor struct {
|
|
Name string `json:"name"`
|
|
Email string `json:"email"`
|
|
}
|
|
|
|
// WikiCommitter represents a wiki commit committer
|
|
type WikiCommitter struct {
|
|
Name string `json:"name"`
|
|
Email string `json:"email"`
|
|
}
|
|
|
|
// CreateWikiPageOption options for creating a wiki page
|
|
type CreateWikiPageOption struct {
|
|
Title string `json:"title"`
|
|
Content string `json:"content_base64"` // base64 encoded
|
|
Message string `json:"message,omitempty"`
|
|
}
|
|
|
|
// EditWikiPageOption options for editing a wiki page
|
|
type EditWikiPageOption struct {
|
|
Title string `json:"title,omitempty"`
|
|
Content string `json:"content_base64,omitempty"` // base64 encoded
|
|
Message string `json:"message,omitempty"`
|
|
}
|
|
|
|
// ListWikiPages lists all wiki pages in a repository
|
|
func (c *Client) ListWikiPages(owner, repo string, opts ListOptions) ([]*WikiPageMeta, *Response, error) {
|
|
opt := newListOptions(opts)
|
|
pages := make([]*WikiPageMeta, 0)
|
|
resp, err := c.getParsedResponse("GET",
|
|
fmt.Sprintf("/repos/%s/%s/wiki/pages?%s",
|
|
url.PathEscape(owner), url.PathEscape(repo), opt.toQuery()),
|
|
nil, nil, &pages)
|
|
return pages, resp, err
|
|
}
|
|
|
|
// GetWikiPage gets a wiki page
|
|
func (c *Client) GetWikiPage(owner, repo, pageName string) (*WikiPage, *Response, error) {
|
|
page := new(WikiPage)
|
|
resp, err := c.getParsedResponse("GET",
|
|
fmt.Sprintf("/repos/%s/%s/wiki/page/%s",
|
|
url.PathEscape(owner), url.PathEscape(repo), url.PathEscape(pageName)),
|
|
nil, nil, page)
|
|
return page, resp, err
|
|
}
|
|
|
|
// GetWikiPageRevisions gets the revision history of a wiki page
|
|
func (c *Client) GetWikiPageRevisions(owner, repo, pageName string, opts ListOptions) ([]*WikiCommit, *Response, error) {
|
|
opt := newListOptions(opts)
|
|
commits := make([]*WikiCommit, 0)
|
|
resp, err := c.getParsedResponse("GET",
|
|
fmt.Sprintf("/repos/%s/%s/wiki/revisions/%s?%s",
|
|
url.PathEscape(owner), url.PathEscape(repo), url.PathEscape(pageName), opt.toQuery()),
|
|
nil, nil, &commits)
|
|
return commits, resp, err
|
|
}
|
|
|
|
// CreateWikiPage creates a new wiki page
|
|
func (c *Client) CreateWikiPage(owner, repo string, opt CreateWikiPageOption) (*WikiPage, *Response, error) {
|
|
page := new(WikiPage)
|
|
resp, err := c.getParsedResponse("POST",
|
|
fmt.Sprintf("/repos/%s/%s/wiki/new",
|
|
url.PathEscape(owner), url.PathEscape(repo)),
|
|
jsonHeader, opt, page)
|
|
return page, resp, err
|
|
}
|
|
|
|
// EditWikiPage edits a wiki page
|
|
func (c *Client) EditWikiPage(owner, repo, pageName string, opt EditWikiPageOption) (*WikiPage, *Response, error) {
|
|
page := new(WikiPage)
|
|
resp, err := c.getParsedResponse("PATCH",
|
|
fmt.Sprintf("/repos/%s/%s/wiki/page/%s",
|
|
url.PathEscape(owner), url.PathEscape(repo), url.PathEscape(pageName)),
|
|
jsonHeader, opt, page)
|
|
return page, resp, err
|
|
}
|
|
|
|
// DeleteWikiPage deletes a wiki page
|
|
func (c *Client) DeleteWikiPage(owner, repo, pageName string) (*Response, error) {
|
|
resp, err := c.getResponse("DELETE",
|
|
fmt.Sprintf("/repos/%s/%s/wiki/page/%s",
|
|
url.PathEscape(owner), url.PathEscape(repo), url.PathEscape(pageName)),
|
|
nil, nil)
|
|
return resp, err
|
|
}
|
|
```
|
|
|
|
#### 2. `forgejo/wiki_test.go` (NEW FILE)
|
|
|
|
Add tests for all wiki operations following the SDK's testing patterns.
|
|
|
|
### API Reference
|
|
|
|
Forgejo/Gitea Wiki API endpoints:
|
|
|
|
| Method | Endpoint | Description |
|
|
|--------|----------|-------------|
|
|
| GET | `/repos/{owner}/{repo}/wiki/pages` | List all wiki pages |
|
|
| GET | `/repos/{owner}/{repo}/wiki/page/{pageName}` | Get a wiki page |
|
|
| GET | `/repos/{owner}/{repo}/wiki/revisions/{pageName}` | Get wiki page revisions |
|
|
| POST | `/repos/{owner}/{repo}/wiki/new` | Create a wiki page |
|
|
| PATCH | `/repos/{owner}/{repo}/wiki/page/{pageName}` | Edit a wiki page |
|
|
| DELETE | `/repos/{owner}/{repo}/wiki/page/{pageName}` | Delete a wiki page |
|
|
|
|
### Pull Request Checklist
|
|
|
|
- [ ] Add `wiki.go` with types and methods
|
|
- [ ] Add `wiki_test.go` with tests
|
|
- [ ] Update CHANGELOG if required
|
|
- [ ] Ensure CI passes
|
|
- [ ] Follow SDK coding conventions
|
|
|
|
---
|
|
|
|
## Part 2: Downstream Integration in forgejo-mcp
|
|
|
|
After forgejo-sdk releases with wiki support:
|
|
|
|
### 1. Update go.mod
|
|
|
|
```bash
|
|
go get codeberg.org/mvdkleijn/forgejo-sdk/forgejo/v2@latest
|
|
```
|
|
|
|
### 2. Update `operation/wiki/wiki.go`
|
|
|
|
Add 3 new tools:
|
|
|
|
- `get_wiki_page` - Get wiki page content and metadata
|
|
- `get_wiki_revisions` - Get revision history
|
|
- `delete_wiki_page` - Delete a wiki page
|
|
|
|
Fix 3 existing tools to use correct SDK methods.
|
|
|
|
### 3. Add to params if needed
|
|
|
|
```go
|
|
// Wiki parameters (already exist)
|
|
WikiTitle = "Wiki page title"
|
|
WikiContent = "Wiki page content"
|
|
WikiPage = "Wiki page name"
|
|
```
|
|
|
|
---
|
|
|
|
## Timeline Estimate
|
|
|
|
1. **SDK Contribution**: 1-2 weeks (including review cycles)
|
|
2. **forgejo-mcp Integration**: 1 day (after SDK release)
|
|
|
|
---
|
|
|
|
## Feature Request Comment for forgejo-sdk
|
|
|
|
Copy the following comment to submit to the Codeberg feature request:
|
|
|
|
---
|
|
|
|
### Wiki API Support for forgejo-sdk
|
|
|
|
**Summary**: Add wiki page management methods to the forgejo-sdk.
|
|
|
|
**Background**: The [forgejo-mcp](https://codeberg.org/goern/forgejo-mcp) project provides an MCP (Model Context Protocol) server for Forgejo integration. We're implementing wiki support but discovered that the forgejo-sdk (v2.0.0-v2.2.0) doesn't include wiki page API methods.
|
|
|
|
**Forgejo/Gitea Wiki API endpoints exist and are documented**:
|
|
|
|
- `GET /repos/{owner}/{repo}/wiki/pages` - List wiki pages
|
|
- `GET /repos/{owner}/{repo}/wiki/page/{pageName}` - Get a wiki page
|
|
- `GET /repos/{owner}/{repo}/wiki/revisions/{pageName}` - Get page revisions
|
|
- `POST /repos/{owner}/{repo}/wiki/new` - Create a wiki page
|
|
- `PATCH /repos/{owner}/{repo}/wiki/page/{pageName}` - Edit a wiki page
|
|
- `DELETE /repos/{owner}/{repo}/wiki/page/{pageName}` - Delete a wiki page
|
|
|
|
**Requested SDK methods**:
|
|
|
|
```go
|
|
// Types
|
|
type WikiPage struct { ... }
|
|
type WikiPageMeta struct { ... }
|
|
type WikiCommit struct { ... }
|
|
type CreateWikiPageOption struct { ... }
|
|
type EditWikiPageOption struct { ... }
|
|
|
|
// Methods on Client
|
|
func (c *Client) ListWikiPages(owner, repo string, opts ListOptions) ([]*WikiPageMeta, *Response, error)
|
|
func (c *Client) GetWikiPage(owner, repo, pageName string) (*WikiPage, *Response, error)
|
|
func (c *Client) GetWikiPageRevisions(owner, repo, pageName string, opts ListOptions) ([]*WikiCommit, *Response, error)
|
|
func (c *Client) CreateWikiPage(owner, repo string, opt CreateWikiPageOption) (*WikiPage, *Response, error)
|
|
func (c *Client) EditWikiPage(owner, repo, pageName string, opt EditWikiPageOption) (*WikiPage, *Response, error)
|
|
func (c *Client) DeleteWikiPage(owner, repo, pageName string) (*Response, error)
|
|
```
|
|
|
|
**Reference implementation**: The [gitea-mcp](https://gitea.com/gitea/gitea-mcp) project implements wiki support using raw HTTP calls. We'd prefer to use proper SDK methods for consistency and maintainability.
|
|
|
|
**Willingness to contribute**: We're happy to submit a PR adding these methods if the maintainers are open to it.
|
|
|
|
---
|
|
|
|
## Current Workaround
|
|
|
|
The `operation/wiki/wiki.go` file uses a Go build tag to exclude it from default builds:
|
|
|
|
```go
|
|
//go:build wiki
|
|
```
|
|
|
|
This means:
|
|
- **Default builds** (`go build ./...`) skip the wiki package entirely
|
|
- **Nix builds** work without special configuration
|
|
- **Wiki-enabled builds** require explicit tag: `go build -tags wiki ./...`
|
|
|
|
When the upstream forgejo-sdk adds wiki support, remove the build tag and register wiki tools in `operation/operation.go`.
|