feat(wiki): add OpenAPI shortcuts
This commit is contained in:
parent
52b7093846
commit
053875b071
19
README.md
19
README.md
|
|
@ -96,6 +96,7 @@ The official [GitLink](https://www.gitlink.org.cn) CLI tool — built for humans
|
|||
| Category | Capabilities |
|
||||
|----------|-------------|
|
||||
| 📦 Repo | List, create, fork, delete repositories, view repo info, insights, and interactions |
|
||||
| Wiki | Create, update, view, list, and delete wiki pages |
|
||||
| 🐛 Issue | Create, update, close, batch close, comment on issues |
|
||||
| 🔖 Label | Create, list, update, delete issue labels |
|
||||
| 🔀 PR | Create, merge, review pull requests, view changed files |
|
||||
|
|
@ -246,6 +247,23 @@ gitlink-cli repo +create -n my-project -d "Project description"
|
|||
gitlink-cli repo +fork --owner Gitlink --repo forgeplus
|
||||
```
|
||||
|
||||
### Wiki Management
|
||||
|
||||
```bash
|
||||
# List and view wiki pages
|
||||
gitlink-cli wiki +pages --owner Gitlink --repo forgeplus --project-id 123
|
||||
gitlink-cli wiki +view --owner Gitlink --repo forgeplus --project-id 123 --page Home
|
||||
|
||||
# Create or update wiki pages
|
||||
gitlink-cli wiki +create --owner Gitlink --repo forgeplus \
|
||||
--project-id 123 --page Home --title Home --content "Welcome to Wiki"
|
||||
gitlink-cli wiki +update --owner Gitlink --repo forgeplus \
|
||||
--project-id 123 --page Home --title Home --content "Updated content"
|
||||
|
||||
# Preview wiki page deletion
|
||||
gitlink-cli wiki +delete --owner Gitlink --repo forgeplus --project-id 123 --page Home --dry-run
|
||||
```
|
||||
|
||||
### Webhook Management
|
||||
|
||||
```bash
|
||||
|
|
@ -638,6 +656,7 @@ See [skills/README.md](skills/README.md) for details.
|
|||
|-------|-------------|
|
||||
| `gitlink-shared` | Authentication, global parameters, safety rules, API notes |
|
||||
| `gitlink-repo` | Repository operations (create, view, delete, fork, insights, etc.) |
|
||||
| `gitlink-wiki` | Wiki operations (create, update, view, list, delete) |
|
||||
| `gitlink-issue` | Issue operations (create, update, close, comment, etc.) |
|
||||
| `gitlink-pr` | Pull request operations (create, merge, review, etc.) |
|
||||
| `gitlink-member` | Repository member and invite link management |
|
||||
|
|
|
|||
|
|
@ -96,6 +96,7 @@
|
|||
| 分类 | 能力 |
|
||||
|------|------|
|
||||
| 📦 仓库 | 列出、创建、Fork、删除仓库,查看仓库信息、洞察数据和互动状态 |
|
||||
| Wiki | 创建、更新、查看、列出和删除 Wiki 页面 |
|
||||
| 🐛 Issue | 创建、更新、关闭、批量关闭、评论 Issue |
|
||||
| 🔖 标签 | 创建、列出、更新、删除 Issue 标签 |
|
||||
| 🔀 PR | 创建、合并、Review Pull Request,查看变更文件 |
|
||||
|
|
@ -257,6 +258,23 @@ gitlink-cli repo +create -n my-project -d "项目描述"
|
|||
gitlink-cli repo +fork --owner Gitlink --repo forgeplus
|
||||
```
|
||||
|
||||
### Wiki 管理
|
||||
|
||||
```bash
|
||||
# 列出和查看 Wiki 页面
|
||||
gitlink-cli wiki +pages --owner Gitlink --repo forgeplus --project-id 123
|
||||
gitlink-cli wiki +view --owner Gitlink --repo forgeplus --project-id 123 --page Home
|
||||
|
||||
# 创建或更新 Wiki 页面
|
||||
gitlink-cli wiki +create --owner Gitlink --repo forgeplus \
|
||||
--project-id 123 --page Home --title Home --content "Welcome to Wiki"
|
||||
gitlink-cli wiki +update --owner Gitlink --repo forgeplus \
|
||||
--project-id 123 --page Home --title Home --content "Updated content"
|
||||
|
||||
# 预览删除 Wiki 页面
|
||||
gitlink-cli wiki +delete --owner Gitlink --repo forgeplus --project-id 123 --page Home --dry-run
|
||||
```
|
||||
|
||||
### Webhook 管理
|
||||
|
||||
```bash
|
||||
|
|
@ -517,6 +535,7 @@ git push gitlink
|
|||
|-------|------|
|
||||
| `gitlink-shared` | 认证、全局参数、安全规则、API 注意事项 |
|
||||
| `gitlink-repo` | 仓库操作(创建、查看、删除、Fork、洞察数据等) |
|
||||
| `gitlink-wiki` | Wiki 操作(创建、更新、查看、列表、删除) |
|
||||
| `gitlink-issue` | Issue 操作(创建、更新、关闭、评论等) |
|
||||
| `gitlink-pr` | Pull Request 操作(创建、合并、Review 等) |
|
||||
| `gitlink-member` | 仓库成员与邀请链接管理 |
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
# Wiki OpenAPI Shortcuts
|
||||
|
||||
## Summary
|
||||
|
||||
This change adds a dedicated `wiki` shortcut group for GitLink Wiki OpenAPI
|
||||
coverage. It includes read, create, update, and delete workflows.
|
||||
|
||||
## Added shortcuts
|
||||
|
||||
| Shortcut | API |
|
||||
|----------|-----|
|
||||
| `wiki +pages` | `GET /api/wiki/wikiPages` |
|
||||
| `wiki +view` | `GET /api/wiki/getWiki` |
|
||||
| `wiki +create` | `POST /api/wiki/createWiki` |
|
||||
| `wiki +update` | `PUT /api/wiki/updateWiki` |
|
||||
| `wiki +delete` | `DELETE /api/wiki/deleteWiki` |
|
||||
|
||||
`wiki +create` and `wiki +update` accept either raw `--content`, which the CLI
|
||||
base64-encodes, or pre-encoded `--content-base64`. `wiki +delete` supports
|
||||
`--dry-run` for safe previews.
|
||||
|
||||
## Submitter
|
||||
|
||||
Wang Yue
|
||||
|
|
@ -22,6 +22,7 @@ import (
|
|||
"github.com/gitlink-org/gitlink-cli/shortcuts/search"
|
||||
"github.com/gitlink-org/gitlink-cli/shortcuts/user"
|
||||
"github.com/gitlink-org/gitlink-cli/shortcuts/webhook"
|
||||
"github.com/gitlink-org/gitlink-cli/shortcuts/wiki"
|
||||
"github.com/gitlink-org/gitlink-cli/shortcuts/workflow"
|
||||
)
|
||||
|
||||
|
|
@ -49,6 +50,7 @@ func RegisterAll(root *cobra.Command, translators ...*i18n.Translator) {
|
|||
"compare": compare.Shortcuts(),
|
||||
"webhook": webhook.Shortcuts(tr),
|
||||
"health": health.Shortcuts(tr),
|
||||
"wiki": wiki.Shortcuts(),
|
||||
"workflow": workflow.Shortcuts(),
|
||||
}
|
||||
|
||||
|
|
@ -70,6 +72,7 @@ func RegisterAll(root *cobra.Command, translators ...*i18n.Translator) {
|
|||
"compare": "Compare branches, tags, or commits",
|
||||
"webhook": tr.T("cmd.webhook.short"),
|
||||
"health": "Project health data collection",
|
||||
"wiki": "Wiki operations",
|
||||
"workflow": "AI agent workflow analysis",
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ func TestRegisterAll(t *testing.T) {
|
|||
"repo", "issue", "label", "license", "pr", "release", "branch",
|
||||
"org", "user", "search", "ci", "workflow",
|
||||
"compare", "member", "milestone", "pipeline", "webhook",
|
||||
"health",
|
||||
"health", "wiki",
|
||||
}
|
||||
|
||||
groupSet := map[string]bool{}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,232 @@
|
|||
package wiki
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strconv"
|
||||
|
||||
"github.com/gitlink-org/gitlink-cli/shortcuts/common"
|
||||
)
|
||||
|
||||
func Shortcuts() []*common.Shortcut {
|
||||
return []*common.Shortcut{
|
||||
{
|
||||
Name: "pages",
|
||||
Description: "List repository wiki pages",
|
||||
Flags: wikiProjectFlags(),
|
||||
Run: func(ctx *common.RuntimeContext) error {
|
||||
if err := ctx.ResolveOwnerRepo(); err != nil {
|
||||
return err
|
||||
}
|
||||
q, err := wikiProjectQuery(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
env, err := ctx.CallAPIWithQuery("GET", "/wiki/wikiPages", q)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return ctx.Output(env)
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "view",
|
||||
Description: "Show a wiki page",
|
||||
Flags: append(wikiProjectFlags(),
|
||||
common.Flag{Name: "page", Short: "p", Usage: "Wiki page name", Required: true},
|
||||
),
|
||||
Run: func(ctx *common.RuntimeContext) error {
|
||||
if err := ctx.ResolveOwnerRepo(); err != nil {
|
||||
return err
|
||||
}
|
||||
q, err := wikiProjectQuery(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
page, err := ctx.RequireArg("page")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
q.Set("pageName", page)
|
||||
env, err := ctx.CallAPIWithQuery("GET", "/wiki/getWiki", q)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return ctx.Output(env)
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "create",
|
||||
Description: "Create a wiki page",
|
||||
Flags: wikiWriteFlags(true),
|
||||
Run: func(ctx *common.RuntimeContext) error {
|
||||
if err := ctx.ResolveOwnerRepo(); err != nil {
|
||||
return err
|
||||
}
|
||||
payload, err := wikiWritePayload(ctx, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
env, err := ctx.CallAPI("POST", "/wiki/createWiki", payload)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return ctx.Output(env)
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "update",
|
||||
Description: "Update a wiki page",
|
||||
Flags: wikiWriteFlags(false),
|
||||
Run: func(ctx *common.RuntimeContext) error {
|
||||
if err := ctx.ResolveOwnerRepo(); err != nil {
|
||||
return err
|
||||
}
|
||||
payload, err := wikiWritePayload(ctx, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
env, err := ctx.CallAPI("PUT", "/wiki/updateWiki", payload)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return ctx.Output(env)
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "delete",
|
||||
Description: "Delete a wiki page",
|
||||
Flags: append(wikiProjectFlags(),
|
||||
common.Flag{Name: "page", Short: "p", Usage: "Wiki page name", Required: true},
|
||||
common.Flag{Name: "dry-run", Usage: "Preview the delete request without changing wiki state", Bool: true, Default: "false"},
|
||||
),
|
||||
Run: func(ctx *common.RuntimeContext) error {
|
||||
if err := ctx.ResolveOwnerRepo(); err != nil {
|
||||
return err
|
||||
}
|
||||
payload, err := wikiBasePayload(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
page, err := ctx.RequireArg("page")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
payload["pageName"] = page
|
||||
if ctx.Arg("dry-run") == "true" {
|
||||
return ctx.OutputData(map[string]interface{}{
|
||||
"dry_run": true,
|
||||
"action": "delete_wiki_page",
|
||||
"method": "DELETE",
|
||||
"path": "/wiki/deleteWiki",
|
||||
"payload": payload,
|
||||
})
|
||||
}
|
||||
env, err := ctx.CallAPI("DELETE", "/wiki/deleteWiki", payload)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return ctx.Output(env)
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func wikiProjectFlags() []common.Flag {
|
||||
return []common.Flag{
|
||||
{Name: "project-id", Usage: "GitLink project ID", Required: true},
|
||||
}
|
||||
}
|
||||
|
||||
func wikiWriteFlags(contentRequired bool) []common.Flag {
|
||||
return append(wikiProjectFlags(),
|
||||
common.Flag{Name: "page", Short: "p", Usage: "Wiki page name", Required: true},
|
||||
common.Flag{Name: "title", Short: "t", Usage: "Wiki page title", Required: true},
|
||||
common.Flag{Name: "message", Short: "m", Usage: "Commit message"},
|
||||
common.Flag{Name: "content", Usage: "Wiki content; encoded to base64 before sending"},
|
||||
common.Flag{Name: "content-base64", Usage: "Pre-encoded wiki content"},
|
||||
)
|
||||
}
|
||||
|
||||
func wikiProjectQuery(ctx *common.RuntimeContext) (url.Values, error) {
|
||||
projectID, err := wikiProjectID(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
q := url.Values{}
|
||||
q.Set("owner", ctx.Owner)
|
||||
q.Set("repo", ctx.Repo)
|
||||
q.Set("projectId", strconv.Itoa(projectID))
|
||||
return q, nil
|
||||
}
|
||||
|
||||
func wikiWritePayload(ctx *common.RuntimeContext, contentRequired bool) (map[string]interface{}, error) {
|
||||
payload, err := wikiBasePayload(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
page, err := ctx.RequireArg("page")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
title, err := ctx.RequireArg("title")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
content, ok, err := wikiContent(ctx, contentRequired)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
payload["pageName"] = page
|
||||
payload["title"] = title
|
||||
if message := ctx.Arg("message"); message != "" {
|
||||
payload["message"] = message
|
||||
}
|
||||
if ok {
|
||||
payload["content_base64"] = content
|
||||
}
|
||||
return payload, nil
|
||||
}
|
||||
|
||||
func wikiBasePayload(ctx *common.RuntimeContext) (map[string]interface{}, error) {
|
||||
projectID, err := wikiProjectID(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return map[string]interface{}{
|
||||
"owner": ctx.Owner,
|
||||
"repo": ctx.Repo,
|
||||
"projectId": projectID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func wikiProjectID(ctx *common.RuntimeContext) (int, error) {
|
||||
value, err := ctx.RequireArg("project-id")
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
id, err := strconv.Atoi(value)
|
||||
if err != nil || id <= 0 {
|
||||
return 0, fmt.Errorf("--project-id must be a positive integer")
|
||||
}
|
||||
return id, nil
|
||||
}
|
||||
|
||||
func wikiContent(ctx *common.RuntimeContext, required bool) (string, bool, error) {
|
||||
content := ctx.Arg("content")
|
||||
encoded := ctx.Arg("content-base64")
|
||||
if content != "" && encoded != "" {
|
||||
return "", false, fmt.Errorf("--content cannot be used with --content-base64")
|
||||
}
|
||||
if content != "" {
|
||||
return base64.StdEncoding.EncodeToString([]byte(content)), true, nil
|
||||
}
|
||||
if encoded != "" {
|
||||
return encoded, true, nil
|
||||
}
|
||||
if required {
|
||||
return "", false, fmt.Errorf("required flag --content is missing (or use --content-base64)")
|
||||
}
|
||||
return "", false, nil
|
||||
}
|
||||
|
|
@ -0,0 +1,218 @@
|
|||
package wiki
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/gitlink-org/gitlink-cli/internal/client"
|
||||
"github.com/gitlink-org/gitlink-cli/internal/i18n"
|
||||
"github.com/gitlink-org/gitlink-cli/shortcuts/common"
|
||||
)
|
||||
|
||||
func TestWikiShortcutsRouteToOpenAPIEndpoints(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
args map[string]string
|
||||
method string
|
||||
path string
|
||||
query map[string]string
|
||||
payload map[string]interface{}
|
||||
}{
|
||||
{
|
||||
name: "pages",
|
||||
args: map[string]string{"project-id": "123"},
|
||||
method: "GET",
|
||||
path: "/wiki/wikiPages.json",
|
||||
query: map[string]string{"owner": "owner", "repo": "repo", "projectId": "123"},
|
||||
},
|
||||
{
|
||||
name: "view",
|
||||
args: map[string]string{"project-id": "123", "page": "Home"},
|
||||
method: "GET",
|
||||
path: "/wiki/getWiki.json",
|
||||
query: map[string]string{"owner": "owner", "repo": "repo", "projectId": "123", "pageName": "Home"},
|
||||
},
|
||||
{
|
||||
name: "create",
|
||||
args: map[string]string{"project-id": "123", "page": "Home", "title": "Home", "message": "Add Home", "content": "hello"},
|
||||
method: "POST",
|
||||
path: "/wiki/createWiki.json",
|
||||
payload: map[string]interface{}{
|
||||
"owner": "owner",
|
||||
"repo": "repo",
|
||||
"projectId": float64(123),
|
||||
"pageName": "Home",
|
||||
"title": "Home",
|
||||
"message": "Add Home",
|
||||
"content_base64": "aGVsbG8=",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "update",
|
||||
args: map[string]string{"project-id": "123", "page": "Home", "title": "Home", "content-base64": "dXBkYXRlZA=="},
|
||||
method: "PUT",
|
||||
path: "/wiki/updateWiki.json",
|
||||
payload: map[string]interface{}{
|
||||
"owner": "owner",
|
||||
"repo": "repo",
|
||||
"projectId": float64(123),
|
||||
"pageName": "Home",
|
||||
"title": "Home",
|
||||
"content_base64": "dXBkYXRlZA==",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "delete",
|
||||
args: map[string]string{"project-id": "123", "page": "Home"},
|
||||
method: "DELETE",
|
||||
path: "/wiki/deleteWiki.json",
|
||||
payload: map[string]interface{}{
|
||||
"owner": "owner",
|
||||
"repo": "repo",
|
||||
"projectId": float64(123),
|
||||
"pageName": "Home",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
called := false
|
||||
server := newWikiTestServer(t, func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != tc.method || r.URL.Path != tc.path {
|
||||
t.Fatalf("unexpected request: %s %s", r.Method, r.URL.Path)
|
||||
}
|
||||
assertWikiQuery(t, r, tc.query)
|
||||
if tc.payload != nil {
|
||||
assertWikiPayload(t, r, tc.payload)
|
||||
}
|
||||
called = true
|
||||
writeWikiJSON(t, w, map[string]interface{}{"message": "success", "data": map[string]interface{}{}})
|
||||
})
|
||||
defer server.Close()
|
||||
|
||||
err := runWikiShortcut(server, tc.name, tc.args)
|
||||
if err != nil {
|
||||
t.Fatalf("%s shortcut failed: %v", tc.name, err)
|
||||
}
|
||||
if !called {
|
||||
t.Fatal("expected API request")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestWikiDeleteDryRunDoesNotCallAPI(t *testing.T) {
|
||||
server := newWikiTestServer(t, func(w http.ResponseWriter, r *http.Request) {
|
||||
t.Fatalf("unexpected request: %s %s", r.Method, r.URL.Path)
|
||||
})
|
||||
defer server.Close()
|
||||
|
||||
err := runWikiShortcut(server, "delete", map[string]string{
|
||||
"project-id": "123",
|
||||
"page": "Home",
|
||||
"dry-run": "true",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("delete dry-run failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWikiShortcutsValidateRequiredArgs(t *testing.T) {
|
||||
server := newWikiTestServer(t, func(w http.ResponseWriter, r *http.Request) {
|
||||
t.Fatalf("unexpected request: %s %s", r.Method, r.URL.Path)
|
||||
})
|
||||
defer server.Close()
|
||||
|
||||
cases := []struct {
|
||||
name string
|
||||
args map[string]string
|
||||
want string
|
||||
}{
|
||||
{name: "pages", args: map[string]string{}, want: "--project-id"},
|
||||
{name: "pages", args: map[string]string{"project-id": "abc"}, want: "--project-id must be a positive integer"},
|
||||
{name: "view", args: map[string]string{"project-id": "123"}, want: "--page"},
|
||||
{name: "create", args: map[string]string{"project-id": "123", "page": "Home", "title": "Home"}, want: "--content"},
|
||||
{name: "create", args: map[string]string{"project-id": "123", "page": "Home", "title": "Home", "content": "x", "content-base64": "eA=="}, want: "--content cannot be used with --content-base64"},
|
||||
{name: "update", args: map[string]string{"project-id": "123", "page": "Home"}, want: "--title"},
|
||||
{name: "delete", args: map[string]string{"project-id": "123"}, want: "--page"},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
err := runWikiShortcut(server, tc.name, tc.args)
|
||||
if err == nil {
|
||||
t.Fatal("expected validation error")
|
||||
}
|
||||
if !strings.Contains(err.Error(), tc.want) {
|
||||
t.Fatalf("error = %q, want it to mention %s", err.Error(), tc.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func runWikiShortcut(server *httptest.Server, name string, args map[string]string) error {
|
||||
for _, shortcut := range Shortcuts() {
|
||||
if shortcut.Name != name {
|
||||
continue
|
||||
}
|
||||
ctx := &common.RuntimeContext{
|
||||
Client: &client.Client{
|
||||
HTTP: server.Client(),
|
||||
BaseURL: server.URL,
|
||||
},
|
||||
Owner: "owner",
|
||||
Repo: "repo",
|
||||
Format: "json",
|
||||
Args: args,
|
||||
Tr: i18n.Default(),
|
||||
}
|
||||
return shortcut.Run(ctx)
|
||||
}
|
||||
return fmt.Errorf("shortcut %q not found", name)
|
||||
}
|
||||
|
||||
func newWikiTestServer(t *testing.T, handler http.HandlerFunc) *httptest.Server {
|
||||
t.Helper()
|
||||
return httptest.NewServer(handler)
|
||||
}
|
||||
|
||||
func assertWikiQuery(t *testing.T, r *http.Request, want map[string]string) {
|
||||
t.Helper()
|
||||
query := r.URL.Query()
|
||||
if len(query) != len(want) {
|
||||
t.Fatalf("query = %v, want %v", query, want)
|
||||
}
|
||||
for key, value := range want {
|
||||
if got := query.Get(key); got != value {
|
||||
t.Fatalf("query %s = %q, want %q", key, got, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func assertWikiPayload(t *testing.T, r *http.Request, want map[string]interface{}) {
|
||||
t.Helper()
|
||||
var got map[string]interface{}
|
||||
if err := json.NewDecoder(r.Body).Decode(&got); err != nil {
|
||||
t.Fatalf("decode request body: %v", err)
|
||||
}
|
||||
if len(got) != len(want) {
|
||||
t.Fatalf("payload = %v, want %v", got, want)
|
||||
}
|
||||
for key, value := range want {
|
||||
if got[key] != value {
|
||||
t.Fatalf("payload %s = %v, want %v", key, got[key], value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func writeWikiJSON(t *testing.T, w http.ResponseWriter, payload interface{}) {
|
||||
t.Helper()
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
if err := json.NewEncoder(w).Encode(payload); err != nil {
|
||||
t.Fatalf("failed to write response: %v", err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
---
|
||||
name: gitlink-wiki
|
||||
version: 1.0.0
|
||||
description: "Wiki management: list, view, create, update, and delete GitLink wiki pages."
|
||||
metadata:
|
||||
requires:
|
||||
bins: ["gitlink-cli"]
|
||||
cliHelp: "gitlink-cli wiki --help"
|
||||
---
|
||||
|
||||
# gitlink-wiki
|
||||
|
||||
Read `../gitlink-shared/SKILL.md` first for authentication, global flags, and safety rules.
|
||||
|
||||
Write and delete operations must be confirmed by the user before execution. Use
|
||||
`wiki +delete --dry-run` before deleting a page.
|
||||
|
||||
## Shortcuts
|
||||
|
||||
| Shortcut | Purpose | Auth |
|
||||
|----------|---------|------|
|
||||
| `wiki +pages` | List wiki pages | No for public repos |
|
||||
| `wiki +view` | Show one wiki page | No for public repos |
|
||||
| `wiki +create` | Create a wiki page | Yes |
|
||||
| `wiki +update` | Update a wiki page | Yes |
|
||||
| `wiki +delete` | Delete a wiki page | Yes |
|
||||
|
||||
All shortcuts require `--project-id` because the Wiki OpenAPI requires the
|
||||
GitLink project ID in addition to owner and repo.
|
||||
|
||||
`wiki +create` and `wiki +update` accept either `--content`, which the CLI
|
||||
base64-encodes, or `--content-base64` for callers that already have encoded
|
||||
content.
|
||||
|
||||
## Examples
|
||||
|
||||
```bash
|
||||
gitlink-cli wiki +pages --owner Gitlink --repo forgeplus --project-id 123
|
||||
gitlink-cli wiki +view --owner Gitlink --repo forgeplus --project-id 123 --page Home
|
||||
|
||||
gitlink-cli wiki +create --owner Gitlink --repo forgeplus \
|
||||
--project-id 123 \
|
||||
--page Home \
|
||||
--title Home \
|
||||
--content "Welcome to Wiki"
|
||||
|
||||
gitlink-cli wiki +update --owner Gitlink --repo forgeplus \
|
||||
--project-id 123 \
|
||||
--page Home \
|
||||
--title Home \
|
||||
--content "Updated content"
|
||||
|
||||
gitlink-cli wiki +delete --owner Gitlink --repo forgeplus --project-id 123 --page Home --dry-run
|
||||
```
|
||||
|
||||
## API Mapping
|
||||
|
||||
| Shortcut | API |
|
||||
|----------|-----|
|
||||
| `wiki +pages` | `GET /api/wiki/wikiPages` |
|
||||
| `wiki +view` | `GET /api/wiki/getWiki` |
|
||||
| `wiki +create` | `POST /api/wiki/createWiki` |
|
||||
| `wiki +update` | `PUT /api/wiki/updateWiki` |
|
||||
| `wiki +delete` | `DELETE /api/wiki/deleteWiki` |
|
||||
Loading…
Reference in New Issue