github.com/google/go-github/v74@v74.0.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 any `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 nil: 207 // Assignee can be null according to GitHub API specification. 208 // See: https://docs.github.com/en/rest/copilot/copilot-user-management?apiVersion=2022-11-28#list-all-copilot-seat-assignments-for-an-organization 209 // Note: Copilot API is in public preview and subject to change. 210 cp.Assignee = nil 211 case map[string]any: 212 jsonData, err := json.Marshal(seatDetail.Assignee) 213 if err != nil { 214 return err 215 } 216 217 if v["type"] == nil { 218 return errors.New("assignee type field is not set") 219 } 220 221 if t, ok := v["type"].(string); ok && t == "User" { 222 user := &User{} 223 if err := json.Unmarshal(jsonData, user); err != nil { 224 return err 225 } 226 cp.Assignee = user 227 } else if t, ok := v["type"].(string); ok && t == "Team" { 228 team := &Team{} 229 if err := json.Unmarshal(jsonData, team); err != nil { 230 return err 231 } 232 cp.Assignee = team 233 } else if t, ok := v["type"].(string); ok && t == "Organization" { 234 organization := &Organization{} 235 if err := json.Unmarshal(jsonData, organization); err != nil { 236 return err 237 } 238 cp.Assignee = organization 239 } else { 240 return fmt.Errorf("unsupported assignee type %v", v["type"]) 241 } 242 default: 243 return fmt.Errorf("unsupported assignee type %T", v) 244 } 245 246 return nil 247 } 248 249 // GetUser gets the User from the CopilotSeatDetails if the assignee is a user. 250 func (cp *CopilotSeatDetails) GetUser() (*User, bool) { u, ok := cp.Assignee.(*User); return u, ok } 251 252 // GetTeam gets the Team from the CopilotSeatDetails if the assignee is a team. 253 func (cp *CopilotSeatDetails) GetTeam() (*Team, bool) { t, ok := cp.Assignee.(*Team); return t, ok } 254 255 // GetOrganization gets the Organization from the CopilotSeatDetails if the assignee is an organization. 256 func (cp *CopilotSeatDetails) GetOrganization() (*Organization, bool) { 257 o, ok := cp.Assignee.(*Organization) 258 return o, ok 259 } 260 261 // GetCopilotBilling gets Copilot for Business billing information and settings for an organization. 262 // 263 // GitHub API docs: https://docs.github.com/rest/copilot/copilot-user-management#get-copilot-seat-information-and-settings-for-an-organization 264 // 265 //meta:operation GET /orgs/{org}/copilot/billing 266 func (s *CopilotService) GetCopilotBilling(ctx context.Context, org string) (*CopilotOrganizationDetails, *Response, error) { 267 u := fmt.Sprintf("orgs/%v/copilot/billing", org) 268 269 req, err := s.client.NewRequest("GET", u, nil) 270 if err != nil { 271 return nil, nil, err 272 } 273 274 var copilotDetails *CopilotOrganizationDetails 275 resp, err := s.client.Do(ctx, req, &copilotDetails) 276 if err != nil { 277 return nil, resp, err 278 } 279 280 return copilotDetails, resp, nil 281 } 282 283 // ListCopilotSeats lists Copilot for Business seat assignments for an organization. 284 // 285 // To paginate through all seats, populate 'Page' with the number of the last page. 286 // 287 // GitHub API docs: https://docs.github.com/rest/copilot/copilot-user-management#list-all-copilot-seat-assignments-for-an-organization 288 // 289 //meta:operation GET /orgs/{org}/copilot/billing/seats 290 func (s *CopilotService) ListCopilotSeats(ctx context.Context, org string, opts *ListOptions) (*ListCopilotSeatsResponse, *Response, error) { 291 u := fmt.Sprintf("orgs/%v/copilot/billing/seats", org) 292 u, err := addOptions(u, opts) 293 if err != nil { 294 return nil, nil, err 295 } 296 297 req, err := s.client.NewRequest("GET", u, nil) 298 if err != nil { 299 return nil, nil, err 300 } 301 302 var copilotSeats *ListCopilotSeatsResponse 303 resp, err := s.client.Do(ctx, req, &copilotSeats) 304 if err != nil { 305 return nil, resp, err 306 } 307 308 return copilotSeats, resp, nil 309 } 310 311 // ListCopilotEnterpriseSeats lists Copilot for Business seat assignments for an enterprise. 312 // 313 // To paginate through all seats, populate 'Page' with the number of the last page. 314 // 315 // GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/copilot/copilot-user-management#list-all-copilot-seat-assignments-for-an-enterprise 316 // 317 //meta:operation GET /enterprises/{enterprise}/copilot/billing/seats 318 func (s *CopilotService) ListCopilotEnterpriseSeats(ctx context.Context, enterprise string, opts *ListOptions) (*ListCopilotSeatsResponse, *Response, error) { 319 u := fmt.Sprintf("enterprises/%v/copilot/billing/seats", enterprise) 320 u, err := addOptions(u, opts) 321 if err != nil { 322 return nil, nil, err 323 } 324 325 req, err := s.client.NewRequest("GET", u, nil) 326 if err != nil { 327 return nil, nil, err 328 } 329 330 var copilotSeats *ListCopilotSeatsResponse 331 resp, err := s.client.Do(ctx, req, &copilotSeats) 332 if err != nil { 333 return nil, resp, err 334 } 335 336 return copilotSeats, resp, nil 337 } 338 339 // AddCopilotTeams adds teams to the Copilot for Business subscription for an organization. 340 // 341 // GitHub API docs: https://docs.github.com/rest/copilot/copilot-user-management#add-teams-to-the-copilot-subscription-for-an-organization 342 // 343 //meta:operation POST /orgs/{org}/copilot/billing/selected_teams 344 func (s *CopilotService) AddCopilotTeams(ctx context.Context, org string, teamNames []string) (*SeatAssignments, *Response, error) { 345 u := fmt.Sprintf("orgs/%v/copilot/billing/selected_teams", org) 346 347 body := struct { 348 SelectedTeams []string `json:"selected_teams"` 349 }{ 350 SelectedTeams: teamNames, 351 } 352 353 req, err := s.client.NewRequest("POST", u, body) 354 if err != nil { 355 return nil, nil, err 356 } 357 358 var seatAssignments *SeatAssignments 359 resp, err := s.client.Do(ctx, req, &seatAssignments) 360 if err != nil { 361 return nil, resp, err 362 } 363 364 return seatAssignments, resp, nil 365 } 366 367 // RemoveCopilotTeams removes teams from the Copilot for Business subscription for an organization. 368 // 369 // GitHub API docs: https://docs.github.com/rest/copilot/copilot-user-management#remove-teams-from-the-copilot-subscription-for-an-organization 370 // 371 //meta:operation DELETE /orgs/{org}/copilot/billing/selected_teams 372 func (s *CopilotService) RemoveCopilotTeams(ctx context.Context, org string, teamNames []string) (*SeatCancellations, *Response, error) { 373 u := fmt.Sprintf("orgs/%v/copilot/billing/selected_teams", org) 374 375 body := struct { 376 SelectedTeams []string `json:"selected_teams"` 377 }{ 378 SelectedTeams: teamNames, 379 } 380 381 req, err := s.client.NewRequest("DELETE", u, body) 382 if err != nil { 383 return nil, nil, err 384 } 385 386 var seatCancellations *SeatCancellations 387 resp, err := s.client.Do(ctx, req, &seatCancellations) 388 if err != nil { 389 return nil, resp, err 390 } 391 392 return seatCancellations, resp, nil 393 } 394 395 // AddCopilotUsers adds users to the Copilot for Business subscription for an organization 396 // 397 // GitHub API docs: https://docs.github.com/rest/copilot/copilot-user-management#add-users-to-the-copilot-subscription-for-an-organization 398 // 399 //meta:operation POST /orgs/{org}/copilot/billing/selected_users 400 func (s *CopilotService) AddCopilotUsers(ctx context.Context, org string, users []string) (*SeatAssignments, *Response, error) { 401 u := fmt.Sprintf("orgs/%v/copilot/billing/selected_users", org) 402 403 body := struct { 404 SelectedUsernames []string `json:"selected_usernames"` 405 }{ 406 SelectedUsernames: users, 407 } 408 409 req, err := s.client.NewRequest("POST", u, body) 410 if err != nil { 411 return nil, nil, err 412 } 413 414 var seatAssignments *SeatAssignments 415 resp, err := s.client.Do(ctx, req, &seatAssignments) 416 if err != nil { 417 return nil, resp, err 418 } 419 420 return seatAssignments, resp, nil 421 } 422 423 // RemoveCopilotUsers removes users from the Copilot for Business subscription for an organization. 424 // 425 // GitHub API docs: https://docs.github.com/rest/copilot/copilot-user-management#remove-users-from-the-copilot-subscription-for-an-organization 426 // 427 //meta:operation DELETE /orgs/{org}/copilot/billing/selected_users 428 func (s *CopilotService) RemoveCopilotUsers(ctx context.Context, org string, users []string) (*SeatCancellations, *Response, error) { 429 u := fmt.Sprintf("orgs/%v/copilot/billing/selected_users", org) 430 431 body := struct { 432 SelectedUsernames []string `json:"selected_usernames"` 433 }{ 434 SelectedUsernames: users, 435 } 436 437 req, err := s.client.NewRequest("DELETE", u, body) 438 if err != nil { 439 return nil, nil, err 440 } 441 442 var seatCancellations *SeatCancellations 443 resp, err := s.client.Do(ctx, req, &seatCancellations) 444 if err != nil { 445 return nil, resp, err 446 } 447 448 return seatCancellations, resp, nil 449 } 450 451 // GetSeatDetails gets Copilot for Business seat assignment details for a user. 452 // 453 // GitHub API docs: https://docs.github.com/rest/copilot/copilot-user-management#get-copilot-seat-assignment-details-for-a-user 454 // 455 //meta:operation GET /orgs/{org}/members/{username}/copilot 456 func (s *CopilotService) GetSeatDetails(ctx context.Context, org, user string) (*CopilotSeatDetails, *Response, error) { 457 u := fmt.Sprintf("orgs/%v/members/%v/copilot", org, user) 458 459 req, err := s.client.NewRequest("GET", u, nil) 460 if err != nil { 461 return nil, nil, err 462 } 463 464 var seatDetails *CopilotSeatDetails 465 resp, err := s.client.Do(ctx, req, &seatDetails) 466 if err != nil { 467 return nil, resp, err 468 } 469 470 return seatDetails, resp, nil 471 } 472 473 // GetEnterpriseMetrics gets Copilot usage metrics for an enterprise. 474 // 475 // GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/copilot/copilot-metrics#get-copilot-metrics-for-an-enterprise 476 // 477 //meta:operation GET /enterprises/{enterprise}/copilot/metrics 478 func (s *CopilotService) GetEnterpriseMetrics(ctx context.Context, enterprise string, opts *CopilotMetricsListOptions) ([]*CopilotMetrics, *Response, error) { 479 u := fmt.Sprintf("enterprises/%v/copilot/metrics", enterprise) 480 u, err := addOptions(u, opts) 481 if err != nil { 482 return nil, nil, err 483 } 484 485 req, err := s.client.NewRequest("GET", u, nil) 486 if err != nil { 487 return nil, nil, err 488 } 489 490 var metrics []*CopilotMetrics 491 resp, err := s.client.Do(ctx, req, &metrics) 492 if err != nil { 493 return nil, resp, err 494 } 495 496 return metrics, resp, nil 497 } 498 499 // GetEnterpriseTeamMetrics gets Copilot usage metrics for an enterprise team. 500 // 501 // GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/copilot/copilot-metrics#get-copilot-metrics-for-an-enterprise-team 502 // 503 //meta:operation GET /enterprises/{enterprise}/team/{team_slug}/copilot/metrics 504 func (s *CopilotService) GetEnterpriseTeamMetrics(ctx context.Context, enterprise, team string, opts *CopilotMetricsListOptions) ([]*CopilotMetrics, *Response, error) { 505 u := fmt.Sprintf("enterprises/%v/team/%v/copilot/metrics", enterprise, team) 506 u, err := addOptions(u, opts) 507 if err != nil { 508 return nil, nil, err 509 } 510 511 req, err := s.client.NewRequest("GET", u, nil) 512 if err != nil { 513 return nil, nil, err 514 } 515 516 var metrics []*CopilotMetrics 517 resp, err := s.client.Do(ctx, req, &metrics) 518 if err != nil { 519 return nil, resp, err 520 } 521 522 return metrics, resp, nil 523 } 524 525 // GetOrganizationMetrics gets Copilot usage metrics for an organization. 526 // 527 // GitHub API docs: https://docs.github.com/rest/copilot/copilot-metrics#get-copilot-metrics-for-an-organization 528 // 529 //meta:operation GET /orgs/{org}/copilot/metrics 530 func (s *CopilotService) GetOrganizationMetrics(ctx context.Context, org string, opts *CopilotMetricsListOptions) ([]*CopilotMetrics, *Response, error) { 531 u := fmt.Sprintf("orgs/%v/copilot/metrics", org) 532 u, err := addOptions(u, opts) 533 if err != nil { 534 return nil, nil, err 535 } 536 537 req, err := s.client.NewRequest("GET", u, nil) 538 if err != nil { 539 return nil, nil, err 540 } 541 542 var metrics []*CopilotMetrics 543 resp, err := s.client.Do(ctx, req, &metrics) 544 if err != nil { 545 return nil, resp, err 546 } 547 548 return metrics, resp, nil 549 } 550 551 // GetOrganizationTeamMetrics gets Copilot usage metrics for an organization team. 552 // 553 // GitHub API docs: https://docs.github.com/rest/copilot/copilot-metrics#get-copilot-metrics-for-a-team 554 // 555 //meta:operation GET /orgs/{org}/team/{team_slug}/copilot/metrics 556 func (s *CopilotService) GetOrganizationTeamMetrics(ctx context.Context, org, team string, opts *CopilotMetricsListOptions) ([]*CopilotMetrics, *Response, error) { 557 u := fmt.Sprintf("orgs/%v/team/%v/copilot/metrics", org, team) 558 u, err := addOptions(u, opts) 559 if err != nil { 560 return nil, nil, err 561 } 562 563 req, err := s.client.NewRequest("GET", u, nil) 564 if err != nil { 565 return nil, nil, err 566 } 567 568 var metrics []*CopilotMetrics 569 resp, err := s.client.Do(ctx, req, &metrics) 570 if err != nil { 571 return nil, resp, err 572 } 573 574 return metrics, resp, nil 575 }