diff --git a/shortcuts/wiki/wiki.go b/shortcuts/wiki/wiki.go index 605de041..d60abff2 100644 --- a/shortcuts/wiki/wiki.go +++ b/shortcuts/wiki/wiki.go @@ -1,6 +1,7 @@ package wiki import ( + "encoding/base64" "fmt" "github.com/gitlink-org/gitlink-cli/shortcuts/common" @@ -23,9 +24,115 @@ func Shortcuts() []*common.Shortcut { return ctx.Output(env) }, }, + { + Name: "view", + Description: "View a wiki page", + Flags: []common.Flag{ + {Name: "slug", Short: "s", Usage: "Wiki page slug", Required: true}, + }, + Run: func(ctx *common.RuntimeContext) error { + if err := ctx.ResolveOwnerRepo(); err != nil { + return err + } + slug, err := ctx.RequireArg("slug") + if err != nil { + return err + } + env, err := ctx.CallAPI("GET", wikiPagePath(ctx, slug), nil) + if err != nil { + return err + } + return ctx.Output(env) + }, + }, + { + Name: "create", + Description: "Create a wiki page", + Flags: []common.Flag{ + {Name: "title", Short: "t", Usage: "Wiki page title", Required: true}, + {Name: "body", Short: "b", Usage: "Wiki page content", Required: true}, + }, + Run: func(ctx *common.RuntimeContext) error { + if err := ctx.ResolveOwnerRepo(); err != nil { + return err + } + title, err := ctx.RequireArg("title") + if err != nil { + return err + } + body, err := ctx.RequireArg("body") + if err != nil { + return err + } + payload := map[string]interface{}{ + "title": title, + "content_base64": base64.StdEncoding.EncodeToString([]byte(body)), + } + env, err := ctx.CallAPI("POST", wikiPagesPath(ctx), payload) + if err != nil { + return err + } + return ctx.Output(env) + }, + }, + { + Name: "update", + Description: "Update a wiki page", + Flags: []common.Flag{ + {Name: "slug", Short: "s", Usage: "Wiki page slug", Required: true}, + {Name: "title", Short: "t", Usage: "New title"}, + {Name: "body", Short: "b", Usage: "New content"}, + }, + Run: func(ctx *common.RuntimeContext) error { + if err := ctx.ResolveOwnerRepo(); err != nil { + return err + } + slug, err := ctx.RequireArg("slug") + if err != nil { + return err + } + payload := map[string]interface{}{} + if title := ctx.Arg("title"); title != "" { + payload["title"] = title + } + if body := ctx.Arg("body"); body != "" { + payload["content_base64"] = base64.StdEncoding.EncodeToString([]byte(body)) + } + env, err := ctx.CallAPI("PATCH", wikiPagePath(ctx, slug), payload) + if err != nil { + return err + } + return ctx.Output(env) + }, + }, + { + Name: "delete", + Description: "Delete a wiki page", + Flags: []common.Flag{ + {Name: "slug", Short: "s", Usage: "Wiki page slug", Required: true}, + }, + Run: func(ctx *common.RuntimeContext) error { + if err := ctx.ResolveOwnerRepo(); err != nil { + return err + } + slug, err := ctx.RequireArg("slug") + if err != nil { + return err + } + env, err := ctx.CallAPI("DELETE", wikiPagePath(ctx, slug), nil) + if err != nil { + return err + } + return ctx.Output(env) + }, + }, } } func wikiPagesPath(ctx *common.RuntimeContext) string { return fmt.Sprintf("/%s/%s/wiki/pages", ctx.Owner, ctx.Repo) } + +func wikiPagePath(ctx *common.RuntimeContext, slug string) string { + return fmt.Sprintf("/%s/%s/wiki/pages/%s", ctx.Owner, ctx.Repo, slug) +} diff --git a/shortcuts/wiki/wiki_test.go b/shortcuts/wiki/wiki_test.go index b140976c..fcf4e8c9 100644 --- a/shortcuts/wiki/wiki_test.go +++ b/shortcuts/wiki/wiki_test.go @@ -1,6 +1,7 @@ package wiki import ( + "encoding/base64" "encoding/json" "net/http" "net/http/httptest" @@ -10,6 +11,8 @@ import ( "github.com/gitlink-org/gitlink-cli/shortcuts/common" ) +// --- List --- + func TestWikiList(t *testing.T) { server := newWikiTestServer(t, func(w http.ResponseWriter, r *http.Request) { assertRequest(t, r, "GET", "/owner/repo/wiki/pages.json") @@ -28,6 +31,99 @@ func TestWikiList(t *testing.T) { } } +// --- View --- + +func TestWikiView(t *testing.T) { + server := newWikiTestServer(t, func(w http.ResponseWriter, r *http.Request) { + assertRequest(t, r, "GET", "/owner/repo/wiki/pages/home.json") + writeJSON(t, w, map[string]interface{}{ + "title": "Home", + "slug": "home", + "content_base64": base64.StdEncoding.EncodeToString([]byte("Welcome to the wiki")), + }) + }) + defer server.Close() + + if err := runWikiShortcut(t, server, "view", map[string]string{"slug": "home"}); err != nil { + t.Fatalf("view shortcut failed: %v", err) + } +} + +// --- Create --- + +func TestWikiCreate(t *testing.T) { + server := newWikiTestServer(t, func(w http.ResponseWriter, r *http.Request) { + assertRequest(t, r, "POST", "/owner/repo/wiki/pages.json") + body := decodeJSON(t, r) + assertEqual(t, body["title"], "TestPage") + decoded, err := base64.StdEncoding.DecodeString(body["content_base64"].(string)) + if err != nil { + t.Fatalf("failed to decode content_base64: %v", err) + } + assertEqual(t, string(decoded), "Hello World") + + writeJSON(t, w, map[string]interface{}{ + "title": "TestPage", + "slug": "TestPage", + }) + }) + defer server.Close() + + if err := runWikiShortcut(t, server, "create", map[string]string{ + "title": "TestPage", + "body": "Hello World", + }); err != nil { + t.Fatalf("create shortcut failed: %v", err) + } +} + +// --- Update --- + +func TestWikiUpdate(t *testing.T) { + server := newWikiTestServer(t, func(w http.ResponseWriter, r *http.Request) { + assertRequest(t, r, "PATCH", "/owner/repo/wiki/pages/home.json") + body := decodeJSON(t, r) + assertEqual(t, body["title"], "Updated Title") + decoded, err := base64.StdEncoding.DecodeString(body["content_base64"].(string)) + if err != nil { + t.Fatalf("failed to decode content_base64: %v", err) + } + assertEqual(t, string(decoded), "Updated content") + + writeJSON(t, w, map[string]interface{}{ + "title": "Updated Title", + "slug": "home", + }) + }) + defer server.Close() + + if err := runWikiShortcut(t, server, "update", map[string]string{ + "slug": "home", + "title": "Updated Title", + "body": "Updated content", + }); err != nil { + t.Fatalf("update shortcut failed: %v", err) + } +} + +// --- Delete --- + +func TestWikiDelete(t *testing.T) { + server := newWikiTestServer(t, func(w http.ResponseWriter, r *http.Request) { + assertRequest(t, r, "DELETE", "/owner/repo/wiki/pages/old-page.json") + writeJSON(t, w, map[string]interface{}{ + "message": "deleted", + }) + }) + defer server.Close() + + if err := runWikiShortcut(t, server, "delete", map[string]string{ + "slug": "old-page", + }); err != nil { + t.Fatalf("delete shortcut failed: %v", err) + } +} + // --- test helpers --- func runWikiShortcut(t *testing.T, server *httptest.Server, name string, args map[string]string) error { @@ -79,3 +175,19 @@ func writeJSON(t *testing.T, w http.ResponseWriter, payload interface{}) { t.Fatalf("failed to write response: %v", err) } } + +func decodeJSON(t *testing.T, r *http.Request) map[string]interface{} { + t.Helper() + var m map[string]interface{} + if err := json.NewDecoder(r.Body).Decode(&m); err != nil { + t.Fatalf("failed to decode request body: %v", err) + } + return m +} + +func assertEqual(t *testing.T, got, want interface{}) { + t.Helper() + if got != want { + t.Fatalf("got %v, want %v", got, want) + } +}