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

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