github.com/cli/cli@v1.14.1-0.20210902173923-1af6a669e342/pkg/cmd/run/list/list.go (about) 1 package list 2 3 import ( 4 "fmt" 5 "net/http" 6 "time" 7 8 "github.com/cli/cli/api" 9 "github.com/cli/cli/internal/ghrepo" 10 "github.com/cli/cli/pkg/cmd/run/shared" 11 workflowShared "github.com/cli/cli/pkg/cmd/workflow/shared" 12 "github.com/cli/cli/pkg/cmdutil" 13 "github.com/cli/cli/pkg/iostreams" 14 "github.com/cli/cli/utils" 15 "github.com/spf13/cobra" 16 ) 17 18 const ( 19 defaultLimit = 20 20 ) 21 22 type ListOptions struct { 23 IO *iostreams.IOStreams 24 HttpClient func() (*http.Client, error) 25 BaseRepo func() (ghrepo.Interface, error) 26 27 PlainOutput bool 28 29 Limit int 30 WorkflowSelector string 31 } 32 33 func NewCmdList(f *cmdutil.Factory, runF func(*ListOptions) error) *cobra.Command { 34 opts := &ListOptions{ 35 IO: f.IOStreams, 36 HttpClient: f.HttpClient, 37 } 38 39 cmd := &cobra.Command{ 40 Use: "list", 41 Short: "List recent workflow runs", 42 Args: cobra.NoArgs, 43 RunE: func(cmd *cobra.Command, args []string) error { 44 // support `-R, --repo` override 45 opts.BaseRepo = f.BaseRepo 46 47 terminal := opts.IO.IsStdoutTTY() && opts.IO.IsStdinTTY() 48 opts.PlainOutput = !terminal 49 50 if opts.Limit < 1 { 51 return &cmdutil.FlagError{Err: fmt.Errorf("invalid limit: %v", opts.Limit)} 52 } 53 54 if runF != nil { 55 return runF(opts) 56 } 57 58 return listRun(opts) 59 }, 60 } 61 62 cmd.Flags().IntVarP(&opts.Limit, "limit", "L", defaultLimit, "Maximum number of runs to fetch") 63 cmd.Flags().StringVarP(&opts.WorkflowSelector, "workflow", "w", "", "Filter runs by workflow") 64 65 return cmd 66 } 67 68 func listRun(opts *ListOptions) error { 69 baseRepo, err := opts.BaseRepo() 70 if err != nil { 71 return fmt.Errorf("failed to determine base repo: %w", err) 72 } 73 74 c, err := opts.HttpClient() 75 if err != nil { 76 return fmt.Errorf("failed to create http client: %w", err) 77 } 78 client := api.NewClientFromHTTP(c) 79 80 var runs []shared.Run 81 var workflow *workflowShared.Workflow 82 83 opts.IO.StartProgressIndicator() 84 if opts.WorkflowSelector != "" { 85 states := []workflowShared.WorkflowState{workflowShared.Active} 86 workflow, err = workflowShared.ResolveWorkflow( 87 opts.IO, client, baseRepo, false, opts.WorkflowSelector, states) 88 if err == nil { 89 runs, err = shared.GetRunsByWorkflow(client, baseRepo, opts.Limit, workflow.ID) 90 } 91 } else { 92 runs, err = shared.GetRuns(client, baseRepo, opts.Limit) 93 } 94 opts.IO.StopProgressIndicator() 95 if err != nil { 96 return fmt.Errorf("failed to get runs: %w", err) 97 } 98 99 tp := utils.NewTablePrinter(opts.IO) 100 101 cs := opts.IO.ColorScheme() 102 103 if len(runs) == 0 { 104 if !opts.PlainOutput { 105 fmt.Fprintln(opts.IO.ErrOut, "No runs found") 106 } 107 return nil 108 } 109 110 out := opts.IO.Out 111 112 if !opts.PlainOutput { 113 tp.AddField("STATUS", nil, nil) 114 tp.AddField("NAME", nil, nil) 115 tp.AddField("WORKFLOW", nil, nil) 116 tp.AddField("BRANCH", nil, nil) 117 tp.AddField("EVENT", nil, nil) 118 tp.AddField("ID", nil, nil) 119 tp.AddField("ELAPSED", nil, nil) 120 tp.AddField("AGE", nil, nil) 121 tp.EndRow() 122 } 123 124 for _, run := range runs { 125 if opts.PlainOutput { 126 tp.AddField(string(run.Status), nil, nil) 127 tp.AddField(string(run.Conclusion), nil, nil) 128 } else { 129 symbol, symbolColor := shared.Symbol(cs, run.Status, run.Conclusion) 130 tp.AddField(symbol, nil, symbolColor) 131 } 132 133 tp.AddField(run.CommitMsg(), nil, cs.Bold) 134 135 tp.AddField(run.Name, nil, nil) 136 tp.AddField(run.HeadBranch, nil, cs.Bold) 137 tp.AddField(string(run.Event), nil, nil) 138 tp.AddField(fmt.Sprintf("%d", run.ID), nil, cs.Cyan) 139 140 elapsed := run.UpdatedAt.Sub(run.CreatedAt) 141 if elapsed < 0 { 142 elapsed = 0 143 } 144 tp.AddField(elapsed.String(), nil, nil) 145 tp.AddField(utils.FuzzyAgoAbbr(time.Now(), run.CreatedAt), nil, nil) 146 tp.EndRow() 147 } 148 149 err = tp.Render() 150 if err != nil { 151 return err 152 } 153 154 if !opts.PlainOutput { 155 fmt.Fprintln(out) 156 fmt.Fprintln(out, "For details on a run, try: gh run view <run-id>") 157 } 158 159 return nil 160 }