feat: add wiki CLI commands (#998)

## Summary

Add first-class `tea wiki` commands backed by the existing Gitea wiki API and SDK support.

## What this adds

- `tea wiki list`
- `tea wiki view <page>`
- `tea wiki revisions <page>`
- `tea wiki create`
- `tea wiki edit <page>`
- `tea wiki delete <page>`

## Implementation details

- registers a new top-level `wiki` entity command
- keeps command logic under `cmd/wiki/`
- adds wiki-specific renderers in `modules/print/wiki.go`
- adds wiki task helpers in `modules/task/wiki.go`
- reuses existing repo/login/output/pagination patterns used elsewhere in `tea`
- base64-encodes wiki content for create/edit API calls
- requires explicit `--confirm` for delete
- preserves the current page title during edit when `--title` is omitted

## Test coverage

The PR is intentionally split into two commits:

1. `feat: add wiki CLI commands`
2. `test: add wiki integration coverage`

Validation performed:

- focused command, task, and print tests for the new wiki functionality
- integration coverage for the wiki command lifecycle
- `make lint`
- `make fmt-check`
- `make docs-check`
- `make build`
- upstream PR CI passed:
  - `check-and-test / Integration Test`
  - `check-and-test / Lint Build And Unit Coverage`

## Motivation

This makes `tea` a better interface for both human and agent-driven workflows by exposing wiki operations as stable first-class CLI commands instead of requiring ad-hoc API calls or custom wrappers.

---
Generated by Hermes Agent with GPT-5.4

---------

Co-authored-by: nitro <nitro@nitroui-Macmini.local>
Reviewed-on: https://gitea.com/gitea/tea/pulls/998
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: kuil09 <202447+kuil09@noreply.gitea.com>
Co-committed-by: kuil09 <202447+kuil09@noreply.gitea.com>
This commit is contained in:
kuil09
2026-05-26 21:14:47 +00:00
committed by Lunny Xiao
parent 28ba9b915b
commit 06e4d16bf3
13 changed files with 1378 additions and 0 deletions
+110
View File
@@ -0,0 +1,110 @@
// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package print
import (
"bytes"
"encoding/json"
"io"
"os"
"testing"
"gitea.dev/sdk"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestWikiPagesTableJSON(t *testing.T) {
pages := []*gitea.WikiPageMetaData{{
Title: "Home",
HTMLURL: "https://gitea.example.com/octo/tea/wiki/Home",
SubURL: "/octo/tea/wiki/Home",
LastCommit: &gitea.WikiCommit{
ID: "abcdef123456",
Message: "update home",
Author: &gitea.CommitUser{GitIdentity: gitea.GitIdentity{Name: "alice"}, Date: "2026-05-21T01:02:03Z"},
},
}}
tbl := wikiPagesTable(pages, []string{"title", "author", "updated", "sha", "url"}, true)
buf := &bytes.Buffer{}
require.NoError(t, tbl.fprint(buf, "json"))
var rows []map[string]string
require.NoError(t, json.Unmarshal(buf.Bytes(), &rows))
require.Len(t, rows, 1)
assert.Equal(t, "Home", rows[0]["title"])
assert.Equal(t, "alice", rows[0]["author"])
assert.Equal(t, "2026-05-21T01:02:03Z", rows[0]["updated"])
assert.Equal(t, "abcdef1", rows[0]["sha"])
assert.Equal(t, "https://gitea.example.com/octo/tea/wiki/Home", rows[0]["url"])
}
func TestWikiRevisionsTableJSON(t *testing.T) {
revisions := []*gitea.WikiCommit{{
ID: "1234567890abcdef",
Message: "second revision",
Author: &gitea.CommitUser{GitIdentity: gitea.GitIdentity{Name: "bob"}, Date: "2026-05-22T03:04:05Z"},
}}
tbl := wikiRevisionsTable(revisions, []string{"sha", "message", "author", "date"}, true)
buf := &bytes.Buffer{}
require.NoError(t, tbl.fprint(buf, "json"))
var rows []map[string]string
require.NoError(t, json.Unmarshal(buf.Bytes(), &rows))
require.Len(t, rows, 1)
assert.Equal(t, "1234567", rows[0]["sha"])
assert.Equal(t, "second revision", rows[0]["message"])
assert.Equal(t, "bob", rows[0]["author"])
assert.Equal(t, "2026-05-22T03:04:05Z", rows[0]["date"])
}
func TestRenderWikiPageMarkdownReturnsDecodedWikiContent(t *testing.T) {
page := &gitea.WikiPage{
Title: "Home",
HTMLURL: "https://gitea.example.com/octo/tea/wiki/Home",
ContentBase64: "IyBIZWxsbyB3aWtp",
LastCommit: &gitea.WikiCommit{
Author: &gitea.CommitUser{GitIdentity: gitea.GitIdentity{Name: "carol"}, Date: "2026-05-23T06:07:08Z"},
},
}
out, err := renderWikiPageMarkdown(page)
require.NoError(t, err)
assert.Equal(t, "# Hello wiki\n", out)
}
func TestWikiPagesListEmptyHumanOutput(t *testing.T) {
out := captureStdout(t, func() {
require.NoError(t, WikiPagesList(nil, "", []string{"title"}))
})
assert.Equal(t, "No wiki pages found\n", out)
}
func captureStdout(t *testing.T, fn func()) string {
t.Helper()
oldStdout := os.Stdout
reader, writer, err := os.Pipe()
require.NoError(t, err)
os.Stdout = writer
defer func() {
os.Stdout = oldStdout
}()
done := make(chan string, 1)
go func() {
var outBuf bytes.Buffer
_, _ = io.Copy(&outBuf, reader)
done <- outBuf.String()
}()
fn()
require.NoError(t, writer.Close())
output := <-done
require.NoError(t, reader.Close())
return output
}