diff --git a/pkg/cmd/agent-task/capi/sessions.go b/pkg/cmd/agent-task/capi/sessions.go index 7f16b4ae5..f4f12254d 100644 --- a/pkg/cmd/agent-task/capi/sessions.go +++ b/pkg/cmd/agent-task/capi/sessions.go @@ -27,21 +27,22 @@ var ErrSessionNotFound = errors.New("not found") // session is an in-flight agent task type session struct { - ID string `json:"id"` - Name string `json:"name"` - UserID int64 `json:"user_id"` - AgentID int64 `json:"agent_id"` - Logs string `json:"logs"` - State string `json:"state"` - OwnerID uint64 `json:"owner_id"` - RepoID uint64 `json:"repo_id"` - ResourceType string `json:"resource_type"` - ResourceID int64 `json:"resource_id"` - LastUpdatedAt time.Time `json:"last_updated_at,omitempty"` - CreatedAt time.Time `json:"created_at,omitempty"` - CompletedAt time.Time `json:"completed_at,omitempty"` - EventURL string `json:"event_url"` - EventType string `json:"event_type"` + ID string `json:"id"` + Name string `json:"name"` + UserID int64 `json:"user_id"` + AgentID int64 `json:"agent_id"` + Logs string `json:"logs"` + State string `json:"state"` + OwnerID uint64 `json:"owner_id"` + RepoID uint64 `json:"repo_id"` + ResourceType string `json:"resource_type"` + ResourceID int64 `json:"resource_id"` + LastUpdatedAt time.Time `json:"last_updated_at,omitempty"` + CreatedAt time.Time `json:"created_at,omitempty"` + CompletedAt time.Time `json:"completed_at,omitempty"` + EventURL string `json:"event_url"` + EventType string `json:"event_type"` + PremiumRequests float64 `json:"premium_requests"` } // A shim of a full pull request because looking up by node ID @@ -66,21 +67,22 @@ type sessionPullRequest struct { // Session is a hydrated in-flight agent task type Session struct { - ID string - Name string - UserID int64 - AgentID int64 - Logs string - State string - OwnerID uint64 - RepoID uint64 - ResourceType string - ResourceID int64 - LastUpdatedAt time.Time - CreatedAt time.Time - CompletedAt time.Time - EventURL string - EventType string + ID string + Name string + UserID int64 + AgentID int64 + Logs string + State string + OwnerID uint64 + RepoID uint64 + ResourceType string + ResourceID int64 + LastUpdatedAt time.Time + CreatedAt time.Time + CompletedAt time.Time + EventURL string + EventType string + PremiumRequests float64 PullRequest *api.PullRequest User *api.GitHubUser @@ -475,20 +477,21 @@ func generateUserNodeID(userID int64) string { func fromAPISession(s session) *Session { return &Session{ - ID: s.ID, - Name: s.Name, - UserID: s.UserID, - AgentID: s.AgentID, - Logs: s.Logs, - State: s.State, - OwnerID: s.OwnerID, - RepoID: s.RepoID, - ResourceType: s.ResourceType, - ResourceID: s.ResourceID, - LastUpdatedAt: s.LastUpdatedAt, - CreatedAt: s.CreatedAt, - CompletedAt: s.CompletedAt, - EventURL: s.EventURL, - EventType: s.EventType, + ID: s.ID, + Name: s.Name, + UserID: s.UserID, + AgentID: s.AgentID, + Logs: s.Logs, + State: s.State, + OwnerID: s.OwnerID, + RepoID: s.RepoID, + ResourceType: s.ResourceType, + ResourceID: s.ResourceID, + LastUpdatedAt: s.LastUpdatedAt, + CreatedAt: s.CreatedAt, + CompletedAt: s.CompletedAt, + EventURL: s.EventURL, + EventType: s.EventType, + PremiumRequests: s.PremiumRequests, } } diff --git a/pkg/cmd/agent-task/capi/sessions_test.go b/pkg/cmd/agent-task/capi/sessions_test.go index e67ed2ab1..45984dfec 100644 --- a/pkg/cmd/agent-task/capi/sessions_test.go +++ b/pkg/cmd/agent-task/capi/sessions_test.go @@ -77,7 +77,8 @@ func TestListSessionsForViewer(t *testing.T) { "repo_id": 1000, "resource_type": "pull", "resource_id": 2000, - "created_at": "%[1]s" + "created_at": "%[1]s", + "premium_requests": 0.1 } ] }`, @@ -125,17 +126,18 @@ func TestListSessionsForViewer(t *testing.T) { wantOut: []*Session{ { - ID: "sess1", - Name: "Build artifacts", - UserID: 1, - AgentID: 2, - Logs: "", - State: "completed", - OwnerID: 10, - RepoID: 1000, - ResourceType: "pull", - ResourceID: 2000, - CreatedAt: sampleDate, + ID: "sess1", + Name: "Build artifacts", + UserID: 1, + AgentID: 2, + Logs: "", + State: "completed", + OwnerID: 10, + RepoID: 1000, + ResourceType: "pull", + ResourceID: 2000, + CreatedAt: sampleDate, + PremiumRequests: 0.1, PullRequest: &api.PullRequest{ ID: "PR_node", FullDatabaseID: "2000", @@ -186,7 +188,8 @@ func TestListSessionsForViewer(t *testing.T) { "repo_id": 1000, "resource_type": "", "resource_id": 0, - "created_at": "%[1]s" + "created_at": "%[1]s", + "premium_requests": 0.1 } ] }`, @@ -218,17 +221,18 @@ func TestListSessionsForViewer(t *testing.T) { wantOut: []*Session{ { - ID: "sess1", - Name: "Build artifacts", - UserID: 1, - AgentID: 2, - Logs: "", - State: "completed", - OwnerID: 10, - RepoID: 1000, - ResourceType: "", - ResourceID: 0, - CreatedAt: sampleDate, + ID: "sess1", + Name: "Build artifacts", + UserID: 1, + AgentID: 2, + Logs: "", + State: "completed", + OwnerID: 10, + RepoID: 1000, + ResourceType: "", + ResourceID: 0, + CreatedAt: sampleDate, + PremiumRequests: 0.1, User: &api.GitHubUser{ Login: "octocat", Name: "Octocat", @@ -264,7 +268,8 @@ func TestListSessionsForViewer(t *testing.T) { "repo_id": 1000, "resource_type": "pull", "resource_id": 2000, - "created_at": "%[1]s" + "created_at": "%[1]s", + "premium_requests": 0.1 } ] }`, @@ -295,7 +300,8 @@ func TestListSessionsForViewer(t *testing.T) { "repo_id": 1000, "resource_type": "pull", "resource_id": 2001, - "created_at": "%[1]s" + "created_at": "%[1]s", + "premium_requests": 0.1 } ] }`, @@ -358,17 +364,18 @@ func TestListSessionsForViewer(t *testing.T) { }, wantOut: []*Session{ { - ID: "sess1", - Name: "Build artifacts", - UserID: 1, - AgentID: 2, - Logs: "", - State: "completed", - OwnerID: 10, - RepoID: 1000, - ResourceType: "pull", - ResourceID: 2000, - CreatedAt: sampleDate, + ID: "sess1", + Name: "Build artifacts", + UserID: 1, + AgentID: 2, + Logs: "", + State: "completed", + OwnerID: 10, + RepoID: 1000, + ResourceType: "pull", + ResourceID: 2000, + CreatedAt: sampleDate, + PremiumRequests: 0.1, PullRequest: &api.PullRequest{ ID: "PR_node", FullDatabaseID: "2000", @@ -391,17 +398,18 @@ func TestListSessionsForViewer(t *testing.T) { }, }, { - ID: "sess2", - Name: "Build artifacts", - UserID: 1, - AgentID: 2, - Logs: "", - State: "completed", - OwnerID: 10, - RepoID: 1000, - ResourceType: "pull", - ResourceID: 2001, - CreatedAt: sampleDate, + ID: "sess2", + Name: "Build artifacts", + UserID: 1, + AgentID: 2, + Logs: "", + State: "completed", + OwnerID: 10, + RepoID: 1000, + ResourceType: "pull", + ResourceID: 2001, + CreatedAt: sampleDate, + PremiumRequests: 0.1, PullRequest: &api.PullRequest{ ID: "PR_node", FullDatabaseID: "2001", @@ -467,7 +475,8 @@ func TestListSessionsForViewer(t *testing.T) { "repo_id": 1000, "resource_type": "pull", "resource_id": 2000, - "created_at": "%[1]s" + "created_at": "%[1]s", + "premium_requests": 0.1 } ] }`, @@ -591,7 +600,8 @@ func TestListSessionsForRepo(t *testing.T) { "repo_id": 1000, "resource_type": "pull", "resource_id": 2000, - "created_at": "%[1]s" + "created_at": "%[1]s", + "premium_requests": 0.1 } ] }`, @@ -638,17 +648,18 @@ func TestListSessionsForRepo(t *testing.T) { }, wantOut: []*Session{ { - ID: "sess1", - Name: "Build artifacts", - UserID: 1, - AgentID: 2, - Logs: "", - State: "completed", - OwnerID: 10, - RepoID: 1000, - ResourceType: "pull", - ResourceID: 2000, - CreatedAt: sampleDate, + ID: "sess1", + Name: "Build artifacts", + UserID: 1, + AgentID: 2, + Logs: "", + State: "completed", + OwnerID: 10, + RepoID: 1000, + ResourceType: "pull", + ResourceID: 2000, + CreatedAt: sampleDate, + PremiumRequests: 0.1, PullRequest: &api.PullRequest{ ID: "PR_node", FullDatabaseID: "2000", @@ -699,7 +710,8 @@ func TestListSessionsForRepo(t *testing.T) { "repo_id": 1000, "resource_type": "", "resource_id": 0, - "created_at": "%[1]s" + "created_at": "%[1]s", + "premium_requests": 0.1 } ] }`, @@ -731,17 +743,18 @@ func TestListSessionsForRepo(t *testing.T) { wantOut: []*Session{ { - ID: "sess1", - Name: "Build artifacts", - UserID: 1, - AgentID: 2, - Logs: "", - State: "completed", - OwnerID: 10, - RepoID: 1000, - ResourceType: "", - ResourceID: 0, - CreatedAt: sampleDate, + ID: "sess1", + Name: "Build artifacts", + UserID: 1, + AgentID: 2, + Logs: "", + State: "completed", + OwnerID: 10, + RepoID: 1000, + ResourceType: "", + ResourceID: 0, + CreatedAt: sampleDate, + PremiumRequests: 0.1, User: &api.GitHubUser{ Login: "octocat", Name: "Octocat", @@ -777,7 +790,8 @@ func TestListSessionsForRepo(t *testing.T) { "repo_id": 1000, "resource_type": "pull", "resource_id": 2000, - "created_at": "%[1]s" + "created_at": "%[1]s", + "premium_requests": 0.1 } ] }`, @@ -808,7 +822,8 @@ func TestListSessionsForRepo(t *testing.T) { "repo_id": 1000, "resource_type": "pull", "resource_id": 2001, - "created_at": "%[1]s" + "created_at": "%[1]s", + "premium_requests": 0.1 } ] }`, @@ -871,17 +886,18 @@ func TestListSessionsForRepo(t *testing.T) { }, wantOut: []*Session{ { - ID: "sess1", - Name: "Build artifacts", - UserID: 1, - AgentID: 2, - Logs: "", - State: "completed", - OwnerID: 10, - RepoID: 1000, - ResourceType: "pull", - ResourceID: 2000, - CreatedAt: sampleDate, + ID: "sess1", + Name: "Build artifacts", + UserID: 1, + AgentID: 2, + Logs: "", + State: "completed", + OwnerID: 10, + RepoID: 1000, + ResourceType: "pull", + ResourceID: 2000, + CreatedAt: sampleDate, + PremiumRequests: 0.1, PullRequest: &api.PullRequest{ ID: "PR_node", FullDatabaseID: "2000", @@ -904,17 +920,18 @@ func TestListSessionsForRepo(t *testing.T) { }, }, { - ID: "sess2", - Name: "Build artifacts", - UserID: 1, - AgentID: 2, - Logs: "", - State: "completed", - OwnerID: 10, - RepoID: 1000, - ResourceType: "pull", - ResourceID: 2001, - CreatedAt: sampleDate, + ID: "sess2", + Name: "Build artifacts", + UserID: 1, + AgentID: 2, + Logs: "", + State: "completed", + OwnerID: 10, + RepoID: 1000, + ResourceType: "pull", + ResourceID: 2001, + CreatedAt: sampleDate, + PremiumRequests: 0.1, PullRequest: &api.PullRequest{ ID: "PR_node", FullDatabaseID: "2001", @@ -980,7 +997,8 @@ func TestListSessionsForRepo(t *testing.T) { "repo_id": 1000, "resource_type": "pull", "resource_id": 2000, - "created_at": "%[1]s" + "created_at": "%[1]s", + "premium_requests": 0.1 } ] }`, @@ -1107,7 +1125,8 @@ func TestListSessionsByResourceID(t *testing.T) { "repo_id": 1000, "resource_type": "pull", "resource_id": 2000, - "created_at": "%[1]s" + "created_at": "%[1]s", + "premium_requests": 0.1 } ] }`, @@ -1155,17 +1174,18 @@ func TestListSessionsByResourceID(t *testing.T) { wantOut: []*Session{ { - ID: "sess1", - Name: "Build artifacts", - UserID: 1, - AgentID: 2, - Logs: "", - State: "completed", - OwnerID: 10, - RepoID: 1000, - ResourceType: "pull", - ResourceID: 2000, - CreatedAt: sampleDate, + ID: "sess1", + Name: "Build artifacts", + UserID: 1, + AgentID: 2, + Logs: "", + State: "completed", + OwnerID: 10, + RepoID: 1000, + ResourceType: "pull", + ResourceID: 2000, + CreatedAt: sampleDate, + PremiumRequests: 0.1, PullRequest: &api.PullRequest{ ID: "PR_node", FullDatabaseID: "2000", @@ -1216,7 +1236,8 @@ func TestListSessionsByResourceID(t *testing.T) { "repo_id": 1000, "resource_type": "pull", "resource_id": 2000, - "created_at": "%[1]s" + "created_at": "%[1]s", + "premium_requests": 0.1 } ] }`, @@ -1247,7 +1268,8 @@ func TestListSessionsByResourceID(t *testing.T) { "repo_id": 1000, "resource_type": "pull", "resource_id": 2001, - "created_at": "%[1]s" + "created_at": "%[1]s", + "premium_requests": 0.1 } ] }`, @@ -1310,17 +1332,18 @@ func TestListSessionsByResourceID(t *testing.T) { }, wantOut: []*Session{ { - ID: "sess1", - Name: "Build artifacts", - UserID: 1, - AgentID: 2, - Logs: "", - State: "completed", - OwnerID: 10, - RepoID: 1000, - ResourceType: "pull", - ResourceID: 2000, - CreatedAt: sampleDate, + ID: "sess1", + Name: "Build artifacts", + UserID: 1, + AgentID: 2, + Logs: "", + State: "completed", + OwnerID: 10, + RepoID: 1000, + ResourceType: "pull", + ResourceID: 2000, + CreatedAt: sampleDate, + PremiumRequests: 0.1, PullRequest: &api.PullRequest{ ID: "PR_node", FullDatabaseID: "2000", @@ -1343,17 +1366,18 @@ func TestListSessionsByResourceID(t *testing.T) { }, }, { - ID: "sess2", - Name: "Build artifacts", - UserID: 1, - AgentID: 2, - Logs: "", - State: "completed", - OwnerID: 10, - RepoID: 1000, - ResourceType: "pull", - ResourceID: 2001, - CreatedAt: sampleDate, + ID: "sess2", + Name: "Build artifacts", + UserID: 1, + AgentID: 2, + Logs: "", + State: "completed", + OwnerID: 10, + RepoID: 1000, + ResourceType: "pull", + ResourceID: 2001, + CreatedAt: sampleDate, + PremiumRequests: 0.1, PullRequest: &api.PullRequest{ ID: "PR_node", FullDatabaseID: "2001", @@ -1419,7 +1443,8 @@ func TestListSessionsByResourceID(t *testing.T) { "repo_id": 1000, "resource_type": "pull", "resource_id": 2000, - "created_at": "%[1]s" + "created_at": "%[1]s", + "premium_requests": 0.1 } ] }`, @@ -1538,7 +1563,8 @@ func TestGetSession(t *testing.T) { "repo_id": 1000, "resource_type": "pull", "resource_id": 2000, - "created_at": "%[1]s" + "created_at": "%[1]s", + "premium_requests": 0.1 }`, sampleDateString, )), @@ -1582,17 +1608,18 @@ func TestGetSession(t *testing.T) { ) }, wantOut: &Session{ - ID: "some-uuid", - Name: "Build artifacts", - UserID: 1, - AgentID: 2, - Logs: "", - State: "completed", - OwnerID: 10, - RepoID: 1000, - ResourceType: "pull", - ResourceID: 2000, - CreatedAt: sampleDate, + ID: "some-uuid", + Name: "Build artifacts", + UserID: 1, + AgentID: 2, + Logs: "", + State: "completed", + OwnerID: 10, + RepoID: 1000, + ResourceType: "pull", + ResourceID: 2000, + CreatedAt: sampleDate, + PremiumRequests: 0.1, PullRequest: &api.PullRequest{ ID: "PR_node", FullDatabaseID: "2000", @@ -1633,7 +1660,8 @@ func TestGetSession(t *testing.T) { "repo_id": 1000, "resource_type": "", "resource_id": 0, - "created_at": "%[1]s" + "created_at": "%[1]s", + "premium_requests": 0.1 }`, sampleDateString, )), @@ -1661,17 +1689,18 @@ func TestGetSession(t *testing.T) { ) }, wantOut: &Session{ - ID: "some-uuid", - Name: "Build artifacts", - UserID: 1, - AgentID: 2, - Logs: "", - State: "completed", - OwnerID: 10, - RepoID: 1000, - ResourceType: "", - ResourceID: 0, - CreatedAt: sampleDate, + ID: "some-uuid", + Name: "Build artifacts", + UserID: 1, + AgentID: 2, + Logs: "", + State: "completed", + OwnerID: 10, + RepoID: 1000, + ResourceType: "", + ResourceID: 0, + CreatedAt: sampleDate, + PremiumRequests: 0.1, User: &api.GitHubUser{ Login: "octocat", Name: "Octocat", @@ -1696,7 +1725,8 @@ func TestGetSession(t *testing.T) { "repo_id": 1000, "resource_type": "pull", "resource_id": 2000, - "created_at": "%[1]s" + "created_at": "%[1]s", + "premium_requests": 0.1 }`, sampleDateString, )), diff --git a/pkg/cmd/agent-task/shared/display.go b/pkg/cmd/agent-task/shared/display.go index e841f4c41..99ae91c43 100644 --- a/pkg/cmd/agent-task/shared/display.go +++ b/pkg/cmd/agent-task/shared/display.go @@ -30,17 +30,17 @@ func SessionStateString(state string) string { case "queued": return "Queued" case "in_progress": - return "In Progress" + return "In progress" case "completed": - return "Completed" + return "Ready for review" case "failed": return "Failed" case "idle": return "Idle" case "waiting_for_user": - return "Waiting for User" + return "Waiting for user" case "timed_out": - return "Timed Out" + return "Timed out" case "cancelled": return "Cancelled" default: diff --git a/pkg/cmd/agent-task/view/view.go b/pkg/cmd/agent-task/view/view.go index 832c20806..2ff09386a 100644 --- a/pkg/cmd/agent-task/view/view.go +++ b/pkg/cmd/agent-task/view/view.go @@ -7,6 +7,7 @@ import ( "net/http" "net/url" "strconv" + "strings" "time" "github.com/MakeNowJust/heredoc" @@ -200,8 +201,9 @@ func viewRun(opts *ViewOptions) error { if prID == 0 { findOptions := prShared.FindOptions{ - Selector: opts.SelectorArg, - Fields: []string{"id", "url", "fullDatabaseId"}, + Selector: opts.SelectorArg, + Fields: []string{"id", "url", "fullDatabaseId"}, + DisableProgress: true, } pr, repo, err := opts.Finder.Find(findOptions) @@ -275,11 +277,11 @@ func viewRun(opts *ViewOptions) error { } } - printSession(opts, session) - if opts.Log { return printLogs(opts, capiClient, session.ID) } + + printSession(opts, session) return nil } @@ -305,6 +307,16 @@ func printSession(opts *ViewOptions, session *capi.Session) { fmt.Fprintf(opts.IO.Out, "Started %s\n", text.FuzzyAgo(time.Now(), session.CreatedAt)) } + usedPremiumRequests := strings.TrimSuffix(fmt.Sprintf("%.1f", session.PremiumRequests), ".0") + usedPremiumRequestsNote := fmt.Sprintf("Used %s premium request(s)", usedPremiumRequests) + + var durationNote string + if session.CompletedAt.After(session.CreatedAt) { + durationNote = fmt.Sprintf(" • Duration %s", session.CompletedAt.Sub(session.CreatedAt).Round(time.Second).String()) + } + + fmt.Fprintf(opts.IO.Out, "%s%s\n", cs.Muted(usedPremiumRequestsNote), cs.Muted(durationNote)) + if !opts.Log { fmt.Fprintln(opts.IO.Out, "") fmt.Fprintf(opts.IO.Out, "For detailed session logs, try:\ngh agent-task view '%s' --log\n", session.ID) @@ -345,7 +357,6 @@ func printLogs(opts *ViewOptions, capiClient capi.CapiClient, sessionID string) return raw, nil } - fmt.Fprintln(opts.IO.Out, "") return renderer.Follow(fetcher, opts.IO.Out, opts.IO) } @@ -354,7 +365,6 @@ func printLogs(opts *ViewOptions, capiClient capi.CapiClient, sessionID string) return fmt.Errorf("failed to fetch session logs: %w", err) } - fmt.Fprintln(opts.IO.Out, "") _, err = renderer.Render(raw, opts.IO.Out, opts.IO) return err } diff --git a/pkg/cmd/agent-task/view/view_test.go b/pkg/cmd/agent-task/view/view_test.go index 1d4a8b2cc..b8f872560 100644 --- a/pkg/cmd/agent-task/view/view_test.go +++ b/pkg/cmd/agent-task/view/view_test.go @@ -159,6 +159,7 @@ func TestNewCmdList(t *testing.T) { func Test_viewRun(t *testing.T) { sampleDate := time.Now().Add(-6 * time.Hour) // 6h ago + sampleCompletedAt := sampleDate.Add(5 * time.Minute) tests := []struct { name string @@ -212,9 +213,11 @@ func Test_viewRun(t *testing.T) { m.GetSessionFunc = func(_ context.Context, id string) (*capi.Session, error) { assert.Equal(t, "some-session-id", id) return &capi.Session{ - ID: "some-session-id", - State: "completed", - CreatedAt: sampleDate, + ID: "some-session-id", + State: "completed", + CreatedAt: sampleDate, + CompletedAt: sampleCompletedAt, + PremiumRequests: 1.5, PullRequest: &api.PullRequest{ Title: "fix something", Number: 101, @@ -230,8 +233,9 @@ func Test_viewRun(t *testing.T) { } }, wantOut: heredoc.Doc(` - Completed • fix something • OWNER/REPO#101 + Ready for review • fix something • OWNER/REPO#101 Started on behalf of octocat about 6 hours ago + Used 1.5 premium request(s) • Duration 5m0s For detailed session logs, try: gh agent-task view 'some-session-id' --log @@ -252,9 +256,11 @@ func Test_viewRun(t *testing.T) { m.GetSessionFunc = func(_ context.Context, id string) (*capi.Session, error) { assert.Equal(t, "some-session-id", id) return &capi.Session{ - ID: "some-session-id", - State: "completed", - CreatedAt: sampleDate, + ID: "some-session-id", + State: "completed", + CreatedAt: sampleDate, + CompletedAt: sampleCompletedAt, + PremiumRequests: 1.5, PullRequest: &api.PullRequest{ Title: "fix something", Number: 101, @@ -267,8 +273,9 @@ func Test_viewRun(t *testing.T) { } }, wantOut: heredoc.Doc(` - Completed • fix something • OWNER/REPO#101 + Ready for review • fix something • OWNER/REPO#101 Started about 6 hours ago + Used 1.5 premium request(s) • Duration 5m0s For detailed session logs, try: gh agent-task view 'some-session-id' --log @@ -289,9 +296,11 @@ func Test_viewRun(t *testing.T) { m.GetSessionFunc = func(_ context.Context, id string) (*capi.Session, error) { assert.Equal(t, "some-session-id", id) return &capi.Session{ - ID: "some-session-id", - State: "completed", - CreatedAt: sampleDate, + ID: "some-session-id", + State: "completed", + CreatedAt: sampleDate, + CompletedAt: sampleCompletedAt, + PremiumRequests: 1.5, User: &api.GitHubUser{ Login: "octocat", }, @@ -299,8 +308,9 @@ func Test_viewRun(t *testing.T) { } }, wantOut: heredoc.Doc(` - Completed + Ready for review Started on behalf of octocat about 6 hours ago + Used 1.5 premium request(s) • Duration 5m0s For detailed session logs, try: gh agent-task view 'some-session-id' --log @@ -318,20 +328,106 @@ func Test_viewRun(t *testing.T) { m.GetSessionFunc = func(_ context.Context, id string) (*capi.Session, error) { assert.Equal(t, "some-session-id", id) return &capi.Session{ - ID: "some-session-id", - State: "completed", - CreatedAt: sampleDate, + ID: "some-session-id", + State: "completed", + CreatedAt: sampleDate, + CompletedAt: sampleCompletedAt, + PremiumRequests: 1.5, }, nil } }, wantOut: heredoc.Doc(` - Completed + Ready for review Started about 6 hours ago + Used 1.5 premium request(s) • Duration 5m0s For detailed session logs, try: gh agent-task view 'some-session-id' --log `), }, + { + name: "with session id, success, with zero premium requests (tty)", + tty: true, + opts: ViewOptions{ + SelectorArg: "some-session-id", + SessionID: "some-session-id", + }, + capiStubs: func(t *testing.T, m *capi.CapiClientMock) { + m.GetSessionFunc = func(_ context.Context, id string) (*capi.Session, error) { + assert.Equal(t, "some-session-id", id) + return &capi.Session{ + ID: "some-session-id", + State: "completed", + CreatedAt: sampleDate, + CompletedAt: sampleCompletedAt, + PremiumRequests: 0, + PullRequest: &api.PullRequest{ + Title: "fix something", + Number: 101, + URL: "https://github.com/OWNER/REPO/pull/101", + Repository: &api.PRRepository{ + NameWithOwner: "OWNER/REPO", + }, + }, + User: &api.GitHubUser{ + Login: "octocat", + }, + }, nil + } + }, + wantOut: heredoc.Doc(` + Ready for review • fix something • OWNER/REPO#101 + Started on behalf of octocat about 6 hours ago + Used 0 premium request(s) • Duration 5m0s + + For detailed session logs, try: + gh agent-task view 'some-session-id' --log + + View this session on GitHub: + https://github.com/OWNER/REPO/pull/101/agent-sessions/some-session-id + `), + }, + { + name: "with session id, success, duration not available (tty)", + tty: true, + opts: ViewOptions{ + SelectorArg: "some-session-id", + SessionID: "some-session-id", + }, + capiStubs: func(t *testing.T, m *capi.CapiClientMock) { + m.GetSessionFunc = func(_ context.Context, id string) (*capi.Session, error) { + assert.Equal(t, "some-session-id", id) + return &capi.Session{ + ID: "some-session-id", + State: "in_progress", + CreatedAt: sampleDate, + PremiumRequests: 1.5, + PullRequest: &api.PullRequest{ + Title: "fix something", + Number: 101, + URL: "https://github.com/OWNER/REPO/pull/101", + Repository: &api.PRRepository{ + NameWithOwner: "OWNER/REPO", + }, + }, + User: &api.GitHubUser{ + Login: "octocat", + }, + }, nil + } + }, + wantOut: heredoc.Doc(` + In progress • fix something • OWNER/REPO#101 + Started on behalf of octocat about 6 hours ago + Used 1.5 premium request(s) + + For detailed session logs, try: + gh agent-task view 'some-session-id' --log + + View this session on GitHub: + https://github.com/OWNER/REPO/pull/101/agent-sessions/some-session-id + `), + }, { name: "with session id, not found, web mode (tty)", tty: true, @@ -360,9 +456,11 @@ func Test_viewRun(t *testing.T) { m.GetSessionFunc = func(_ context.Context, id string) (*capi.Session, error) { assert.Equal(t, "some-session-id", id) return &capi.Session{ - ID: "some-session-id", - State: "completed", - CreatedAt: sampleDate, + ID: "some-session-id", + State: "completed", + CreatedAt: sampleDate, + CompletedAt: sampleCompletedAt, + PremiumRequests: 1.5, // User data is irrelevant in this case }, nil } @@ -382,9 +480,11 @@ func Test_viewRun(t *testing.T) { m.GetSessionFunc = func(_ context.Context, id string) (*capi.Session, error) { assert.Equal(t, "some-session-id", id) return &capi.Session{ - ID: "some-session-id", - State: "completed", - CreatedAt: sampleDate, + ID: "some-session-id", + State: "completed", + CreatedAt: sampleDate, + CompletedAt: sampleCompletedAt, + PremiumRequests: 1.5, PullRequest: &api.PullRequest{ Title: "fix something", Number: 101, @@ -488,9 +588,11 @@ func Test_viewRun(t *testing.T) { assert.Equal(t, defaultLimit, limit) return []*capi.Session{ { - ID: "some-session-id", - State: "completed", - CreatedAt: sampleDate, + ID: "some-session-id", + State: "completed", + CreatedAt: sampleDate, + CompletedAt: sampleCompletedAt, + PremiumRequests: 1.5, PullRequest: &api.PullRequest{ Title: "fix something", Number: 101, @@ -507,8 +609,9 @@ func Test_viewRun(t *testing.T) { } }, wantOut: heredoc.Doc(` - Completed • fix something • OWNER/REPO#101 + Ready for review • fix something • OWNER/REPO#101 Started on behalf of octocat about 6 hours ago + Used 1.5 premium request(s) • Duration 5m0s For detailed session logs, try: gh agent-task view 'some-session-id' --log @@ -538,10 +641,12 @@ func Test_viewRun(t *testing.T) { assert.Equal(t, defaultLimit, limit) return []*capi.Session{ { - ID: "some-session-id", - Name: "session one", - State: "completed", - CreatedAt: sampleDate, + ID: "some-session-id", + Name: "session one", + State: "completed", + CreatedAt: sampleDate, + CompletedAt: sampleCompletedAt, + PremiumRequests: 1.5, PullRequest: &api.PullRequest{ Title: "fix something", Number: 101, @@ -555,10 +660,12 @@ func Test_viewRun(t *testing.T) { }, }, { - ID: "some-other-session-id", - Name: "session two", - State: "completed", - CreatedAt: sampleDate, + ID: "some-other-session-id", + Name: "session two", + State: "completed", + CreatedAt: sampleDate, + CompletedAt: sampleCompletedAt, + PremiumRequests: 1.5, PullRequest: &api.PullRequest{ Title: "fix something", Number: 101, @@ -587,8 +694,9 @@ func Test_viewRun(t *testing.T) { ) }, wantOut: heredoc.Doc(` - Completed • fix something • OWNER/REPO#101 + Ready for review • fix something • OWNER/REPO#101 Started on behalf of octocat about 6 hours ago + Used 1.5 premium request(s) • Duration 5m0s For detailed session logs, try: gh agent-task view 'some-session-id' --log @@ -620,10 +728,12 @@ func Test_viewRun(t *testing.T) { assert.Equal(t, defaultLimit, limit) return []*capi.Session{ { - ID: "some-session-id", - Name: "session one", - State: "completed", - CreatedAt: sampleDate, + ID: "some-session-id", + Name: "session one", + State: "completed", + CreatedAt: sampleDate, + CompletedAt: sampleCompletedAt, + PremiumRequests: 1.5, PullRequest: &api.PullRequest{ Title: "fix something", Number: 101, @@ -637,10 +747,12 @@ func Test_viewRun(t *testing.T) { }, }, { - ID: "some-other-session-id", - Name: "session two", - State: "completed", - CreatedAt: sampleDate, + ID: "some-other-session-id", + Name: "session two", + State: "completed", + CreatedAt: sampleDate, + CompletedAt: sampleCompletedAt, + PremiumRequests: 1.5, PullRequest: &api.PullRequest{ Title: "fix something", Number: 101, @@ -669,8 +781,9 @@ func Test_viewRun(t *testing.T) { ) }, wantOut: heredoc.Doc(` - Completed • fix something • OWNER/REPO#101 + Ready for review • fix something • OWNER/REPO#101 Started on behalf of octocat about 6 hours ago + Used 1.5 premium request(s) • Duration 5m0s For detailed session logs, try: gh agent-task view 'some-session-id' --log @@ -723,9 +836,11 @@ func Test_viewRun(t *testing.T) { assert.Equal(t, defaultLimit, limit) return []*capi.Session{ { - ID: "some-session-id", - State: "completed", - CreatedAt: sampleDate, + ID: "some-session-id", + State: "completed", + CreatedAt: sampleDate, + CompletedAt: sampleCompletedAt, + PremiumRequests: 1.5, PullRequest: &api.PullRequest{ Title: "fix something", Number: 101, @@ -764,10 +879,12 @@ func Test_viewRun(t *testing.T) { assert.Equal(t, defaultLimit, limit) return []*capi.Session{ { - ID: "some-session-id", - Name: "session one", - State: "completed", - CreatedAt: sampleDate, + ID: "some-session-id", + Name: "session one", + State: "completed", + CreatedAt: sampleDate, + CompletedAt: sampleCompletedAt, + PremiumRequests: 1.5, PullRequest: &api.PullRequest{ Title: "fix something", Number: 101, @@ -779,10 +896,12 @@ func Test_viewRun(t *testing.T) { // User data is irrelevant in this case }, { - ID: "some-other-session-id", - Name: "session two", - State: "completed", - CreatedAt: sampleDate, + ID: "some-other-session-id", + Name: "session two", + State: "completed", + CreatedAt: sampleDate, + CompletedAt: sampleCompletedAt, + PremiumRequests: 1.5, PullRequest: &api.PullRequest{ Title: "fix something", Number: 101, @@ -823,10 +942,12 @@ func Test_viewRun(t *testing.T) { assert.Equal(t, defaultLimit, limit) return []*capi.Session{ { - ID: "some-session-id", - Name: "session one", - State: "completed", - CreatedAt: sampleDate, + ID: "some-session-id", + Name: "session one", + State: "completed", + CreatedAt: sampleDate, + CompletedAt: sampleCompletedAt, + PremiumRequests: 1.5, PullRequest: &api.PullRequest{ Title: "fix something", Number: 101, @@ -838,10 +959,12 @@ func Test_viewRun(t *testing.T) { // User data is irrelevant in this case }, { - ID: "some-other-session-id", - Name: "session two", - State: "completed", - CreatedAt: sampleDate, + ID: "some-other-session-id", + Name: "session two", + State: "completed", + CreatedAt: sampleDate, + CompletedAt: sampleCompletedAt, + PremiumRequests: 1.5, PullRequest: &api.PullRequest{ Title: "fix something", Number: 101, @@ -870,9 +993,11 @@ func Test_viewRun(t *testing.T) { m.GetSessionFunc = func(_ context.Context, id string) (*capi.Session, error) { assert.Equal(t, "some-session-id", id) return &capi.Session{ - ID: "some-session-id", - State: "completed", - CreatedAt: sampleDate, + ID: "some-session-id", + State: "completed", + CreatedAt: sampleDate, + CompletedAt: sampleCompletedAt, + PremiumRequests: 1.5, User: &api.GitHubUser{ Login: "octocat", }, @@ -890,12 +1015,6 @@ func Test_viewRun(t *testing.T) { } }, wantOut: heredoc.Doc(` - Completed - Started on behalf of octocat about 6 hours ago - - To follow session logs, try: - gh agent-task view 'some-session-id' --log --follow - (rendered:) `), }, @@ -913,9 +1032,11 @@ func Test_viewRun(t *testing.T) { m.GetSessionFunc = func(_ context.Context, id string) (*capi.Session, error) { assert.Equal(t, "some-session-id", id) return &capi.Session{ - ID: "some-session-id", - State: "completed", - CreatedAt: sampleDate, + ID: "some-session-id", + State: "completed", + CreatedAt: sampleDate, + CompletedAt: sampleCompletedAt, + PremiumRequests: 1.5, User: &api.GitHubUser{ Login: "octocat", }, @@ -947,9 +1068,6 @@ func Test_viewRun(t *testing.T) { } }, wantOut: heredoc.Doc(` - Completed - Started on behalf of octocat about 6 hours ago - (rendered:) (rendered:) `), diff --git a/pkg/cmd/pr/shared/finder.go b/pkg/cmd/pr/shared/finder.go index 7d66d60f3..1879fff62 100644 --- a/pkg/cmd/pr/shared/finder.go +++ b/pkg/cmd/pr/shared/finder.go @@ -103,6 +103,8 @@ type FindOptions struct { // States lists the possible PR states to scope the PR-for-branch lookup to. States []string + DisableProgress bool + Detector fd.Detector } @@ -196,8 +198,9 @@ func (f *finder) Find(opts FindOptions) (*api.PullRequest, ghrepo.Interface, err return nil, nil, err } + // TODO: Decouple the PR finder from IO // TODO(josebalius): Should we be guarding here? - if f.progress != nil { + if !opts.DisableProgress && f.progress != nil { f.progress.StartProgressIndicator() defer f.progress.StopProgressIndicator() } diff --git a/pkg/cmd/pr/shared/finder_test.go b/pkg/cmd/pr/shared/finder_test.go index 470709480..3f9ba6f50 100644 --- a/pkg/cmd/pr/shared/finder_test.go +++ b/pkg/cmd/pr/shared/finder_test.go @@ -190,9 +190,11 @@ type args struct { baseRepoFn func() (ghrepo.Interface, error) branchFn func() (string, error) gitConfigClient stubGitConfigClient + progress *stubProgressIndicator selector string fields []string baseBranch string + disableProgress bool } func TestFind(t *testing.T) { @@ -228,12 +230,13 @@ func TestFind(t *testing.T) { } tests := []struct { - name string - args args - httpStub func(*httpmock.Registry) - wantPR int - wantRepo string - wantErr bool + name string + args args + httpStub func(*httpmock.Registry) + wantUseProgress bool + wantPR int + wantRepo string + wantErr bool }{ { name: "number argument", @@ -824,6 +827,51 @@ func TestFind(t *testing.T) { wantPR: 13, wantRepo: "https://github.com/OWNER/REPO", }, + { + name: "number argument, with non nil-progress indicator", + args: args{ + selector: "13", + fields: []string{"id", "number"}, + baseRepoFn: stubBaseRepoFn(ghrepo.New("ORIGINOWNER", "REPO"), nil), + branchFn: func() (string, error) { + return "blueberries", nil + }, + progress: &stubProgressIndicator{}, + }, + httpStub: func(r *httpmock.Registry) { + r.Register( + httpmock.GraphQL(`query PullRequestByNumber\b`), + httpmock.StringResponse(`{"data":{"repository":{ + "pullRequest":{"number":13} + }}}`)) + }, + wantPR: 13, + wantRepo: "https://github.com/ORIGINOWNER/REPO", + wantUseProgress: true, + }, + { + name: "number argument, with non-nil progress indicator and DisableProgress set", + args: args{ + selector: "13", + fields: []string{"id", "number"}, + baseRepoFn: stubBaseRepoFn(ghrepo.New("ORIGINOWNER", "REPO"), nil), + branchFn: func() (string, error) { + return "blueberries", nil + }, + progress: &stubProgressIndicator{}, + disableProgress: true, + }, + httpStub: func(r *httpmock.Registry) { + r.Register( + httpmock.GraphQL(`query PullRequestByNumber\b`), + httpmock.StringResponse(`{"data":{"repository":{ + "pullRequest":{"number":13} + }}}`)) + }, + wantPR: 13, + wantRepo: "https://github.com/ORIGINOWNER/REPO", + wantUseProgress: false, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -847,11 +895,25 @@ func TestFind(t *testing.T) { }, nil), } + if tt.args.progress != nil { + f.progress = tt.args.progress + } + pr, repo, err := f.Find(FindOptions{ - Selector: tt.args.selector, - Fields: tt.args.fields, - BaseBranch: tt.args.baseBranch, + Selector: tt.args.selector, + Fields: tt.args.fields, + BaseBranch: tt.args.baseBranch, + DisableProgress: tt.args.disableProgress, }) + + if tt.args.progress != nil { + if tt.args.progress.startCalled != tt.wantUseProgress { + t.Errorf("progress was (not) used as expected") + } else if tt.args.progress.startCalled != tt.args.progress.stopCalled { + t.Errorf("progress was started but not stopped") + } + } + if (err != nil) != tt.wantErr { t.Errorf("Find() error = %v, wantErr %v", err, tt.wantErr) return @@ -947,3 +1009,16 @@ func (s stubGitConfigClient) PushRevision(ctx context.Context, branchName string } return s.pushRevisionFn(ctx, branchName) } + +type stubProgressIndicator struct { + startCalled bool + stopCalled bool +} + +func (s *stubProgressIndicator) StartProgressIndicator() { + s.startCalled = true +} + +func (s *stubProgressIndicator) StopProgressIndicator() { + s.stopCalled = true +}