Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion tools/cfl/internal/cmd/page/edit.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ type editOptions struct {
bodyFormatExplicit bool
legacy bool
parent string
message string
messageExplicit bool
}

func newEditCmd(rootOpts *root.Options) *cobra.Command {
Expand Down Expand Up @@ -71,6 +73,9 @@ without conversion.`,
# Move page to a new parent
cfl page edit 12345 --parent 67890

# Update with a custom version comment
cfl page edit 12345 --file content.md -m "Fixed typos"

# Move page and update title
cfl page edit 12345 --parent 67890 --title "New Title"

Expand All @@ -93,13 +98,15 @@ without conversion.`,
RunE: func(cmd *cobra.Command, args []string) error {
opts.pageID = args[0]
opts.bodyFormatExplicit = cmd.Flags().Changed("body-format")
opts.messageExplicit = cmd.Flags().Changed("message")
return runEdit(cmd.Context(), opts)
},
}

cmd.Flags().StringVarP(&opts.title, "title", "t", "", "New page title")
cmd.Flags().StringVarP(&opts.file, "file", "f", "", "Read content from file")
cmd.Flags().StringVarP(&opts.parent, "parent", "p", "", "Move page to new parent page ID")
cmd.Flags().StringVarP(&opts.message, "message", "m", "", "Version comment for the update")
cmd.Flags().BoolVar(&opts.editor, "editor", false, "Open editor for content")
cmd.Flags().StringVar(&opts.bodyFormat, "body-format", bodyFormatMarkdown, "Input format: markdown, adf, or xhtml")
cmd.Flags().BoolVar(&opts.legacy, "legacy", false, "Edit page in legacy editor format (Markdown input only)")
Expand Down Expand Up @@ -187,13 +194,19 @@ func runEdit(ctx context.Context, opts *editOptions) error {
}
}

// Backwards compatibility
versionMessage := "Updated via cfl"
if opts.messageExplicit {
versionMessage = opts.message
}

req := &api.UpdatePageRequest{
ID: opts.pageID,
Status: "current",
Title: newTitle,
Version: &api.Version{
Number: existingPage.Version.Number + 1,
Message: "Updated via cfl",
Message: versionMessage,
},
}

Expand Down
99 changes: 99 additions & 0 deletions tools/cfl/internal/cmd/page/edit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,105 @@ func TestRunEdit_TitleOnly(t *testing.T) {
testutil.Equal(t, "<p>Keep this</p>", storage["value"])
}

func TestRunEdit_CustomMessage(t *testing.T) {
t.Parallel()
var receivedBody map[string]any
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch {
case r.Method == "GET" && strings.Contains(r.URL.Path, "/pages/12345"):
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte(`{
"id": "12345",
"title": "Old Title",
"version": {"number": 3},
"body": {"storage": {"representation": "storage", "value": "<p>Keep this</p>"}},
"_links": {"webui": "/pages/12345"}
}`))
case r.Method == "PUT" && strings.Contains(r.URL.Path, "/pages/12345"):
body, _ := io.ReadAll(r.Body)
_ = json.Unmarshal(body, &receivedBody)
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte(`{
"id": "12345",
"title": "Old Title",
"version": {"number": 4},
"_links": {"webui": "/pages/12345"}
}`))
default:
w.WriteHeader(http.StatusNotFound)
}
}))
defer server.Close()

rootOpts := newEditTestRootOptions()
client := api.NewClient(server.URL, "test@example.com", "token")
rootOpts.SetAPIClient(client)
rootOpts.Stdin = nil
opts := &editOptions{
Options: rootOpts,
pageID: "12345",
title: "Old Title",
message: "Fixed typos",
messageExplicit: true,
}

err := runEdit(context.Background(), opts)
testutil.RequireNoError(t, err)

version := receivedBody["version"].(map[string]any)
testutil.Equal(t, "Fixed typos", version["message"])
}

func TestRunEdit_EmptyMessageOmitsField(t *testing.T) {
t.Parallel()
var receivedBody map[string]any
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch {
case r.Method == "GET" && strings.Contains(r.URL.Path, "/pages/12345"):
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte(`{
"id": "12345",
"title": "Old Title",
"version": {"number": 3},
"body": {"storage": {"representation": "storage", "value": "<p>Keep this</p>"}},
"_links": {"webui": "/pages/12345"}
}`))
case r.Method == "PUT" && strings.Contains(r.URL.Path, "/pages/12345"):
body, _ := io.ReadAll(r.Body)
_ = json.Unmarshal(body, &receivedBody)
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte(`{
"id": "12345",
"title": "Old Title",
"version": {"number": 4},
"_links": {"webui": "/pages/12345"}
}`))
default:
w.WriteHeader(http.StatusNotFound)
}
}))
defer server.Close()

rootOpts := newEditTestRootOptions()
client := api.NewClient(server.URL, "test@example.com", "token")
rootOpts.SetAPIClient(client)
rootOpts.Stdin = nil
opts := &editOptions{
Options: rootOpts,
pageID: "12345",
title: "Old Title",
message: "",
messageExplicit: true,
}

err := runEdit(context.Background(), opts)
testutil.RequireNoError(t, err)

version := receivedBody["version"].(map[string]any)
_, hasMessage := version["message"]
testutil.Equal(t, false, hasMessage)
}

func TestRunEdit_PageNotFound(t *testing.T) {
t.Parallel()
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
Expand Down