cli/pkg/cmd/discussion/create/create.go
Babak K. Shandiz 47cabb26ae
fix(discussion create): remove success message from stderr
Only print the discussion URL to stdout. No additional output on stderr.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-07 09:08:51 +01:00

162 lines
4.2 KiB
Go

package create
import (
"fmt"
"net/http"
"strings"
"github.com/MakeNowJust/heredoc"
"github.com/cli/cli/v2/internal/ghrepo"
"github.com/cli/cli/v2/internal/prompter"
"github.com/cli/cli/v2/pkg/cmd/discussion/client"
"github.com/cli/cli/v2/pkg/cmd/discussion/shared"
"github.com/cli/cli/v2/pkg/cmdutil"
"github.com/cli/cli/v2/pkg/iostreams"
"github.com/spf13/cobra"
)
// CreateOptions holds the configuration for the discussion create command.
type CreateOptions struct {
IO *iostreams.IOStreams
HttpClient func() (*http.Client, error)
BaseRepo func() (ghrepo.Interface, error)
Client func() (client.DiscussionClient, error)
Prompter prompter.Prompter
Title string
Body string
Category string
Labels []string
}
// NewCmdCreate returns a cobra command for creating a GitHub Discussion.
func NewCmdCreate(f *cmdutil.Factory, runF func(*CreateOptions) error) *cobra.Command {
opts := &CreateOptions{
IO: f.IOStreams,
HttpClient: f.HttpClient,
Prompter: f.Prompter,
Client: shared.DiscussionClientFunc(f),
}
cmd := &cobra.Command{
Use: "create",
Short: "Create a new discussion",
Long: heredoc.Doc(`
Create a new GitHub Discussion in a repository.
With '--title', '--body', and '--category', a discussion is created non-interactively.
Omitting any of these flags triggers interactive prompts when connected to a terminal.
`),
Example: heredoc.Doc(`
# Create interactively
$ gh discussion create
# Create non-interactively
$ gh discussion create --title "My question" --category "Q&A" --body "Details here"
`),
Args: cmdutil.NoArgsQuoteReminder,
RunE: func(cmd *cobra.Command, args []string) error {
opts.BaseRepo = f.BaseRepo
if opts.Title != "" && strings.TrimSpace(opts.Title) == "" {
return cmdutil.FlagErrorf("title cannot be blank")
}
if opts.Body != "" && strings.TrimSpace(opts.Body) == "" {
return cmdutil.FlagErrorf("body cannot be blank")
}
if opts.Category != "" && strings.TrimSpace(opts.Category) == "" {
return cmdutil.FlagErrorf("category cannot be blank")
}
needsInput := opts.Title == "" || opts.Category == "" || opts.Body == ""
if needsInput && !opts.IO.CanPrompt() {
return cmdutil.FlagErrorf("--title, --body, and --category are required when not running interactively")
}
if runF != nil {
return runF(opts)
}
return createRun(opts)
},
}
cmdutil.EnableRepoOverride(cmd, f)
cmd.Flags().StringVarP(&opts.Title, "title", "t", "", "Title for the discussion")
cmd.Flags().StringVarP(&opts.Body, "body", "b", "", "Body for the discussion")
cmd.Flags().StringVarP(&opts.Category, "category", "c", "", "Category name or slug for the discussion")
cmd.Flags().StringSliceVarP(&opts.Labels, "label", "l", nil, "Labels to apply to the discussion")
return cmd
}
func createRun(opts *CreateOptions) error {
repo, err := opts.BaseRepo()
if err != nil {
return err
}
c, err := opts.Client()
if err != nil {
return err
}
categories, err := c.ListCategories(repo)
if err != nil {
return fmt.Errorf("fetching categories: %w", err)
}
if opts.Title == "" {
opts.Title, err = opts.Prompter.Input("Discussion title", "")
if err != nil {
return err
}
if strings.TrimSpace(opts.Title) == "" {
return fmt.Errorf("title cannot be blank")
}
}
var category *client.DiscussionCategory
if opts.Category != "" {
category, err = shared.MatchCategory(opts.Category, categories)
if err != nil {
return err
}
} else {
names := make([]string, len(categories))
for i, cat := range categories {
names[i] = cat.Name
}
idx, err := opts.Prompter.Select("Discussion category", "", names)
if err != nil {
return err
}
category = &categories[idx]
}
if opts.Body == "" {
opts.Body, err = opts.Prompter.MarkdownEditor("Discussion body", "", false)
if err != nil {
return err
}
if strings.TrimSpace(opts.Body) == "" {
return fmt.Errorf("body cannot be blank")
}
}
input := client.CreateDiscussionInput{
CategoryID: category.ID,
Title: opts.Title,
Body: opts.Body,
Labels: opts.Labels,
}
discussion, err := c.Create(repo, input)
if err != nil {
return fmt.Errorf("failed to create discussion: %w", err)
}
fmt.Fprintln(opts.IO.Out, discussion.URL)
return nil
}