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

     1  package list
     2  
     3  import (
     4  	"fmt"
     5  	"net/http"
     6  	"time"
     7  
     8  	"github.com/ungtb10d/cli/v2/api"
     9  	"github.com/ungtb10d/cli/v2/internal/ghrepo"
    10  	"github.com/ungtb10d/cli/v2/internal/text"
    11  	"github.com/ungtb10d/cli/v2/pkg/cmd/run/shared"
    12  	workflowShared "github.com/ungtb10d/cli/v2/pkg/cmd/workflow/shared"
    13  	"github.com/ungtb10d/cli/v2/pkg/cmdutil"
    14  	"github.com/ungtb10d/cli/v2/pkg/iostreams"
    15  	"github.com/ungtb10d/cli/v2/utils"
    16  	"github.com/spf13/cobra"
    17  )
    18  
    19  const (
    20  	defaultLimit = 20
    21  )
    22  
    23  type ListOptions struct {
    24  	IO         *iostreams.IOStreams
    25  	HttpClient func() (*http.Client, error)
    26  	BaseRepo   func() (ghrepo.Interface, error)
    27  
    28  	Exporter cmdutil.Exporter
    29  
    30  	Limit            int
    31  	WorkflowSelector string
    32  	Branch           string
    33  	Actor            string
    34  
    35  	now time.Time
    36  }
    37  
    38  func NewCmdList(f *cmdutil.Factory, runF func(*ListOptions) error) *cobra.Command {
    39  	opts := &ListOptions{
    40  		IO:         f.IOStreams,
    41  		HttpClient: f.HttpClient,
    42  		now:        time.Now(),
    43  	}
    44  
    45  	cmd := &cobra.Command{
    46  		Use:     "list",
    47  		Short:   "List recent workflow runs",
    48  		Aliases: []string{"ls"},
    49  		Args:    cobra.NoArgs,
    50  		RunE: func(cmd *cobra.Command, args []string) error {
    51  			// support `-R, --repo` override
    52  			opts.BaseRepo = f.BaseRepo
    53  
    54  			if opts.Limit < 1 {
    55  				return cmdutil.FlagErrorf("invalid limit: %v", opts.Limit)
    56  			}
    57  
    58  			if runF != nil {
    59  				return runF(opts)
    60  			}
    61  
    62  			return listRun(opts)
    63  		},
    64  	}
    65  
    66  	cmd.Flags().IntVarP(&opts.Limit, "limit", "L", defaultLimit, "Maximum number of runs to fetch")
    67  	cmd.Flags().StringVarP(&opts.WorkflowSelector, "workflow", "w", "", "Filter runs by workflow")
    68  	cmd.Flags().StringVarP(&opts.Branch, "branch", "b", "", "Filter runs by branch")
    69  	cmd.Flags().StringVarP(&opts.Actor, "user", "u", "", "Filter runs by user who triggered the run")
    70  	cmdutil.AddJSONFlags(cmd, &opts.Exporter, shared.RunFields)
    71  
    72  	return cmd
    73  }
    74  
    75  func listRun(opts *ListOptions) error {
    76  	baseRepo, err := opts.BaseRepo()
    77  	if err != nil {
    78  		return fmt.Errorf("failed to determine base repo: %w", err)
    79  	}
    80  
    81  	c, err := opts.HttpClient()
    82  	if err != nil {
    83  		return fmt.Errorf("failed to create http client: %w", err)
    84  	}
    85  	client := api.NewClientFromHTTP(c)
    86  
    87  	filters := &shared.FilterOptions{
    88  		Branch: opts.Branch,
    89  		Actor:  opts.Actor,
    90  	}
    91  
    92  	opts.IO.StartProgressIndicator()
    93  	if opts.WorkflowSelector != "" {
    94  		states := []workflowShared.WorkflowState{workflowShared.Active}
    95  		if workflow, err := workflowShared.ResolveWorkflow(opts.IO, client, baseRepo, false, opts.WorkflowSelector, states); err == nil {
    96  			filters.WorkflowID = workflow.ID
    97  			filters.WorkflowName = workflow.Name
    98  		} else {
    99  			return err
   100  		}
   101  	}
   102  	runsResult, err := shared.GetRuns(client, baseRepo, filters, opts.Limit)
   103  	opts.IO.StopProgressIndicator()
   104  	if err != nil {
   105  		return fmt.Errorf("failed to get runs: %w", err)
   106  	}
   107  	runs := runsResult.WorkflowRuns
   108  	if len(runs) == 0 && opts.Exporter == nil {
   109  		return cmdutil.NewNoResultsError("no runs found")
   110  	}
   111  
   112  	if err := opts.IO.StartPager(); err == nil {
   113  		defer opts.IO.StopPager()
   114  	} else {
   115  		fmt.Fprintf(opts.IO.ErrOut, "failed to start pager: %v\n", err)
   116  	}
   117  
   118  	if opts.Exporter != nil {
   119  		return opts.Exporter.Write(opts.IO, runs)
   120  	}
   121  
   122  	//nolint:staticcheck // SA1019: utils.NewTablePrinter is deprecated: use internal/tableprinter
   123  	tp := utils.NewTablePrinter(opts.IO)
   124  
   125  	cs := opts.IO.ColorScheme()
   126  
   127  	if tp.IsTTY() {
   128  		tp.AddField("STATUS", nil, nil)
   129  		tp.AddField("TITLE", nil, nil)
   130  		tp.AddField("WORKFLOW", nil, nil)
   131  		tp.AddField("BRANCH", nil, nil)
   132  		tp.AddField("EVENT", nil, nil)
   133  		tp.AddField("ID", nil, nil)
   134  		tp.AddField("ELAPSED", nil, nil)
   135  		tp.AddField("AGE", nil, nil)
   136  		tp.EndRow()
   137  	}
   138  
   139  	for _, run := range runs {
   140  		if tp.IsTTY() {
   141  			symbol, symbolColor := shared.Symbol(cs, run.Status, run.Conclusion)
   142  			tp.AddField(symbol, nil, symbolColor)
   143  		} else {
   144  			tp.AddField(string(run.Status), nil, nil)
   145  			tp.AddField(string(run.Conclusion), nil, nil)
   146  		}
   147  
   148  		tp.AddField(run.Title(), nil, cs.Bold)
   149  
   150  		tp.AddField(run.WorkflowName(), nil, nil)
   151  		tp.AddField(run.HeadBranch, nil, cs.Bold)
   152  		tp.AddField(string(run.Event), nil, nil)
   153  		tp.AddField(fmt.Sprintf("%d", run.ID), nil, cs.Cyan)
   154  
   155  		tp.AddField(run.Duration(opts.now).String(), nil, nil)
   156  		tp.AddField(text.FuzzyAgoAbbr(time.Now(), run.StartedTime()), nil, nil)
   157  		tp.EndRow()
   158  	}
   159  
   160  	err = tp.Render()
   161  	if err != nil {
   162  		return err
   163  	}
   164  
   165  	return nil
   166  }