github.com/secman-team/gh-api@v1.8.2/pkg/cmd/repo/list/list.go (about)

     1  package list
     2  
     3  import (
     4  	"fmt"
     5  	"net/http"
     6  	"time"
     7  
     8  	"github.com/secman-team/gh-api/core/config"
     9  	"github.com/secman-team/gh-api/pkg/cmdutil"
    10  	"github.com/secman-team/gh-api/pkg/iostreams"
    11  	"github.com/secman-team/gh-api/pkg/text"
    12  	"github.com/secman-team/gh-api/utils"
    13  	"github.com/spf13/cobra"
    14  )
    15  
    16  type ListOptions struct {
    17  	HttpClient func() (*http.Client, error)
    18  	Config     func() (config.Config, error)
    19  	IO         *iostreams.IOStreams
    20  
    21  	Limit int
    22  	Owner string
    23  
    24  	Visibility  string
    25  	Fork        bool
    26  	Source      bool
    27  	Language    string
    28  	Archived    bool
    29  	NonArchived bool
    30  
    31  	Now func() time.Time
    32  }
    33  
    34  func NewCmdList(f *cmdutil.Factory, runF func(*ListOptions) error) *cobra.Command {
    35  	opts := ListOptions{
    36  		IO:         f.IOStreams,
    37  		Config:     f.Config,
    38  		HttpClient: f.HttpClient,
    39  		Now:        time.Now,
    40  	}
    41  
    42  	var (
    43  		flagPublic  bool
    44  		flagPrivate bool
    45  	)
    46  
    47  	cmd := &cobra.Command{
    48  		Use:   "list [<owner>]",
    49  		Args:  cobra.MaximumNArgs(1),
    50  		Short: "List repositories owned by user or organization",
    51  		RunE: func(c *cobra.Command, args []string) error {
    52  			if opts.Limit < 1 {
    53  				return &cmdutil.FlagError{Err: fmt.Errorf("invalid limit: %v", opts.Limit)}
    54  			}
    55  
    56  			if flagPrivate && flagPublic {
    57  				return &cmdutil.FlagError{Err: fmt.Errorf("specify only one of `--public` or `--private`")}
    58  			}
    59  			if opts.Source && opts.Fork {
    60  				return &cmdutil.FlagError{Err: fmt.Errorf("specify only one of `--source` or `--fork`")}
    61  			}
    62  			if opts.Archived && opts.NonArchived {
    63  				return &cmdutil.FlagError{Err: fmt.Errorf("specify only one of `--archived` or `--no-archived`")}
    64  			}
    65  
    66  			if flagPrivate {
    67  				opts.Visibility = "private"
    68  			} else if flagPublic {
    69  				opts.Visibility = "public"
    70  			}
    71  
    72  			if len(args) > 0 {
    73  				opts.Owner = args[0]
    74  			}
    75  
    76  			if runF != nil {
    77  				return runF(&opts)
    78  			}
    79  			return listRun(&opts)
    80  		},
    81  	}
    82  
    83  	cmd.Flags().IntVarP(&opts.Limit, "limit", "L", 30, "Maximum number of repositories to list")
    84  	cmd.Flags().BoolVar(&flagPrivate, "private", false, "Show only private repositories")
    85  	cmd.Flags().BoolVar(&flagPublic, "public", false, "Show only public repositories")
    86  	cmd.Flags().BoolVar(&opts.Source, "source", false, "Show only non-forks")
    87  	cmd.Flags().BoolVar(&opts.Fork, "fork", false, "Show only forks")
    88  	cmd.Flags().StringVarP(&opts.Language, "language", "l", "", "Filter by primary coding language")
    89  	cmd.Flags().BoolVar(&opts.Archived, "archived", false, "Show only archived repositories")
    90  	cmd.Flags().BoolVar(&opts.NonArchived, "no-archived", false, "Omit archived repositories")
    91  
    92  	return cmd
    93  }
    94  
    95  func listRun(opts *ListOptions) error {
    96  	httpClient, err := opts.HttpClient()
    97  	if err != nil {
    98  		return err
    99  	}
   100  
   101  	filter := FilterOptions{
   102  		Visibility:  opts.Visibility,
   103  		Fork:        opts.Fork,
   104  		Source:      opts.Source,
   105  		Language:    opts.Language,
   106  		Archived:    opts.Archived,
   107  		NonArchived: opts.NonArchived,
   108  	}
   109  
   110  	cfg, err := opts.Config()
   111  	if err != nil {
   112  		return err
   113  	}
   114  
   115  	host, err := cfg.DefaultHost()
   116  	if err != nil {
   117  		return err
   118  	}
   119  
   120  	listResult, err := listRepos(httpClient, host, opts.Limit, opts.Owner, filter)
   121  	if err != nil {
   122  		return err
   123  	}
   124  
   125  	if err := opts.IO.StartPager(); err != nil {
   126  		fmt.Fprintf(opts.IO.ErrOut, "error starting pager: %v\n", err)
   127  	}
   128  	defer opts.IO.StopPager()
   129  
   130  	cs := opts.IO.ColorScheme()
   131  	tp := utils.NewTablePrinter(opts.IO)
   132  	now := opts.Now()
   133  
   134  	for _, repo := range listResult.Repositories {
   135  		info := repo.Info()
   136  		infoColor := cs.Gray
   137  		if repo.IsPrivate {
   138  			infoColor = cs.Yellow
   139  		}
   140  
   141  		t := repo.PushedAt
   142  		// if listResult.FromSearch {
   143  		// 	t = repo.UpdatedAt
   144  		// }
   145  
   146  		tp.AddField(repo.NameWithOwner, nil, cs.Bold)
   147  		tp.AddField(text.ReplaceExcessiveWhitespace(repo.Description), nil, nil)
   148  		tp.AddField(info, nil, infoColor)
   149  		if tp.IsTTY() {
   150  			tp.AddField(utils.FuzzyAgoAbbr(now, t), nil, cs.Gray)
   151  		} else {
   152  			tp.AddField(t.Format(time.RFC3339), nil, nil)
   153  		}
   154  		tp.EndRow()
   155  	}
   156  
   157  	if opts.IO.IsStdoutTTY() {
   158  		hasFilters := filter.Visibility != "" || filter.Fork || filter.Source || filter.Language != ""
   159  		title := listHeader(listResult.Owner, len(listResult.Repositories), listResult.TotalCount, hasFilters)
   160  		fmt.Fprintf(opts.IO.Out, "\n%s\n\n", title)
   161  	}
   162  
   163  	return tp.Render()
   164  }
   165  
   166  func listHeader(owner string, matchCount, totalMatchCount int, hasFilters bool) string {
   167  	if totalMatchCount == 0 {
   168  		if hasFilters {
   169  			return "No results match your search"
   170  		} else if owner != "" {
   171  			return "There are no repositories in @" + owner
   172  		}
   173  		return "No results"
   174  	}
   175  
   176  	var matchStr string
   177  	if hasFilters {
   178  		matchStr = " that match your search"
   179  	}
   180  	return fmt.Sprintf("Showing %d of %d repositories in @%s%s", matchCount, totalMatchCount, owner, matchStr)
   181  }