Skip to content

Commit 002ba54

Browse files
authored
Merge pull request cli#11763 from cli/babakks/display-session-error
`gh agent-task view`: display session error if any
2 parents 03f4b77 + eb3c842 commit 002ba54

4 files changed

Lines changed: 661 additions & 304 deletions

File tree

pkg/cmd/agent-task/capi/sessions.go

Lines changed: 94 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -27,22 +27,28 @@ var ErrSessionNotFound = errors.New("not found")
2727

2828
// session is an in-flight agent task
2929
type session struct {
30-
ID string `json:"id"`
31-
Name string `json:"name"`
32-
UserID int64 `json:"user_id"`
33-
AgentID int64 `json:"agent_id"`
34-
Logs string `json:"logs"`
35-
State string `json:"state"`
36-
OwnerID uint64 `json:"owner_id"`
37-
RepoID uint64 `json:"repo_id"`
38-
ResourceType string `json:"resource_type"`
39-
ResourceID int64 `json:"resource_id"`
40-
LastUpdatedAt time.Time `json:"last_updated_at,omitempty"`
41-
CreatedAt time.Time `json:"created_at,omitempty"`
42-
CompletedAt time.Time `json:"completed_at,omitempty"`
43-
EventURL string `json:"event_url"`
44-
EventType string `json:"event_type"`
45-
PremiumRequests float64 `json:"premium_requests"`
30+
ID string `json:"id"`
31+
Name string `json:"name"`
32+
UserID int64 `json:"user_id"`
33+
AgentID int64 `json:"agent_id"`
34+
Logs string `json:"logs"`
35+
State string `json:"state"`
36+
OwnerID uint64 `json:"owner_id"`
37+
RepoID uint64 `json:"repo_id"`
38+
ResourceType string `json:"resource_type"`
39+
ResourceID int64 `json:"resource_id"`
40+
ResourceGlobalID string `json:"resource_global_id"`
41+
LastUpdatedAt time.Time `json:"last_updated_at,omitempty"`
42+
CreatedAt time.Time `json:"created_at,omitempty"`
43+
CompletedAt time.Time `json:"completed_at,omitempty"`
44+
EventURL string `json:"event_url"`
45+
EventType string `json:"event_type"`
46+
PremiumRequests float64 `json:"premium_requests"`
47+
WorkflowRunID uint64 `json:"workflow_run_id,omitempty"`
48+
Error *struct {
49+
Code string `json:"code"`
50+
Message string `json:"message"`
51+
} `json:"error,omitempty"`
4652
}
4753

4854
// A shim of a full pull request because looking up by node ID
@@ -83,11 +89,38 @@ type Session struct {
8389
EventURL string
8490
EventType string
8591
PremiumRequests float64
92+
WorkflowRunID uint64
93+
Error *SessionError
8694

8795
PullRequest *api.PullRequest
8896
User *api.GitHubUser
8997
}
9098

