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

     1  package label
     2  
     3  import (
     4  	"fmt"
     5  	"net/http"
     6  
     7  	"github.com/MakeNowJust/heredoc"
     8  	"github.com/ungtb10d/cli/v2/internal/browser"
     9  	"github.com/ungtb10d/cli/v2/internal/ghrepo"
    10  	"github.com/ungtb10d/cli/v2/internal/text"
    11  	"github.com/ungtb10d/cli/v2/pkg/cmdutil"
    12  	"github.com/ungtb10d/cli/v2/pkg/iostreams"
    13  	"github.com/ungtb10d/cli/v2/utils"
    14  	"github.com/spf13/cobra"
    15  )
    16  
    17  type listOptions struct {
    18  	BaseRepo   func() (ghrepo.Interface, error)
    19  	Browser    browser.Browser
    20  	HttpClient func() (*http.Client, error)
    21  	IO         *iostreams.IOStreams
    22  
    23  	Exporter cmdutil.Exporter
    24  	Query    listQueryOptions
    25  	WebMode  bool
    26  }
    27  
    28  func newCmdList(f *cmdutil.Factory, runF func(*listOptions) error) *cobra.Command {
    29  	opts := listOptions{
    30  		Browser:    f.Browser,
    31  		HttpClient: f.HttpClient,
    32  		IO:         f.IOStreams,
    33  	}
    34  
    35  	cmd := &cobra.Command{
    36  		Use:   "list",
    37  		Short: "List labels in a repository",
    38  		Long: heredoc.Docf(`
    39  			Display labels in a GitHub repository.
    40  
    41  			When using the %[1]s--search%[1]s flag results are sorted by best match of the query.
    42  			This behavior cannot be configured with the %[1]s--order%[1]s or %[1]s--sort%[1]s flags.
    43  		`, "`"),
    44  		Example: heredoc.Doc(`
    45  			# sort labels by name
    46  			$ gh label list --sort name
    47  
    48  			# find labels with "bug" in the name or description
    49  			$ gh label list --search bug
    50  		`),
    51  		Args:    cobra.NoArgs,
    52  		Aliases: []string{"ls"},
    53  		RunE: func(c *cobra.Command, args []string) error {
    54  			// support `-R, --repo` override
    55  			opts.BaseRepo = f.BaseRepo
    56  
    57  			if opts.Query.Limit < 1 {
    58  				return cmdutil.FlagErrorf("invalid limit: %v", opts.Query.Limit)
    59  			}
    60  
    61  			if opts.Query.Query != "" &&
    62  				(c.Flags().Changed("order") || c.Flags().Changed("sort")) {
    63  				return cmdutil.FlagErrorf("cannot specify `--order` or `--sort` with `--search`")
    64  			}
    65  
    66  			if runF != nil {
    67  				return runF(&opts)
    68  			}
    69  			return listRun(&opts)
    70  		},
    71  	}
    72  
    73  	cmd.Flags().BoolVarP(&opts.WebMode, "web", "w", false, "List labels in the web browser")
    74  	cmd.Flags().IntVarP(&opts.Query.Limit, "limit", "L", 30, "Maximum number of labels to fetch")
    75  	cmd.Flags().StringVarP(&opts.Query.Query, "search", "S", "", "Search label names and descriptions")
    76  	cmdutil.StringEnumFlag(cmd, &opts.Query.Order, "order", "", defaultOrder, []string{"asc", "desc"}, "Order of labels returned")
    77  	cmdutil.StringEnumFlag(cmd, &opts.Query.Sort, "sort", "", defaultSort, []string{"created", "name"}, "Sort fetched labels")
    78  
    79  	cmdutil.AddJSONFlags(cmd, &opts.Exporter, labelFields)
    80  
    81  	return cmd
    82  }
    83  
    84  func listRun(opts *listOptions) error {
    85  	httpClient, err := opts.HttpClient()
    86  	if err != nil {
    87  		return err
    88  	}
    89  
    90  	baseRepo, err := opts.BaseRepo()
    91  	if err != nil {
    92  		return err
    93  	}
    94  
    95  	if opts.WebMode {
    96  		labelListURL := ghrepo.GenerateRepoURL(baseRepo, "labels")
    97  
    98  		if opts.IO.IsStdoutTTY() {
    99  			fmt.Fprintf(opts.IO.ErrOut, "Opening %s in your browser.\n", text.DisplayURL(labelListURL))
   100  		}
   101  
   102  		return opts.Browser.Browse(labelListURL)
   103  	}
   104  
   105  	if opts.Exporter != nil {
   106  		opts.Query.fields = opts.Exporter.Fields()
   107  	}
   108  
   109  	opts.IO.StartProgressIndicator()
   110  	labels, totalCount, err := listLabels(httpClient, baseRepo, opts.Query)
   111  	opts.IO.StopProgressIndicator()
   112  	if err != nil {
   113  		return err
   114  	}
   115  
   116  	if len(labels) == 0 {
   117  		if opts.Query.Query != "" {
   118  			return cmdutil.NewNoResultsError(fmt.Sprintf("no labels in %s matched your search", ghrepo.FullName(baseRepo)))
   119  		}
   120  		return cmdutil.NewNoResultsError(fmt.Sprintf("no labels found in %s", ghrepo.FullName(baseRepo)))
   121  	}
   122  
   123  	if opts.Exporter != nil {
   124  		return opts.Exporter.Write(opts.IO, labels)
   125  	}
   126  
   127  	if opts.IO.IsStdoutTTY() {
   128  		title := listHeader(ghrepo.FullName(baseRepo), len(labels), totalCount)
   129  		fmt.Fprintf(opts.IO.Out, "\n%s\n\n", title)
   130  	}
   131  
   132  	return printLabels(opts.IO, labels)
   133  }
   134  
   135  func printLabels(io *iostreams.IOStreams, labels []label) error {
   136  	cs := io.ColorScheme()
   137  	//nolint:staticcheck // SA1019: utils.NewTablePrinter is deprecated: use internal/tableprinter
   138  	table := utils.NewTablePrinter(io)
   139  
   140  	for _, label := range labels {
   141  		table.AddField(label.Name, nil, cs.ColorFromRGB(label.Color))
   142  		table.AddField(label.Description, text.Truncate, nil)
   143  		table.AddField("#"+label.Color, nil, nil)
   144  
   145  		table.EndRow()
   146  	}
   147  
   148  	return table.Render()
   149  }
   150  
   151  func listHeader(repoName string, count int, totalCount int) string {
   152  	return fmt.Sprintf("Showing %d of %s in %s", count, text.Pluralize(totalCount, "label"), repoName)
   153  }