From 6bf8b76aab82e0385440a2f46ecf7efed6aaf403 Mon Sep 17 00:00:00 2001 From: Robin Olsen Date: Sat, 7 Feb 2026 12:15:09 +0100 Subject: [PATCH] add descriptive comment to variour commands move completions to its own class --- pkg/cli/cli.go | 3 ++ pkg/cli/commands/completion.go | 42 +++++++++++++++++++++ pkg/cli/commands/create.go | 8 +++- pkg/cli/commands/ls.go | 14 +++++-- pkg/cli/commands/read.go | 67 ++++++++++------------------------ 5 files changed, 82 insertions(+), 52 deletions(-) create mode 100644 pkg/cli/commands/completion.go diff --git a/pkg/cli/cli.go b/pkg/cli/cli.go index e26ef0f..c85a988 100644 --- a/pkg/cli/cli.go +++ b/pkg/cli/cli.go @@ -7,8 +7,10 @@ import ( "github.com/LazyBachelor/LazyPM/pkg/cli/commands" ) +// CLIConfig is an alias for service.Config, which contains all the necessary type CLIConfig = service.Config +// Run initializes the services and executes the CLI commands. func Run(ctx context.Context, config CLIConfig) error { svc, cleanup, err := service.NewServices(ctx, config) if err != nil { @@ -26,6 +28,7 @@ func Run(ctx context.Context, config CLIConfig) error { return nil } +// RunWithArgs initializes the services and executes the CLI commands with the provided arguments. func RunWithArgs(ctx context.Context, config CLIConfig, args []string) error { svc, cleanup, err := service.NewServices(ctx, config) if err != nil { diff --git a/pkg/cli/commands/completion.go b/pkg/cli/commands/completion.go new file mode 100644 index 0000000..ff13107 --- /dev/null +++ b/pkg/cli/commands/completion.go @@ -0,0 +1,42 @@ +package commands + +import ( + "context" + "strings" + + "github.com/LazyBachelor/LazyPM/internal/models" + "github.com/spf13/cobra" +) + +// completeIssues provides shell completion for issue IDs and titles. +func completeIssues(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + issues, _ := GetIssueCompletions(cmd.Context(), toComplete) + var ids []string + for _, issue := range issues { + ids = append(ids, issue.ID) + } + return ids, cobra.ShellCompDirectiveNoFileComp +} + +// GetIssueCompletions fetches issues matching the toComplete string for shell completion. +func GetIssueCompletions(ctx context.Context, toComplete string) ([]models.Issue, cobra.ShellCompDirective) { + if svc == nil { + return nil, cobra.ShellCompDirectiveNoFileComp + } + + issues, err := svc.Beads.AllIssues(ctx) + if err != nil { + return nil, cobra.ShellCompDirectiveNoFileComp + } + + var completions []models.Issue + for _, issue := range issues { + if strings.HasPrefix(issue.ID, toComplete) { + completions = append(completions, issue) + } else if strings.HasPrefix(issue.Title, toComplete) { + completions = append(completions, issue) + } + } + + return completions, cobra.ShellCompDirectiveNoFileComp +} diff --git a/pkg/cli/commands/create.go b/pkg/cli/commands/create.go index 6f95f00..289c72f 100644 --- a/pkg/cli/commands/create.go +++ b/pkg/cli/commands/create.go @@ -9,6 +9,7 @@ import ( "github.com/spf13/cobra" ) +// Variables to hold flag values for the create command. var ( createDescription string createStatus string @@ -21,6 +22,7 @@ const ( pm create Fix bug --desc "Bug description" --status in_progress --type bug --priority 5` ) +// createCmd represents the create command, which allows users to create a new issue with specified details. var createCmd = &cobra.Command{ Use: "create [title]", Short: "Create a new issue", @@ -32,6 +34,7 @@ var createCmd = &cobra.Command{ RunE: runCreateCmd, } +// runCreateCmd executes the create command logic, func runCreateCmd(cmd *cobra.Command, args []string) error { createTitle := strings.Join(args, " ") @@ -47,11 +50,13 @@ func runCreateCmd(cmd *cobra.Command, args []string) error { Priority: createPriority, } + // Create the issue using the service layer. err := svc.Beads.CreateIssue(cmd.Context(), issue, "test_actor") if err != nil { return fmt.Errorf("error creating issue: %w", err) } + // Build the output string with the created issue details. str := fmt.Sprintf("Created issue with ID: %s\n", issue.ID) if issue.Title != "" { @@ -74,11 +79,12 @@ func runCreateCmd(cmd *cobra.Command, args []string) error { str += fmt.Sprintf("Priority: %d\n", issue.Priority) } - fmt.Print(str) + cmd.Print(str) return nil } +// init function to set up the create command and its flags. func init() { createCmd.Flags().StringVarP(&createDescription, "desc", "d", "", "Issue description") createCmd.Flags().StringVarP(&createStatus, "status", "s", "open", "Issue status(open, closed, in_progress)") diff --git a/pkg/cli/commands/ls.go b/pkg/cli/commands/ls.go index 76e68aa..5bd841c 100644 --- a/pkg/cli/commands/ls.go +++ b/pkg/cli/commands/ls.go @@ -7,6 +7,7 @@ import ( "github.com/spf13/cobra" ) +// Variables for get-issues command flags. var ( titleFlag string descriptionFlag string @@ -23,18 +24,21 @@ pm ls --title "New feature" --desc "feature description" pm ls -p 1 -l 10` ) +// getIssuesCmd represents the get issues command. var getIssuesCmd = &cobra.Command{ Use: "ls [search query]", Short: "List all issues", Long: `List all issues in the project management system.`, - Aliases: []string{"list", "search"}, Example: lsExamples, + + Aliases: []string{"list", "search"}, Args: cobra.MinimumNArgs(0), RunE: runGetIssuesCmd, } +// runGetIssuesCmd executes the get issues command logic, +// which retrieves and displays a list of issues based on the provided search query and filters. func runGetIssuesCmd(cmd *cobra.Command, args []string) error { - queryArg := strings.Join(args, " ") filter := models.IssueFilter{ @@ -43,6 +47,8 @@ func runGetIssuesCmd(cmd *cobra.Command, args []string) error { Limit: limit, } + // Only set filter fields if the corresponding flags + // were explicitly provided by the user. if cmd.Flags().Changed("status") { s := models.Status(statusFlag) filter.Status = &s @@ -55,18 +61,20 @@ func runGetIssuesCmd(cmd *cobra.Command, args []string) error { filter.Priority = &priorityFlag } + // Fetch issues based on the search query and filters. issuesPtr, err := svc.Beads.SearchIssues(cmd.Context(), queryArg, filter) if err != nil { return err } + // Convert the returned issue pointers to issue values and print them. issues := models.IssuesPtrToIssues(issuesPtr) - models.PrintIssues(issues) return nil } +// init function to set up the get issues command and its flags. func init() { getIssuesCmd.Flags().StringVar(&titleFlag, "title", "", "Filter issues by title") getIssuesCmd.Flags().StringVarP(&descriptionFlag, "desc", "d", "", "Filter issues by description") diff --git a/pkg/cli/commands/read.go b/pkg/cli/commands/read.go index a6ed216..4ea6a54 100644 --- a/pkg/cli/commands/read.go +++ b/pkg/cli/commands/read.go @@ -1,76 +1,47 @@ package commands import ( - "context" - "strings" - "github.com/LazyBachelor/LazyPM/internal/models" "github.com/spf13/cobra" ) +// getIssueCmd represents the get issue command. var getIssueCmd = &cobra.Command{ - Use: "describe [issue ID]", - Short: "Get issue details", - Long: `Get issue details by ID`, - Aliases: []string{"get", "read"}, - Args: cobra.ExactArgs(1), - RunE: runGetCmd, + Use: "describe [issue ID]", + Short: "Get issue details", + Long: `Get issue details by ID`, + ValidArgsFunction: completeIssues, + + Aliases: []string{"get", "read"}, + Args: cobra.ExactArgs(1), + RunE: runGetCmd, } +// runGetCmd executes the get issue command logic, +// which retrieves and displays issue details by its ID. func runGetCmd(cmd *cobra.Command, args []string) error { issueID := args[0] - issue, err := svc.Beads.GetIssue(cmd.Context(), issueID) + // Fetch the issue details using the service layer. + issuePtr, err := svc.Beads.GetIssue(cmd.Context(), issueID) if err != nil { return err } - if issue == nil { - cmd.Printf("Issue with ID '%s' not found\n", issueID) + // If the issue is not found, inform the user. + if issuePtr == nil { + cmd.Printf("Issue with ID %s not found\n", issueID) return nil } - cmd.Printf("Title: %s\n", issue.Title) - cmd.Printf("Description: %s\n", issue.Description) - cmd.Printf("Status: %s\n", issue.Status) - cmd.Printf("Type: %s\n", issue.IssueType) - cmd.Printf("Priority: %d\n", issue.Priority) + // Display the issue details to the user. + cmd.Println(models.IssueString(*issuePtr)) return nil } +// init function to set up the get issue command. func init() { rootCmd.AddCommand(getIssueCmd) } - -func completeIssues(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - issues, _ := GetIssueCompletions(cmd.Context(), toComplete) - var ids []string - for _, issue := range issues { - ids = append(ids, issue.ID) - } - return ids, cobra.ShellCompDirectiveNoFileComp -} - -func GetIssueCompletions(ctx context.Context, toComplete string) ([]models.Issue, cobra.ShellCompDirective) { - if svc == nil { - return nil, cobra.ShellCompDirectiveNoFileComp - } - - issues, err := svc.Beads.AllIssues(ctx) - if err != nil { - return nil, cobra.ShellCompDirectiveNoFileComp - } - - var completions []models.Issue - for _, issue := range issues { - if strings.HasPrefix(issue.ID, toComplete) { - completions = append(completions, issue) - } else if strings.HasPrefix(issue.Title, toComplete) { - completions = append(completions, issue) - } - } - - return completions, cobra.ShellCompDirectiveNoFileComp -}