github.com/abdfnx/gh-api@v0.0.0-20210414084727-f5432eec23b8/pkg/cmd/run/list/list.go (about) 1 package list 2 3 import ( 4 "fmt" 5 "net/http" 6 7 "github.com/abdfnx/gh-api/api" 8 "github.com/abdfnx/gh-api/internal/ghrepo" 9 "github.com/abdfnx/gh-api/pkg/cmd/run/shared" 10 workflowShared "github.com/abdfnx/gh-api/pkg/cmd/workflow/shared" 11 "github.com/abdfnx/gh-api/pkg/cmdutil" 12 "github.com/abdfnx/gh-api/pkg/iostreams" 13 "github.com/abdfnx/gh-api/utils" 14 "github.com/spf13/cobra" 15 ) 16 17 const ( 18 defaultLimit = 10 19 ) 20 21 type ListOptions struct { 22 IO *iostreams.IOStreams 23 HttpClient func() (*http.Client, error) 24 BaseRepo func() (ghrepo.Interface, error) 25 26 PlainOutput bool 27 28 Limit int 29 WorkflowSelector string 30 } 31 32 func NewCmdList(f *cmdutil.Factory, runF func(*ListOptions) error) *cobra.Command { 33 opts := &ListOptions{ 34 IO: f.IOStreams, 35 HttpClient: f.HttpClient, 36 } 37 38 cmd := &cobra.Command{ 39 Use: "list", 40 Short: "List recent workflow runs", 41 Args: cobra.NoArgs, 42 Hidden: true, 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 for _, run := range runs { 113 if opts.PlainOutput { 114 tp.AddField(string(run.Status), nil, nil) 115 tp.AddField(string(run.Conclusion), nil, nil) 116 } else { 117 symbol, symbolColor := shared.Symbol(cs, run.Status, run.Conclusion) 118 tp.AddField(symbol, nil, symbolColor) 119 } 120 121 tp.AddField(run.CommitMsg(), nil, cs.Bold) 122 123 tp.AddField(run.Name, nil, nil) 124 tp.AddField(run.HeadBranch, nil, cs.Bold) 125 tp.AddField(string(run.Event), nil, nil) 126 127 if opts.PlainOutput { 128 elapsed := run.UpdatedAt.Sub(run.CreatedAt) 129 if elapsed < 0 { 130 elapsed = 0 131 } 132 tp.AddField(elapsed.String(), nil, nil) 133 } 134 135 tp.AddField(fmt.Sprintf("%d", run.ID), nil, cs.Cyan) 136 137 tp.EndRow() 138 } 139 140 err = tp.Render() 141 if err != nil { 142 return err 143 } 144 145 if !opts.PlainOutput { 146 fmt.Fprintln(out) 147 fmt.Fprintln(out, "For details on a run, try: gh run view <run-id>") 148 } 149 150 return nil 151 }