package list import ( "context" "fmt" "time" "github.com/cli/cli/v2/internal/browser" "github.com/cli/cli/v2/internal/tableprinter" "github.com/cli/cli/v2/internal/text" "github.com/cli/cli/v2/pkg/cmd/agent-task/capi" "github.com/cli/cli/v2/pkg/cmd/agent-task/shared" prShared "github.com/cli/cli/v2/pkg/cmd/pr/shared" "github.com/cli/cli/v2/pkg/cmdutil" "github.com/cli/cli/v2/pkg/iostreams" "github.com/spf13/cobra" ) const defaultLimit = 30 // ListOptions are the options for the list command type ListOptions struct { IO *iostreams.IOStreams Limit int CapiClient func() (capi.CapiClient, error) Web bool Browser browser.Browser Exporter cmdutil.Exporter } // NewCmdList creates the list command func NewCmdList(f *cmdutil.Factory, runF func(*ListOptions) error) *cobra.Command { opts := &ListOptions{ IO: f.IOStreams, CapiClient: shared.CapiClientFunc(f), Limit: defaultLimit, Browser: f.Browser, } cmd := &cobra.Command{ Use: "list", Short: "List agent tasks (preview)", Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { 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", defaultLimit, "Maximum number of agent tasks to fetch") cmd.Flags().BoolVarP(&opts.Web, "web", "w", false, "Open agent tasks in the browser") cmdutil.AddJSONFlags(cmd, &opts.Exporter, capi.SessionFields) return cmd } func listRun(opts *ListOptions) error { if opts.Web { webURL := capi.AgentsHomeURL if opts.IO.IsStdoutTTY() { fmt.Fprintf(opts.IO.ErrOut, "Opening %s in your browser.\n", text.DisplayURL(webURL)) } return opts.Browser.Browse(webURL) } if opts.Limit <= 0 { opts.Limit = defaultLimit } capiClient, err := opts.CapiClient() if err != nil { return err } opts.IO.StartProgressIndicatorWithLabel("Fetching agent tasks...") defer opts.IO.StopProgressIndicator() var sessions []*capi.Session ctx := context.Background() sessions, err = capiClient.ListLatestSessionsForViewer(ctx, opts.Limit) if err != nil { return err } opts.IO.StopProgressIndicator() if len(sessions) == 0 && opts.Exporter == nil { return cmdutil.NewNoResultsError("no agent tasks found") } if opts.Exporter != nil { return opts.Exporter.Write(opts.IO, sessions) } if err := opts.IO.StartPager(); err == nil { defer opts.IO.StopPager() } else { fmt.Fprintf(opts.IO.ErrOut, "error starting pager: %v\n", err) } if opts.IO.IsStdoutTTY() { count := len(sessions) header := fmt.Sprintf("Showing %s", text.Pluralize(count, "session")) fmt.Fprintf(opts.IO.Out, "%s\n\n", header) } cs := opts.IO.ColorScheme() tp := tableprinter.New(opts.IO, tableprinter.WithHeader("Session Name", "Pull Request", "Repo", "Session State", "Created")) for _, s := range sessions { if s.ResourceType != "pull" || s.PullRequest == nil || s.PullRequest.Repository == nil { // Skip these sessions in case they happen, for now. continue } pr := fmt.Sprintf("#%d", s.PullRequest.Number) repo := s.PullRequest.Repository.NameWithOwner // Name tp.AddField(s.Name) if tp.IsTTY() { tp.AddField(pr, tableprinter.WithColor(cs.ColorFromString(prShared.ColorForPRState(*s.PullRequest)))) } else { tp.AddField(pr) } // Repo tp.AddField(repo, tableprinter.WithColor(cs.Muted)) // State if tp.IsTTY() { tp.AddField(shared.SessionStateString(s.State), tableprinter.WithColor(shared.ColorFuncForSessionState(*s, cs))) } else { tp.AddField(shared.SessionStateString(s.State)) } // Created if tp.IsTTY() { tp.AddTimeField(time.Now(), s.CreatedAt, cs.Muted) } else { tp.AddField(s.CreatedAt.Format(time.RFC3339)) } tp.EndRow() } if err := tp.Render(); err != nil { return err } return nil }