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