github.com/google/go-github/v68@v68.0.0/github/copilot_test.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 "fmt" 12 "log" 13 "net/http" 14 "testing" 15 "time" 16 17 "github.com/google/go-cmp/cmp" 18 ) 19 20 // Test invalid JSON responses, valid responses are covered in the other tests. 21 func TestCopilotSeatDetails_UnmarshalJSON(t *testing.T) { 22 t.Parallel() 23 tests := []struct { 24 name string 25 data string 26 want *CopilotSeatDetails 27 wantErr bool 28 }{ 29 { 30 name: "Invalid JSON", 31 data: `{`, 32 want: &CopilotSeatDetails{ 33 Assignee: nil, 34 }, 35 wantErr: true, 36 }, 37 { 38 name: "Invalid top level type", 39 data: `{ 40 "assignee": { 41 "type": "User", 42 "name": "octokittens", 43 "id": 1 44 }, 45 "assigning_team": "this should be an object" 46 }`, 47 want: &CopilotSeatDetails{}, 48 wantErr: true, 49 }, 50 { 51 name: "No Type Field", 52 data: `{ 53 "assignee": { 54 "name": "octokittens", 55 "id": 1 56 } 57 }`, 58 want: &CopilotSeatDetails{}, 59 wantErr: true, 60 }, 61 { 62 name: "Invalid Assignee Field Type", 63 data: `{ 64 "assignee": "test" 65 }`, 66 want: &CopilotSeatDetails{}, 67 wantErr: true, 68 }, 69 { 70 name: "Invalid Assignee Type", 71 data: `{ 72 "assignee": { 73 "name": "octokittens", 74 "id": 1, 75 "type": [] 76 } 77 }`, 78 want: &CopilotSeatDetails{}, 79 wantErr: true, 80 }, 81 { 82 name: "Invalid User", 83 data: `{ 84 "assignee": { 85 "type": "User", 86 "id": "bad" 87 } 88 }`, 89 want: &CopilotSeatDetails{}, 90 wantErr: true, 91 }, 92 { 93 name: "Invalid Team", 94 data: `{ 95 "assignee": { 96 "type": "Team", 97 "id": "bad" 98 } 99 }`, 100 want: &CopilotSeatDetails{}, 101 wantErr: true, 102 }, 103 { 104 name: "Invalid Organization", 105 data: `{ 106 "assignee": { 107 "type": "Organization", 108 "id": "bad" 109 } 110 }`, 111 want: &CopilotSeatDetails{}, 112 wantErr: true, 113 }, 114 } 115 116 for _, tc := range tests { 117 tc := tc 118 seatDetails := &CopilotSeatDetails{} 119 120 t.Run(tc.name, func(t *testing.T) { 121 t.Parallel() 122 err := json.Unmarshal([]byte(tc.data), seatDetails) 123 if err == nil && tc.wantErr { 124 t.Errorf("CopilotSeatDetails.UnmarshalJSON returned nil instead of an error") 125 } 126 if err != nil && !tc.wantErr { 127 t.Errorf("CopilotSeatDetails.UnmarshalJSON returned an unexpected error: %v", err) 128 } 129 if !cmp.Equal(tc.want, seatDetails) { 130 t.Errorf("CopilotSeatDetails.UnmarshalJSON expected %+v, got %+v", tc.want, seatDetails) 131 } 132 }) 133 } 134 } 135 136 func TestCopilotService_GetSeatDetailsUser(t *testing.T) { 137 t.Parallel() 138 data := `{ 139 "assignee": { 140 "type": "User", 141 "id": 1 142 } 143 }` 144 145 seatDetails := &CopilotSeatDetails{} 146 147 err := json.Unmarshal([]byte(data), seatDetails) 148 if err != nil { 149 t.Errorf("CopilotSeatDetails.UnmarshalJSON returned an unexpected error: %v", err) 150 } 151 152 want := &User{ 153 ID: Ptr(int64(1)), 154 Type: Ptr("User"), 155 } 156 157 if got, ok := seatDetails.GetUser(); ok && !cmp.Equal(got, want) { 158 t.Errorf("CopilotSeatDetails.GetTeam returned %+v, want %+v", got, want) 159 } else if !ok { 160 t.Errorf("CopilotSeatDetails.GetUser returned false, expected true") 161 } 162 163 data = `{ 164 "assignee": { 165 "type": "Organization", 166 "id": 1 167 } 168 }` 169 170 bad := &Organization{ 171 ID: Ptr(int64(1)), 172 Type: Ptr("Organization"), 173 } 174 175 err = json.Unmarshal([]byte(data), seatDetails) 176 if err != nil { 177 t.Errorf("CopilotSeatDetails.UnmarshalJSON returned an unexpected error: %v", err) 178 } 179 180 if got, ok := seatDetails.GetUser(); ok { 181 t.Errorf("CopilotSeatDetails.GetUser returned true, expected false. Returned %v, expected %v", got, bad) 182 } 183 } 184 185 func TestCopilotService_GetSeatDetailsTeam(t *testing.T) { 186 t.Parallel() 187 data := `{ 188 "assignee": { 189 "type": "Team", 190 "id": 1 191 } 192 }` 193 194 seatDetails := &CopilotSeatDetails{} 195 196 err := json.Unmarshal([]byte(data), seatDetails) 197 if err != nil { 198 t.Errorf("CopilotSeatDetails.UnmarshalJSON returned an unexpected error: %v", err) 199 } 200 201 want := &Team{ 202 ID: Ptr(int64(1)), 203 } 204 205 if got, ok := seatDetails.GetTeam(); ok && !cmp.Equal(got, want) { 206 t.Errorf("CopilotSeatDetails.GetTeam returned %+v, want %+v", got, want) 207 } else if !ok { 208 t.Errorf("CopilotSeatDetails.GetTeam returned false, expected true") 209 } 210 211 data = `{ 212 "assignee": { 213 "type": "User", 214 "id": 1 215 } 216 }` 217 218 bad := &User{ 219 ID: Ptr(int64(1)), 220 Type: Ptr("User"), 221 } 222 223 err = json.Unmarshal([]byte(data), seatDetails) 224 if err != nil { 225 t.Errorf("CopilotSeatDetails.UnmarshalJSON returned an unexpected error: %v", err) 226 } 227 228 if got, ok := seatDetails.GetTeam(); ok { 229 t.Errorf("CopilotSeatDetails.GetTeam returned true, expected false. Returned %v, expected %v", got, bad) 230 } 231 } 232 233 func TestCopilotService_GetSeatDetailsOrganization(t *testing.T) { 234 t.Parallel() 235 data := `{ 236 "assignee": { 237 "type": "Organization", 238 "id": 1 239 } 240 }` 241 242 seatDetails := &CopilotSeatDetails{} 243 244 err := json.Unmarshal([]byte(data), seatDetails) 245 if err != nil { 246 t.Errorf("CopilotSeatDetails.UnmarshalJSON returned an unexpected error: %v", err) 247 } 248 249 want := &Organization{ 250 ID: Ptr(int64(1)), 251 Type: Ptr("Organization"), 252 } 253 254 if got, ok := seatDetails.GetOrganization(); ok && !cmp.Equal(got, want) { 255 t.Errorf("CopilotSeatDetails.GetOrganization returned %+v, want %+v", got, want) 256 } else if !ok { 257 t.Errorf("CopilotSeatDetails.GetOrganization returned false, expected true") 258 } 259 260 data = `{ 261 "assignee": { 262 "type": "Team", 263 "id": 1 264 } 265 }` 266 267 bad := &Team{ 268 ID: Ptr(int64(1)), 269 } 270 271 err = json.Unmarshal([]byte(data), seatDetails) 272 if err != nil { 273 t.Errorf("CopilotSeatDetails.UnmarshalJSON returned an unexpected error: %v", err) 274 } 275 276 if got, ok := seatDetails.GetOrganization(); ok { 277 t.Errorf("CopilotSeatDetails.GetOrganization returned true, expected false. Returned %v, expected %v", got, bad) 278 } 279 } 280 281 func TestCopilotService_GetCopilotBilling(t *testing.T) { 282 t.Parallel() 283 client, mux, _ := setup(t) 284 285 mux.HandleFunc("/orgs/o/copilot/billing", func(w http.ResponseWriter, r *http.Request) { 286 testMethod(t, r, "GET") 287 fmt.Fprint(w, `{ 288 "seat_breakdown": { 289 "total": 12, 290 "added_this_cycle": 9, 291 "pending_invitation": 0, 292 "pending_cancellation": 0, 293 "active_this_cycle": 12, 294 "inactive_this_cycle": 11 295 }, 296 "seat_management_setting": "assign_selected", 297 "public_code_suggestions": "block" 298 }`) 299 }) 300 301 ctx := context.Background() 302 got, _, err := client.Copilot.GetCopilotBilling(ctx, "o") 303 if err != nil { 304 t.Errorf("Copilot.GetCopilotBilling returned error: %v", err) 305 } 306 307 want := &CopilotOrganizationDetails{ 308 SeatBreakdown: &CopilotSeatBreakdown{ 309 Total: 12, 310 AddedThisCycle: 9, 311 PendingInvitation: 0, 312 PendingCancellation: 0, 313 ActiveThisCycle: 12, 314 InactiveThisCycle: 11, 315 }, 316 PublicCodeSuggestions: "block", 317 CopilotChat: "", 318 SeatManagementSetting: "assign_selected", 319 } 320 if !cmp.Equal(got, want) { 321 t.Errorf("Copilot.GetCopilotBilling returned %+v, want %+v", got, want) 322 } 323 324 const methodName = "GetCopilotBilling" 325 326 testBadOptions(t, methodName, func() (err error) { 327 _, _, err = client.Copilot.GetCopilotBilling(ctx, "\n") 328 return err 329 }) 330 331 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 332 got, resp, err := client.Copilot.GetCopilotBilling(ctx, "o") 333 if got != nil { 334 t.Errorf("Copilot.GetCopilotBilling returned %+v, want nil", got) 335 } 336 return resp, err 337 }) 338 } 339 340 func TestCopilotService_ListCopilotSeats(t *testing.T) { 341 t.Parallel() 342 client, mux, _ := setup(t) 343 344 mux.HandleFunc("/orgs/o/copilot/billing/seats", func(w http.ResponseWriter, r *http.Request) { 345 testMethod(t, r, "GET") 346 testFormValues(t, r, values{ 347 "per_page": "100", 348 "page": "1", 349 }) 350 fmt.Fprint(w, `{ 351 "total_seats": 4, 352 "seats": [ 353 { 354 "created_at": "2021-08-03T18:00:00-06:00", 355 "updated_at": "2021-09-23T15:00:00-06:00", 356 "pending_cancellation_date": null, 357 "last_activity_at": "2021-10-14T00:53:32-06:00", 358 "last_activity_editor": "vscode/1.77.3/copilot/1.86.82", 359 "assignee": { 360 "login": "octocat", 361 "id": 1, 362 "node_id": "MDQ6VXNlcjE=", 363 "avatar_url": "https://github.com/images/error/octocat_happy.gif", 364 "gravatar_id": "", 365 "url": "https://api.github.com/users/octocat", 366 "html_url": "https://github.com/octocat", 367 "followers_url": "https://api.github.com/users/octocat/followers", 368 "following_url": "https://api.github.com/users/octocat/following{/other_user}", 369 "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", 370 "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", 371 "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", 372 "organizations_url": "https://api.github.com/users/octocat/orgs", 373 "repos_url": "https://api.github.com/users/octocat/repos", 374 "events_url": "https://api.github.com/users/octocat/events{/privacy}", 375 "received_events_url": "https://api.github.com/users/octocat/received_events", 376 "type": "User", 377 "site_admin": false 378 }, 379 "assigning_team": { 380 "id": 1, 381 "node_id": "MDQ6VGVhbTE=", 382 "url": "https://api.github.com/teams/1", 383 "html_url": "https://github.com/orgs/github/teams/justice-league", 384 "name": "Justice League", 385 "slug": "justice-league", 386 "description": "A great team.", 387 "privacy": "closed", 388 "notification_setting": "notifications_enabled", 389 "permission": "admin", 390 "members_url": "https://api.github.com/teams/1/members{/member}", 391 "repositories_url": "https://api.github.com/teams/1/repos", 392 "parent": null 393 } 394 }, 395 { 396 "created_at": "2021-09-23T18:00:00-06:00", 397 "updated_at": "2021-09-23T15:00:00-06:00", 398 "pending_cancellation_date": "2021-11-01", 399 "last_activity_at": "2021-10-13T00:53:32-06:00", 400 "last_activity_editor": "vscode/1.77.3/copilot/1.86.82", 401 "assignee": { 402 "login": "octokitten", 403 "id": 1, 404 "node_id": "MDQ76VNlcjE=", 405 "avatar_url": "https://github.com/images/error/octokitten_happy.gif", 406 "gravatar_id": "", 407 "url": "https://api.github.com/users/octokitten", 408 "html_url": "https://github.com/octokitten", 409 "followers_url": "https://api.github.com/users/octokitten/followers", 410 "following_url": "https://api.github.com/users/octokitten/following{/other_user}", 411 "gists_url": "https://api.github.com/users/octokitten/gists{/gist_id}", 412 "starred_url": "https://api.github.com/users/octokitten/starred{/owner}{/repo}", 413 "subscriptions_url": "https://api.github.com/users/octokitten/subscriptions", 414 "organizations_url": "https://api.github.com/users/octokitten/orgs", 415 "repos_url": "https://api.github.com/users/octokitten/repos", 416 "events_url": "https://api.github.com/users/octokitten/events{/privacy}", 417 "received_events_url": "https://api.github.com/users/octokitten/received_events", 418 "type": "User", 419 "site_admin": false 420 } 421 }, 422 { 423 "created_at": "2021-09-23T18:00:00-06:00", 424 "updated_at": "2021-09-23T15:00:00-06:00", 425 "pending_cancellation_date": "2021-11-01", 426 "last_activity_at": "2021-10-13T00:53:32-06:00", 427 "last_activity_editor": "vscode/1.77.3/copilot/1.86.82", 428 "assignee": { 429 "name": "octokittens", 430 "id": 1, 431 "type": "Team" 432 } 433 }, 434 { 435 "created_at": "2021-09-23T18:00:00-06:00", 436 "updated_at": "2021-09-23T15:00:00-06:00", 437 "pending_cancellation_date": "2021-11-01", 438 "last_activity_at": "2021-10-13T00:53:32-06:00", 439 "last_activity_editor": "vscode/1.77.3/copilot/1.86.82", 440 "assignee": { 441 "name": "octocats", 442 "id": 1, 443 "type": "Organization" 444 } 445 } 446 ] 447 }`) 448 }) 449 450 tmp, err := time.Parse(time.RFC3339, "2021-08-03T18:00:00-06:00") 451 if err != nil { 452 panic(err) 453 } 454 createdAt1 := Timestamp{tmp} 455 456 tmp, err = time.Parse(time.RFC3339, "2021-09-23T15:00:00-06:00") 457 if err != nil { 458 panic(err) 459 } 460 updatedAt1 := Timestamp{tmp} 461 462 tmp, err = time.Parse(time.RFC3339, "2021-10-14T00:53:32-06:00") 463 if err != nil { 464 panic(err) 465 } 466 lastActivityAt1 := Timestamp{tmp} 467 468 tmp, err = time.Parse(time.RFC3339, "2021-09-23T18:00:00-06:00") 469 if err != nil { 470 panic(err) 471 } 472 createdAt2 := Timestamp{tmp} 473 474 tmp, err = time.Parse(time.RFC3339, "2021-09-23T15:00:00-06:00") 475 if err != nil { 476 panic(err) 477 } 478 updatedAt2 := Timestamp{tmp} 479 480 tmp, err = time.Parse(time.RFC3339, "2021-10-13T00:53:32-06:00") 481 if err != nil { 482 panic(err) 483 } 484 lastActivityAt2 := Timestamp{tmp} 485 486 ctx := context.Background() 487 opts := &ListOptions{Page: 1, PerPage: 100} 488 got, _, err := client.Copilot.ListCopilotSeats(ctx, "o", opts) 489 if err != nil { 490 t.Errorf("Copilot.ListCopilotSeats returned error: %v", err) 491 } 492 493 want := &ListCopilotSeatsResponse{ 494 TotalSeats: 4, 495 Seats: []*CopilotSeatDetails{ 496 { 497 Assignee: &User{ 498 Login: Ptr("octocat"), 499 ID: Ptr(int64(1)), 500 NodeID: Ptr("MDQ6VXNlcjE="), 501 AvatarURL: Ptr("https://github.com/images/error/octocat_happy.gif"), 502 GravatarID: Ptr(""), 503 URL: Ptr("https://api.github.com/users/octocat"), 504 HTMLURL: Ptr("https://github.com/octocat"), 505 FollowersURL: Ptr("https://api.github.com/users/octocat/followers"), 506 FollowingURL: Ptr("https://api.github.com/users/octocat/following{/other_user}"), 507 GistsURL: Ptr("https://api.github.com/users/octocat/gists{/gist_id}"), 508 StarredURL: Ptr("https://api.github.com/users/octocat/starred{/owner}{/repo}"), 509 SubscriptionsURL: Ptr("https://api.github.com/users/octocat/subscriptions"), 510 OrganizationsURL: Ptr("https://api.github.com/users/octocat/orgs"), 511 ReposURL: Ptr("https://api.github.com/users/octocat/repos"), 512 EventsURL: Ptr("https://api.github.com/users/octocat/events{/privacy}"), 513 ReceivedEventsURL: Ptr("https://api.github.com/users/octocat/received_events"), 514 Type: Ptr("User"), 515 SiteAdmin: Ptr(false), 516 }, 517 AssigningTeam: &Team{ 518 ID: Ptr(int64(1)), 519 NodeID: Ptr("MDQ6VGVhbTE="), 520 URL: Ptr("https://api.github.com/teams/1"), 521 HTMLURL: Ptr("https://github.com/orgs/github/teams/justice-league"), 522 Name: Ptr("Justice League"), 523 Slug: Ptr("justice-league"), 524 Description: Ptr("A great team."), 525 Privacy: Ptr("closed"), 526 Permission: Ptr("admin"), 527 MembersURL: Ptr("https://api.github.com/teams/1/members{/member}"), 528 RepositoriesURL: Ptr("https://api.github.com/teams/1/repos"), 529 Parent: nil, 530 }, 531 CreatedAt: &createdAt1, 532 UpdatedAt: &updatedAt1, 533 PendingCancellationDate: nil, 534 LastActivityAt: &lastActivityAt1, 535 LastActivityEditor: Ptr("vscode/1.77.3/copilot/1.86.82"), 536 }, 537 { 538 Assignee: &User{ 539 Login: Ptr("octokitten"), 540 ID: Ptr(int64(1)), 541 NodeID: Ptr("MDQ76VNlcjE="), 542 AvatarURL: Ptr("https://github.com/images/error/octokitten_happy.gif"), 543 GravatarID: Ptr(""), 544 URL: Ptr("https://api.github.com/users/octokitten"), 545 HTMLURL: Ptr("https://github.com/octokitten"), 546 FollowersURL: Ptr("https://api.github.com/users/octokitten/followers"), 547 FollowingURL: Ptr("https://api.github.com/users/octokitten/following{/other_user}"), 548 GistsURL: Ptr("https://api.github.com/users/octokitten/gists{/gist_id}"), 549 StarredURL: Ptr("https://api.github.com/users/octokitten/starred{/owner}{/repo}"), 550 SubscriptionsURL: Ptr("https://api.github.com/users/octokitten/subscriptions"), 551 OrganizationsURL: Ptr("https://api.github.com/users/octokitten/orgs"), 552 ReposURL: Ptr("https://api.github.com/users/octokitten/repos"), 553 EventsURL: Ptr("https://api.github.com/users/octokitten/events{/privacy}"), 554 ReceivedEventsURL: Ptr("https://api.github.com/users/octokitten/received_events"), 555 Type: Ptr("User"), 556 SiteAdmin: Ptr(false), 557 }, 558 AssigningTeam: nil, 559 CreatedAt: &createdAt2, 560 UpdatedAt: &updatedAt2, 561 PendingCancellationDate: Ptr("2021-11-01"), 562 LastActivityAt: &lastActivityAt2, 563 LastActivityEditor: Ptr("vscode/1.77.3/copilot/1.86.82"), 564 }, 565 { 566 Assignee: &Team{ 567 ID: Ptr(int64(1)), 568 Name: Ptr("octokittens"), 569 }, 570 AssigningTeam: nil, 571 CreatedAt: &createdAt2, 572 UpdatedAt: &updatedAt2, 573 PendingCancellationDate: Ptr("2021-11-01"), 574 LastActivityAt: &lastActivityAt2, 575 LastActivityEditor: Ptr("vscode/1.77.3/copilot/1.86.82"), 576 }, 577 { 578 Assignee: &Organization{ 579 ID: Ptr(int64(1)), 580 Name: Ptr("octocats"), 581 Type: Ptr("Organization"), 582 }, 583 AssigningTeam: nil, 584 CreatedAt: &createdAt2, 585 UpdatedAt: &updatedAt2, 586 PendingCancellationDate: Ptr("2021-11-01"), 587 LastActivityAt: &lastActivityAt2, 588 LastActivityEditor: Ptr("vscode/1.77.3/copilot/1.86.82"), 589 }, 590 }, 591 } 592 593 if !cmp.Equal(got, want) { 594 t.Errorf("Copilot.ListCopilotSeats returned %+v, want %+v", got, want) 595 } 596 597 const methodName = "ListCopilotSeats" 598 599 testBadOptions(t, methodName, func() (err error) { 600 _, _, err = client.Copilot.ListCopilotSeats(ctx, "\n", opts) 601 return err 602 }) 603 604 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 605 got, resp, err := client.Copilot.ListCopilotSeats(ctx, "o", opts) 606 if got != nil { 607 t.Errorf("Copilot.ListCopilotSeats returned %+v, want nil", got) 608 } 609 return resp, err 610 }) 611 } 612 613 func TestCopilotService_ListCopilotEnterpriseSeats(t *testing.T) { 614 t.Parallel() 615 client, mux, _ := setup(t) 616 617 mux.HandleFunc("/enterprises/e/copilot/billing/seats", func(w http.ResponseWriter, r *http.Request) { 618 testMethod(t, r, "GET") 619 testFormValues(t, r, values{ 620 "per_page": "100", 621 "page": "1", 622 }) 623 fmt.Fprint(w, `{ 624 "total_seats": 2, 625 "seats": [ 626 { 627 "created_at": "2021-08-03T18:00:00-06:00", 628 "updated_at": "2021-09-23T15:00:00-06:00", 629 "pending_cancellation_date": null, 630 "last_activity_at": "2021-10-14T00:53:32-06:00", 631 "last_activity_editor": "vscode/1.77.3/copilot/1.86.82", 632 "plan_type": "business", 633 "assignee": { 634 "login": "octocat", 635 "id": 1, 636 "node_id": "MDQ6VXNlcjE=", 637 "avatar_url": "https://github.com/images/error/octocat_happy.gif", 638 "gravatar_id": "", 639 "url": "https://api.github.com/users/octocat", 640 "html_url": "https://github.com/octocat", 641 "followers_url": "https://api.github.com/users/octocat/followers", 642 "following_url": "https://api.github.com/users/octocat/following{/other_user}", 643 "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", 644 "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", 645 "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", 646 "organizations_url": "https://api.github.com/users/octocat/orgs", 647 "repos_url": "https://api.github.com/users/octocat/repos", 648 "events_url": "https://api.github.com/users/octocat/events{/privacy}", 649 "received_events_url": "https://api.github.com/users/octocat/received_events", 650 "type": "User", 651 "site_admin": false 652 }, 653 "assigning_team": { 654 "id": 1, 655 "node_id": "MDQ6VGVhbTE=", 656 "url": "https://api.github.com/teams/1", 657 "html_url": "https://github.com/orgs/github/teams/justice-league", 658 "name": "Justice League", 659 "slug": "justice-league", 660 "description": "A great team.", 661 "privacy": "closed", 662 "notification_setting": "notifications_enabled", 663 "permission": "admin", 664 "members_url": "https://api.github.com/teams/1/members{/member}", 665 "repositories_url": "https://api.github.com/teams/1/repos", 666 "parent": null 667 } 668 }, 669 { 670 "created_at": "2021-09-23T18:00:00-06:00", 671 "updated_at": "2021-09-23T15:00:00-06:00", 672 "pending_cancellation_date": "2021-11-01", 673 "last_activity_at": "2021-10-13T00:53:32-06:00", 674 "last_activity_editor": "vscode/1.77.3/copilot/1.86.82", 675 "assignee": { 676 "login": "octokitten", 677 "id": 1, 678 "node_id": "MDQ76VNlcjE=", 679 "avatar_url": "https://github.com/images/error/octokitten_happy.gif", 680 "gravatar_id": "", 681 "url": "https://api.github.com/users/octokitten", 682 "html_url": "https://github.com/octokitten", 683 "followers_url": "https://api.github.com/users/octokitten/followers", 684 "following_url": "https://api.github.com/users/octokitten/following{/other_user}", 685 "gists_url": "https://api.github.com/users/octokitten/gists{/gist_id}", 686 "starred_url": "https://api.github.com/users/octokitten/starred{/owner}{/repo}", 687 "subscriptions_url": "https://api.github.com/users/octokitten/subscriptions", 688 "organizations_url": "https://api.github.com/users/octokitten/orgs", 689 "repos_url": "https://api.github.com/users/octokitten/repos", 690 "events_url": "https://api.github.com/users/octokitten/events{/privacy}", 691 "received_events_url": "https://api.github.com/users/octokitten/received_events", 692 "type": "User", 693 "site_admin": false 694 } 695 } 696 ] 697 }`) 698 }) 699 700 tmp, err := time.Parse(time.RFC3339, "2021-08-03T18:00:00-06:00") 701 if err != nil { 702 panic(err) 703 } 704 createdAt1 := Timestamp{tmp} 705 706 tmp, err = time.Parse(time.RFC3339, "2021-09-23T15:00:00-06:00") 707 if err != nil { 708 panic(err) 709 } 710 updatedAt1 := Timestamp{tmp} 711 712 tmp, err = time.Parse(time.RFC3339, "2021-10-14T00:53:32-06:00") 713 if err != nil { 714 panic(err) 715 } 716 lastActivityAt1 := Timestamp{tmp} 717 718 tmp, err = time.Parse(time.RFC3339, "2021-09-23T18:00:00-06:00") 719 if err != nil { 720 panic(err) 721 } 722 createdAt2 := Timestamp{tmp} 723 724 tmp, err = time.Parse(time.RFC3339, "2021-09-23T15:00:00-06:00") 725 if err != nil { 726 panic(err) 727 } 728 updatedAt2 := Timestamp{tmp} 729 730 tmp, err = time.Parse(time.RFC3339, "2021-10-13T00:53:32-06:00") 731 if err != nil { 732 panic(err) 733 } 734 lastActivityAt2 := Timestamp{tmp} 735 736 ctx := context.Background() 737 opts := &ListOptions{Page: 1, PerPage: 100} 738 got, _, err := client.Copilot.ListCopilotEnterpriseSeats(ctx, "e", opts) 739 if err != nil { 740 t.Errorf("Copilot.ListCopilotEnterpriseSeats returned error: %v", err) 741 } 742 743 want := &ListCopilotSeatsResponse{ 744 TotalSeats: 2, 745 Seats: []*CopilotSeatDetails{ 746 { 747 Assignee: &User{ 748 Login: Ptr("octocat"), 749 ID: Ptr(int64(1)), 750 NodeID: Ptr("MDQ6VXNlcjE="), 751 AvatarURL: Ptr("https://github.com/images/error/octocat_happy.gif"), 752 GravatarID: Ptr(""), 753 URL: Ptr("https://api.github.com/users/octocat"), 754 HTMLURL: Ptr("https://github.com/octocat"), 755 FollowersURL: Ptr("https://api.github.com/users/octocat/followers"), 756 FollowingURL: Ptr("https://api.github.com/users/octocat/following{/other_user}"), 757 GistsURL: Ptr("https://api.github.com/users/octocat/gists{/gist_id}"), 758 StarredURL: Ptr("https://api.github.com/users/octocat/starred{/owner}{/repo}"), 759 SubscriptionsURL: Ptr("https://api.github.com/users/octocat/subscriptions"), 760 OrganizationsURL: Ptr("https://api.github.com/users/octocat/orgs"), 761 ReposURL: Ptr("https://api.github.com/users/octocat/repos"), 762 EventsURL: Ptr("https://api.github.com/users/octocat/events{/privacy}"), 763 ReceivedEventsURL: Ptr("https://api.github.com/users/octocat/received_events"), 764 Type: Ptr("User"), 765 SiteAdmin: Ptr(false), 766 }, 767 AssigningTeam: &Team{ 768 ID: Ptr(int64(1)), 769 NodeID: Ptr("MDQ6VGVhbTE="), 770 URL: Ptr("https://api.github.com/teams/1"), 771 HTMLURL: Ptr("https://github.com/orgs/github/teams/justice-league"), 772 Name: Ptr("Justice League"), 773 Slug: Ptr("justice-league"), 774 Description: Ptr("A great team."), 775 Privacy: Ptr("closed"), 776 Permission: Ptr("admin"), 777 MembersURL: Ptr("https://api.github.com/teams/1/members{/member}"), 778 RepositoriesURL: Ptr("https://api.github.com/teams/1/repos"), 779 Parent: nil, 780 }, 781 CreatedAt: &createdAt1, 782 UpdatedAt: &updatedAt1, 783 PendingCancellationDate: nil, 784 LastActivityAt: &lastActivityAt1, 785 LastActivityEditor: Ptr("vscode/1.77.3/copilot/1.86.82"), 786 PlanType: Ptr("business"), 787 }, 788 { 789 Assignee: &User{ 790 Login: Ptr("octokitten"), 791 ID: Ptr(int64(1)), 792 NodeID: Ptr("MDQ76VNlcjE="), 793 AvatarURL: Ptr("https://github.com/images/error/octokitten_happy.gif"), 794 GravatarID: Ptr(""), 795 URL: Ptr("https://api.github.com/users/octokitten"), 796 HTMLURL: Ptr("https://github.com/octokitten"), 797 FollowersURL: Ptr("https://api.github.com/users/octokitten/followers"), 798 FollowingURL: Ptr("https://api.github.com/users/octokitten/following{/other_user}"), 799 GistsURL: Ptr("https://api.github.com/users/octokitten/gists{/gist_id}"), 800 StarredURL: Ptr("https://api.github.com/users/octokitten/starred{/owner}{/repo}"), 801 SubscriptionsURL: Ptr("https://api.github.com/users/octokitten/subscriptions"), 802 OrganizationsURL: Ptr("https://api.github.com/users/octokitten/orgs"), 803 ReposURL: Ptr("https://api.github.com/users/octokitten/repos"), 804 EventsURL: Ptr("https://api.github.com/users/octokitten/events{/privacy}"), 805 ReceivedEventsURL: Ptr("https://api.github.com/users/octokitten/received_events"), 806 Type: Ptr("User"), 807 SiteAdmin: Ptr(false), 808 }, 809 AssigningTeam: nil, 810 CreatedAt: &createdAt2, 811 UpdatedAt: &updatedAt2, 812 PendingCancellationDate: Ptr("2021-11-01"), 813 LastActivityAt: &lastActivityAt2, 814 LastActivityEditor: Ptr("vscode/1.77.3/copilot/1.86.82"), 815 PlanType: nil, 816 }, 817 }, 818 } 819 820 if !cmp.Equal(got, want) { 821 log.Printf("got: %+v", got.Seats[1]) 822 log.Printf("want: %+v", want.Seats[1]) 823 t.Errorf("Copilot.ListCopilotEnterpriseSeats returned %+v, want %+v", got, want) 824 } 825 826 const methodName = "ListCopilotEnterpriseSeats" 827 828 testBadOptions(t, methodName, func() (err error) { 829 _, _, err = client.Copilot.ListCopilotEnterpriseSeats(ctx, "\n", opts) 830 return err 831 }) 832 833 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 834 got, resp, err := client.Copilot.ListCopilotEnterpriseSeats(ctx, "e", opts) 835 if got != nil { 836 t.Errorf("Copilot.ListCopilotEnterpriseSeats returned %+v, want nil", got) 837 } 838 return resp, err 839 }) 840 } 841 842 func TestCopilotService_AddCopilotTeams(t *testing.T) { 843 t.Parallel() 844 client, mux, _ := setup(t) 845 846 mux.HandleFunc("/orgs/o/copilot/billing/selected_teams", func(w http.ResponseWriter, r *http.Request) { 847 testMethod(t, r, "POST") 848 testBody(t, r, `{"selected_teams":["team1","team2"]}`+"\n") 849 fmt.Fprint(w, `{"seats_created": 2}`) 850 }) 851 852 ctx := context.Background() 853 got, _, err := client.Copilot.AddCopilotTeams(ctx, "o", []string{"team1", "team2"}) 854 if err != nil { 855 t.Errorf("Copilot.AddCopilotTeams returned error: %v", err) 856 } 857 858 want := &SeatAssignments{SeatsCreated: 2} 859 860 if !cmp.Equal(got, want) { 861 t.Errorf("Copilot.AddCopilotTeams returned %+v, want %+v", got, want) 862 } 863 864 const methodName = "AddCopilotTeams" 865 866 testBadOptions(t, methodName, func() (err error) { 867 _, _, err = client.Copilot.AddCopilotTeams(ctx, "\n", []string{"team1", "team2"}) 868 return err 869 }) 870 871 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 872 got, resp, err := client.Copilot.AddCopilotTeams(ctx, "o", []string{"team1", "team2"}) 873 if got != nil { 874 t.Errorf("Copilot.AddCopilotTeams returned %+v, want nil", got) 875 } 876 return resp, err 877 }) 878 } 879 880 func TestCopilotService_RemoveCopilotTeams(t *testing.T) { 881 t.Parallel() 882 client, mux, _ := setup(t) 883 884 mux.HandleFunc("/orgs/o/copilot/billing/selected_teams", func(w http.ResponseWriter, r *http.Request) { 885 testMethod(t, r, "DELETE") 886 testBody(t, r, `{"selected_teams":["team1","team2"]}`+"\n") 887 fmt.Fprint(w, `{"seats_cancelled": 2}`) 888 }) 889 890 ctx := context.Background() 891 got, _, err := client.Copilot.RemoveCopilotTeams(ctx, "o", []string{"team1", "team2"}) 892 if err != nil { 893 t.Errorf("Copilot.RemoveCopilotTeams returned error: %v", err) 894 } 895 896 want := &SeatCancellations{SeatsCancelled: 2} 897 898 if !cmp.Equal(got, want) { 899 t.Errorf("Copilot.RemoveCopilotTeams returned %+v, want %+v", got, want) 900 } 901 902 const methodName = "RemoveCopilotTeams" 903 904 testBadOptions(t, methodName, func() (err error) { 905 _, _, err = client.Copilot.RemoveCopilotTeams(ctx, "\n", []string{"team1", "team2"}) 906 return err 907 }) 908 909 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 910 got, resp, err := client.Copilot.RemoveCopilotTeams(ctx, "o", []string{"team1", "team2"}) 911 if got != nil { 912 t.Errorf("Copilot.RemoveCopilotTeams returned %+v, want nil", got) 913 } 914 return resp, err 915 }) 916 } 917 918 func TestCopilotService_AddCopilotUsers(t *testing.T) { 919 t.Parallel() 920 client, mux, _ := setup(t) 921 922 mux.HandleFunc("/orgs/o/copilot/billing/selected_users", func(w http.ResponseWriter, r *http.Request) { 923 testMethod(t, r, "POST") 924 testBody(t, r, `{"selected_usernames":["user1","user2"]}`+"\n") 925 fmt.Fprint(w, `{"seats_created": 2}`) 926 }) 927 928 ctx := context.Background() 929 got, _, err := client.Copilot.AddCopilotUsers(ctx, "o", []string{"user1", "user2"}) 930 if err != nil { 931 t.Errorf("Copilot.AddCopilotUsers returned error: %v", err) 932 } 933 934 want := &SeatAssignments{SeatsCreated: 2} 935 936 if !cmp.Equal(got, want) { 937 t.Errorf("Copilot.AddCopilotUsers returned %+v, want %+v", got, want) 938 } 939 940 const methodName = "AddCopilotUsers" 941 942 testBadOptions(t, methodName, func() (err error) { 943 _, _, err = client.Copilot.AddCopilotUsers(ctx, "\n", []string{"user1", "user2"}) 944 return err 945 }) 946 947 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 948 got, resp, err := client.Copilot.AddCopilotUsers(ctx, "o", []string{"user1", "user2"}) 949 if got != nil { 950 t.Errorf("Copilot.AddCopilotUsers returned %+v, want nil", got) 951 } 952 return resp, err 953 }) 954 } 955 956 func TestCopilotService_RemoveCopilotUsers(t *testing.T) { 957 t.Parallel() 958 client, mux, _ := setup(t) 959 960 mux.HandleFunc("/orgs/o/copilot/billing/selected_users", func(w http.ResponseWriter, r *http.Request) { 961 testMethod(t, r, "DELETE") 962 testBody(t, r, `{"selected_usernames":["user1","user2"]}`+"\n") 963 fmt.Fprint(w, `{"seats_cancelled": 2}`) 964 }) 965 966 ctx := context.Background() 967 got, _, err := client.Copilot.RemoveCopilotUsers(ctx, "o", []string{"user1", "user2"}) 968 if err != nil { 969 t.Errorf("Copilot.RemoveCopilotUsers returned error: %v", err) 970 } 971 972 want := &SeatCancellations{SeatsCancelled: 2} 973 974 if !cmp.Equal(got, want) { 975 t.Errorf("Copilot.RemoveCopilotUsers returned %+v, want %+v", got, want) 976 } 977 978 const methodName = "RemoveCopilotUsers" 979 980 testBadOptions(t, methodName, func() (err error) { 981 _, _, err = client.Copilot.RemoveCopilotUsers(ctx, "\n", []string{"user1", "user2"}) 982 return err 983 }) 984 985 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 986 got, resp, err := client.Copilot.RemoveCopilotUsers(ctx, "o", []string{"user1", "user2"}) 987 if got != nil { 988 t.Errorf("Copilot.RemoveCopilotUsers returned %+v, want nil", got) 989 } 990 return resp, err 991 }) 992 } 993 994 func TestCopilotService_GetSeatDetails(t *testing.T) { 995 t.Parallel() 996 client, mux, _ := setup(t) 997 998 mux.HandleFunc("/orgs/o/members/u/copilot", func(w http.ResponseWriter, r *http.Request) { 999 testMethod(t, r, "GET") 1000 fmt.Fprint(w, `{ 1001 "created_at": "2021-08-03T18:00:00-06:00", 1002 "updated_at": "2021-09-23T15:00:00-06:00", 1003 "pending_cancellation_date": null, 1004 "last_activity_at": "2021-10-14T00:53:32-06:00", 1005 "last_activity_editor": "vscode/1.77.3/copilot/1.86.82", 1006 "assignee": { 1007 "login": "octocat", 1008 "id": 1, 1009 "node_id": "MDQ6VXNlcjE=", 1010 "avatar_url": "https://github.com/images/error/octocat_happy.gif", 1011 "gravatar_id": "", 1012 "url": "https://api.github.com/users/octocat", 1013 "html_url": "https://github.com/octocat", 1014 "followers_url": "https://api.github.com/users/octocat/followers", 1015 "following_url": "https://api.github.com/users/octocat/following{/other_user}", 1016 "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", 1017 "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", 1018 "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", 1019 "organizations_url": "https://api.github.com/users/octocat/orgs", 1020 "repos_url": "https://api.github.com/users/octocat/repos", 1021 "events_url": "https://api.github.com/users/octocat/events{/privacy}", 1022 "received_events_url": "https://api.github.com/users/octocat/received_events", 1023 "type": "User", 1024 "site_admin": false 1025 }, 1026 "assigning_team": { 1027 "id": 1, 1028 "node_id": "MDQ6VGVhbTE=", 1029 "url": "https://api.github.com/teams/1", 1030 "html_url": "https://github.com/orgs/github/teams/justice-league", 1031 "name": "Justice League", 1032 "slug": "justice-league", 1033 "description": "A great team.", 1034 "privacy": "closed", 1035 "notification_setting": "notifications_enabled", 1036 "permission": "admin", 1037 "members_url": "https://api.github.com/teams/1/members{/member}", 1038 "repositories_url": "https://api.github.com/teams/1/repos", 1039 "parent": null 1040 } 1041 }`) 1042 }) 1043 1044 tmp, err := time.Parse(time.RFC3339, "2021-08-03T18:00:00-06:00") 1045 if err != nil { 1046 panic(err) 1047 } 1048 createdAt := Timestamp{tmp} 1049 1050 tmp, err = time.Parse(time.RFC3339, "2021-09-23T15:00:00-06:00") 1051 if err != nil { 1052 panic(err) 1053 } 1054 updatedAt := Timestamp{tmp} 1055 1056 tmp, err = time.Parse(time.RFC3339, "2021-10-14T00:53:32-06:00") 1057 if err != nil { 1058 panic(err) 1059 } 1060 lastActivityAt := Timestamp{tmp} 1061 1062 ctx := context.Background() 1063 got, _, err := client.Copilot.GetSeatDetails(ctx, "o", "u") 1064 if err != nil { 1065 t.Errorf("Copilot.GetSeatDetails returned error: %v", err) 1066 } 1067 1068 want := &CopilotSeatDetails{ 1069 Assignee: &User{ 1070 Login: Ptr("octocat"), 1071 ID: Ptr(int64(1)), 1072 NodeID: Ptr("MDQ6VXNlcjE="), 1073 AvatarURL: Ptr("https://github.com/images/error/octocat_happy.gif"), 1074 GravatarID: Ptr(""), 1075 URL: Ptr("https://api.github.com/users/octocat"), 1076 HTMLURL: Ptr("https://github.com/octocat"), 1077 FollowersURL: Ptr("https://api.github.com/users/octocat/followers"), 1078 FollowingURL: Ptr("https://api.github.com/users/octocat/following{/other_user}"), 1079 GistsURL: Ptr("https://api.github.com/users/octocat/gists{/gist_id}"), 1080 StarredURL: Ptr("https://api.github.com/users/octocat/starred{/owner}{/repo}"), 1081 SubscriptionsURL: Ptr("https://api.github.com/users/octocat/subscriptions"), 1082 OrganizationsURL: Ptr("https://api.github.com/users/octocat/orgs"), 1083 ReposURL: Ptr("https://api.github.com/users/octocat/repos"), 1084 EventsURL: Ptr("https://api.github.com/users/octocat/events{/privacy}"), 1085 ReceivedEventsURL: Ptr("https://api.github.com/users/octocat/received_events"), 1086 Type: Ptr("User"), 1087 SiteAdmin: Ptr(false), 1088 }, 1089 AssigningTeam: &Team{ 1090 ID: Ptr(int64(1)), 1091 NodeID: Ptr("MDQ6VGVhbTE="), 1092 URL: Ptr("https://api.github.com/teams/1"), 1093 HTMLURL: Ptr("https://github.com/orgs/github/teams/justice-league"), 1094 Name: Ptr("Justice League"), 1095 Slug: Ptr("justice-league"), 1096 Description: Ptr("A great team."), 1097 Privacy: Ptr("closed"), 1098 Permission: Ptr("admin"), 1099 MembersURL: Ptr("https://api.github.com/teams/1/members{/member}"), 1100 RepositoriesURL: Ptr("https://api.github.com/teams/1/repos"), 1101 Parent: nil, 1102 }, 1103 CreatedAt: &createdAt, 1104 UpdatedAt: &updatedAt, 1105 PendingCancellationDate: nil, 1106 LastActivityAt: &lastActivityAt, 1107 LastActivityEditor: Ptr("vscode/1.77.3/copilot/1.86.82"), 1108 } 1109 1110 if !cmp.Equal(got, want) { 1111 t.Errorf("Copilot.GetSeatDetails returned %+v, want %+v", got, want) 1112 } 1113 1114 const methodName = "GetSeatDetails" 1115 1116 testBadOptions(t, methodName, func() (err error) { 1117 _, _, err = client.Copilot.GetSeatDetails(ctx, "\n", "u") 1118 return err 1119 }) 1120 1121 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 1122 got, resp, err := client.Copilot.GetSeatDetails(ctx, "o", "u") 1123 if got != nil { 1124 t.Errorf("Copilot.GetSeatDetails returned %+v, want nil", got) 1125 } 1126 return resp, err 1127 }) 1128 } 1129 1130 func TestCopilotService_GetEnterpriseMetrics(t *testing.T) { 1131 t.Parallel() 1132 client, mux, _ := setup(t) 1133 1134 mux.HandleFunc("/enterprises/e/copilot/metrics", func(w http.ResponseWriter, r *http.Request) { 1135 testMethod(t, r, "GET") 1136 fmt.Fprint(w, `[ 1137 { 1138 "date": "2024-06-24", 1139 "total_active_users": 24, 1140 "total_engaged_users": 20, 1141 "copilot_ide_code_completions": { 1142 "total_engaged_users": 20, 1143 "languages": [ 1144 { 1145 "name": "python", 1146 "total_engaged_users": 10 1147 }, 1148 { 1149 "name": "ruby", 1150 "total_engaged_users": 10 1151 } 1152 ], 1153 "editors": [ 1154 { 1155 "name": "vscode", 1156 "total_engaged_users": 13, 1157 "models": [ 1158 { 1159 "name": "default", 1160 "is_custom_model": false, 1161 "custom_model_training_date": null, 1162 "total_engaged_users": 13, 1163 "languages": [ 1164 { 1165 "name": "python", 1166 "total_engaged_users": 6, 1167 "total_code_suggestions": 249, 1168 "total_code_acceptances": 123, 1169 "total_code_lines_suggested": 225, 1170 "total_code_lines_accepted": 135 1171 }, 1172 { 1173 "name": "ruby", 1174 "total_engaged_users": 7, 1175 "total_code_suggestions": 496, 1176 "total_code_acceptances": 253, 1177 "total_code_lines_suggested": 520, 1178 "total_code_lines_accepted": 270 1179 } 1180 ] 1181 } 1182 ] 1183 }, 1184 { 1185 "name": "neovim", 1186 "total_engaged_users": 7, 1187 "models": [ 1188 { 1189 "name": "a-custom-model", 1190 "is_custom_model": true, 1191 "custom_model_training_date": "2024-02-01", 1192 "languages": [ 1193 { 1194 "name": "typescript", 1195 "total_engaged_users": 3, 1196 "total_code_suggestions": 112, 1197 "total_code_acceptances": 56, 1198 "total_code_lines_suggested": 143, 1199 "total_code_lines_accepted": 61 1200 }, 1201 { 1202 "name": "go", 1203 "total_engaged_users": 4, 1204 "total_code_suggestions": 132, 1205 "total_code_acceptances": 67, 1206 "total_code_lines_suggested": 154, 1207 "total_code_lines_accepted": 72 1208 } 1209 ] 1210 } 1211 ] 1212 } 1213 ] 1214 }, 1215 "copilot_ide_chat": { 1216 "total_engaged_users": 13, 1217 "editors": [ 1218 { 1219 "name": "vscode", 1220 "total_engaged_users": 13, 1221 "models": [ 1222 { 1223 "name": "default", 1224 "is_custom_model": false, 1225 "custom_model_training_date": null, 1226 "total_engaged_users": 12, 1227 "total_chats": 45, 1228 "total_chat_insertion_events": 12, 1229 "total_chat_copy_events": 16 1230 }, 1231 { 1232 "name": "a-custom-model", 1233 "is_custom_model": true, 1234 "custom_model_training_date": "2024-02-01", 1235 "total_engaged_users": 1, 1236 "total_chats": 10, 1237 "total_chat_insertion_events": 11, 1238 "total_chat_copy_events": 3 1239 } 1240 ] 1241 } 1242 ] 1243 }, 1244 "copilot_dotcom_chat": { 1245 "total_engaged_users": 14, 1246 "models": [ 1247 { 1248 "name": "default", 1249 "is_custom_model": false, 1250 "custom_model_training_date": null, 1251 "total_engaged_users": 14, 1252 "total_chats": 38 1253 } 1254 ] 1255 }, 1256 "copilot_dotcom_pull_requests": { 1257 "total_engaged_users": 12, 1258 "repositories": [ 1259 { 1260 "name": "demo/repo1", 1261 "total_engaged_users": 8, 1262 "models": [ 1263 { 1264 "name": "default", 1265 "is_custom_model": false, 1266 "custom_model_training_date": null, 1267 "total_pr_summaries_created": 6, 1268 "total_engaged_users": 8 1269 } 1270 ] 1271 }, 1272 { 1273 "name": "demo/repo2", 1274 "total_engaged_users": 4, 1275 "models": [ 1276 { 1277 "name": "a-custom-model", 1278 "is_custom_model": true, 1279 "custom_model_training_date": "2024-02-01", 1280 "total_pr_summaries_created": 10, 1281 "total_engaged_users": 4 1282 } 1283 ] 1284 } 1285 ] 1286 } 1287 } 1288 ]`) 1289 }) 1290 1291 ctx := context.Background() 1292 got, _, err := client.Copilot.GetEnterpriseMetrics(ctx, "e", &CopilotMetricsListOptions{}) 1293 if err != nil { 1294 t.Errorf("Copilot.GetEnterpriseMetrics returned error: %v", err) 1295 } 1296 1297 totalActiveUsers := 24 1298 totalEngagedUsers := 20 1299 want := []*CopilotMetrics{ 1300 { 1301 Date: "2024-06-24", 1302 TotalActiveUsers: &totalActiveUsers, 1303 TotalEngagedUsers: &totalEngagedUsers, 1304 CopilotIDECodeCompletions: &CopilotIDECodeCompletions{ 1305 TotalEngagedUsers: 20, 1306 Languages: []*CopilotIDECodeCompletionsLanguage{ 1307 { 1308 Name: "python", 1309 TotalEngagedUsers: 10, 1310 }, 1311 { 1312 Name: "ruby", 1313 TotalEngagedUsers: 10, 1314 }, 1315 }, 1316 Editors: []*CopilotIDECodeCompletionsEditor{ 1317 { 1318 Name: "vscode", 1319 TotalEngagedUsers: 13, 1320 Models: []*CopilotIDECodeCompletionsModel{ 1321 { 1322 Name: "default", 1323 IsCustomModel: false, 1324 CustomModelTrainingDate: nil, 1325 TotalEngagedUsers: 13, 1326 Languages: []*CopilotIDECodeCompletionsModelLanguage{ 1327 { 1328 Name: "python", 1329 TotalEngagedUsers: 6, 1330 TotalCodeSuggestions: 249, 1331 TotalCodeAcceptances: 123, 1332 TotalCodeLinesSuggested: 225, 1333 TotalCodeLinesAccepted: 135, 1334 }, 1335 { 1336 Name: "ruby", 1337 TotalEngagedUsers: 7, 1338 TotalCodeSuggestions: 496, 1339 TotalCodeAcceptances: 253, 1340 TotalCodeLinesSuggested: 520, 1341 TotalCodeLinesAccepted: 270, 1342 }, 1343 }, 1344 }, 1345 }, 1346 }, 1347 { 1348 Name: "neovim", 1349 TotalEngagedUsers: 7, 1350 Models: []*CopilotIDECodeCompletionsModel{ 1351 { 1352 Name: "a-custom-model", 1353 IsCustomModel: true, 1354 CustomModelTrainingDate: Ptr("2024-02-01"), 1355 Languages: []*CopilotIDECodeCompletionsModelLanguage{ 1356 { 1357 Name: "typescript", 1358 TotalEngagedUsers: 3, 1359 TotalCodeSuggestions: 112, 1360 TotalCodeAcceptances: 56, 1361 TotalCodeLinesSuggested: 143, 1362 TotalCodeLinesAccepted: 61, 1363 }, 1364 { 1365 Name: "go", 1366 TotalEngagedUsers: 4, 1367 TotalCodeSuggestions: 132, 1368 TotalCodeAcceptances: 67, 1369 TotalCodeLinesSuggested: 154, 1370 TotalCodeLinesAccepted: 72, 1371 }, 1372 }, 1373 }, 1374 }, 1375 }, 1376 }, 1377 }, 1378 CopilotIDEChat: &CopilotIDEChat{ 1379 TotalEngagedUsers: 13, 1380 Editors: []*CopilotIDEChatEditor{ 1381 { 1382 Name: "vscode", 1383 TotalEngagedUsers: 13, 1384 Models: []*CopilotIDEChatModel{ 1385 { 1386 Name: "default", 1387 IsCustomModel: false, 1388 CustomModelTrainingDate: nil, 1389 TotalEngagedUsers: 12, 1390 TotalChats: 45, 1391 TotalChatInsertionEvents: 12, 1392 TotalChatCopyEvents: 16, 1393 }, 1394 { 1395 Name: "a-custom-model", 1396 IsCustomModel: true, 1397 CustomModelTrainingDate: Ptr("2024-02-01"), 1398 TotalEngagedUsers: 1, 1399 TotalChats: 10, 1400 TotalChatInsertionEvents: 11, 1401 TotalChatCopyEvents: 3, 1402 }, 1403 }, 1404 }, 1405 }, 1406 }, 1407 CopilotDotcomChat: &CopilotDotcomChat{ 1408 TotalEngagedUsers: 14, 1409 Models: []*CopilotDotcomChatModel{ 1410 { 1411 Name: "default", 1412 IsCustomModel: false, 1413 CustomModelTrainingDate: nil, 1414 TotalEngagedUsers: 14, 1415 TotalChats: 38, 1416 }, 1417 }, 1418 }, 1419 CopilotDotcomPullRequests: &CopilotDotcomPullRequests{ 1420 TotalEngagedUsers: 12, 1421 Repositories: []*CopilotDotcomPullRequestsRepository{ 1422 { 1423 Name: "demo/repo1", 1424 TotalEngagedUsers: 8, 1425 Models: []*CopilotDotcomPullRequestsModel{ 1426 { 1427 Name: "default", 1428 IsCustomModel: false, 1429 CustomModelTrainingDate: nil, 1430 TotalPRSummariesCreated: 6, 1431 TotalEngagedUsers: 8, 1432 }, 1433 }, 1434 }, 1435 { 1436 Name: "demo/repo2", 1437 TotalEngagedUsers: 4, 1438 Models: []*CopilotDotcomPullRequestsModel{ 1439 { 1440 Name: "a-custom-model", 1441 IsCustomModel: true, 1442 CustomModelTrainingDate: Ptr("2024-02-01"), 1443 TotalPRSummariesCreated: 10, 1444 TotalEngagedUsers: 4, 1445 }, 1446 }, 1447 }, 1448 }, 1449 }, 1450 }, 1451 } 1452 1453 if !cmp.Equal(got, want) { 1454 t.Errorf("Copilot.GetEnterpriseMetrics returned %+v, want %+v", got, want) 1455 } 1456 1457 const methodName = "GetEnterpriseMetrics" 1458 1459 testBadOptions(t, methodName, func() (err error) { 1460 _, _, err = client.Copilot.GetEnterpriseMetrics(ctx, "\n", &CopilotMetricsListOptions{}) 1461 return err 1462 }) 1463 1464 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 1465 got, resp, err := client.Copilot.GetEnterpriseMetrics(ctx, "e", &CopilotMetricsListOptions{}) 1466 if got != nil { 1467 t.Errorf("Copilot.GetEnterpriseMetrics returned %+v, want nil", got) 1468 } 1469 return resp, err 1470 }) 1471 } 1472 1473 func TestCopilotService_GetEnterpriseTeamMetrics(t *testing.T) { 1474 t.Parallel() 1475 client, mux, _ := setup(t) 1476 1477 mux.HandleFunc("/enterprises/e/team/t/copilot/metrics", func(w http.ResponseWriter, r *http.Request) { 1478 testMethod(t, r, "GET") 1479 fmt.Fprint(w, `[ 1480 { 1481 "date": "2024-06-24", 1482 "total_active_users": 24, 1483 "total_engaged_users": 20, 1484 "copilot_ide_code_completions": { 1485 "total_engaged_users": 20, 1486 "languages": [ 1487 { 1488 "name": "python", 1489 "total_engaged_users": 10 1490 }, 1491 { 1492 "name": "ruby", 1493 "total_engaged_users": 10 1494 } 1495 ], 1496 "editors": [ 1497 { 1498 "name": "vscode", 1499 "total_engaged_users": 13, 1500 "models": [ 1501 { 1502 "name": "default", 1503 "is_custom_model": false, 1504 "custom_model_training_date": null, 1505 "total_engaged_users": 13, 1506 "languages": [ 1507 { 1508 "name": "python", 1509 "total_engaged_users": 6, 1510 "total_code_suggestions": 249, 1511 "total_code_acceptances": 123, 1512 "total_code_lines_suggested": 225, 1513 "total_code_lines_accepted": 135 1514 }, 1515 { 1516 "name": "ruby", 1517 "total_engaged_users": 7, 1518 "total_code_suggestions": 496, 1519 "total_code_acceptances": 253, 1520 "total_code_lines_suggested": 520, 1521 "total_code_lines_accepted": 270 1522 } 1523 ] 1524 } 1525 ] 1526 }, 1527 { 1528 "name": "neovim", 1529 "total_engaged_users": 7, 1530 "models": [ 1531 { 1532 "name": "a-custom-model", 1533 "is_custom_model": true, 1534 "custom_model_training_date": "2024-02-01", 1535 "languages": [ 1536 { 1537 "name": "typescript", 1538 "total_engaged_users": 3, 1539 "total_code_suggestions": 112, 1540 "total_code_acceptances": 56, 1541 "total_code_lines_suggested": 143, 1542 "total_code_lines_accepted": 61 1543 }, 1544 { 1545 "name": "go", 1546 "total_engaged_users": 4, 1547 "total_code_suggestions": 132, 1548 "total_code_acceptances": 67, 1549 "total_code_lines_suggested": 154, 1550 "total_code_lines_accepted": 72 1551 } 1552 ] 1553 } 1554 ] 1555 } 1556 ] 1557 }, 1558 "copilot_ide_chat": { 1559 "total_engaged_users": 13, 1560 "editors": [ 1561 { 1562 "name": "vscode", 1563 "total_engaged_users": 13, 1564 "models": [ 1565 { 1566 "name": "default", 1567 "is_custom_model": false, 1568 "custom_model_training_date": null, 1569 "total_engaged_users": 12, 1570 "total_chats": 45, 1571 "total_chat_insertion_events": 12, 1572 "total_chat_copy_events": 16 1573 }, 1574 { 1575 "name": "a-custom-model", 1576 "is_custom_model": true, 1577 "custom_model_training_date": "2024-02-01", 1578 "total_engaged_users": 1, 1579 "total_chats": 10, 1580 "total_chat_insertion_events": 11, 1581 "total_chat_copy_events": 3 1582 } 1583 ] 1584 } 1585 ] 1586 }, 1587 "copilot_dotcom_chat": { 1588 "total_engaged_users": 14, 1589 "models": [ 1590 { 1591 "name": "default", 1592 "is_custom_model": false, 1593 "custom_model_training_date": null, 1594 "total_engaged_users": 14, 1595 "total_chats": 38 1596 } 1597 ] 1598 }, 1599 "copilot_dotcom_pull_requests": { 1600 "total_engaged_users": 12, 1601 "repositories": [ 1602 { 1603 "name": "demo/repo1", 1604 "total_engaged_users": 8, 1605 "models": [ 1606 { 1607 "name": "default", 1608 "is_custom_model": false, 1609 "custom_model_training_date": null, 1610 "total_pr_summaries_created": 6, 1611 "total_engaged_users": 8 1612 } 1613 ] 1614 }, 1615 { 1616 "name": "demo/repo2", 1617 "total_engaged_users": 4, 1618 "models": [ 1619 { 1620 "name": "a-custom-model", 1621 "is_custom_model": true, 1622 "custom_model_training_date": "2024-02-01", 1623 "total_pr_summaries_created": 10, 1624 "total_engaged_users": 4 1625 } 1626 ] 1627 } 1628 ] 1629 } 1630 } 1631 ]`) 1632 }) 1633 1634 ctx := context.Background() 1635 got, _, err := client.Copilot.GetEnterpriseTeamMetrics(ctx, "e", "t", &CopilotMetricsListOptions{}) 1636 if err != nil { 1637 t.Errorf("Copilot.GetEnterpriseTeamMetrics returned error: %v", err) 1638 } 1639 1640 totalActiveUsers := 24 1641 totalEngagedUsers := 20 1642 want := []*CopilotMetrics{ 1643 { 1644 Date: "2024-06-24", 1645 TotalActiveUsers: &totalActiveUsers, 1646 TotalEngagedUsers: &totalEngagedUsers, 1647 CopilotIDECodeCompletions: &CopilotIDECodeCompletions{ 1648 TotalEngagedUsers: 20, 1649 Languages: []*CopilotIDECodeCompletionsLanguage{ 1650 { 1651 Name: "python", 1652 TotalEngagedUsers: 10, 1653 }, 1654 { 1655 Name: "ruby", 1656 TotalEngagedUsers: 10, 1657 }, 1658 }, 1659 Editors: []*CopilotIDECodeCompletionsEditor{ 1660 { 1661 Name: "vscode", 1662 TotalEngagedUsers: 13, 1663 Models: []*CopilotIDECodeCompletionsModel{ 1664 { 1665 Name: "default", 1666 IsCustomModel: false, 1667 CustomModelTrainingDate: nil, 1668 TotalEngagedUsers: 13, 1669 Languages: []*CopilotIDECodeCompletionsModelLanguage{ 1670 { 1671 Name: "python", 1672 TotalEngagedUsers: 6, 1673 TotalCodeSuggestions: 249, 1674 TotalCodeAcceptances: 123, 1675 TotalCodeLinesSuggested: 225, 1676 TotalCodeLinesAccepted: 135, 1677 }, 1678 { 1679 Name: "ruby", 1680 TotalEngagedUsers: 7, 1681 TotalCodeSuggestions: 496, 1682 TotalCodeAcceptances: 253, 1683 TotalCodeLinesSuggested: 520, 1684 TotalCodeLinesAccepted: 270, 1685 }, 1686 }, 1687 }, 1688 }, 1689 }, 1690 { 1691 Name: "neovim", 1692 TotalEngagedUsers: 7, 1693 Models: []*CopilotIDECodeCompletionsModel{ 1694 { 1695 Name: "a-custom-model", 1696 IsCustomModel: true, 1697 CustomModelTrainingDate: Ptr("2024-02-01"), 1698 Languages: []*CopilotIDECodeCompletionsModelLanguage{ 1699 { 1700 Name: "typescript", 1701 TotalEngagedUsers: 3, 1702 TotalCodeSuggestions: 112, 1703 TotalCodeAcceptances: 56, 1704 TotalCodeLinesSuggested: 143, 1705 TotalCodeLinesAccepted: 61, 1706 }, 1707 { 1708 Name: "go", 1709 TotalEngagedUsers: 4, 1710 TotalCodeSuggestions: 132, 1711 TotalCodeAcceptances: 67, 1712 TotalCodeLinesSuggested: 154, 1713 TotalCodeLinesAccepted: 72, 1714 }, 1715 }, 1716 }, 1717 }, 1718 }, 1719 }, 1720 }, 1721 CopilotIDEChat: &CopilotIDEChat{ 1722 TotalEngagedUsers: 13, 1723 Editors: []*CopilotIDEChatEditor{ 1724 { 1725 Name: "vscode", 1726 TotalEngagedUsers: 13, 1727 Models: []*CopilotIDEChatModel{ 1728 { 1729 Name: "default", 1730 IsCustomModel: false, 1731 CustomModelTrainingDate: nil, 1732 TotalEngagedUsers: 12, 1733 TotalChats: 45, 1734 TotalChatInsertionEvents: 12, 1735 TotalChatCopyEvents: 16, 1736 }, 1737 { 1738 Name: "a-custom-model", 1739 IsCustomModel: true, 1740 CustomModelTrainingDate: Ptr("2024-02-01"), 1741 TotalEngagedUsers: 1, 1742 TotalChats: 10, 1743 TotalChatInsertionEvents: 11, 1744 TotalChatCopyEvents: 3, 1745 }, 1746 }, 1747 }, 1748 }, 1749 }, 1750 CopilotDotcomChat: &CopilotDotcomChat{ 1751 TotalEngagedUsers: 14, 1752 Models: []*CopilotDotcomChatModel{ 1753 { 1754 Name: "default", 1755 IsCustomModel: false, 1756 CustomModelTrainingDate: nil, 1757 TotalEngagedUsers: 14, 1758 TotalChats: 38, 1759 }, 1760 }, 1761 }, 1762 CopilotDotcomPullRequests: &CopilotDotcomPullRequests{ 1763 TotalEngagedUsers: 12, 1764 Repositories: []*CopilotDotcomPullRequestsRepository{ 1765 { 1766 Name: "demo/repo1", 1767 TotalEngagedUsers: 8, 1768 Models: []*CopilotDotcomPullRequestsModel{ 1769 { 1770 Name: "default", 1771 IsCustomModel: false, 1772 CustomModelTrainingDate: nil, 1773 TotalPRSummariesCreated: 6, 1774 TotalEngagedUsers: 8, 1775 }, 1776 }, 1777 }, 1778 { 1779 Name: "demo/repo2", 1780 TotalEngagedUsers: 4, 1781 Models: []*CopilotDotcomPullRequestsModel{ 1782 { 1783 Name: "a-custom-model", 1784 IsCustomModel: true, 1785 CustomModelTrainingDate: Ptr("2024-02-01"), 1786 TotalPRSummariesCreated: 10, 1787 TotalEngagedUsers: 4, 1788 }, 1789 }, 1790 }, 1791 }, 1792 }, 1793 }, 1794 } 1795 1796 if !cmp.Equal(got, want) { 1797 t.Errorf("Copilot.GetEnterpriseTeamMetrics returned %+v, want %+v", got, want) 1798 } 1799 1800 const methodName = "GetEnterpriseTeamMetrics" 1801 1802 testBadOptions(t, methodName, func() (err error) { 1803 _, _, err = client.Copilot.GetEnterpriseTeamMetrics(ctx, "\n", "t", &CopilotMetricsListOptions{}) 1804 return err 1805 }) 1806 1807 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 1808 got, resp, err := client.Copilot.GetEnterpriseTeamMetrics(ctx, "e", "t", &CopilotMetricsListOptions{}) 1809 if got != nil { 1810 t.Errorf("Copilot.GetEnterpriseTeamMetrics returned %+v, want nil", got) 1811 } 1812 return resp, err 1813 }) 1814 } 1815 1816 func TestCopilotService_GetOrganizationMetrics(t *testing.T) { 1817 t.Parallel() 1818 client, mux, _ := setup(t) 1819 1820 mux.HandleFunc("/orgs/o/copilot/metrics", func(w http.ResponseWriter, r *http.Request) { 1821 testMethod(t, r, "GET") 1822 fmt.Fprint(w, `[ 1823 { 1824 "date": "2024-06-24", 1825 "total_active_users": 24, 1826 "total_engaged_users": 20, 1827 "copilot_ide_code_completions": { 1828 "total_engaged_users": 20, 1829 "languages": [ 1830 { 1831 "name": "python", 1832 "total_engaged_users": 10 1833 }, 1834 { 1835 "name": "ruby", 1836 "total_engaged_users": 10 1837 } 1838 ], 1839 "editors": [ 1840 { 1841 "name": "vscode", 1842 "total_engaged_users": 13, 1843 "models": [ 1844 { 1845 "name": "default", 1846 "is_custom_model": false, 1847 "custom_model_training_date": null, 1848 "total_engaged_users": 13, 1849 "languages": [ 1850 { 1851 "name": "python", 1852 "total_engaged_users": 6, 1853 "total_code_suggestions": 249, 1854 "total_code_acceptances": 123, 1855 "total_code_lines_suggested": 225, 1856 "total_code_lines_accepted": 135 1857 }, 1858 { 1859 "name": "ruby", 1860 "total_engaged_users": 7, 1861 "total_code_suggestions": 496, 1862 "total_code_acceptances": 253, 1863 "total_code_lines_suggested": 520, 1864 "total_code_lines_accepted": 270 1865 } 1866 ] 1867 } 1868 ] 1869 }, 1870 { 1871 "name": "neovim", 1872 "total_engaged_users": 7, 1873 "models": [ 1874 { 1875 "name": "a-custom-model", 1876 "is_custom_model": true, 1877 "custom_model_training_date": "2024-02-01", 1878 "languages": [ 1879 { 1880 "name": "typescript", 1881 "total_engaged_users": 3, 1882 "total_code_suggestions": 112, 1883 "total_code_acceptances": 56, 1884 "total_code_lines_suggested": 143, 1885 "total_code_lines_accepted": 61 1886 }, 1887 { 1888 "name": "go", 1889 "total_engaged_users": 4, 1890 "total_code_suggestions": 132, 1891 "total_code_acceptances": 67, 1892 "total_code_lines_suggested": 154, 1893 "total_code_lines_accepted": 72 1894 } 1895 ] 1896 } 1897 ] 1898 } 1899 ] 1900 }, 1901 "copilot_ide_chat": { 1902 "total_engaged_users": 13, 1903 "editors": [ 1904 { 1905 "name": "vscode", 1906 "total_engaged_users": 13, 1907 "models": [ 1908 { 1909 "name": "default", 1910 "is_custom_model": false, 1911 "custom_model_training_date": null, 1912 "total_engaged_users": 12, 1913 "total_chats": 45, 1914 "total_chat_insertion_events": 12, 1915 "total_chat_copy_events": 16 1916 }, 1917 { 1918 "name": "a-custom-model", 1919 "is_custom_model": true, 1920 "custom_model_training_date": "2024-02-01", 1921 "total_engaged_users": 1, 1922 "total_chats": 10, 1923 "total_chat_insertion_events": 11, 1924 "total_chat_copy_events": 3 1925 } 1926 ] 1927 } 1928 ] 1929 }, 1930 "copilot_dotcom_chat": { 1931 "total_engaged_users": 14, 1932 "models": [ 1933 { 1934 "name": "default", 1935 "is_custom_model": false, 1936 "custom_model_training_date": null, 1937 "total_engaged_users": 14, 1938 "total_chats": 38 1939 } 1940 ] 1941 }, 1942 "copilot_dotcom_pull_requests": { 1943 "total_engaged_users": 12, 1944 "repositories": [ 1945 { 1946 "name": "demo/repo1", 1947 "total_engaged_users": 8, 1948 "models": [ 1949 { 1950 "name": "default", 1951 "is_custom_model": false, 1952 "custom_model_training_date": null, 1953 "total_pr_summaries_created": 6, 1954 "total_engaged_users": 8 1955 } 1956 ] 1957 }, 1958 { 1959 "name": "demo/repo2", 1960 "total_engaged_users": 4, 1961 "models": [ 1962 { 1963 "name": "a-custom-model", 1964 "is_custom_model": true, 1965 "custom_model_training_date": "2024-02-01", 1966 "total_pr_summaries_created": 10, 1967 "total_engaged_users": 4 1968 } 1969 ] 1970 } 1971 ] 1972 } 1973 } 1974 ]`) 1975 }) 1976 1977 ctx := context.Background() 1978 got, _, err := client.Copilot.GetOrganizationMetrics(ctx, "o", &CopilotMetricsListOptions{}) 1979 if err != nil { 1980 t.Errorf("Copilot.GetOrganizationMetrics returned error: %v", err) 1981 } 1982 1983 totalActiveUsers := 24 1984 totalEngagedUsers := 20 1985 want := []*CopilotMetrics{ 1986 { 1987 Date: "2024-06-24", 1988 TotalActiveUsers: &totalActiveUsers, 1989 TotalEngagedUsers: &totalEngagedUsers, 1990 CopilotIDECodeCompletions: &CopilotIDECodeCompletions{ 1991 TotalEngagedUsers: 20, 1992 Languages: []*CopilotIDECodeCompletionsLanguage{ 1993 { 1994 Name: "python", 1995 TotalEngagedUsers: 10, 1996 }, 1997 { 1998 Name: "ruby", 1999 TotalEngagedUsers: 10, 2000 }, 2001 }, 2002 Editors: []*CopilotIDECodeCompletionsEditor{ 2003 { 2004 Name: "vscode", 2005 TotalEngagedUsers: 13, 2006 Models: []*CopilotIDECodeCompletionsModel{ 2007 { 2008 Name: "default", 2009 IsCustomModel: false, 2010 CustomModelTrainingDate: nil, 2011 TotalEngagedUsers: 13, 2012 Languages: []*CopilotIDECodeCompletionsModelLanguage{ 2013 { 2014 Name: "python", 2015 TotalEngagedUsers: 6, 2016 TotalCodeSuggestions: 249, 2017 TotalCodeAcceptances: 123, 2018 TotalCodeLinesSuggested: 225, 2019 TotalCodeLinesAccepted: 135, 2020 }, 2021 { 2022 Name: "ruby", 2023 TotalEngagedUsers: 7, 2024 TotalCodeSuggestions: 496, 2025 TotalCodeAcceptances: 253, 2026 TotalCodeLinesSuggested: 520, 2027 TotalCodeLinesAccepted: 270, 2028 }, 2029 }, 2030 }, 2031 }, 2032 }, 2033 { 2034 Name: "neovim", 2035 TotalEngagedUsers: 7, 2036 Models: []*CopilotIDECodeCompletionsModel{ 2037 { 2038 Name: "a-custom-model", 2039 IsCustomModel: true, 2040 CustomModelTrainingDate: Ptr("2024-02-01"), 2041 Languages: []*CopilotIDECodeCompletionsModelLanguage{ 2042 { 2043 Name: "typescript", 2044 TotalEngagedUsers: 3, 2045 TotalCodeSuggestions: 112, 2046 TotalCodeAcceptances: 56, 2047 TotalCodeLinesSuggested: 143, 2048 TotalCodeLinesAccepted: 61, 2049 }, 2050 { 2051 Name: "go", 2052 TotalEngagedUsers: 4, 2053 TotalCodeSuggestions: 132, 2054 TotalCodeAcceptances: 67, 2055 TotalCodeLinesSuggested: 154, 2056 TotalCodeLinesAccepted: 72, 2057 }, 2058 }, 2059 }, 2060 }, 2061 }, 2062 }, 2063 }, 2064 CopilotIDEChat: &CopilotIDEChat{ 2065 TotalEngagedUsers: 13, 2066 Editors: []*CopilotIDEChatEditor{ 2067 { 2068 Name: "vscode", 2069 TotalEngagedUsers: 13, 2070 Models: []*CopilotIDEChatModel{ 2071 { 2072 Name: "default", 2073 IsCustomModel: false, 2074 CustomModelTrainingDate: nil, 2075 TotalEngagedUsers: 12, 2076 TotalChats: 45, 2077 TotalChatInsertionEvents: 12, 2078 TotalChatCopyEvents: 16, 2079 }, 2080 { 2081 Name: "a-custom-model", 2082 IsCustomModel: true, 2083 CustomModelTrainingDate: Ptr("2024-02-01"), 2084 TotalEngagedUsers: 1, 2085 TotalChats: 10, 2086 TotalChatInsertionEvents: 11, 2087 TotalChatCopyEvents: 3, 2088 }, 2089 }, 2090 }, 2091 }, 2092 }, 2093 CopilotDotcomChat: &CopilotDotcomChat{ 2094 TotalEngagedUsers: 14, 2095 Models: []*CopilotDotcomChatModel{ 2096 { 2097 Name: "default", 2098 IsCustomModel: false, 2099 CustomModelTrainingDate: nil, 2100 TotalEngagedUsers: 14, 2101 TotalChats: 38, 2102 }, 2103 }, 2104 }, 2105 CopilotDotcomPullRequests: &CopilotDotcomPullRequests{ 2106 TotalEngagedUsers: 12, 2107 Repositories: []*CopilotDotcomPullRequestsRepository{ 2108 { 2109 Name: "demo/repo1", 2110 TotalEngagedUsers: 8, 2111 Models: []*CopilotDotcomPullRequestsModel{ 2112 { 2113 Name: "default", 2114 IsCustomModel: false, 2115 CustomModelTrainingDate: nil, 2116 TotalPRSummariesCreated: 6, 2117 TotalEngagedUsers: 8, 2118 }, 2119 }, 2120 }, 2121 { 2122 Name: "demo/repo2", 2123 TotalEngagedUsers: 4, 2124 Models: []*CopilotDotcomPullRequestsModel{ 2125 { 2126 Name: "a-custom-model", 2127 IsCustomModel: true, 2128 CustomModelTrainingDate: Ptr("2024-02-01"), 2129 TotalPRSummariesCreated: 10, 2130 TotalEngagedUsers: 4, 2131 }, 2132 }, 2133 }, 2134 }, 2135 }, 2136 }, 2137 } 2138 2139 if !cmp.Equal(got, want) { 2140 t.Errorf("Copilot.GetOrganizationMetrics returned %+v, want %+v", got, want) 2141 } 2142 2143 const methodName = "GetOrganizationMetrics" 2144 2145 testBadOptions(t, methodName, func() (err error) { 2146 _, _, err = client.Copilot.GetOrganizationMetrics(ctx, "\n", &CopilotMetricsListOptions{}) 2147 return err 2148 }) 2149 2150 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 2151 got, resp, err := client.Copilot.GetOrganizationMetrics(ctx, "o", &CopilotMetricsListOptions{}) 2152 if got != nil { 2153 t.Errorf("Copilot.GetOrganizationMetrics returned %+v, want nil", got) 2154 } 2155 return resp, err 2156 }) 2157 } 2158 2159 func TestCopilotService_GetOrganizationTeamMetrics(t *testing.T) { 2160 t.Parallel() 2161 client, mux, _ := setup(t) 2162 2163 mux.HandleFunc("/orgs/o/team/t/copilot/metrics", func(w http.ResponseWriter, r *http.Request) { 2164 testMethod(t, r, "GET") 2165 fmt.Fprint(w, `[ 2166 { 2167 "date": "2024-06-24", 2168 "total_active_users": 24, 2169 "total_engaged_users": 20, 2170 "copilot_ide_code_completions": { 2171 "total_engaged_users": 20, 2172 "languages": [ 2173 { 2174 "name": "python", 2175 "total_engaged_users": 10 2176 }, 2177 { 2178 "name": "ruby", 2179 "total_engaged_users": 10 2180 } 2181 ], 2182 "editors": [ 2183 { 2184 "name": "vscode", 2185 "total_engaged_users": 13, 2186 "models": [ 2187 { 2188 "name": "default", 2189 "is_custom_model": false, 2190 "custom_model_training_date": null, 2191 "total_engaged_users": 13, 2192 "languages": [ 2193 { 2194 "name": "python", 2195 "total_engaged_users": 6, 2196 "total_code_suggestions": 249, 2197 "total_code_acceptances": 123, 2198 "total_code_lines_suggested": 225, 2199 "total_code_lines_accepted": 135 2200 }, 2201 { 2202 "name": "ruby", 2203 "total_engaged_users": 7, 2204 "total_code_suggestions": 496, 2205 "total_code_acceptances": 253, 2206 "total_code_lines_suggested": 520, 2207 "total_code_lines_accepted": 270 2208 } 2209 ] 2210 } 2211 ] 2212 }, 2213 { 2214 "name": "neovim", 2215 "total_engaged_users": 7, 2216 "models": [ 2217 { 2218 "name": "a-custom-model", 2219 "is_custom_model": true, 2220 "custom_model_training_date": "2024-02-01", 2221 "languages": [ 2222 { 2223 "name": "typescript", 2224 "total_engaged_users": 3, 2225 "total_code_suggestions": 112, 2226 "total_code_acceptances": 56, 2227 "total_code_lines_suggested": 143, 2228 "total_code_lines_accepted": 61 2229 }, 2230 { 2231 "name": "go", 2232 "total_engaged_users": 4, 2233 "total_code_suggestions": 132, 2234 "total_code_acceptances": 67, 2235 "total_code_lines_suggested": 154, 2236 "total_code_lines_accepted": 72 2237 } 2238 ] 2239 } 2240 ] 2241 } 2242 ] 2243 }, 2244 "copilot_ide_chat": { 2245 "total_engaged_users": 13, 2246 "editors": [ 2247 { 2248 "name": "vscode", 2249 "total_engaged_users": 13, 2250 "models": [ 2251 { 2252 "name": "default", 2253 "is_custom_model": false, 2254 "custom_model_training_date": null, 2255 "total_engaged_users": 12, 2256 "total_chats": 45, 2257 "total_chat_insertion_events": 12, 2258 "total_chat_copy_events": 16 2259 }, 2260 { 2261 "name": "a-custom-model", 2262 "is_custom_model": true, 2263 "custom_model_training_date": "2024-02-01", 2264 "total_engaged_users": 1, 2265 "total_chats": 10, 2266 "total_chat_insertion_events": 11, 2267 "total_chat_copy_events": 3 2268 } 2269 ] 2270 } 2271 ] 2272 }, 2273 "copilot_dotcom_chat": { 2274 "total_engaged_users": 14, 2275 "models": [ 2276 { 2277 "name": "default", 2278 "is_custom_model": false, 2279 "custom_model_training_date": null, 2280 "total_engaged_users": 14, 2281 "total_chats": 38 2282 } 2283 ] 2284 }, 2285 "copilot_dotcom_pull_requests": { 2286 "total_engaged_users": 12, 2287 "repositories": [ 2288 { 2289 "name": "demo/repo1", 2290 "total_engaged_users": 8, 2291 "models": [ 2292 { 2293 "name": "default", 2294 "is_custom_model": false, 2295 "custom_model_training_date": null, 2296 "total_pr_summaries_created": 6, 2297 "total_engaged_users": 8 2298 } 2299 ] 2300 }, 2301 { 2302 "name": "demo/repo2", 2303 "total_engaged_users": 4, 2304 "models": [ 2305 { 2306 "name": "a-custom-model", 2307 "is_custom_model": true, 2308 "custom_model_training_date": "2024-02-01", 2309 "total_pr_summaries_created": 10, 2310 "total_engaged_users": 4 2311 } 2312 ] 2313 } 2314 ] 2315 } 2316 } 2317 ]`) 2318 }) 2319 2320 ctx := context.Background() 2321 got, _, err := client.Copilot.GetOrganizationTeamMetrics(ctx, "o", "t", &CopilotMetricsListOptions{}) 2322 if err != nil { 2323 t.Errorf("Copilot.GetOrganizationTeamMetrics returned error: %v", err) 2324 } 2325 2326 totalActiveUsers := 24 2327 totalEngagedUsers := 20 2328 want := []*CopilotMetrics{ 2329 { 2330 Date: "2024-06-24", 2331 TotalActiveUsers: &totalActiveUsers, 2332 TotalEngagedUsers: &totalEngagedUsers, 2333 CopilotIDECodeCompletions: &CopilotIDECodeCompletions{ 2334 TotalEngagedUsers: 20, 2335 Languages: []*CopilotIDECodeCompletionsLanguage{ 2336 { 2337 Name: "python", 2338 TotalEngagedUsers: 10, 2339 }, 2340 { 2341 Name: "ruby", 2342 TotalEngagedUsers: 10, 2343 }, 2344 }, 2345 Editors: []*CopilotIDECodeCompletionsEditor{ 2346 { 2347 Name: "vscode", 2348 TotalEngagedUsers: 13, 2349 Models: []*CopilotIDECodeCompletionsModel{ 2350 { 2351 Name: "default", 2352 IsCustomModel: false, 2353 CustomModelTrainingDate: nil, 2354 TotalEngagedUsers: 13, 2355 Languages: []*CopilotIDECodeCompletionsModelLanguage{ 2356 { 2357 Name: "python", 2358 TotalEngagedUsers: 6, 2359 TotalCodeSuggestions: 249, 2360 TotalCodeAcceptances: 123, 2361 TotalCodeLinesSuggested: 225, 2362 TotalCodeLinesAccepted: 135, 2363 }, 2364 { 2365 Name: "ruby", 2366 TotalEngagedUsers: 7, 2367 TotalCodeSuggestions: 496, 2368 TotalCodeAcceptances: 253, 2369 TotalCodeLinesSuggested: 520, 2370 TotalCodeLinesAccepted: 270, 2371 }, 2372 }, 2373 }, 2374 }, 2375 }, 2376 { 2377 Name: "neovim", 2378 TotalEngagedUsers: 7, 2379 Models: []*CopilotIDECodeCompletionsModel{ 2380 { 2381 Name: "a-custom-model", 2382 IsCustomModel: true, 2383 CustomModelTrainingDate: Ptr("2024-02-01"), 2384 Languages: []*CopilotIDECodeCompletionsModelLanguage{ 2385 { 2386 Name: "typescript", 2387 TotalEngagedUsers: 3, 2388 TotalCodeSuggestions: 112, 2389 TotalCodeAcceptances: 56, 2390 TotalCodeLinesSuggested: 143, 2391 TotalCodeLinesAccepted: 61, 2392 }, 2393 { 2394 Name: "go", 2395 TotalEngagedUsers: 4, 2396 TotalCodeSuggestions: 132, 2397 TotalCodeAcceptances: 67, 2398 TotalCodeLinesSuggested: 154, 2399 TotalCodeLinesAccepted: 72, 2400 }, 2401 }, 2402 }, 2403 }, 2404 }, 2405 }, 2406 }, 2407 CopilotIDEChat: &CopilotIDEChat{ 2408 TotalEngagedUsers: 13, 2409 Editors: []*CopilotIDEChatEditor{ 2410 { 2411 Name: "vscode", 2412 TotalEngagedUsers: 13, 2413 Models: []*CopilotIDEChatModel{ 2414 { 2415 Name: "default", 2416 IsCustomModel: false, 2417 CustomModelTrainingDate: nil, 2418 TotalEngagedUsers: 12, 2419 TotalChats: 45, 2420 TotalChatInsertionEvents: 12, 2421 TotalChatCopyEvents: 16, 2422 }, 2423 { 2424 Name: "a-custom-model", 2425 IsCustomModel: true, 2426 CustomModelTrainingDate: Ptr("2024-02-01"), 2427 TotalEngagedUsers: 1, 2428 TotalChats: 10, 2429 TotalChatInsertionEvents: 11, 2430 TotalChatCopyEvents: 3, 2431 }, 2432 }, 2433 }, 2434 }, 2435 }, 2436 CopilotDotcomChat: &CopilotDotcomChat{ 2437 TotalEngagedUsers: 14, 2438 Models: []*CopilotDotcomChatModel{ 2439 { 2440 Name: "default", 2441 IsCustomModel: false, 2442 CustomModelTrainingDate: nil, 2443 TotalEngagedUsers: 14, 2444 TotalChats: 38, 2445 }, 2446 }, 2447 }, 2448 CopilotDotcomPullRequests: &CopilotDotcomPullRequests{ 2449 TotalEngagedUsers: 12, 2450 Repositories: []*CopilotDotcomPullRequestsRepository{ 2451 { 2452 Name: "demo/repo1", 2453 TotalEngagedUsers: 8, 2454 Models: []*CopilotDotcomPullRequestsModel{ 2455 { 2456 Name: "default", 2457 IsCustomModel: false, 2458 CustomModelTrainingDate: nil, 2459 TotalPRSummariesCreated: 6, 2460 TotalEngagedUsers: 8, 2461 }, 2462 }, 2463 }, 2464 { 2465 Name: "demo/repo2", 2466 TotalEngagedUsers: 4, 2467 Models: []*CopilotDotcomPullRequestsModel{ 2468 { 2469 Name: "a-custom-model", 2470 IsCustomModel: true, 2471 CustomModelTrainingDate: Ptr("2024-02-01"), 2472 TotalPRSummariesCreated: 10, 2473 TotalEngagedUsers: 4, 2474 }, 2475 }, 2476 }, 2477 }, 2478 }, 2479 }, 2480 } 2481 2482 if !cmp.Equal(got, want) { 2483 t.Errorf("Copilot.GetOrganizationTeamMetrics returned %+v, want %+v", got, want) 2484 } 2485 2486 const methodName = "GetOrganizationTeamMetrics" 2487 2488 testBadOptions(t, methodName, func() (err error) { 2489 _, _, err = client.Copilot.GetOrganizationTeamMetrics(ctx, "\n", "\n", &CopilotMetricsListOptions{}) 2490 return err 2491 }) 2492 2493 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 2494 got, resp, err := client.Copilot.GetOrganizationTeamMetrics(ctx, "o", "t", &CopilotMetricsListOptions{}) 2495 if got != nil { 2496 t.Errorf("Copilot.GetOrganizationTeamMetrics returned %+v, want nil", got) 2497 } 2498 return resp, err 2499 }) 2500 }