1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
|
package list
import (
"fmt"
"net/http"
"strings"
"time"
"github.com/MakeNowJust/heredoc"
"github.com/cli/cli/v2/api"
"github.com/cli/cli/v2/internal/ghrepo"
"github.com/cli/cli/v2/internal/tableprinter"
"github.com/cli/cli/v2/internal/text"
"github.com/cli/cli/v2/pkg/cmd/cache/shared"
"github.com/cli/cli/v2/pkg/cmdutil"
"github.com/cli/cli/v2/pkg/iostreams"
"github.com/spf13/cobra"
)
type ListOptions struct {
BaseRepo func() (ghrepo.Interface, error)
HttpClient func() (*http.Client, error)
IO *iostreams.IOStreams
Exporter cmdutil.Exporter
Now time.Time
Limit int
Order string
Sort string
Key string
Ref string
}
func NewCmdList(f *cmdutil.Factory, runF func(*ListOptions) error) *cobra.Command {
opts := ListOptions{
IO: f.IOStreams,
HttpClient: f.HttpClient,
}
cmd := &cobra.Command{
Use: "list",
Short: "List Github Actions caches",
Example: heredoc.Doc(`
# List caches for current repository
$ gh cache list
# List caches for specific repository
$ gh cache list --repo cli/cli
# List caches sorted by least recently accessed
$ gh cache list --sort last_accessed_at --order asc
# List caches that have keys matching a prefix (or that match exactly)
$ gh cache list --key key-prefix
# To list caches for a specific branch, replace <branch-name> with the actual branch name
$ gh cache list --ref refs/heads/<branch-name>
# To list caches for a specific pull request, replace <pr-number> with the actual pull request number
$ gh cache list --ref refs/pull/<pr-number>/merge
`),
Aliases: []string{"ls"},
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
// support `-R, --repo` override
opts.BaseRepo = f.BaseRepo
if opts.Limit < 1 {
return cmdutil.FlagErrorf("invalid limit: %v", opts.Limit)
}
if runF != nil {
return runF(&opts)
}
return listRun(&opts)
},
}
cmd.Flags().IntVarP(&opts.Limit, "limit", "L", 30, "Maximum number of caches to fetch")
cmdutil.StringEnumFlag(cmd, &opts.Order, "order", "O", "desc", []string{"asc", "desc"}, "Order of caches returned")
cmdutil.StringEnumFlag(cmd, &opts.Sort, "sort", "S", "last_accessed_at", []string{"created_at", "last_accessed_at", "size_in_bytes"}, "Sort fetched caches")
cmd.Flags().StringVarP(&opts.Key, "key", "k", "", "Filter by cache key prefix")
cmd.Flags().StringVarP(&opts.Ref, "ref", "r", "", "Filter by ref, formatted as refs/heads/<branch name> or refs/pull/<number>/merge")
cmdutil.AddJSONFlags(cmd, &opts.Exporter, shared.CacheFields)
return cmd
}
func listRun(opts *ListOptions) error {
repo, err := opts.BaseRepo()
if err != nil {
return err
}
httpClient, err := opts.HttpClient()
if err != nil {
return err
}
client := api.NewClientFromHTTP(httpClient)
opts.IO.StartProgressIndicator()
result, err := shared.GetCaches(client, repo, shared.GetCachesOptions{Limit: opts.Limit, Sort: opts.Sort, Order: opts.Order, Key: opts.Key, Ref: opts.Ref})
opts.IO.StopProgressIndicator()
if err != nil {
return fmt.Errorf("%s Failed to get caches: %w", opts.IO.ColorScheme().FailureIcon(), err)
}
if len(result.ActionsCaches) == 0 {
return cmdutil.NewNoResultsError(fmt.Sprintf("No caches found in %s", ghrepo.FullName(repo)))
}
if err := opts.IO.StartPager(); err == nil {
defer opts.IO.StopPager()
} else {
fmt.Fprintf(opts.IO.Out, "Failed to start pager: %v\n", err)
}
if opts.Exporter != nil {
return opts.Exporter.Write(opts.IO, result.ActionsCaches)
}
if opts.IO.IsStdoutTTY() {
fmt.Fprintf(opts.IO.Out, "\nShowing %d of %s in %s\n\n", len(result.ActionsCaches), text.Pluralize(result.TotalCount, "cache"), ghrepo.FullName(repo))
}
if opts.Now.IsZero() {
opts.Now = time.Now()
}
tp := tableprinter.New(opts.IO, tableprinter.WithHeader("ID", "KEY", "SIZE", "CREATED", "ACCESSED"))
for _, cache := range result.ActionsCaches {
tp.AddField(opts.IO.ColorScheme().Cyan(fmt.Sprintf("%d", cache.Id)))
tp.AddField(cache.Key)
tp.AddField(humanFileSize(cache.SizeInBytes))
tp.AddTimeField(opts.Now, cache.CreatedAt, opts.IO.ColorScheme().Gray)
tp.AddTimeField(opts.Now, cache.LastAccessedAt, opts.IO.ColorScheme().Gray)
tp.EndRow()
}
return tp.Render()
}
func humanFileSize(s int64) string {
if s < 1024 {
return fmt.Sprintf("%d B", s)
}
kb := float64(s) / 1024
if kb < 1024 {
return fmt.Sprintf("%s KiB", floatToString(kb, 2))
}
mb := kb / 1024
if mb < 1024 {
return fmt.Sprintf("%s MiB", floatToString(mb, 2))
}
gb := mb / 1024
return fmt.Sprintf("%s GiB", floatToString(gb, 2))
}
func floatToString(f float64, p uint8) string {
fs := fmt.Sprintf("%#f%0*s", f, p, "")
idx := strings.IndexRune(fs, '.')
return fs[:idx+int(p)+1]
}
|