commands/mr/list/mr_list.go (260 lines of code) (raw):

package list import ( "encoding/json" "errors" "fmt" "gitlab.com/gitlab-org/cli/pkg/iostreams" "github.com/MakeNowJust/heredoc/v2" "gitlab.com/gitlab-org/cli/internal/glrepo" "gitlab.com/gitlab-org/cli/api" "gitlab.com/gitlab-org/cli/commands/cmdutils" "gitlab.com/gitlab-org/cli/commands/flag" "gitlab.com/gitlab-org/cli/commands/mr/mrutils" "gitlab.com/gitlab-org/cli/pkg/utils" "github.com/spf13/cobra" gitlab "gitlab.com/gitlab-org/api/client-go" ) type ListOptions struct { // metadata Assignee []string Reviewer []string Author string Labels []string NotLabels []string Milestone string SourceBranch string TargetBranch string Search string Mine bool Group string // issue states State string Closed bool Merged bool All bool Draft bool NotDraft bool // Pagination Page int PerPage int OutputFormat string // display opts ListType string TitleQualifier string // sort options Sort string OrderBy string IO *iostreams.IOStreams BaseRepo func() (glrepo.Interface, error) HTTPClient func() (*gitlab.Client, error) } func NewCmdList(f *cmdutils.Factory, runE func(opts *ListOptions) error) *cobra.Command { opts := &ListOptions{ IO: f.IO, } mrListCmd := &cobra.Command{ Use: "list [flags]", Short: `List merge requests.`, Long: ``, Aliases: []string{"ls"}, Example: heredoc.Doc(` $ glab mr list --all $ glab mr ls -a $ glab mr list --assignee=@me $ glab mr list --reviewer=@me $ glab mr list --source-branch=new-feature $ glab mr list --target-branch=main $ glab mr list --search "this adds feature X" $ glab mr list --label needs-review $ glab mr list --not-label waiting-maintainer-feedback,subsystem-x $ glab mr list -M --per-page 10 $ glab mr list --draft $ glab mr list --not-draft `), Args: cobra.ExactArgs(0), RunE: func(cmd *cobra.Command, args []string) error { // supports repo override opts.BaseRepo = f.BaseRepo opts.HTTPClient = f.HttpClient if len(opts.Labels) != 0 && len(opts.NotLabels) != 0 { return cmdutils.FlagError{ Err: errors.New("flags --label and --not-label are mutually exclusive."), } } // check if any of the two or all of states flag are specified if opts.Closed && opts.Merged { return cmdutils.FlagError{ Err: errors.New("specify either --closed or --merged. Use --all issues in all states."), } } if opts.All { opts.State = "all" } else if opts.Closed { opts.State = "closed" opts.TitleQualifier = opts.State } else if opts.Merged { opts.State = "merged" opts.TitleQualifier = opts.State } else { opts.State = "opened" opts.TitleQualifier = "open" } group, err := flag.GroupOverride(cmd) if err != nil { return err } opts.Group = group if runE != nil { return runE(opts) } return listRun(opts) }, } cmdutils.EnableRepoOverride(mrListCmd, f) mrListCmd.Flags().StringSliceVarP(&opts.Labels, "label", "l", []string{}, "Filter merge request by label <name>.") mrListCmd.Flags().StringSliceVar(&opts.NotLabels, "not-label", []string{}, "Filter merge requests by not having label <name>.") mrListCmd.Flags().StringVar(&opts.Author, "author", "", "Filter merge request by author <username>.") mrListCmd.Flags().StringVarP(&opts.Milestone, "milestone", "m", "", "Filter merge request by milestone <id>.") mrListCmd.Flags().StringVarP(&opts.SourceBranch, "source-branch", "s", "", "Filter by source branch <name>.") mrListCmd.Flags().StringVarP(&opts.TargetBranch, "target-branch", "t", "", "Filter by target branch <name>.") mrListCmd.Flags().StringVar(&opts.Search, "search", "", "Filter by <string> in title and description.") mrListCmd.Flags().BoolVarP(&opts.All, "all", "A", false, "Get all merge requests.") mrListCmd.Flags().BoolVarP(&opts.Closed, "closed", "c", false, "Get only closed merge requests.") mrListCmd.Flags().BoolVarP(&opts.Merged, "merged", "M", false, "Get only merged merge requests.") mrListCmd.Flags().BoolVarP(&opts.Draft, "draft", "d", false, "Filter by draft merge requests.") mrListCmd.Flags().BoolVarP(&opts.NotDraft, "not-draft", "", false, "Filter by non-draft merge requests.") mrListCmd.Flags().StringVarP(&opts.OutputFormat, "output", "F", "text", "Format output as: text, json.") mrListCmd.Flags().IntVarP(&opts.Page, "page", "p", 1, "Page number.") mrListCmd.Flags().IntVarP(&opts.PerPage, "per-page", "P", 30, "Number of items to list per page.") mrListCmd.Flags().StringSliceVarP(&opts.Assignee, "assignee", "a", []string{}, "Get only merge requests assigned to users.") mrListCmd.Flags().StringSliceVarP(&opts.Reviewer, "reviewer", "r", []string{}, "Get only merge requests with users as reviewer.") mrListCmd.Flags().StringVarP(&opts.Sort, "sort", "S", "", "Sort merge requests by <field>. Sort options: asc, desc.") mrListCmd.Flags().StringVarP(&opts.OrderBy, "order", "o", "", "Order merge requests by <field>. Order options: created_at, title, merged_at or updated_at.") mrListCmd.Flags().BoolP("opened", "O", false, "Get only open merge requests.") _ = mrListCmd.Flags().MarkHidden("opened") _ = mrListCmd.Flags().MarkDeprecated("opened", "default value if neither --closed, --locked or --merged is used.") mrListCmd.Flags().BoolVarP(&opts.Mine, "mine", "", false, "Get only merge requests assigned to me.") _ = mrListCmd.Flags().MarkHidden("mine") _ = mrListCmd.Flags().MarkDeprecated("mine", "use --assignee=@me.") mrListCmd.PersistentFlags().StringP("group", "g", "", "Select a group/subgroup. This option is ignored if a repo argument is set.") mrListCmd.MarkFlagsMutuallyExclusive("draft", "not-draft") return mrListCmd } func listRun(opts *ListOptions) error { var mergeRequests []*gitlab.BasicMergeRequest apiClient, err := opts.HTTPClient() if err != nil { return err } repo, err := opts.BaseRepo() if err != nil { return err } l := &gitlab.ListProjectMergeRequestsOptions{ State: gitlab.Ptr(opts.State), ListOptions: gitlab.ListOptions{ Page: 1, PerPage: 30, }, } jsonOutput := opts.OutputFormat == "json" if jsonOutput { l.Page = 0 l.PerPage = 0 } if opts.Author != "" { u, err := api.UserByName(apiClient, opts.Author) if err != nil { return err } l.AuthorID = gitlab.Ptr(u.ID) opts.ListType = "search" } if opts.SourceBranch != "" { l.SourceBranch = gitlab.Ptr(opts.SourceBranch) opts.ListType = "search" } if opts.TargetBranch != "" { l.TargetBranch = gitlab.Ptr(opts.TargetBranch) opts.ListType = "search" } if opts.Search != "" { l.Search = gitlab.Ptr(opts.Search) opts.ListType = "search" } if len(opts.Labels) > 0 { l.Labels = (*gitlab.LabelOptions)(&opts.Labels) opts.ListType = "search" } if len(opts.NotLabels) > 0 { l.NotLabels = (*gitlab.LabelOptions)(&opts.NotLabels) opts.ListType = "search" } if opts.Milestone != "" { l.Milestone = gitlab.Ptr(opts.Milestone) opts.ListType = "search" } if opts.Page != 0 { l.Page = opts.Page } if opts.PerPage != 0 { l.PerPage = opts.PerPage } if opts.Draft { l.WIP = gitlab.Ptr("yes") opts.ListType = "search" } if opts.NotDraft { l.WIP = gitlab.Ptr("no") opts.ListType = "search" } if opts.Mine { l.Scope = gitlab.Ptr("assigned_to_me") opts.ListType = "search" } if opts.OrderBy != "" { l.OrderBy = gitlab.Ptr(opts.OrderBy) opts.ListType = "search" } if opts.Sort != "" { l.Sort = gitlab.Ptr(opts.Sort) } assigneeIds := make([]int, 0) if len(opts.Assignee) > 0 { users, err := api.UsersByNames(apiClient, opts.Assignee) if err != nil { return err } for _, user := range users { assigneeIds = append(assigneeIds, user.ID) } } reviewerIds := make([]int, 0) if len(opts.Reviewer) > 0 { users, err := api.UsersByNames(apiClient, opts.Reviewer) if err != nil { return err } for _, user := range users { reviewerIds = append(reviewerIds, user.ID) } } title := utils.NewListTitle(opts.TitleQualifier + " merge request") title.RepoName = repo.FullName() if opts.Group != "" { mergeRequests, err = api.ListGroupMRs(apiClient, opts.Group, api.ProjectListMROptionsToGroup(l), api.WithMRAssignees(assigneeIds), api.WithMRReviewers(reviewerIds)) title.RepoName = opts.Group } else { mergeRequests, err = api.ListMRs(apiClient, repo.FullName(), l, api.WithMRAssignees(assigneeIds), api.WithMRReviewers(reviewerIds)) } if err != nil { return err } title.Page = l.Page title.ListActionType = opts.ListType title.CurrentPageTotal = len(mergeRequests) if jsonOutput { mrListJSON, _ := json.Marshal(mergeRequests) fmt.Fprintln(opts.IO.StdOut, string(mrListJSON)) } else { if err = opts.IO.StartPager(); err != nil { return err } defer opts.IO.StopPager() fmt.Fprintf(opts.IO.StdOut, "%s\n%s\n", title.Describe(), mrutils.DisplayAllMRs(opts.IO, mergeRequests)) } return nil }