github.com/ungtb10d/cli/v2@v2.0.0-20221110210412-98537dd9d6a1/pkg/cmd/search/issues/issues.go (about)

     1  package issues
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/MakeNowJust/heredoc"
     7  	"github.com/ungtb10d/cli/v2/pkg/cmd/search/shared"
     8  	"github.com/ungtb10d/cli/v2/pkg/cmdutil"
     9  	"github.com/ungtb10d/cli/v2/pkg/search"
    10  	"github.com/spf13/cobra"
    11  )
    12  
    13  func NewCmdIssues(f *cmdutil.Factory, runF func(*shared.IssuesOptions) error) *cobra.Command {
    14  	var locked, includePrs bool
    15  	var noAssignee, noLabel, noMilestone, noProject bool
    16  	var order, sort string
    17  	var appAuthor string
    18  	opts := &shared.IssuesOptions{
    19  		Browser: f.Browser,
    20  		Entity:  shared.Issues,
    21  		IO:      f.IOStreams,
    22  		Query: search.Query{Kind: search.KindIssues,
    23  			Qualifiers: search.Qualifiers{Type: "issue"}},
    24  	}
    25  
    26  	cmd := &cobra.Command{
    27  		Use:   "issues [<query>]",
    28  		Short: "Search for issues",
    29  		Long: heredoc.Doc(`
    30  			Search for issues on GitHub.
    31  
    32  			The command supports constructing queries using the GitHub search syntax,
    33  			using the parameter and qualifier flags, or a combination of the two.
    34  
    35  			GitHub search syntax is documented at:
    36  			<https://docs.github.com/search-github/searching-on-github/searching-issues-and-pull-requests>
    37      `),
    38  		Example: heredoc.Doc(`
    39  			# search issues matching set of keywords "readme" and "typo"
    40  			$ gh search issues readme typo
    41  
    42  			# search issues matching phrase "broken feature"
    43  			$ gh search issues "broken feature"
    44  
    45  			# search issues and pull requests in cli organization
    46  			$ gh search issues --include-prs --owner=cli
    47  
    48  			# search open issues assigned to yourself
    49  			$ gh search issues --assignee=@me --state=open
    50  
    51  			# search issues with numerous comments
    52  			$ gh search issues --comments=">100"
    53  
    54  			# search issues without label "bug"
    55  			$ gh search issues -- -label:bug
    56      `),
    57  		RunE: func(c *cobra.Command, args []string) error {
    58  			if len(args) == 0 && c.Flags().NFlag() == 0 {
    59  				return cmdutil.FlagErrorf("specify search keywords or flags")
    60  			}
    61  			if opts.Query.Limit < 1 || opts.Query.Limit > shared.SearchMaxResults {
    62  				return cmdutil.FlagErrorf("`--limit` must be between 1 and 1000")
    63  			}
    64  			if c.Flags().Changed("author") && c.Flags().Changed("app") {
    65  				return cmdutil.FlagErrorf("specify only `--author` or `--app`")
    66  			}
    67  			if c.Flags().Changed("app") {
    68  				opts.Query.Qualifiers.Author = fmt.Sprintf("app/%s", appAuthor)
    69  			}
    70  			if includePrs {
    71  				opts.Entity = shared.Both
    72  				opts.Query.Qualifiers.Type = ""
    73  			}
    74  			if c.Flags().Changed("order") {
    75  				opts.Query.Order = order
    76  			}
    77  			if c.Flags().Changed("sort") {
    78  				opts.Query.Sort = sort
    79  			}
    80  			if c.Flags().Changed("locked") {
    81  				if locked {
    82  					opts.Query.Qualifiers.Is = append(opts.Query.Qualifiers.Is, "locked")
    83  				} else {
    84  					opts.Query.Qualifiers.Is = append(opts.Query.Qualifiers.Is, "unlocked")
    85  				}
    86  			}
    87  			if c.Flags().Changed("no-assignee") && noAssignee {
    88  				opts.Query.Qualifiers.No = append(opts.Query.Qualifiers.No, "assignee")
    89  			}
    90  			if c.Flags().Changed("no-label") && noLabel {
    91  				opts.Query.Qualifiers.No = append(opts.Query.Qualifiers.No, "label")
    92  			}
    93  			if c.Flags().Changed("no-milestone") && noMilestone {
    94  				opts.Query.Qualifiers.No = append(opts.Query.Qualifiers.No, "milestone")
    95  			}
    96  			if c.Flags().Changed("no-project") && noProject {
    97  				opts.Query.Qualifiers.No = append(opts.Query.Qualifiers.No, "project")
    98  			}
    99  			opts.Query.Keywords = args
   100  			if runF != nil {
   101  				return runF(opts)
   102  			}
   103  			var err error
   104  			opts.Searcher, err = shared.Searcher(f)
   105  			if err != nil {
   106  				return err
   107  			}
   108  			return shared.SearchIssues(opts)
   109  		},
   110  	}
   111  
   112  	// Output flags
   113  	cmdutil.AddJSONFlags(cmd, &opts.Exporter, search.IssueFields)
   114  	cmd.Flags().BoolVarP(&opts.WebMode, "web", "w", false, "Open the search query in the web browser")
   115  
   116  	// Query parameter flags
   117  	cmd.Flags().IntVarP(&opts.Query.Limit, "limit", "L", 30, "Maximum number of results to fetch")
   118  	cmdutil.StringEnumFlag(cmd, &order, "order", "", "desc", []string{"asc", "desc"}, "Order of results returned, ignored unless '--sort' flag is specified")
   119  	cmdutil.StringEnumFlag(cmd, &sort, "sort", "", "best-match",
   120  		[]string{
   121  			"comments",
   122  			"created",
   123  			"interactions",
   124  			"reactions",
   125  			"reactions-+1",
   126  			"reactions--1",
   127  			"reactions-heart",
   128  			"reactions-smile",
   129  			"reactions-tada",
   130  			"reactions-thinking_face",
   131  			"updated",
   132  		}, "Sort fetched results")
   133  
   134  	// Query qualifier flags
   135  	cmd.Flags().BoolVar(&includePrs, "include-prs", false, "Include pull requests in results")
   136  	cmd.Flags().StringVar(&appAuthor, "app", "", "Filter by GitHub App author")
   137  	cmdutil.NilBoolFlag(cmd, &opts.Query.Qualifiers.Archived, "archived", "", "Restrict search to archived repositories")
   138  	cmd.Flags().StringVar(&opts.Query.Qualifiers.Assignee, "assignee", "", "Filter by assignee")
   139  	cmd.Flags().StringVar(&opts.Query.Qualifiers.Author, "author", "", "Filter by author")
   140  	cmd.Flags().StringVar(&opts.Query.Qualifiers.Closed, "closed", "", "Filter on closed at `date`")
   141  	cmd.Flags().StringVar(&opts.Query.Qualifiers.Commenter, "commenter", "", "Filter based on comments by `user`")
   142  	cmd.Flags().StringVar(&opts.Query.Qualifiers.Comments, "comments", "", "Filter on `number` of comments")
   143  	cmd.Flags().StringVar(&opts.Query.Qualifiers.Created, "created", "", "Filter based on created at `date`")
   144  	cmdutil.StringSliceEnumFlag(cmd, &opts.Query.Qualifiers.In, "match", "", nil, []string{"title", "body", "comments"}, "Restrict search to specific field of issue")
   145  	cmd.Flags().StringVar(&opts.Query.Qualifiers.Interactions, "interactions", "", "Filter on `number` of reactions and comments")
   146  	cmd.Flags().StringVar(&opts.Query.Qualifiers.Involves, "involves", "", "Filter based on involvement of `user`")
   147  	cmdutil.StringSliceEnumFlag(cmd, &opts.Query.Qualifiers.Is, "visibility", "", nil, []string{"public", "private", "internal"}, "Filter based on repository visibility")
   148  	cmd.Flags().StringSliceVar(&opts.Query.Qualifiers.Label, "label", nil, "Filter on label")
   149  	cmd.Flags().StringVar(&opts.Query.Qualifiers.Language, "language", "", "Filter based on the coding language")
   150  	cmd.Flags().BoolVar(&locked, "locked", false, "Filter on locked conversation status")
   151  	cmd.Flags().StringVar(&opts.Query.Qualifiers.Mentions, "mentions", "", "Filter based on `user` mentions")
   152  	cmd.Flags().StringVar(&opts.Query.Qualifiers.Milestone, "milestone", "", "Filter by milestone `title`")
   153  	cmd.Flags().BoolVar(&noAssignee, "no-assignee", false, "Filter on missing assignee")
   154  	cmd.Flags().BoolVar(&noLabel, "no-label", false, "Filter on missing label")
   155  	cmd.Flags().BoolVar(&noMilestone, "no-milestone", false, "Filter on missing milestone")
   156  	cmd.Flags().BoolVar(&noProject, "no-project", false, "Filter on missing project")
   157  	cmd.Flags().StringVar(&opts.Query.Qualifiers.Project, "project", "", "Filter on project board `number`")
   158  	cmd.Flags().StringVar(&opts.Query.Qualifiers.Reactions, "reactions", "", "Filter on `number` of reactions")
   159  	cmd.Flags().StringSliceVar(&opts.Query.Qualifiers.Repo, "repo", nil, "Filter on repository")
   160  	cmdutil.StringEnumFlag(cmd, &opts.Query.Qualifiers.State, "state", "", "", []string{"open", "closed"}, "Filter based on state")
   161  	cmd.Flags().StringVar(&opts.Query.Qualifiers.Team, "team-mentions", "", "Filter based on team mentions")
   162  	cmd.Flags().StringVar(&opts.Query.Qualifiers.Updated, "updated", "", "Filter on last updated at `date`")
   163  	cmd.Flags().StringVar(&opts.Query.Qualifiers.User, "owner", "", "Filter on repository owner")
   164  
   165  	return cmd
   166  }