diff --git a/tools/cfl/internal/cmd/page/edit.go b/tools/cfl/internal/cmd/page/edit.go index 0165a6f2..c24ed72b 100644 --- a/tools/cfl/internal/cmd/page/edit.go +++ b/tools/cfl/internal/cmd/page/edit.go @@ -26,6 +26,8 @@ type editOptions struct { bodyFormatExplicit bool legacy bool parent string + message string + messageExplicit bool } func newEditCmd(rootOpts *root.Options) *cobra.Command { @@ -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" @@ -93,6 +98,7 @@ 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) }, } @@ -100,6 +106,7 @@ without conversion.`, 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)") @@ -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, }, } diff --git a/tools/cfl/internal/cmd/page/edit_test.go b/tools/cfl/internal/cmd/page/edit_test.go index 5a2c1ff3..2bc69a58 100644 --- a/tools/cfl/internal/cmd/page/edit_test.go +++ b/tools/cfl/internal/cmd/page/edit_test.go @@ -124,6 +124,105 @@ func TestRunEdit_TitleOnly(t *testing.T) { testutil.Equal(t, "

Keep this

", 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": "

Keep this

"}}, + "_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": "

Keep this

"}}, + "_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) {