From d721bba29f6e592877a2d32774e347b58722aa97 Mon Sep 17 00:00:00 2001 From: Moira Daniella A Sebastian Date: Wed, 25 Feb 2026 13:10:42 +0100 Subject: [PATCH] Fix comment commands, comments reads multiple words, fix user as author, and implemented a function to list comments --- cmd/pm/main.go | 2 + internal/commands/issues/comment.go | 42 ++++++++++++------- internal/commands/issues/comments_list.go | 50 +++++++++++++++++++++++ pkg/repl/repl.go | 2 + pkg/repl/suggestions.go | 35 +++++++++++----- 5 files changed, 106 insertions(+), 25 deletions(-) create mode 100644 internal/commands/issues/comments_list.go diff --git a/cmd/pm/main.go b/cmd/pm/main.go index 291d10b..8fb8863 100644 --- a/cmd/pm/main.go +++ b/cmd/pm/main.go @@ -22,5 +22,7 @@ func init() { issuesCmd.RootCmd.AddCommand(issuesCmd.CreateCmd) issuesCmd.RootCmd.AddCommand(issuesCmd.DeleteCmd) issuesCmd.RootCmd.AddCommand(issuesCmd.UpdateCmd) + issuesCmd.RootCmd.AddCommand(issuesCmd.CommentCmd) + issuesCmd.RootCmd.AddCommand(issuesCmd.CommentsCmd) issuesCmd.RootCmd.AddCommand(surveyCmd.StatusCmd) } diff --git a/internal/commands/issues/comment.go b/internal/commands/issues/comment.go index e4ff27f..decef9c 100644 --- a/internal/commands/issues/comment.go +++ b/internal/commands/issues/comment.go @@ -2,6 +2,8 @@ package issuesCmd import ( "fmt" + "os" + "os/user" "strings" "github.com/spf13/cobra" @@ -13,19 +15,17 @@ var commentFlags struct { author string } -const commentCmdExample = `pm comment ISSUE-1 "Fix the login bug" -pm comment ISSUE-1 "LGTM" --author "alice" +const commentCmdExample = `pm comment ISSUE-1 Fix the login bug +pm comment ISSUE-1 LGTM --author alice pm comment ISSUE-1 -m "Needs review"` -// CommentCmd represents the comment command, -// which allows users to add a comment on an existing issue by its ID. var CommentCmd = &cobra.Command{ - Use: "comment [issue ID] [message]", + Use: "comment [issue ID] [message...]", Short: "Add a comment on an issue", - Long: `Add a comment on an issue by ID. Message can be passed as an argument or via --message.`, + Long: `Add a comment on an issue by ID. All arguments after the issue ID form the message (no quotes needed), or use --message.`, Example: commentCmdExample, - Args: cobra.RangeArgs(1, 2), + Args: cobra.RangeArgs(1, 100), // issue ID + up to 99 words for the message RunE: runCommentCmd, ValidArgsFunction: completeIssues, } @@ -35,13 +35,13 @@ var CommentCmd = &cobra.Command{ func runCommentCmd(cmd *cobra.Command, args []string) error { issueID := args[0] var text string - if len(args) >= 2 { - text = args[1] + if len(args) > 1 { + text = strings.Join(args[1:], " ") } else { text = commentFlags.message } if strings.TrimSpace(text) == "" { - return fmt.Errorf("comment text cannot be empty (use --message or pass as argument)") + return fmt.Errorf("comment text cannot be empty (use --message or pass words after the issue ID)") } app := AppFromContext(cmd.Context()) @@ -57,7 +57,7 @@ func runCommentCmd(cmd *cobra.Command, args []string) error { author := commentFlags.author if author == "" { - author = "cli" + author = defaultCommentAuthor() } comment, err := app.Issues.AddIssueComment(cmd.Context(), issue.ID, author, text) @@ -70,7 +70,21 @@ func runCommentCmd(cmd *cobra.Command, args []string) error { return nil } -func init() { - CommentCmd.Flags().StringVarP(&commentFlags.message, "message", "m", "", "Comment text (alternative to positional argument)") - CommentCmd.Flags().StringVarP(&commentFlags.author, "author", "a", "cli", "Author name for the comment") + +func defaultCommentAuthor() string { + if u, err := user.Current(); err == nil && u.Username != "" { + return u.Username + } + if s := os.Getenv("USER"); s != "" { + return s + } + if s := os.Getenv("USERNAME"); s != "" { + return s + } + return "user" +} + +func init() { + CommentCmd.Flags().StringVarP(&commentFlags.message, "message", "m", "", "Comment text (alternative to positional arguments)") + CommentCmd.Flags().StringVarP(&commentFlags.author, "author", "a", "", "Author name (default: current OS user)") } diff --git a/internal/commands/issues/comments_list.go b/internal/commands/issues/comments_list.go new file mode 100644 index 0000000..897ebfb --- /dev/null +++ b/internal/commands/issues/comments_list.go @@ -0,0 +1,50 @@ +package issuesCmd + +import ( + "fmt" + + "github.com/spf13/cobra" +) + +// CommentsCmd represents the command to list comments on an issue. +var CommentsCmd = &cobra.Command{ + Use: "comments [issue ID]", + Short: "List comments on an issue", + Long: `List all comments on an issue by ID.`, + + Args: cobra.ExactArgs(1), + RunE: runCommentsCmd, + ValidArgsFunction: completeIssues, +} + +// runCommentsCmd executes the comments command logic. +func runCommentsCmd(cmd *cobra.Command, args []string) error { + issueID := args[0] + + app := AppFromContext(cmd.Context()) + + issue, err := app.Issues.GetIssue(cmd.Context(), issueID) + if err != nil { + return fmt.Errorf("error fetching issue: %w", err) + } + if issue == nil { + return fmt.Errorf("issue with ID %s not found", issueID) + } + + comments, err := app.Issues.GetIssueComments(cmd.Context(), issue.ID) + if err != nil { + return fmt.Errorf("error fetching comments: %w", err) + } + + cmd.Printf("Comments on %s (%s):\n\n", issueID, issue.Title) + if len(comments) == 0 { + cmd.Println(" No comments yet.") + return nil + } + for _, c := range comments { + if c != nil { + cmd.Printf(" %s @ %s:\n %s\n\n", c.Author, c.CreatedAt.Format("2006-01-02 15:04"), c.Text) + } + } + return nil +} diff --git a/pkg/repl/repl.go b/pkg/repl/repl.go index bfbf51f..c12ab13 100644 --- a/pkg/repl/repl.go +++ b/pkg/repl/repl.go @@ -150,5 +150,7 @@ func init() { issuesCmd.RootCmd.AddCommand(issuesCmd.CreateCmd) issuesCmd.RootCmd.AddCommand(issuesCmd.DeleteCmd) issuesCmd.RootCmd.AddCommand(issuesCmd.UpdateCmd) + issuesCmd.RootCmd.AddCommand(issuesCmd.CommentCmd) + issuesCmd.RootCmd.AddCommand(issuesCmd.CommentsCmd) issuesCmd.RootCmd.AddCommand(surveyCmd.StatusCmd) } diff --git a/pkg/repl/suggestions.go b/pkg/repl/suggestions.go index 522afa1..48fd494 100644 --- a/pkg/repl/suggestions.go +++ b/pkg/repl/suggestions.go @@ -28,6 +28,8 @@ var baseSuggestions = []prompt.Suggest{ {Text: "update", Description: "Update an existing issue by ID"}, {Text: "describe", Description: "Get issue details by ID"}, {Text: "list", Description: "List all issues"}, + {Text: "comment", Description: "Add a comment on an issue by ID"}, + {Text: "comments", Description: "List comments on an issue by ID"}, } // createFlags is a list of prompt suggestions for the create command flags. @@ -63,6 +65,13 @@ var deleteFlags = []prompt.Suggest{ {Text: "--interactive", Description: "Select issues to delete interactively"}, } +var commentFlags = []prompt.Suggest{ + {Text: "--message", Description: "Comment text (alternative to positional args)"}, + {Text: "-m", Description: "Comment text (short)"}, + {Text: "--author", Description: "Author name for the comment"}, + {Text: "-a", Description: "Author name (short)"}, +} + // statusValues is a list of prompt suggestions for status types var statusValues = []prompt.Suggest{ {Text: "open", Description: "Open status"}, @@ -98,20 +107,24 @@ var isIDCommand = map[string]bool{ "close": true, "update": true, "edit": true, + "comment": true, + "comments": true, } var commandFlags = map[string][]prompt.Suggest{ - "create": createFlags, - "add": createFlags, - "update": updateFlags, - "edit": updateFlags, - "list": listFlags, - "ls": listFlags, - "search": listFlags, - "delete": deleteFlags, - "del": deleteFlags, - "rm": deleteFlags, - "remove": deleteFlags, + "create": createFlags, + "add": createFlags, + "update": updateFlags, + "edit": updateFlags, + "list": listFlags, + "ls": listFlags, + "search": listFlags, + "delete": deleteFlags, + "del": deleteFlags, + "rm": deleteFlags, + "remove": deleteFlags, + "comment": commentFlags, + "comments": nil, // no flags, just issue ID } // commandSuggestions returns a list of prompt suggestions based on the current input words.