github.com/google/go-github/v69@v69.2.0/github/copilot.go (about) 1 // Copyright 2023 The go-github AUTHORS. All rights reserved. 2 // 3 // Use of this source code is governed by a BSD-style 4 // license that can be found in the LICENSE file. 5 6 package github 7 8 import ( 9 "context" 10 "encoding/json" 11 "errors" 12 "fmt" 13 "time" 14 ) 15 16 // CopilotService provides access to the Copilot-related functions 17 // in the GitHub API. 18 // 19 // GitHub API docs: https://docs.github.com/en/rest/copilot/ 20 type CopilotService service 21 22 // CopilotOrganizationDetails represents the details of an organization's Copilot for Business subscription. 23 type CopilotOrganizationDetails struct { 24 SeatBreakdown *CopilotSeatBreakdown `json:"seat_breakdown"` 25 PublicCodeSuggestions string `json:"public_code_suggestions"` 26 CopilotChat string `json:"copilot_chat"` 27 SeatManagementSetting string `json:"seat_management_setting"` 28 } 29 30 // CopilotSeatBreakdown represents the breakdown of Copilot for Business seats for the organization. 31 type CopilotSeatBreakdown struct { 32 Total int `json:"total"` 33 AddedThisCycle int `json:"added_this_cycle"` 34 PendingCancellation int `json:"pending_cancellation"` 35 PendingInvitation int `json:"pending_invitation"` 36 ActiveThisCycle int `json:"active_this_cycle"` 37 InactiveThisCycle int `json:"inactive_this_cycle"` 38 } 39 40 // ListCopilotSeatsResponse represents the Copilot for Business seat assignments for an organization. 41 type ListCopilotSeatsResponse struct { 42 TotalSeats int64 `json:"total_seats"` 43 Seats []*CopilotSeatDetails `json:"seats"` 44 } 45 46 // CopilotSeatDetails represents the details of a Copilot for Business seat. 47 type CopilotSeatDetails struct { 48 // Assignee can either be a User, Team, or Organization. 49 Assignee interface{} `json:"assignee"` 50 AssigningTeam *Team `json:"assigning_team,omitempty"` 51 PendingCancellationDate *string `json:"pending_cancellation_date,omitempty"` 52 LastActivityAt *Timestamp `json:"last_activity_at,omitempty"` 53 LastActivityEditor *string `json:"last_activity_editor,omitempty"` 54 CreatedAt *Timestamp `json:"created_at"` 55 UpdatedAt *Timestamp `json:"updated_at,omitempty"` 56 PlanType *string `json:"plan_type,omitempty"` 57 } 58 59 // SeatAssignments represents the number of seats assigned. 60 type SeatAssignments struct { 61 SeatsCreated int `json:"seats_created"` 62 } 63 64 // SeatCancellations represents the number of seats cancelled. 65 type SeatCancellations struct { 66 SeatsCancelled int `json:"seats_cancelled"` 67 } 68 69 // CopilotMetricsListOptions represents the optional parameters to the CopilotService get metrics methods. 70 type CopilotMetricsListOptions struct { 71 Since *time.Time `url:"since,omitempty"` 72 Until *time.Time `url:"until,omitempty"` 73 74 ListOptions 75 } 76 77 // CopilotIDECodeCompletionsLanguage represents Copilot usage metrics for completions in the IDE for a language. 78 type CopilotIDECodeCompletionsLanguage struct { 79 Name string `json:"name"` 80 TotalEngagedUsers int `json:"total_engaged_users"` 81 } 82 83 // CopilotIDECodeCompletionsModelLanguage represents Copilot usage metrics for completions in the IDE for a model and language. 84 type CopilotIDECodeCompletionsModelLanguage struct { 85 Name string `json:"name"` 86 TotalEngagedUsers int `json:"total_engaged_users"` 87 TotalCodeSuggestions int `json:"total_code_suggestions"` 88 TotalCodeAcceptances int `json:"total_code_acceptances"` 89 TotalCodeLinesSuggested int `json:"total_code_lines_suggested"` 90 TotalCodeLinesAccepted int `json:"total_code_lines_accepted"` 91 } 92 93 // CopilotIDECodeCompletionsModel represents Copilot usage metrics for completions in the IDE for a model. 94 type CopilotIDECodeCompletionsModel struct { 95 Name string `json:"name"` 96 IsCustomModel bool `json:"is_custom_model"` 97 CustomModelTrainingDate *string `json:"custom_model_training_date,omitempty"` 98 TotalEngagedUsers int `json:"total_engaged_users"` 99 Languages []*CopilotIDECodeCompletionsModelLanguage `json:"languages"` 100 } 101 102 // CopilotIDECodeCompletionsEditor represents Copilot usage metrics for completions in the IDE for an editor. 103 type CopilotIDECodeCompletionsEditor struct { 104 Name string `json:"name"` 105 TotalEngagedUsers int `json:"total_engaged_users"` 106 Models []*CopilotIDECodeCompletionsModel `json:"models"` 107 } 108 109 // CopilotIDECodeCompletions represents Copilot usage metrics for Copilot code completions in the IDE, categorized by editor, model and language. 110 type CopilotIDECodeCompletions struct { 111 TotalEngagedUsers int `json:"total_engaged_users"` 112 Languages []*CopilotIDECodeCompletionsLanguage `json:"languages"` 113 Editors []*CopilotIDECodeCompletionsEditor `json:"editors"` 114 } 115 116 // CopilotIDEChatModel represents Copilot usage metrics for chatting with a model in the IDE. 117 type CopilotIDEChatModel struct { 118 Name string `json:"name"` 119 IsCustomModel bool `json:"is_custom_model"` 120 CustomModelTrainingDate *string `json:"custom_model_training_date,omitempty"` 121 TotalEngagedUsers int `json:"total_engaged_users"` 122 TotalChats int `json:"total_chats"` 123 TotalChatInsertionEvents int `json:"total_chat_insertion_events"` 124 TotalChatCopyEvents int `json:"total_chat_copy_events"` 125 } 126 127 // CopilotIDEChatEditor represents Copilot usage metrics for chatting with a model in the IDE, categorized by editor and model. 128 type CopilotIDEChatEditor struct { 129 Name string `json:"name"` 130 TotalEngagedUsers int `json:"total_engaged_users"` 131 Models []*CopilotIDEChatModel `json:"models"` 132 } 133 134 // CopilotIDEChat represents Copilot usage metrics for Copilot Chat in the IDE, categorized by editor and model. 135 type CopilotIDEChat struct { 136 TotalEngagedUsers int `json:"total_engaged_users"` 137 Editors []*CopilotIDEChatEditor `json:"editors"` 138 } 139 140 // CopilotDotcomChatModel represents Copilot usage metrics for chatting with a model in the webbrowser. 141 type CopilotDotcomChatModel struct { 142 Name string `json:"name"` 143 IsCustomModel bool `json:"is_custom_model"` 144 CustomModelTrainingDate *string `json:"custom_model_training_date,omitempty"` 145 TotalEngagedUsers int `json:"total_engaged_users"` 146 TotalChats int `json:"total_chats"` 147 } 148 149 // CopilotDotcomChat represents Copilot usage metrics for Copilot Chat in the webbrowser, categorized by model. 150 type CopilotDotcomChat struct { 151 TotalEngagedUsers int `json:"total_engaged_users"` 152 Models []*CopilotDotcomChatModel `json:"models"` 153 } 154 155 // CopilotDotcomPullRequestsModel represents Copilot usage metrics for pull requests in the webbrowser, categorized by model. 156 type CopilotDotcomPullRequestsModel struct { 157 Name string `json:"name"` 158 IsCustomModel bool `json:"is_custom_model"` 159 CustomModelTrainingDate *string `json:"custom_model_training_date,omitempty"` 160 TotalPRSummariesCreated int `json:"total_pr_summaries_created"` 161 TotalEngagedUsers int `json:"total_engaged_users"` 162 } 163 164 // CopilotDotcomPullRequestsRepository represents Copilot usage metrics for pull requests in the webbrowser, categorized by repository. 165 type CopilotDotcomPullRequestsRepository struct { 166 Name string `json:"name"` 167 TotalEngagedUsers int `json:"total_engaged_users"` 168 Models []*CopilotDotcomPullRequestsModel `json:"models"` 169 } 170 171 // CopilotDotcomPullRequests represents Copilot usage metrics for pull requests in the webbrowser, categorized by repository and model. 172 type CopilotDotcomPullRequests struct { 173 TotalEngagedUsers int `json:"total_engaged_users"` 174 Repositories []*CopilotDotcomPullRequestsRepository `json:"repositories"` 175 } 176 177 // CopilotMetrics represents Copilot usage metrics for a given day. 178 type CopilotMetrics struct { 179 Date string `json:"date"` 180 TotalActiveUsers *int `json:"total_active_users,omitempty"` 181 TotalEngagedUsers *int `json:"total_engaged_users,omitempty"` 182 CopilotIDECodeCompletions *CopilotIDECodeCompletions `json:"copilot_ide_code_completions,omitempty"` 183 CopilotIDEChat *CopilotIDEChat `json:"copilot_ide_chat,omitempty"` 184 CopilotDotcomChat *CopilotDotcomChat `json:"copilot_dotcom_chat,omitempty"` 185 CopilotDotcomPullRequests *CopilotDotcomPullRequests `json:"copilot_dotcom_pull_requests,omitempty"` 186 } 187 188 func (cp *CopilotSeatDetails) UnmarshalJSON(data []byte) error { 189 // Using an alias to avoid infinite recursion when calling json.Unmarshal 190 type alias CopilotSeatDetails 191 var seatDetail alias 192 193 if err := json.Unmarshal(data, &seatDetail); err != nil { 194 return err 195 } 196 197 cp.AssigningTeam = seatDetail.AssigningTeam 198 cp.PendingCancellationDate = seatDetail.PendingCancellationDate 199 cp.LastActivityAt = seatDetail.LastActivityAt 200 cp.LastActivityEditor = seatDetail.LastActivityEditor 201 cp.CreatedAt = seatDetail.CreatedAt 202 cp.UpdatedAt = seatDetail.UpdatedAt 203 cp.PlanType = seatDetail.PlanType 204 205 switch v := seatDetail.Assignee.(type) { 206 case map[string]interface{}: 207 jsonData, err := json.Marshal(seatDetail.Assignee) 208 if err != nil { 209 return err 210 } 211 212 if v["type"] == nil { 213 return errors.New("assignee type field is not set") 214 } 215 216 if t, ok := v["type"].(string); ok && t == "User" { 217 user := &User{} 218 if err := json.Unmarshal(jsonData, user); err != nil { 219 return err 220 } 221 cp.Assignee = user 222 } else if t, ok := v["type"].(string); ok && t == "Team" { 223 team := &Team{} 224 if err := json.Unmarshal(jsonData, team); err != nil { 225 return err 226 } 227 cp.Assignee = team 228 } else if t, ok := v["type"].(string); ok && t == "Organization" { 229 organization := &Organization{} 230 if err := json.Unmarshal(jsonData, organization); err != nil { 231 return err 232 } 233 cp.Assignee = organization 234 } else { 235 return fmt.Errorf("unsupported assignee type %v", v["type"]) 236 } 237 default: 238 return fmt.Errorf("unsupported assignee type %T", v) 239 } 240 241 return nil 242 } 243 244 // GetUser gets the User from the CopilotSeatDetails if the assignee is a user. 245 func (cp *CopilotSeatDetails) GetUser() (*User, bool) { u, ok := cp.Assignee.(*User); return u, ok } 246 247 // GetTeam gets the Team from the CopilotSeatDetails if the assignee is a team. 248 func (cp *CopilotSeatDetails) GetTeam() (*Team, bool) { t, ok := cp.Assignee.(*Team); return t, ok } 249 250 // GetOrganization gets the Organization from the CopilotSeatDetails if the assignee is an organization. 251 func (cp *CopilotSeatDetails) GetOrganization() (*Organization, bool) { 252 o, ok := cp.Assignee.(*Organization) 253 return o, ok 254 } 255 256 // GetCopilotBilling gets Copilot for Business billing information and settings for an organization. 257 // 258 // GitHub API docs: https://docs.github.com/rest/copilot/copilot-user-management#get-copilot-seat-information-and-settings-for-an-organization 259 // 260 //meta:operation GET /orgs/{org}/copilot/billing 261 func (s *CopilotService) GetCopilotBilling(ctx context.Context, org string) (*CopilotOrganizationDetails, *Response, error) { 262 u := fmt.Sprintf("orgs/%v/copilot/billing", org) 263 264 req, err := s.client.NewRequest("GET", u, nil) 265 if err != nil { 266 return nil, nil, err 267 } 268 269 var copilotDetails *CopilotOrganizationDetails 270 resp, err := s.client.Do(ctx, req, &copilotDetails) 271 if err != nil { 272 return nil, resp, err 273 } 274 275 return copilotDetails, resp, nil 276 } 277 278 // ListCopilotSeats lists Copilot for Business seat assignments for an organization. 279 // 280 // To paginate through all seats, populate 'Page' with the number of the last page. 281 // 282 // GitHub API docs: https://docs.github.com/rest/copilot/copilot-user-management#list-all-copilot-seat-assignments-for-an-organization 283 // 284 //meta:operation GET /orgs/{org}/copilot/billing/seats 285 func (s *CopilotService) ListCopilotSeats(ctx context.Context, org string, opts *ListOptions) (*ListCopilotSeatsResponse, *Response, error) { 286 u := fmt.Sprintf("orgs/%v/copilot/billing/seats", org) 287 u, err := addOptions(u, opts) 288 if err != nil { 289 return nil, nil, err 290 } 291 292 req, err := s.client.NewRequest("GET", u, nil) 293 if err != nil { 294 return nil, nil, err 295 } 296 297 var copilotSeats *ListCopilotSeatsResponse 298 resp, err := s.client.Do(ctx, req, &copilotSeats) 299 if err != nil { 300 return nil, resp, err 301 } 302 303 return copilotSeats, resp, nil 304 } 305 306 // ListCopilotEnterpriseSeats lists Copilot for Business seat assignments for an enterprise. 307 // 308 // To paginate through all seats, populate 'Page' with the number of the last page. 309 // 310 // GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/copilot/copilot-user-management#list-all-copilot-seat-assignments-for-an-enterprise 311 // 312 //meta:operation GET /enterprises/{enterprise}/copilot/billing/seats 313 func (s *CopilotService) ListCopilotEnterpriseSeats(ctx context.Context, enterprise string, opts *ListOptions) (*ListCopilotSeatsResponse, *Response, error) { 314 u := fmt.Sprintf("enterprises/%v/copilot/billing/seats", enterprise) 315 u, err := addOptions(u, opts) 316 if err != nil { 317 return nil, nil, err 318 } 319 320 req, err := s.client.NewRequest("GET", u, nil) 321 if err != nil { 322 return nil, nil, err 323 } 324 325 var copilotSeats *ListCopilotSeatsResponse 326 resp, err := s.client.Do(ctx, req, &copilotSeats) 327 if err != nil { 328 return nil, resp, err 329 } 330 331 return copilotSeats, resp, nil 332 } 333 334 // AddCopilotTeams adds teams to the Copilot for Business subscription for an organization. 335 // 336 // GitHub API docs: https://docs.github.com/rest/copilot/copilot-user-management#add-teams-to-the-copilot-subscription-for-an-organization 337 // 338 //meta:operation POST /orgs/{org}/copilot/billing/selected_teams 339 func (s *CopilotService) AddCopilotTeams(ctx context.Context, org string, teamNames []string) (*SeatAssignments, *Response, error) { 340 u := fmt.Sprintf("orgs/%v/copilot/billing/selected_teams", org) 341 342 body := struct { 343 SelectedTeams []string `json:"selected_teams"` 344 }{ 345 SelectedTeams: teamNames, 346 } 347 348 req, err := s.client.NewRequest("POST", u, body) 349 if err != nil { 350 return nil, nil, err 351 } 352 353 var seatAssignments *SeatAssignments 354 resp, err := s.client.Do(ctx, req, &seatAssignments) 355 if err != nil { 356 return nil, resp, err 357 } 358 359 return seatAssignments, resp, nil 360 } 361 362 // RemoveCopilotTeams removes teams from the Copilot for Business subscription for an organization. 363 // 364 // GitHub API docs: https://docs.github.com/rest/copilot/copilot-user-management#remove-teams-from-the-copilot-subscription-for-an-organization 365 // 366 //meta:operation DELETE /orgs/{org}/copilot/billing/selected_teams 367 func (s *CopilotService) RemoveCopilotTeams(ctx context.Context, org string, teamNames []string) (*SeatCancellations, *Response, error) { 368 u := fmt.Sprintf("orgs/%v/copilot/billing/selected_teams", org) 369 370 body := struct { 371 SelectedTeams []string `json:"selected_teams"` 372 }{ 373 SelectedTeams: teamNames, 374 } 375 376 req, err := s.client.NewRequest("DELETE", u, body) 377 if err != nil { 378 return nil, nil, err 379 } 380 381 var seatCancellations *SeatCancellations 382 resp, err := s.client.Do(ctx, req, &seatCancellations) 383 if err != nil { 384 return nil, resp, err 385 } 386 387 return seatCancellations, resp, nil 388 } 389 390 // AddCopilotUsers adds users to the Copilot for Business subscription for an organization 391 // 392 // GitHub API docs: https://docs.github.com/rest/copilot/copilot-user-management#add-users-to-the-copilot-subscription-for-an-organization 393 // 394 //meta:operation POST /orgs/{org}/copilot/billing/selected_users 395 func (s *CopilotService) AddCopilotUsers(ctx context.Context, org string, users []string) (*SeatAssignments, *Response, error) { 396 u := fmt.Sprintf("orgs/%v/copilot/billing/selected_users", org) 397 398 body := struct { 399 SelectedUsernames []string `json:"selected_usernames"` 400 }{ 401 SelectedUsernames: users, 402 } 403 404 req, err := s.client.NewRequest("POST", u, body) 405 if err != nil { 406 return nil, nil, err 407 } 408 409 var seatAssignments *SeatAssignments 410 resp, err := s.client.Do(ctx, req, &seatAssignments) 411 if err != nil { 412 return nil, resp, err 413 } 414 415 return seatAssignments, resp, nil 416 } 417 418 // RemoveCopilotUsers removes users from the Copilot for Business subscription for an organization. 419 // 420 // GitHub API docs: https://docs.github.com/rest/copilot/copilot-user-management#remove-users-from-the-copilot-subscription-for-an-organization 421 // 422 //meta:operation DELETE /orgs/{org}/copilot/billing/selected_users 423 func (s *CopilotService) RemoveCopilotUsers(ctx context.Context, org string, users []string) (*SeatCancellations, *Response, error) { 424 u := fmt.Sprintf("orgs/%v/copilot/billing/selected_users", org) 425 426 body := struct { 427 SelectedUsernames []string `json:"selected_usernames"` 428 }{ 429 SelectedUsernames: users, 430 } 431 432 req, err := s.client.NewRequest("DELETE", u, body) 433 if err != nil { 434 return nil, nil, err 435 } 436 437 var seatCancellations *SeatCancellations 438 resp, err := s.client.Do(ctx, req, &seatCancellations) 439 if err != nil { 440 return nil, resp, err 441 } 442 443 return seatCancellations, resp, nil 444 } 445 446 // GetSeatDetails gets Copilot for Business seat assignment details for a user. 447 // 448 // GitHub API docs: https://docs.github.com/rest/copilot/copilot-user-management#get-copilot-seat-assignment-details-for-a-user 449 // 450 //meta:operation GET /orgs/{org}/members/{username}/copilot 451 func (s *CopilotService) GetSeatDetails(ctx context.Context, org, user string) (*CopilotSeatDetails, *Response, error) { 452 u := fmt.Sprintf("orgs/%v/members/%v/copilot", org, user) 453 454 req, err := s.client.NewRequest("GET", u, nil) 455 if err != nil { 456 return nil, nil, err 457 } 458 459 var seatDetails *CopilotSeatDetails 460 resp, err := s.client.Do(ctx, req, &seatDetails) 461 if err != nil { 462 return nil, resp, err 463 } 464 465 return seatDetails, resp, nil 466 } 467 468 // GetEnterpriseMetrics gets Copilot usage metrics for an enterprise. 469 // 470 // GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/copilot/copilot-metrics#get-copilot-metrics-for-an-enterprise 471 // 472 //meta:operation GET /enterprises/{enterprise}/copilot/metrics 473 func (s *CopilotService) GetEnterpriseMetrics(ctx context.Context, enterprise string, opts *CopilotMetricsListOptions) ([]*CopilotMetrics, *Response, error) { 474 u := fmt.Sprintf("enterprises/%v/copilot/metrics", enterprise) 475 u, err := addOptions(u, opts) 476 if err != nil { 477 return nil, nil, err 478 } 479 480 req, err := s.client.NewRequest("GET", u, nil) 481 if err != nil { 482 return nil, nil, err 483 } 484 485 var metrics []*CopilotMetrics 486 resp, err := s.client.Do(ctx, req, &metrics) 487 if err != nil { 488 return nil, resp, err 489 } 490 491 return metrics, resp, nil 492 } 493 494 // GetEnterpriseTeamMetrics gets Copilot usage metrics for an enterprise team. 495 // 496 // GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/copilot/copilot-metrics#get-copilot-metrics-for-an-enterprise-team 497 // 498 //meta:operation GET /enterprises/{enterprise}/team/{team_slug}/copilot/metrics 499 func (s *CopilotService) GetEnterpriseTeamMetrics(ctx context.Context, enterprise, team string, opts *CopilotMetricsListOptions) ([]*CopilotMetrics, *Response, error) { 500 u := fmt.Sprintf("enterprises/%v/team/%v/copilot/metrics", enterprise, team) 501 u, err := addOptions(u, opts) 502 if err != nil { 503 return nil, nil, err 504 } 505 506 req, err := s.client.NewRequest("GET", u, nil) 507 if err != nil { 508 return nil, nil, err 509 } 510 511 var metrics []*CopilotMetrics 512 resp, err := s.client.Do(ctx, req, &metrics) 513 if err != nil { 514 return nil, resp, err 515 } 516 517 return metrics, resp, nil 518 } 519 520 // GetOrganizationMetrics gets Copilot usage metrics for an organization. 521 // 522 // GitHub API docs: https://docs.github.com/rest/copilot/copilot-metrics#get-copilot-metrics-for-an-organization 523 // 524 //meta:operation GET /orgs/{org}/copilot/metrics 525 func (s *CopilotService) GetOrganizationMetrics(ctx context.Context, org string, opts *CopilotMetricsListOptions) ([]*CopilotMetrics, *Response, error) { 526 u := fmt.Sprintf("orgs/%v/copilot/metrics", org) 527 u, err := addOptions(u, opts) 528 if err != nil { 529 return nil, nil, err 530 } 531 532 req, err := s.client.NewRequest("GET", u, nil) 533 if err != nil { 534 return nil, nil, err 535 } 536 537 var metrics []*CopilotMetrics 538 resp, err := s.client.Do(ctx, req, &metrics) 539 if err != nil { 540 return nil, resp, err 541 } 542 543 return metrics, resp, nil 544 } 545 546 // GetOrganizationTeamMetrics gets Copilot usage metrics for an organization team. 547 // 548 // GitHub API docs: https://docs.github.com/rest/copilot/copilot-metrics#get-copilot-metrics-for-a-team 549 // 550 //meta:operation GET /orgs/{org}/team/{team_slug}/copilot/metrics 551 func (s *CopilotService) GetOrganizationTeamMetrics(ctx context.Context, org, team string, opts *CopilotMetricsListOptions) ([]*CopilotMetrics, *Response, error) { 552 u := fmt.Sprintf("orgs/%v/team/%v/copilot/metrics", org, team) 553 u, err := addOptions(u, opts) 554 if err != nil { 555 return nil, nil, err 556 } 557 558 req, err := s.client.NewRequest("GET", u, nil) 559 if err != nil { 560 return nil, nil, err 561 } 562 563 var metrics []*CopilotMetrics 564 resp, err := s.client.Do(ctx, req, &metrics) 565 if err != nil { 566 return nil, resp, err 567 } 568 569 return metrics, resp, nil 570 }