99+
type SessionError struct {
100+
Code string
101+
Message string
102+
}
103+
104+
type resource struct {
105+
ID string `json:"id"`
106+
UserID uint64 `json:"user_id"`
107+
ResourceType string `json:"resource_type"`
108+
ResourceID int64 `json:"resource_id"`
109+
ResourceGlobalID string `json:"resource_global_id"`
110+
SessionCount int `json:"session_count"`
111+
SessionLastUpdatedAt int64 `json:"last_updated_at"`
112+
SessionState string `json:"state,omitempty"`
113+
ResourceState string `json:"resource_state"`
114+
Sessions []resourceSession `json:"sessions"`
115+
}
116+
117+
type resourceSession struct {
118+
SessionID string `json:"id"`
119+
Name string `json:"name"`
120+
SessionState string `json:"state,omitempty"`
121+
SessionLastUpdatedAt int64 `json:"last_updated_at"`
122+
}
123+
91124
// ListLatestSessionsForViewer lists all agent sessions for the
92125
// authenticated user up to limit.
93126
func (c *CAPIClient) ListLatestSessionsForViewer(ctx context.Context, limit int) ([]*Session, error) {
@@ -98,7 +131,6 @@ func (c *CAPIClient) ListLatestSessionsForViewer(ctx context.Context, limit int)
98131
url := baseCAPIURL + "/agents/sessions"
99132
pageSize := defaultSessionsPerPage
100133

101-
sessions := make([]session, 0, limit+pageSize)
102134
seenResources := make(map[int64]struct{})
103135
latestSessions := make([]session, 0, limit)
104136
for page := 1; ; page++ {
@@ -130,7 +162,6 @@ func (c *CAPIClient) ListLatestSessionsForViewer(ctx context.Context, limit int)
130162

131163
// Process only the newly fetched page worth of sessions.
132164
pageSessions := response.Sessions
133-
sessions = append(sessions, pageSessions...)
134165

135166
// De-duplicate sessions by resource ID.
136167
// Because the API returns newest first, once we've seen
@@ -248,46 +279,42 @@ func (c *CAPIClient) ListSessionsByResourceID(ctx context.Context, resourceType
248279
return nil, nil
249280
}
250281

251-
url := fmt.Sprintf("%s/agents/sessions/resource/%s/%d", baseCAPIURL, url.PathEscape(resourceType), resourceID)
252-
pageSize := defaultSessionsPerPage
282+
url := fmt.Sprintf("%s/agents/resource/%s/%d", baseCAPIURL, url.PathEscape(resourceType), resourceID)
253283

254-
sessions := make([]session, 0, limit+pageSize)
284+
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, http.NoBody)
285+
if err != nil {
286+
return nil, err
287+
}
255288

256-
for page := 1; ; page++ {
257-
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, http.NoBody)
258-
if err != nil {
259-
return nil, err
260-
}
289+
res, err := c.httpClient.Do(req)
290+
if err != nil {
291+
return nil, err
292+
}
293+
defer res.Body.Close()
294+
if res.StatusCode != http.StatusOK {
295+
return nil, fmt.Errorf("failed to list sessions: %s", res.Status)
296+
}
261297

262-
q := req.URL.Query()
263-
q.Set("page_size", strconv.Itoa(pageSize))
264-
q.Set("page_number", strconv.Itoa(page))
265-
req.URL.RawQuery = q.Encode()
298+
var response resource
299+
if err := json.NewDecoder(res.Body).Decode(&response); err != nil {
300+
return nil, fmt.Errorf("failed to decode sessions response: %w", err)
301+
}
266302

267-
res, err := c.httpClient.Do(req)
268-
if err != nil {
269-
return nil, err
270-
}
271-
defer res.Body.Close()
272-
if res.StatusCode != http.StatusOK {
273-
return nil, fmt.Errorf("failed to list sessions: %s", res.Status)
274-
}
275-
var response struct {
276-
Sessions []session `json:"sessions"`
277-
}
278-
if err := json.NewDecoder(res.Body).Decode(&response); err != nil {
279-
return nil, fmt.Errorf("failed to decode sessions response: %w", err)
303+
sessions := make([]session, 0, len(response.Sessions))
304+
for _, s := range response.Sessions {
305+
session := session{
306+
ID: s.SessionID,
307+
Name: s.Name,
308+
UserID: int64(response.UserID),
309+
ResourceType: response.ResourceType,
310+
ResourceID: response.ResourceID,
311+
ResourceGlobalID: response.ResourceGlobalID,
312+
State: s.SessionState,
280313
}
281-
282-
sessions = append(sessions, response.Sessions...)
283-
if len(response.Sessions) < pageSize || len(sessions) >= limit {
284-
break
314+
if s.SessionLastUpdatedAt != 0 {
315+
session.LastUpdatedAt = time.Unix(s.SessionLastUpdatedAt, 0).UTC()
285316
}
286-
}
287-
288-
// Drop any above the limit
289-
if len(sessions) > limit {
290-
sessions = sessions[:limit]
317+
sessions = append(sessions, session)
291318
}
292319

293320
result, err := c.hydrateSessionPullRequestsAndUsers(sessions)
@@ -307,7 +334,12 @@ func (c *CAPIClient) hydrateSessionPullRequestsAndUsers(sessions []session) ([]*
307334
userNodeIds := make([]string, 0, len(sessions))
308335
for _, session := range sessions {
309336
if session.ResourceType == "pull" {
310-
prNodeID := generatePullRequestNodeID(int64(session.RepoID), session.ResourceID)
337+
prNodeID := session.ResourceGlobalID
338+
// TODO: probably this can be dropped since the API should always
339+
// keep returning the resource global ID.
340+
if session.ResourceGlobalID == "" {
341+
prNodeID = generatePullRequestNodeID(int64(session.RepoID), session.ResourceID)
342+
}
311343
if !slices.Contains(prNodeIds, prNodeID) {
312344
prNodeIds = append(prNodeIds, prNodeID)
313345
}
@@ -442,7 +474,7 @@ func generateUserNodeID(userID int64) string {
442474
}
443475

444476
func fromAPISession(s session) *Session {
445-
return &Session{
477+
result := Session{
446478
ID: s.ID,
447479
Name: s.Name,
448480
UserID: s.UserID,
@@ -459,5 +491,13 @@ func fromAPISession(s session) *Session {
459491
EventURL: s.EventURL,
460492
EventType: s.EventType,
461493
PremiumRequests: s.PremiumRequests,
494+
WorkflowRunID: s.WorkflowRunID,
495+
}
496+
if s.Error != nil {
497+
result.Error = &SessionError{
498+
Code: s.Error.Code,
499+
Message: s.Error.Message,
500+
}
462501
}
502+
return &result
463503
}

0 commit comments

Comments
 (0)