mirror of
https://gitea.com/gitea/tea.git
synced 2026-10-26 11:01:25 +01:00
feat(wiki): rename pages with --title alone, page lists on the client
wiki edit P --title New failed with "supply --body": renaming now keeps the page's content, and edit needs one of --title, --body, --body-file or --editor. wiki list --limit 1 returned every page because Gitea replaces a limit of 1 with its default; the page list is now read whole and paged on the client, so --limit and --page hold and the context line counts the pages. wiki create takes the title as an argument and, without --body, asks for the content in the editor or an inline multi-line field. wiki view shows the author, last update and revision count above the rendered page, and --web opens it. wiki list and revisions show headed columns, page names complete with Tab, and every change reports a ✓ line. Signed-off-by: bircni <bircni@icloud.com>
This commit is contained in:
6 files changed
+400
-143
No files matched your search
@@ -494,12 +494,6 @@ const (
|
||||
time delete
|
||||
time list
|
||||
time reset
|
||||
wiki create
|
||||
wiki delete
|
||||
wiki edit
|
||||
wiki list
|
||||
wiki revisions
|
||||
wiki view
|
||||
`
|
||||
longsToWrite = `
|
||||
issue
|
||||
@@ -512,6 +506,5 @@ const (
|
||||
pr attachment
|
||||
pr comment
|
||||
time
|
||||
wiki
|
||||
`
|
||||
)
|
||||
@@ -240,7 +240,7 @@ func TestUsageErrorsPrecedeRequests(t *testing.T) {
|
||||
{[]string{"webhook", "delete", "not-an-id"}, "invalid resource number \"not-an-id\""},
|
||||
{[]string{"webhook", "list", "--org", "organization", "--account"}, "--org, --account, --global, and --repo select mutually exclusive scopes"},
|
||||
{[]string{"webhook", "list", "--global", "-R", "owner/repo"}, "--org, --account, --global, and --repo select mutually exclusive scopes"},
|
||||
{[]string{"wiki", "create", "--body-file", "-"}, "--body-file - requires --title"},
|
||||
{[]string{"wiki", "create", "--body-file", "-"}, "--body-file - requires a title"},
|
||||
{[]string{"wiki", "create", "--title", "Home", "--body", "text", "--json=created_at"}, "unknown JSON field \"created_at\""},
|
||||
{[]string{"wiki", "edit", "Home", "--body="}, "wiki content cannot be empty"},
|
||||
{[]string{"wiki", "revisions", "Home", "--page", "0"}, `"--page" flag: must be a positive integer`},
|
||||
@@ -258,7 +258,6 @@ func TestConfirmationsNameResolvedValues(t *testing.T) {
|
||||
inputs map[string]string
|
||||
want string
|
||||
}{
|
||||
{[]string{"wiki", "create"}, map[string]string{"title": "Home", "body": "text"}, "create wiki page Home on alice/project"},
|
||||
{[]string{"release", "create"}, map[string]string{"Tag": "v1.0.0"}, "Create release v1.0.0 in alice/project?"},
|
||||
{[]string{"time", "delete", "5", "7"}, nil, "delete tracked time entry 7 on alice/project #5"},
|
||||
} {
|
||||
|
||||
+294
-119
@@ -4,8 +4,10 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"gitea.dev/tea/internal/clierr"
|
||||
@@ -14,146 +16,319 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func wikiRecord(item services.WikiPage) terminal.Record {
|
||||
return terminal.Record{Heading: []terminal.Cell{{Text: item.Title, Bold: true}}, Lines: []string{item.Body, item.URL}}
|
||||
func (a *application) wikiCommand() *cobra.Command {
|
||||
group := &cobra.Command{
|
||||
Use: "wiki",
|
||||
Short: "Manage repository wiki pages",
|
||||
Long: "List, view, create, edit and delete the pages of a repository's wiki, and list their revisions.",
|
||||
}
|
||||
group.AddCommand(a.wikiListCommand(), a.wikiViewCommand(), a.wikiRevisionsCommand(), a.wikiCreateCommand(), a.wikiEditCommand(), a.wikiDeleteCommand())
|
||||
return group
|
||||
}
|
||||
|
||||
func (a *application) wikiCommand() *cobra.Command {
|
||||
group := &cobra.Command{Use: "wiki", Short: "Manage repository wiki pages"}
|
||||
// completeWikiPages completes the titles of the repository's wiki pages.
|
||||
func (a *application) completeWikiPages() cobra.CompletionFunc {
|
||||
return a.apiCompletion(true, func(ctx context.Context, t target, _ string) ([]cobra.Completion, error) {
|
||||
pages, err := services.Wiki{Client: t.client, Repository: t.Repo}.List(ctx, completionLimit, 1)
|
||||
return describe(pages, func(page services.WikiPage) (string, string) { return page.Title, "" }), err
|
||||
})
|
||||
}
|
||||
|
||||
func (a *application) wikiListCommand() *cobra.Command {
|
||||
var limit, page int
|
||||
list := &cobra.Command{Use: "list", Short: "List wiki pages", Args: argsExact(0), RunE: func(cmd *cobra.Command, _ []string) error {
|
||||
target, err := a.resolve(cmd.Context(), true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
items, err := (services.Wiki{Client: target.client, Repository: target.Repo}).List(cmd.Context(), limit, page)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return writeList(a, cmd, items, func(item services.WikiPage) []terminal.Cell {
|
||||
return terminal.Row(item.Title, item.Author, item.UpdatedAt)
|
||||
})
|
||||
}}
|
||||
pageFlags(list, &limit, &page)
|
||||
group.AddCommand(list)
|
||||
var revisionPage int
|
||||
revisions := &cobra.Command{Use: "revisions <page>", Short: "List revisions of a wiki page", Args: argsExact(1), RunE: func(cmd *cobra.Command, args []string) error {
|
||||
target, err := a.resolve(cmd.Context(), true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
items, err := (services.Wiki{Client: target.client, Repository: target.Repo}).Revisions(cmd.Context(), args[0], revisionPage)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return writeList(a, cmd, items, func(item services.WikiRevision) []terminal.Cell {
|
||||
return terminal.Row(item.SHA, item.Author, item.CreatedAt, item.Message)
|
||||
})
|
||||
}}
|
||||
positiveIntVar(revisions, &revisionPage, "page", 1, math.MaxInt, "Revision page (server controls page size)")
|
||||
group.AddCommand(revisions)
|
||||
for _, verb := range []string{"view", "create", "edit", "delete"} {
|
||||
var title, body, file, message string
|
||||
var useEditor bool
|
||||
command := &cobra.Command{Use: verb + " <page>", Short: titleCase(verb) + " a wiki page", Args: argsExact(1)}
|
||||
switch verb {
|
||||
case "create":
|
||||
command.Use = verb
|
||||
command.Args = argsExact(0)
|
||||
case "delete":
|
||||
command.Annotations = textOutput("wiki page deletion does not return a resource")
|
||||
}
|
||||
if verb == "create" || verb == "edit" {
|
||||
command.Flags().StringVar(&title, "title", "", "Page title")
|
||||
command.Flags().BoolVar(&useEditor, "editor", false, "Edit page content in an editor")
|
||||
command.Flags().StringVar(&body, "body", "", "Page content")
|
||||
command.Flags().StringVar(&file, "body-file", "", "Read content from file, or - for stdin")
|
||||
command.Flags().StringVar(&message, "message", "", "Wiki commit message")
|
||||
}
|
||||
command.RunE = func(cmd *cobra.Command, args []string) (runErr error) {
|
||||
var editorDraft terminal.Draft
|
||||
defer finishDraft(&editorDraft, &runErr)
|
||||
command := &cobra.Command{
|
||||
Use: "list",
|
||||
Short: "List wiki pages",
|
||||
Example: "$ tea wiki list\n$ tea wiki list -R alice/project --json title,url",
|
||||
Args: argsExact(0),
|
||||
RunE: func(cmd *cobra.Command, _ []string) error {
|
||||
target, err := a.resolve(cmd.Context(), true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
result, err := (services.Wiki{Client: target.client, Repository: target.Repo}).ListPage(cmd.Context(), limit, page)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
spec := listSpec[services.WikiPage]{
|
||||
Columns: []terminal.Column{{Header: "Title", Flex: true}, {Header: "Author"}, {Header: "Updated"}, {Header: "URL", PipedOnly: true}},
|
||||
Row: func(item services.WikiPage) []terminal.Cell {
|
||||
return []terminal.Cell{{Text: item.Title, Link: item.URL}, {Text: item.Author}, {Time: terminal.ParseTime(item.UpdatedAt)}, {Text: item.URL}}
|
||||
},
|
||||
Context: "wiki pages in " + target.Repo, Empty: "no wiki pages in " + target.Repo,
|
||||
}
|
||||
return writeTable(a, cmd, result.Items, spec, listPage{Number: page, More: result.More, Total: result.Total, Counted: result.Counted})
|
||||
},
|
||||
}
|
||||
pageFlags(command, &limit, &page)
|
||||
return command
|
||||
}
|
||||
|
||||
func (a *application) wikiViewCommand() *cobra.Command {
|
||||
var web bool
|
||||
command := &cobra.Command{
|
||||
Use: "view <page>",
|
||||
Short: "View a wiki page",
|
||||
Long: "View a wiki page, rendered on a terminal.",
|
||||
Example: "$ tea wiki view Home\n$ tea wiki view \"Getting Started\" --web",
|
||||
Args: argsExact(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
target, err := a.resolve(cmd.Context(), true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
item, err := (services.Wiki{Client: target.client, Repository: target.Repo}).View(cmd.Context(), args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if web {
|
||||
return a.openBrowser(cmd, item.URL)
|
||||
}
|
||||
return writeView(a, cmd, item, a.wikiView)
|
||||
},
|
||||
}
|
||||
command.Flags().BoolVarP(&web, "web", "w", false, "Open the page in the browser")
|
||||
command.ValidArgsFunction = a.completeWikiPages()
|
||||
return command
|
||||
}
|
||||
|
||||
// wikiView shows a wiki page with its content as the body.
|
||||
func (a *application) wikiView(item services.WikiPage) terminal.View {
|
||||
var meta []string
|
||||
if item.Author != "" {
|
||||
meta = append(meta, item.Author)
|
||||
}
|
||||
if updated := terminal.ParseTime(item.UpdatedAt); !updated.IsZero() {
|
||||
meta = append(meta, "updated "+terminal.RelativeTime(a.deps.Now(), updated))
|
||||
}
|
||||
if item.CommitCount > 0 {
|
||||
meta = append(meta, countNoun(int(item.CommitCount), "revision"))
|
||||
}
|
||||
return terminal.View{
|
||||
Title: item.Title, Meta: strings.Join(meta, " · "), Body: item.Body, Kind: "wiki page", URL: item.URL,
|
||||
Fields: []terminal.Field{{Label: "Author", Value: item.Author, PipedOnly: true}, {Label: "Updated", Value: item.UpdatedAt, PipedOnly: true}},
|
||||
}
|
||||
}
|
||||
|
||||
func (a *application) wikiRevisionsCommand() *cobra.Command {
|
||||
var page int
|
||||
command := &cobra.Command{
|
||||
Use: "revisions <page>",
|
||||
Short: "List revisions of a wiki page",
|
||||
Example: "$ tea wiki revisions Home",
|
||||
Args: argsExact(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
target, err := a.resolve(cmd.Context(), true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
items, err := (services.Wiki{Client: target.client, Repository: target.Repo}).Revisions(cmd.Context(), args[0], page)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
spec := listSpec[services.WikiRevision]{
|
||||
Columns: []terminal.Column{{Header: "Commit"}, {Header: "Author"}, {Header: "Date"}, {Header: "Message", Flex: true}},
|
||||
Row: func(item services.WikiRevision) []terminal.Cell {
|
||||
message, _, _ := strings.Cut(item.Message, "\n")
|
||||
sha := item.SHA
|
||||
if a.deps.Streams.OutTTY {
|
||||
sha = shortSHA(sha)
|
||||
}
|
||||
return []terminal.Cell{{Text: sha, Muted: true}, {Text: item.Author}, {Time: terminal.ParseTime(item.CreatedAt)}, {Text: message}}
|
||||
},
|
||||
Context: "revisions of wiki page " + strconv.Quote(args[0]), Empty: "no revisions of wiki page " + strconv.Quote(args[0]),
|
||||
}
|
||||
return writeTable(a, cmd, items, spec, listPage{Number: page, Counted: false, More: false})
|
||||
},
|
||||
}
|
||||
positiveIntVar(command, &page, "page", 1, math.MaxInt, "Revision page (server controls page size)")
|
||||
command.ValidArgsFunction = a.completeWikiPages()
|
||||
return command
|
||||
}
|
||||
|
||||
// wikiContent are the flags of wiki create and wiki edit.
|
||||
type wikiContent struct {
|
||||
title, body, file, message string
|
||||
editor bool
|
||||
}
|
||||
|
||||
func (c *wikiContent) register(cmd *cobra.Command) {
|
||||
flags := cmd.Flags()
|
||||
flags.StringVarP(&c.title, "title", "t", "", "Page title")
|
||||
flags.BoolVarP(&c.editor, "editor", "e", false, "Write the page content in an editor")
|
||||
flags.StringVarP(&c.body, "body", "b", "", "Page content")
|
||||
flags.StringVarP(&c.file, "body-file", "F", "", "Read the page content from a file, or - for standard input")
|
||||
flags.StringVarP(&c.message, "message", "m", "", "Commit message of the change")
|
||||
}
|
||||
|
||||
func (a *application) wikiCreateCommand() *cobra.Command {
|
||||
var content wikiContent
|
||||
command := &cobra.Command{
|
||||
Use: "create [<title>]",
|
||||
Short: "Create a wiki page",
|
||||
Long: "Create a wiki page. Without --body or --body-file, the content is written in an editor or typed on the terminal.",
|
||||
Example: `$ tea wiki create "Getting Started" --body-file docs/start.md
|
||||
$ tea wiki create Home --editor`,
|
||||
Args: usageArgs(cobra.MaximumNArgs(1)),
|
||||
RunE: func(cmd *cobra.Command, args []string) (runErr error) {
|
||||
var draft terminal.Draft
|
||||
defer finishDraft(&draft, &runErr)
|
||||
if len(args) > 0 {
|
||||
if cmd.Flags().Changed("title") {
|
||||
return clierr.Wrap(clierr.Usage, errors.New("supply the title as an argument or --title, not both"))
|
||||
}
|
||||
content.title = args[0]
|
||||
}
|
||||
if err := validateBodySources(cmd); err != nil {
|
||||
return err
|
||||
}
|
||||
prompted := false
|
||||
if verb == "create" || verb == "edit" {
|
||||
if file == "-" && verb == "create" && title == "" {
|
||||
return clierr.Wrap(clierr.Usage, errors.New("--body-file - requires --title; stdin cannot also supply a prompt"))
|
||||
}
|
||||
var err error
|
||||
if body, err = a.readBody(cmd, body, file); err != nil {
|
||||
if content.file == "-" && content.title == "" {
|
||||
return clierr.Wrap(clierr.Usage, errors.New("--body-file - requires a title; stdin cannot also supply a prompt"))
|
||||
}
|
||||
body, err := a.readBody(cmd, content.body, content.file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := a.requireInput(cmd, &content.title, "title", "Page title", nil); err != nil {
|
||||
return err
|
||||
}
|
||||
if strings.TrimSpace(content.title) == "" {
|
||||
return clierr.Wrap(clierr.Usage, errors.New("wiki title cannot be empty"))
|
||||
}
|
||||
target, err := a.resolve(cmd.Context(), true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !cmd.Flags().Changed("body") && !cmd.Flags().Changed("body-file") {
|
||||
if draft, err = a.wikiBody(cmd, content.editor, ""); err != nil {
|
||||
return err
|
||||
}
|
||||
if verb == "create" {
|
||||
prompted, err = a.require(cmd, &title, "title")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if !useEditor && !cmd.Flags().Changed("body") && !cmd.Flags().Changed("body-file") {
|
||||
asked, err := a.require(cmd, &body, "body")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
prompted = prompted || asked
|
||||
}
|
||||
if !useEditor && strings.TrimSpace(body) == "" {
|
||||
return clierr.Wrap(clierr.Usage, errors.New("wiki content cannot be empty"))
|
||||
}
|
||||
if (verb == "create" || cmd.Flags().Changed("title")) && strings.TrimSpace(title) == "" {
|
||||
return clierr.Wrap(clierr.Usage, errors.New("wiki title cannot be empty"))
|
||||
}
|
||||
body = draft.Body
|
||||
}
|
||||
if strings.TrimSpace(body) == "" {
|
||||
return clierr.Wrap(clierr.Usage, errors.New("wiki content cannot be empty"))
|
||||
}
|
||||
item, err := (services.Wiki{Client: target.client, Repository: target.Repo}).Create(cmd.Context(), services.WikiOptions{Title: content.title, Body: body, Message: content.message})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a.done(cmd, "Created wiki page %q in %s", item.Title, target.Repo)
|
||||
if a.options.json != "" {
|
||||
return a.writeJSON(cmd, item)
|
||||
}
|
||||
return a.printURL(cmd, item.URL)
|
||||
},
|
||||
}
|
||||
content.register(command)
|
||||
return command
|
||||
}
|
||||
|
||||
// wikiBody collects page content: in the editor with --editor, else in the editor or an inline
|
||||
// field on a terminal. Without a terminal it fails, naming --body.
|
||||
func (a *application) wikiBody(cmd *cobra.Command, editor bool, initial string) (terminal.Draft, error) {
|
||||
if editor {
|
||||
return a.editDraft(cmd, initial)
|
||||
}
|
||||
s, err := a.deps.Settings.Load()
|
||||
if err != nil {
|
||||
return terminal.Draft{}, err
|
||||
}
|
||||
if !a.policy(s).CanPrompt(a.deps.Streams) {
|
||||
return terminal.Draft{}, clierr.Wrap(clierr.Usage, errors.New("missing required input: supply --body, --body-file or --editor"))
|
||||
}
|
||||
return a.bodyEditor(cmd)(cmd.Context(), initial)
|
||||
}
|
||||
|
||||
func (a *application) wikiEditCommand() *cobra.Command {
|
||||
var content wikiContent
|
||||
command := &cobra.Command{
|
||||
Use: "edit <page>",
|
||||
Short: "Edit a wiki page",
|
||||
Long: "Change the title or the content of a wiki page. Renaming with --title alone keeps the content.",
|
||||
Example: `$ tea wiki edit Home --body-file docs/home.md --message "Rewrite the home page"
|
||||
$ tea wiki edit "Old Title" --title "New Title"
|
||||
$ tea wiki edit Home --editor`,
|
||||
Args: argsExact(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) (runErr error) {
|
||||
var draft terminal.Draft
|
||||
defer finishDraft(&draft, &runErr)
|
||||
if err := validateBodySources(cmd); err != nil {
|
||||
return err
|
||||
}
|
||||
changed := cmd.Flags().Changed
|
||||
if !changed("title") && !changed("body") && !changed("body-file") && !content.editor {
|
||||
return clierr.Wrap(clierr.Usage, errors.New("supply --title, --body, --body-file or --editor"))
|
||||
}
|
||||
if changed("title") && strings.TrimSpace(content.title) == "" {
|
||||
return clierr.Wrap(clierr.Usage, errors.New("wiki title cannot be empty"))
|
||||
}
|
||||
body, err := a.readBody(cmd, content.body, content.file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if (changed("body") || changed("body-file")) && strings.TrimSpace(body) == "" {
|
||||
return clierr.Wrap(clierr.Usage, errors.New("wiki content cannot be empty"))
|
||||
}
|
||||
target, err := a.resolve(cmd.Context(), true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
service := services.Wiki{Client: target.client, Repository: target.Repo}
|
||||
if useEditor {
|
||||
initial := ""
|
||||
if verb == "edit" {
|
||||
item, err := service.View(cmd.Context(), args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
initial = item.Body
|
||||
}
|
||||
editorDraft, err = a.editDraft(cmd, initial)
|
||||
if content.editor || (!changed("body") && !changed("body-file")) {
|
||||
current, err := service.View(cmd.Context(), args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
body = editorDraft.Body
|
||||
if strings.TrimSpace(body) == "" {
|
||||
return clierr.Wrap(clierr.Usage, errors.New("wiki content cannot be empty"))
|
||||
body = current.Body
|
||||
if content.editor {
|
||||
if draft, err = a.editDraft(cmd, current.Body); err != nil {
|
||||
return err
|
||||
}
|
||||
if body = draft.Body; strings.TrimSpace(body) == "" {
|
||||
return clierr.Wrap(clierr.Usage, errors.New("wiki content cannot be empty"))
|
||||
}
|
||||
}
|
||||
}
|
||||
if verb == "delete" || prompted {
|
||||
subject := title
|
||||
if verb != "create" {
|
||||
subject = args[0]
|
||||
}
|
||||
if err := a.confirm(cmd, verb+" wiki page "+subject+" on "+target.Repo); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
var item services.WikiPage
|
||||
switch verb {
|
||||
case "view":
|
||||
item, err = service.View(cmd.Context(), args[0])
|
||||
case "create":
|
||||
item, err = service.Create(cmd.Context(), services.WikiOptions{Title: title, Body: body, Message: message})
|
||||
case "edit":
|
||||
item, err = service.Edit(cmd.Context(), args[0], services.WikiOptions{Title: title, Body: body, Message: message})
|
||||
case "delete":
|
||||
return service.Delete(cmd.Context(), args[0])
|
||||
}
|
||||
item, err := service.Edit(cmd.Context(), args[0], services.WikiOptions{Title: content.title, Body: body, Message: content.message})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return writeRecord(a, cmd, item, wikiRecord)
|
||||
}
|
||||
group.AddCommand(command)
|
||||
if item.Title != args[0] {
|
||||
a.done(cmd, "Renamed wiki page %q to %q in %s", args[0], item.Title, target.Repo)
|
||||
} else {
|
||||
a.done(cmd, "Edited wiki page %q in %s", item.Title, target.Repo)
|
||||
}
|
||||
return a.writeMutationJSON(cmd, item)
|
||||
},
|
||||
}
|
||||
return group
|
||||
content.register(command)
|
||||
command.ValidArgsFunction = a.completeWikiPages()
|
||||
return command
|
||||
}
|
||||
|
||||
func (a *application) wikiDeleteCommand() *cobra.Command {
|
||||
command := &cobra.Command{
|
||||
Use: "delete <page>",
|
||||
Short: "Delete a wiki page",
|
||||
Example: "$ tea wiki delete \"Old Notes\" --yes",
|
||||
Annotations: map[string]string{"tea.confirm": "true", "tea.text": "wiki page deletion does not return a resource"},
|
||||
Args: argsExact(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
target, err := a.resolve(cmd.Context(), true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
subject := "wiki page " + strconv.Quote(args[0]) + " from " + target.Repo
|
||||
if err := a.confirmAction(cmd, terminal.Confirmation{Prompt: "Delete " + subject + "?", NonTTY: "delete " + subject}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := (services.Wiki{Client: target.client, Repository: target.Repo}).Delete(cmd.Context(), args[0]); err != nil {
|
||||
return err
|
||||
}
|
||||
a.done(cmd, "Deleted %s", subject)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
command.ValidArgsFunction = a.completeWikiPages()
|
||||
return command
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
// Copyright 2026 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestWikiEditRenamesAndKeepsTheContent(t *testing.T) {
|
||||
var requests []string
|
||||
server := newAuthenticatedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
requests = append(requests, r.Method+" "+r.URL.Path)
|
||||
if r.Method == http.MethodPatch {
|
||||
requirePayload(t, `{"title":"New Title","content_base64":"S2VlcCBtZQ=="}`, r.Body)
|
||||
_, _ = w.Write([]byte(`{"title":"New Title","content_base64":"S2VlcCBtZQ=="}`))
|
||||
return
|
||||
}
|
||||
_, _ = w.Write([]byte(`{"title":"Old Title","content_base64":"S2VlcCBtZQ=="}`))
|
||||
}))
|
||||
defer server.Close()
|
||||
deps, out, diagnostics := repoTTYDeps(t, server.URL)
|
||||
require.NoError(t, Execute(context.Background(), deps, []string{"wiki", "edit", "Old Title", "--title", "New Title", "-R", "alice/x", "--no-input"}))
|
||||
require.Equal(t, []string{"GET /api/v1/repos/alice/x/wiki/page/Old Title", "PATCH /api/v1/repos/alice/x/wiki/page/Old Title"}, requests)
|
||||
require.Empty(t, out.String())
|
||||
require.Equal(t, "✓ Renamed wiki page \"Old Title\" to \"New Title\" in alice/x\n", diagnostics.String())
|
||||
err := Execute(context.Background(), deps, []string{"wiki", "edit", "Home", "-R", "alice/x"})
|
||||
require.ErrorContains(t, err, "supply --title, --body, --body-file or --editor")
|
||||
}
|
||||
|
||||
func TestWikiListLimitsPagesOnTheClient(t *testing.T) {
|
||||
server := newAuthenticatedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Query().Get("page") != "1" {
|
||||
_, _ = w.Write([]byte(`[]`))
|
||||
return
|
||||
}
|
||||
_, _ = w.Write([]byte(`[{"title":"Getting Started","last_commit":{"author":{"name":"alice","date":"2026-10-11T18:00:00Z"}}},{"title":"Home"}]`))
|
||||
}))
|
||||
defer server.Close()
|
||||
deps, out, _ := repoTTYDeps(t, server.URL)
|
||||
require.NoError(t, Execute(context.Background(), deps, []string{"wiki", "list", "--limit", "1", "-R", "alice/x"}))
|
||||
require.Equal(t, `Showing 1 of 2 wiki pages in alice/x · next: --page 2
|
||||
|
||||
TITLE AUTHOR UPDATED
|
||||
Getting Started alice about 2 hours ago
|
||||
`, out.String())
|
||||
}
|
||||
|
||||
func TestWikiViewAndCreate(t *testing.T) {
|
||||
server := newAuthenticatedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method == http.MethodPost {
|
||||
requirePayload(t, `{"title":"Page Two","content_base64":"Ym9keQ=="}`, r.Body)
|
||||
}
|
||||
_, _ = w.Write([]byte(`{"title":"Page Two","html_url":"https://gitea.test/alice/x/wiki/Page-Two","content_base64":"Ym9keQ==","commit_count":3,
|
||||
"last_commit":{"author":{"name":"alice","date":"2026-10-11T19:00:00Z"}}}`))
|
||||
}))
|
||||
defer server.Close()
|
||||
deps, out, diagnostics := repoTTYDeps(t, server.URL)
|
||||
deps.Getenv = serverEnv(server.URL, map[string]string{"TERM": "dumb", "TEA_MARKDOWN": "raw"})
|
||||
require.NoError(t, Execute(context.Background(), deps, []string{"wiki", "view", "Page Two", "-R", "alice/x"}))
|
||||
require.Equal(t, "Page Two\nalice · updated about 1 hour ago · 3 revisions\n\nbody\n\nView this wiki page on Gitea: https://gitea.test/alice/x/wiki/Page-Two\n", out.String())
|
||||
out.Reset()
|
||||
require.NoError(t, Execute(context.Background(), deps, []string{"wiki", "create", "Page Two", "-b", "body", "-R", "alice/x"}))
|
||||
require.Equal(t, "https://gitea.test/alice/x/wiki/Page-Two\n", out.String())
|
||||
require.Equal(t, "✓ Created wiki page \"Page Two\" in alice/x\n", diagnostics.String())
|
||||
}
|
||||
Reference in new issue
Block a user