diff --git a/pkg/cmd/agent-task/capi/sessions.go b/pkg/cmd/agent-task/capi/sessions.go index 8e3969d69..c1f7fd846 100644 --- a/pkg/cmd/agent-task/capi/sessions.go +++ b/pkg/cmd/agent-task/capi/sessions.go @@ -102,6 +102,58 @@ type SessionError struct { Message string } +// SessionFields defines the available fields for JSON export of a Session. +var SessionFields = []string{ + "id", + "name", + "status", + "repository", + "createdAt", + "updatedAt", + "pullRequestNumber", + "pullRequestUrl", +} + +// ExportData implements the exportable interface for JSON output. +func (s *Session) ExportData(fields []string) map[string]interface{} { + data := make(map[string]interface{}, len(fields)) + for _, f := range fields { + switch f { + case "id": + data[f] = s.ID + case "name": + data[f] = s.Name + case "status": + data[f] = s.State + case "repository": + if s.PullRequest != nil && s.PullRequest.Repository != nil { + data[f] = s.PullRequest.Repository.NameWithOwner + } else { + data[f] = nil + } + case "createdAt": + data[f] = s.CreatedAt + case "updatedAt": + data[f] = s.LastUpdatedAt + case "pullRequestNumber": + if s.PullRequest != nil { + data[f] = s.PullRequest.Number + } else { + data[f] = nil + } + case "pullRequestUrl": + if s.PullRequest != nil { + data[f] = s.PullRequest.URL + } else { + data[f] = nil + } + default: + data[f] = nil + } + } + return data +} + type resource struct { ID string `json:"id"` UserID uint64 `json:"user_id"` diff --git a/pkg/cmd/agent-task/list/list.go b/pkg/cmd/agent-task/list/list.go index 211dc07ea..913a22295 100644 --- a/pkg/cmd/agent-task/list/list.go +++ b/pkg/cmd/agent-task/list/list.go @@ -25,6 +25,7 @@ type ListOptions struct { CapiClient func() (capi.CapiClient, error) Web bool Browser browser.Browser + Exporter cmdutil.Exporter } // NewCmdList creates the list command @@ -54,6 +55,8 @@ func NewCmdList(f *cmdutil.Factory, runF func(*ListOptions) error) *cobra.Comman 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 } @@ -91,6 +94,10 @@ func listRun(opts *ListOptions) error { 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 { diff --git a/pkg/cmd/agent-task/list/list_test.go b/pkg/cmd/agent-task/list/list_test.go index 747650283..3e146c934 100644 --- a/pkg/cmd/agent-task/list/list_test.go +++ b/pkg/cmd/agent-task/list/list_test.go @@ -99,6 +99,7 @@ func Test_listRun(t *testing.T) { capiStubs func(*testing.T, *capi.CapiClientMock) limit int web bool + jsonFields []string wantOut string wantErr error wantStderr string @@ -286,6 +287,33 @@ func Test_listRun(t *testing.T) { wantStderr: "Opening https://github.com/copilot/agents in your browser.\n", wantBrowserURL: "https://github.com/copilot/agents", }, + { + name: "json output", + tty: false, + capiStubs: func(t *testing.T, m *capi.CapiClientMock) { + m.ListLatestSessionsForViewerFunc = func(ctx context.Context, limit int) ([]*capi.Session, error) { + return []*capi.Session{ + { + ID: "abc-123", + Name: "s1", + State: "completed", + CreatedAt: sampleDate, + LastUpdatedAt: sampleDate, + ResourceType: "pull", + PullRequest: &api.PullRequest{ + Number: 101, + URL: "https://github.com/OWNER/REPO/pull/101", + Repository: &api.PRRepository{ + NameWithOwner: "OWNER/REPO", + }, + }, + }, + }, nil + } + }, + jsonFields: []string{"id", "name", "status", "repository", "pullRequestNumber", "pullRequestUrl"}, + wantOut: "[{\"id\":\"abc-123\",\"name\":\"s1\",\"pullRequestNumber\":101,\"pullRequestUrl\":\"https://github.com/OWNER/REPO/pull/101\",\"repository\":\"OWNER/REPO\",\"status\":\"completed\"}]\n", + }, } for _, tt := range tests { @@ -316,6 +344,12 @@ func Test_listRun(t *testing.T) { }, } + if tt.jsonFields != nil { + exporter := cmdutil.NewJSONExporter() + exporter.SetFields(tt.jsonFields) + opts.Exporter = exporter + } + err := listRun(opts) if tt.wantErr != nil { assert.Error(t, err)