github.com/google/go-github/v74@v74.0.0/github/repos_test.go (about) 1 // Copyright 2013 The go-github AUTHORS. All rights reserved. 2 // 3 // Use of this source code is governed by a BSD-style 4 // license that can be found in the LICENSE file. 5 6 package github 7 8 import ( 9 "context" 10 "encoding/json" 11 "errors" 12 "fmt" 13 "net/http" 14 "net/url" 15 "strings" 16 "testing" 17 "time" 18 19 "github.com/google/go-cmp/cmp" 20 ) 21 22 func TestRepositoriesService_ListByAuthenticatedUser(t *testing.T) { 23 t.Parallel() 24 client, mux, _ := setup(t) 25 26 mux.HandleFunc("/user/repos", func(w http.ResponseWriter, r *http.Request) { 27 testMethod(t, r, "GET") 28 fmt.Fprint(w, `[{"id":1},{"id":2}]`) 29 }) 30 31 ctx := context.Background() 32 got, _, err := client.Repositories.ListByAuthenticatedUser(ctx, nil) 33 if err != nil { 34 t.Errorf("Repositories.List returned error: %v", err) 35 } 36 37 want := []*Repository{{ID: Ptr(int64(1))}, {ID: Ptr(int64(2))}} 38 if !cmp.Equal(got, want) { 39 t.Errorf("Repositories.ListByAuthenticatedUser returned %+v, want %+v", got, want) 40 } 41 42 const methodName = "ListByAuthenticatedUser" 43 44 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 45 got, resp, err := client.Repositories.ListByAuthenticatedUser(ctx, nil) 46 if got != nil { 47 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 48 } 49 return resp, err 50 }) 51 } 52 53 func TestRepositoriesService_ListByUser(t *testing.T) { 54 t.Parallel() 55 client, mux, _ := setup(t) 56 57 mux.HandleFunc("/users/u/repos", func(w http.ResponseWriter, r *http.Request) { 58 testMethod(t, r, "GET") 59 testFormValues(t, r, values{ 60 "sort": "created", 61 "direction": "asc", 62 "page": "2", 63 }) 64 fmt.Fprint(w, `[{"id":1}]`) 65 }) 66 67 opt := &RepositoryListByUserOptions{ 68 Sort: "created", 69 Direction: "asc", 70 ListOptions: ListOptions{Page: 2}, 71 } 72 ctx := context.Background() 73 repos, _, err := client.Repositories.ListByUser(ctx, "u", opt) 74 if err != nil { 75 t.Errorf("Repositories.List returned error: %v", err) 76 } 77 78 want := []*Repository{{ID: Ptr(int64(1))}} 79 if !cmp.Equal(repos, want) { 80 t.Errorf("Repositories.ListByUser returned %+v, want %+v", repos, want) 81 } 82 83 const methodName = "ListByUser" 84 testBadOptions(t, methodName, func() (err error) { 85 _, _, err = client.Repositories.ListByUser(ctx, "\n", &RepositoryListByUserOptions{}) 86 return err 87 }) 88 89 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 90 got, resp, err := client.Repositories.ListByUser(ctx, "u", nil) 91 if got != nil { 92 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 93 } 94 return resp, err 95 }) 96 } 97 98 func TestRepositoriesService_ListByUser_type(t *testing.T) { 99 t.Parallel() 100 client, mux, _ := setup(t) 101 102 mux.HandleFunc("/users/u/repos", func(w http.ResponseWriter, r *http.Request) { 103 testMethod(t, r, "GET") 104 testFormValues(t, r, values{ 105 "type": "owner", 106 }) 107 fmt.Fprint(w, `[{"id":1}]`) 108 }) 109 110 opt := &RepositoryListByUserOptions{ 111 Type: "owner", 112 } 113 ctx := context.Background() 114 repos, _, err := client.Repositories.ListByUser(ctx, "u", opt) 115 if err != nil { 116 t.Errorf("Repositories.ListByUser returned error: %v", err) 117 } 118 119 want := []*Repository{{ID: Ptr(int64(1))}} 120 if !cmp.Equal(repos, want) { 121 t.Errorf("Repositories.ListByUser returned %+v, want %+v", repos, want) 122 } 123 } 124 125 func TestRepositoriesService_ListByUser_invalidUser(t *testing.T) { 126 t.Parallel() 127 client, _, _ := setup(t) 128 129 ctx := context.Background() 130 _, _, err := client.Repositories.ListByUser(ctx, "%", nil) 131 testURLParseError(t, err) 132 } 133 134 func TestRepositoriesService_ListByOrg(t *testing.T) { 135 t.Parallel() 136 client, mux, _ := setup(t) 137 138 wantAcceptHeaders := []string{mediaTypeTopicsPreview, mediaTypeRepositoryVisibilityPreview} 139 mux.HandleFunc("/orgs/o/repos", func(w http.ResponseWriter, r *http.Request) { 140 testMethod(t, r, "GET") 141 testHeader(t, r, "Accept", strings.Join(wantAcceptHeaders, ", ")) 142 testFormValues(t, r, values{ 143 "type": "forks", 144 "page": "2", 145 }) 146 fmt.Fprint(w, `[{"id":1}]`) 147 }) 148 149 ctx := context.Background() 150 opt := &RepositoryListByOrgOptions{ 151 Type: "forks", 152 ListOptions: ListOptions{Page: 2}, 153 } 154 got, _, err := client.Repositories.ListByOrg(ctx, "o", opt) 155 if err != nil { 156 t.Errorf("Repositories.ListByOrg returned error: %v", err) 157 } 158 159 want := []*Repository{{ID: Ptr(int64(1))}} 160 if !cmp.Equal(got, want) { 161 t.Errorf("Repositories.ListByOrg returned %+v, want %+v", got, want) 162 } 163 164 const methodName = "ListByOrg" 165 testBadOptions(t, methodName, func() (err error) { 166 _, _, err = client.Repositories.ListByOrg(ctx, "\n", opt) 167 return err 168 }) 169 170 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 171 got, resp, err := client.Repositories.ListByOrg(ctx, "o", opt) 172 if got != nil { 173 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 174 } 175 return resp, err 176 }) 177 } 178 179 func TestRepositoriesService_ListByOrg_invalidOrg(t *testing.T) { 180 t.Parallel() 181 client, _, _ := setup(t) 182 183 ctx := context.Background() 184 _, _, err := client.Repositories.ListByOrg(ctx, "%", nil) 185 testURLParseError(t, err) 186 } 187 188 func TestRepositoriesService_ListAll(t *testing.T) { 189 t.Parallel() 190 client, mux, _ := setup(t) 191 192 mux.HandleFunc("/repositories", func(w http.ResponseWriter, r *http.Request) { 193 testMethod(t, r, "GET") 194 testFormValues(t, r, values{ 195 "since": "1", 196 }) 197 fmt.Fprint(w, `[{"id":1}]`) 198 }) 199 200 ctx := context.Background() 201 opt := &RepositoryListAllOptions{1} 202 got, _, err := client.Repositories.ListAll(ctx, opt) 203 if err != nil { 204 t.Errorf("Repositories.ListAll returned error: %v", err) 205 } 206 207 want := []*Repository{{ID: Ptr(int64(1))}} 208 if !cmp.Equal(got, want) { 209 t.Errorf("Repositories.ListAll returned %+v, want %+v", got, want) 210 } 211 212 const methodName = "ListAll" 213 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 214 got, resp, err := client.Repositories.ListAll(ctx, &RepositoryListAllOptions{1}) 215 if got != nil { 216 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 217 } 218 return resp, err 219 }) 220 } 221 222 func TestRepositoriesService_Create_user(t *testing.T) { 223 t.Parallel() 224 client, mux, _ := setup(t) 225 226 input := &Repository{ 227 Name: Ptr("n"), 228 Archived: Ptr(true), // not passed along. 229 } 230 231 wantAcceptHeaders := []string{mediaTypeRepositoryTemplatePreview, mediaTypeRepositoryVisibilityPreview} 232 mux.HandleFunc("/user/repos", func(w http.ResponseWriter, r *http.Request) { 233 v := new(createRepoRequest) 234 assertNilError(t, json.NewDecoder(r.Body).Decode(v)) 235 236 testMethod(t, r, "POST") 237 testHeader(t, r, "Accept", strings.Join(wantAcceptHeaders, ", ")) 238 want := &createRepoRequest{Name: Ptr("n")} 239 if !cmp.Equal(v, want) { 240 t.Errorf("Request body = %+v, want %+v", v, want) 241 } 242 243 fmt.Fprint(w, `{"id":1}`) 244 }) 245 246 ctx := context.Background() 247 got, _, err := client.Repositories.Create(ctx, "", input) 248 if err != nil { 249 t.Errorf("Repositories.Create returned error: %v", err) 250 } 251 252 want := &Repository{ID: Ptr(int64(1))} 253 if !cmp.Equal(got, want) { 254 t.Errorf("Repositories.Create returned %+v, want %+v", got, want) 255 } 256 257 const methodName = "Create" 258 testBadOptions(t, methodName, func() (err error) { 259 _, _, err = client.Repositories.Create(ctx, "\n", input) 260 return err 261 }) 262 263 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 264 got, resp, err := client.Repositories.Create(ctx, "", input) 265 if got != nil { 266 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 267 } 268 return resp, err 269 }) 270 } 271 272 func TestRepositoriesService_Create_org(t *testing.T) { 273 t.Parallel() 274 client, mux, _ := setup(t) 275 276 input := &Repository{ 277 Name: Ptr("n"), 278 Archived: Ptr(true), // not passed along. 279 } 280 281 wantAcceptHeaders := []string{mediaTypeRepositoryTemplatePreview, mediaTypeRepositoryVisibilityPreview} 282 mux.HandleFunc("/orgs/o/repos", func(w http.ResponseWriter, r *http.Request) { 283 v := new(createRepoRequest) 284 assertNilError(t, json.NewDecoder(r.Body).Decode(v)) 285 286 testMethod(t, r, "POST") 287 testHeader(t, r, "Accept", strings.Join(wantAcceptHeaders, ", ")) 288 want := &createRepoRequest{Name: Ptr("n")} 289 if !cmp.Equal(v, want) { 290 t.Errorf("Request body = %+v, want %+v", v, want) 291 } 292 293 fmt.Fprint(w, `{"id":1}`) 294 }) 295 296 ctx := context.Background() 297 repo, _, err := client.Repositories.Create(ctx, "o", input) 298 if err != nil { 299 t.Errorf("Repositories.Create returned error: %v", err) 300 } 301 302 want := &Repository{ID: Ptr(int64(1))} 303 if !cmp.Equal(repo, want) { 304 t.Errorf("Repositories.Create returned %+v, want %+v", repo, want) 305 } 306 } 307 308 func TestRepositoriesService_CreateFromTemplate(t *testing.T) { 309 t.Parallel() 310 client, mux, _ := setup(t) 311 312 templateRepoReq := &TemplateRepoRequest{ 313 Name: Ptr("n"), 314 } 315 316 mux.HandleFunc("/repos/to/tr/generate", func(w http.ResponseWriter, r *http.Request) { 317 v := new(TemplateRepoRequest) 318 assertNilError(t, json.NewDecoder(r.Body).Decode(v)) 319 320 testMethod(t, r, "POST") 321 testHeader(t, r, "Accept", mediaTypeRepositoryTemplatePreview) 322 want := &TemplateRepoRequest{Name: Ptr("n")} 323 if !cmp.Equal(v, want) { 324 t.Errorf("Request body = %+v, want %+v", v, want) 325 } 326 327 fmt.Fprint(w, `{"id":1,"name":"n"}`) 328 }) 329 330 ctx := context.Background() 331 got, _, err := client.Repositories.CreateFromTemplate(ctx, "to", "tr", templateRepoReq) 332 if err != nil { 333 t.Errorf("Repositories.CreateFromTemplate returned error: %v", err) 334 } 335 336 want := &Repository{ID: Ptr(int64(1)), Name: Ptr("n")} 337 if !cmp.Equal(got, want) { 338 t.Errorf("Repositories.CreateFromTemplate returned %+v, want %+v", got, want) 339 } 340 341 const methodName = "CreateFromTemplate" 342 testBadOptions(t, methodName, func() (err error) { 343 _, _, err = client.Repositories.CreateFromTemplate(ctx, "\n", "\n", templateRepoReq) 344 return err 345 }) 346 347 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 348 got, resp, err := client.Repositories.CreateFromTemplate(ctx, "to", "tr", templateRepoReq) 349 if got != nil { 350 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 351 } 352 return resp, err 353 }) 354 } 355 356 func TestRepositoriesService_Get(t *testing.T) { 357 t.Parallel() 358 client, mux, _ := setup(t) 359 360 wantAcceptHeaders := []string{mediaTypeCodesOfConductPreview, mediaTypeTopicsPreview, mediaTypeRepositoryTemplatePreview, mediaTypeRepositoryVisibilityPreview} 361 mux.HandleFunc("/repos/o/r", func(w http.ResponseWriter, r *http.Request) { 362 testMethod(t, r, "GET") 363 testHeader(t, r, "Accept", strings.Join(wantAcceptHeaders, ", ")) 364 fmt.Fprint(w, `{"id":1,"name":"n","description":"d","owner":{"login":"l"},"license":{"key":"mit"},"security_and_analysis":{"advanced_security":{"status":"enabled"},"secret_scanning":{"status":"enabled"},"secret_scanning_push_protection":{"status":"enabled"},"dependabot_security_updates":{"status": "enabled"}, "secret_scanning_validity_checks":{"status":"enabled"}}}`) 365 }) 366 367 ctx := context.Background() 368 got, _, err := client.Repositories.Get(ctx, "o", "r") 369 if err != nil { 370 t.Errorf("Repositories.Get returned error: %v", err) 371 } 372 373 want := &Repository{ID: Ptr(int64(1)), Name: Ptr("n"), Description: Ptr("d"), Owner: &User{Login: Ptr("l")}, License: &License{Key: Ptr("mit")}, SecurityAndAnalysis: &SecurityAndAnalysis{AdvancedSecurity: &AdvancedSecurity{Status: Ptr("enabled")}, SecretScanning: &SecretScanning{Ptr("enabled")}, SecretScanningPushProtection: &SecretScanningPushProtection{Ptr("enabled")}, DependabotSecurityUpdates: &DependabotSecurityUpdates{Ptr("enabled")}, SecretScanningValidityChecks: &SecretScanningValidityChecks{Ptr("enabled")}}} 374 if !cmp.Equal(got, want) { 375 t.Errorf("Repositories.Get returned %+v, want %+v", got, want) 376 } 377 378 const methodName = "Get" 379 testBadOptions(t, methodName, func() (err error) { 380 _, _, err = client.Repositories.Get(ctx, "\n", "\n") 381 return err 382 }) 383 384 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 385 got, resp, err := client.Repositories.Get(ctx, "o", "r") 386 if got != nil { 387 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 388 } 389 return resp, err 390 }) 391 } 392 393 func TestRepositoriesService_GetCodeOfConduct(t *testing.T) { 394 t.Parallel() 395 client, mux, _ := setup(t) 396 397 mux.HandleFunc("/repos/o/r", func(w http.ResponseWriter, r *http.Request) { 398 testMethod(t, r, "GET") 399 testHeader(t, r, "Accept", mediaTypeCodesOfConductPreview) 400 fmt.Fprint(w, `{ 401 "code_of_conduct": { 402 "key": "key", 403 "name": "name", 404 "url": "url", 405 "body": "body" 406 }}`, 407 ) 408 }) 409 410 ctx := context.Background() 411 got, _, err := client.Repositories.GetCodeOfConduct(ctx, "o", "r") 412 if err != nil { 413 t.Errorf("Repositories.GetCodeOfConduct returned error: %v", err) 414 } 415 416 want := &CodeOfConduct{ 417 Key: Ptr("key"), 418 Name: Ptr("name"), 419 URL: Ptr("url"), 420 Body: Ptr("body"), 421 } 422 423 if !cmp.Equal(got, want) { 424 t.Errorf("Repositories.GetCodeOfConduct returned %+v, want %+v", got, want) 425 } 426 427 const methodName = "GetCodeOfConduct" 428 testBadOptions(t, methodName, func() (err error) { 429 _, _, err = client.Repositories.GetCodeOfConduct(ctx, "\n", "\n") 430 return err 431 }) 432 433 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 434 got, resp, err := client.Repositories.GetCodeOfConduct(ctx, "o", "r") 435 if got != nil { 436 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 437 } 438 return resp, err 439 }) 440 } 441 442 func TestRepositoriesService_GetByID(t *testing.T) { 443 t.Parallel() 444 client, mux, _ := setup(t) 445 446 mux.HandleFunc("/repositories/1", func(w http.ResponseWriter, r *http.Request) { 447 testMethod(t, r, "GET") 448 fmt.Fprint(w, `{"id":1,"name":"n","description":"d","owner":{"login":"l"},"license":{"key":"mit"}}`) 449 }) 450 451 ctx := context.Background() 452 got, _, err := client.Repositories.GetByID(ctx, 1) 453 if err != nil { 454 t.Fatalf("Repositories.GetByID returned error: %v", err) 455 } 456 457 want := &Repository{ID: Ptr(int64(1)), Name: Ptr("n"), Description: Ptr("d"), Owner: &User{Login: Ptr("l")}, License: &License{Key: Ptr("mit")}} 458 if !cmp.Equal(got, want) { 459 t.Errorf("Repositories.GetByID returned %+v, want %+v", got, want) 460 } 461 462 const methodName = "GetByID" 463 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 464 got, resp, err := client.Repositories.GetByID(ctx, 1) 465 if got != nil { 466 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 467 } 468 return resp, err 469 }) 470 } 471 472 func TestRepositoriesService_Edit(t *testing.T) { 473 t.Parallel() 474 client, mux, _ := setup(t) 475 476 i := true 477 input := &Repository{HasIssues: &i} 478 479 wantAcceptHeaders := []string{mediaTypeRepositoryTemplatePreview, mediaTypeRepositoryVisibilityPreview} 480 mux.HandleFunc("/repos/o/r", func(w http.ResponseWriter, r *http.Request) { 481 v := new(Repository) 482 assertNilError(t, json.NewDecoder(r.Body).Decode(v)) 483 484 testMethod(t, r, "PATCH") 485 testHeader(t, r, "Accept", strings.Join(wantAcceptHeaders, ", ")) 486 if !cmp.Equal(v, input) { 487 t.Errorf("Request body = %+v, want %+v", v, input) 488 } 489 fmt.Fprint(w, `{"id":1}`) 490 }) 491 492 ctx := context.Background() 493 got, _, err := client.Repositories.Edit(ctx, "o", "r", input) 494 if err != nil { 495 t.Errorf("Repositories.Edit returned error: %v", err) 496 } 497 498 want := &Repository{ID: Ptr(int64(1))} 499 if !cmp.Equal(got, want) { 500 t.Errorf("Repositories.Edit returned %+v, want %+v", got, want) 501 } 502 503 const methodName = "Edit" 504 testBadOptions(t, methodName, func() (err error) { 505 _, _, err = client.Repositories.Edit(ctx, "\n", "\n", input) 506 return err 507 }) 508 509 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 510 got, resp, err := client.Repositories.Edit(ctx, "o", "r", input) 511 if got != nil { 512 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 513 } 514 return resp, err 515 }) 516 } 517 518 func TestRepositoriesService_Delete(t *testing.T) { 519 t.Parallel() 520 client, mux, _ := setup(t) 521 522 mux.HandleFunc("/repos/o/r", func(_ http.ResponseWriter, r *http.Request) { 523 testMethod(t, r, "DELETE") 524 }) 525 526 ctx := context.Background() 527 _, err := client.Repositories.Delete(ctx, "o", "r") 528 if err != nil { 529 t.Errorf("Repositories.Delete returned error: %v", err) 530 } 531 532 const methodName = "Delete" 533 testBadOptions(t, methodName, func() (err error) { 534 _, err = client.Repositories.Delete(ctx, "\n", "\n") 535 return err 536 }) 537 538 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 539 return client.Repositories.Delete(ctx, "o", "r") 540 }) 541 } 542 543 func TestRepositoriesService_Get_invalidOwner(t *testing.T) { 544 t.Parallel() 545 client, _, _ := setup(t) 546 547 ctx := context.Background() 548 _, _, err := client.Repositories.Get(ctx, "%", "r") 549 testURLParseError(t, err) 550 } 551 552 func TestRepositoriesService_Edit_invalidOwner(t *testing.T) { 553 t.Parallel() 554 client, _, _ := setup(t) 555 556 ctx := context.Background() 557 _, _, err := client.Repositories.Edit(ctx, "%", "r", nil) 558 testURLParseError(t, err) 559 } 560 561 func TestRepositoriesService_GetVulnerabilityAlerts(t *testing.T) { 562 t.Parallel() 563 client, mux, _ := setup(t) 564 565 mux.HandleFunc("/repos/o/r/vulnerability-alerts", func(w http.ResponseWriter, r *http.Request) { 566 testMethod(t, r, "GET") 567 testHeader(t, r, "Accept", mediaTypeRequiredVulnerabilityAlertsPreview) 568 569 w.WriteHeader(http.StatusNoContent) 570 }) 571 572 ctx := context.Background() 573 vulnerabilityAlertsEnabled, _, err := client.Repositories.GetVulnerabilityAlerts(ctx, "o", "r") 574 if err != nil { 575 t.Errorf("Repositories.GetVulnerabilityAlerts returned error: %v", err) 576 } 577 578 if want := true; vulnerabilityAlertsEnabled != want { 579 t.Errorf("Repositories.GetVulnerabilityAlerts returned %+v, want %+v", vulnerabilityAlertsEnabled, want) 580 } 581 582 const methodName = "GetVulnerabilityAlerts" 583 testBadOptions(t, methodName, func() (err error) { 584 _, _, err = client.Repositories.GetVulnerabilityAlerts(ctx, "\n", "\n") 585 return err 586 }) 587 588 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 589 got, resp, err := client.Repositories.GetVulnerabilityAlerts(ctx, "o", "r") 590 if got { 591 t.Errorf("testNewRequestAndDoFailure %v = %#v, want false", methodName, got) 592 } 593 return resp, err 594 }) 595 } 596 597 func TestRepositoriesService_EnableVulnerabilityAlerts(t *testing.T) { 598 t.Parallel() 599 client, mux, _ := setup(t) 600 601 mux.HandleFunc("/repos/o/r/vulnerability-alerts", func(w http.ResponseWriter, r *http.Request) { 602 testMethod(t, r, "PUT") 603 testHeader(t, r, "Accept", mediaTypeRequiredVulnerabilityAlertsPreview) 604 605 w.WriteHeader(http.StatusNoContent) 606 }) 607 608 ctx := context.Background() 609 if _, err := client.Repositories.EnableVulnerabilityAlerts(ctx, "o", "r"); err != nil { 610 t.Errorf("Repositories.EnableVulnerabilityAlerts returned error: %v", err) 611 } 612 613 const methodName = "EnableVulnerabilityAlerts" 614 testBadOptions(t, methodName, func() (err error) { 615 _, err = client.Repositories.EnableVulnerabilityAlerts(ctx, "\n", "\n") 616 return err 617 }) 618 619 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 620 return client.Repositories.EnableVulnerabilityAlerts(ctx, "o", "r") 621 }) 622 } 623 624 func TestRepositoriesService_DisableVulnerabilityAlerts(t *testing.T) { 625 t.Parallel() 626 client, mux, _ := setup(t) 627 628 mux.HandleFunc("/repos/o/r/vulnerability-alerts", func(w http.ResponseWriter, r *http.Request) { 629 testMethod(t, r, "DELETE") 630 testHeader(t, r, "Accept", mediaTypeRequiredVulnerabilityAlertsPreview) 631 632 w.WriteHeader(http.StatusNoContent) 633 }) 634 635 ctx := context.Background() 636 if _, err := client.Repositories.DisableVulnerabilityAlerts(ctx, "o", "r"); err != nil { 637 t.Errorf("Repositories.DisableVulnerabilityAlerts returned error: %v", err) 638 } 639 640 const methodName = "DisableVulnerabilityAlerts" 641 testBadOptions(t, methodName, func() (err error) { 642 _, err = client.Repositories.DisableVulnerabilityAlerts(ctx, "\n", "\n") 643 return err 644 }) 645 646 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 647 return client.Repositories.DisableVulnerabilityAlerts(ctx, "o", "r") 648 }) 649 } 650 651 func TestRepositoriesService_EnableAutomatedSecurityFixes(t *testing.T) { 652 t.Parallel() 653 client, mux, _ := setup(t) 654 655 mux.HandleFunc("/repos/o/r/automated-security-fixes", func(w http.ResponseWriter, r *http.Request) { 656 testMethod(t, r, "PUT") 657 658 w.WriteHeader(http.StatusNoContent) 659 }) 660 661 ctx := context.Background() 662 if _, err := client.Repositories.EnableAutomatedSecurityFixes(ctx, "o", "r"); err != nil { 663 t.Errorf("Repositories.EnableAutomatedSecurityFixes returned error: %v", err) 664 } 665 } 666 667 func TestRepositoriesService_GetAutomatedSecurityFixes(t *testing.T) { 668 t.Parallel() 669 client, mux, _ := setup(t) 670 671 mux.HandleFunc("/repos/o/r/automated-security-fixes", func(w http.ResponseWriter, r *http.Request) { 672 testMethod(t, r, "GET") 673 fmt.Fprint(w, `{"enabled": true, "paused": false}`) 674 }) 675 676 ctx := context.Background() 677 fixes, _, err := client.Repositories.GetAutomatedSecurityFixes(ctx, "o", "r") 678 if err != nil { 679 t.Errorf("Repositories.GetAutomatedSecurityFixes returned error: %v", err) 680 } 681 682 want := &AutomatedSecurityFixes{ 683 Enabled: Ptr(true), 684 Paused: Ptr(false), 685 } 686 if !cmp.Equal(fixes, want) { 687 t.Errorf("Repositories.GetAutomatedSecurityFixes returned %#v, want %#v", fixes, want) 688 } 689 690 const methodName = "GetAutomatedSecurityFixes" 691 testBadOptions(t, methodName, func() (err error) { 692 _, _, err = client.Repositories.GetAutomatedSecurityFixes(ctx, "\n", "\n") 693 return err 694 }) 695 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 696 got, resp, err := client.Repositories.GetAutomatedSecurityFixes(ctx, "o", "r") 697 if got != nil { 698 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 699 } 700 return resp, err 701 }) 702 } 703 704 func TestRepositoriesService_DisableAutomatedSecurityFixes(t *testing.T) { 705 t.Parallel() 706 client, mux, _ := setup(t) 707 708 mux.HandleFunc("/repos/o/r/automated-security-fixes", func(w http.ResponseWriter, r *http.Request) { 709 testMethod(t, r, "DELETE") 710 711 w.WriteHeader(http.StatusNoContent) 712 }) 713 714 ctx := context.Background() 715 if _, err := client.Repositories.DisableAutomatedSecurityFixes(ctx, "o", "r"); err != nil { 716 t.Errorf("Repositories.DisableAutomatedSecurityFixes returned error: %v", err) 717 } 718 } 719 720 func TestRepositoriesService_ListContributors(t *testing.T) { 721 t.Parallel() 722 client, mux, _ := setup(t) 723 724 mux.HandleFunc("/repos/o/r/contributors", func(w http.ResponseWriter, r *http.Request) { 725 testMethod(t, r, "GET") 726 testFormValues(t, r, values{ 727 "anon": "true", 728 "page": "2", 729 }) 730 fmt.Fprint(w, `[{"contributions":42}]`) 731 }) 732 733 opts := &ListContributorsOptions{Anon: "true", ListOptions: ListOptions{Page: 2}} 734 ctx := context.Background() 735 contributors, _, err := client.Repositories.ListContributors(ctx, "o", "r", opts) 736 if err != nil { 737 t.Errorf("Repositories.ListContributors returned error: %v", err) 738 } 739 740 want := []*Contributor{{Contributions: Ptr(42)}} 741 if !cmp.Equal(contributors, want) { 742 t.Errorf("Repositories.ListContributors returned %+v, want %+v", contributors, want) 743 } 744 745 const methodName = "ListContributors" 746 testBadOptions(t, methodName, func() (err error) { 747 _, _, err = client.Repositories.ListContributors(ctx, "\n", "\n", opts) 748 return err 749 }) 750 751 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 752 got, resp, err := client.Repositories.ListContributors(ctx, "o", "r", opts) 753 if got != nil { 754 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 755 } 756 return resp, err 757 }) 758 } 759 760 func TestRepositoriesService_ListLanguages(t *testing.T) { 761 t.Parallel() 762 client, mux, _ := setup(t) 763 764 mux.HandleFunc("/repos/o/r/languages", func(w http.ResponseWriter, r *http.Request) { 765 testMethod(t, r, "GET") 766 fmt.Fprint(w, `{"go":1}`) 767 }) 768 769 ctx := context.Background() 770 languages, _, err := client.Repositories.ListLanguages(ctx, "o", "r") 771 if err != nil { 772 t.Errorf("Repositories.ListLanguages returned error: %v", err) 773 } 774 775 want := map[string]int{"go": 1} 776 if !cmp.Equal(languages, want) { 777 t.Errorf("Repositories.ListLanguages returned %+v, want %+v", languages, want) 778 } 779 780 const methodName = "ListLanguages" 781 testBadOptions(t, methodName, func() (err error) { 782 _, _, err = client.Repositories.ListLanguages(ctx, "\n", "\n") 783 return err 784 }) 785 786 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 787 got, resp, err := client.Repositories.ListLanguages(ctx, "o", "r") 788 if got != nil { 789 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 790 } 791 return resp, err 792 }) 793 } 794 795 func TestRepositoriesService_ListTeams(t *testing.T) { 796 t.Parallel() 797 client, mux, _ := setup(t) 798 799 mux.HandleFunc("/repos/o/r/teams", func(w http.ResponseWriter, r *http.Request) { 800 testMethod(t, r, "GET") 801 testFormValues(t, r, values{"page": "2"}) 802 fmt.Fprint(w, `[{"id":1}]`) 803 }) 804 805 opt := &ListOptions{Page: 2} 806 ctx := context.Background() 807 teams, _, err := client.Repositories.ListTeams(ctx, "o", "r", opt) 808 if err != nil { 809 t.Errorf("Repositories.ListTeams returned error: %v", err) 810 } 811 812 want := []*Team{{ID: Ptr(int64(1))}} 813 if !cmp.Equal(teams, want) { 814 t.Errorf("Repositories.ListTeams returned %+v, want %+v", teams, want) 815 } 816 817 const methodName = "ListTeams" 818 testBadOptions(t, methodName, func() (err error) { 819 _, _, err = client.Repositories.ListTeams(ctx, "\n", "\n", opt) 820 return err 821 }) 822 823 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 824 got, resp, err := client.Repositories.ListTeams(ctx, "o", "r", opt) 825 if got != nil { 826 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 827 } 828 return resp, err 829 }) 830 } 831 832 func TestRepositoriesService_ListTags(t *testing.T) { 833 t.Parallel() 834 client, mux, _ := setup(t) 835 836 mux.HandleFunc("/repos/o/r/tags", func(w http.ResponseWriter, r *http.Request) { 837 testMethod(t, r, "GET") 838 testFormValues(t, r, values{"page": "2"}) 839 fmt.Fprint(w, `[{"name":"n", "commit" : {"sha" : "s", "url" : "u"}, "zipball_url": "z", "tarball_url": "t"}]`) 840 }) 841 842 opt := &ListOptions{Page: 2} 843 ctx := context.Background() 844 tags, _, err := client.Repositories.ListTags(ctx, "o", "r", opt) 845 if err != nil { 846 t.Errorf("Repositories.ListTags returned error: %v", err) 847 } 848 849 want := []*RepositoryTag{ 850 { 851 Name: Ptr("n"), 852 Commit: &Commit{ 853 SHA: Ptr("s"), 854 URL: Ptr("u"), 855 }, 856 ZipballURL: Ptr("z"), 857 TarballURL: Ptr("t"), 858 }, 859 } 860 if !cmp.Equal(tags, want) { 861 t.Errorf("Repositories.ListTags returned %+v, want %+v", tags, want) 862 } 863 864 const methodName = "ListTags" 865 testBadOptions(t, methodName, func() (err error) { 866 _, _, err = client.Repositories.ListTags(ctx, "\n", "\n", opt) 867 return err 868 }) 869 870 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 871 got, resp, err := client.Repositories.ListTags(ctx, "o", "r", opt) 872 if got != nil { 873 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 874 } 875 return resp, err 876 }) 877 } 878 879 func TestRepositoriesService_ListBranches(t *testing.T) { 880 t.Parallel() 881 client, mux, _ := setup(t) 882 883 mux.HandleFunc("/repos/o/r/branches", func(w http.ResponseWriter, r *http.Request) { 884 testMethod(t, r, "GET") 885 testFormValues(t, r, values{"page": "2"}) 886 fmt.Fprint(w, `[{"name":"master", "commit" : {"sha" : "a57781", "url" : "https://api.github.com/repos/o/r/commits/a57781"}}]`) 887 }) 888 889 opt := &BranchListOptions{ 890 Protected: nil, 891 ListOptions: ListOptions{Page: 2}, 892 } 893 ctx := context.Background() 894 branches, _, err := client.Repositories.ListBranches(ctx, "o", "r", opt) 895 if err != nil { 896 t.Errorf("Repositories.ListBranches returned error: %v", err) 897 } 898 899 want := []*Branch{{Name: Ptr("master"), Commit: &RepositoryCommit{SHA: Ptr("a57781"), URL: Ptr("https://api.github.com/repos/o/r/commits/a57781")}}} 900 if !cmp.Equal(branches, want) { 901 t.Errorf("Repositories.ListBranches returned %+v, want %+v", branches, want) 902 } 903 904 const methodName = "ListBranches" 905 testBadOptions(t, methodName, func() (err error) { 906 _, _, err = client.Repositories.ListBranches(ctx, "\n", "\n", opt) 907 return err 908 }) 909 910 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 911 got, resp, err := client.Repositories.ListBranches(ctx, "o", "r", opt) 912 if got != nil { 913 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 914 } 915 return resp, err 916 }) 917 } 918 919 func TestRepositoriesService_GetBranch(t *testing.T) { 920 t.Parallel() 921 client, mux, _ := setup(t) 922 923 tests := []struct { 924 branch string 925 urlPath string 926 }{ 927 {branch: "b", urlPath: "/repos/o/r/branches/b"}, 928 {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat%2fbranch-50%25"}, 929 } 930 931 for _, test := range tests { 932 mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { 933 testMethod(t, r, "GET") 934 fmt.Fprint(w, `{"name":"n", "commit":{"sha":"s","commit":{"message":"m"}}, "protected":true, "protection":{"required_status_checks":{"contexts":["c"]}}}`) 935 }) 936 937 ctx := context.Background() 938 branch, _, err := client.Repositories.GetBranch(ctx, "o", "r", test.branch, 0) 939 if err != nil { 940 t.Errorf("Repositories.GetBranch returned error: %v", err) 941 } 942 943 want := &Branch{ 944 Name: Ptr("n"), 945 Commit: &RepositoryCommit{ 946 SHA: Ptr("s"), 947 Commit: &Commit{ 948 Message: Ptr("m"), 949 }, 950 }, 951 Protected: Ptr(true), 952 Protection: &Protection{ 953 RequiredStatusChecks: &RequiredStatusChecks{ 954 Contexts: &[]string{"c"}, 955 }, 956 }, 957 } 958 959 if !cmp.Equal(branch, want) { 960 t.Errorf("Repositories.GetBranch returned %+v, want %+v", branch, want) 961 } 962 963 const methodName = "GetBranch" 964 testBadOptions(t, methodName, func() (err error) { 965 _, _, err = client.Repositories.GetBranch(ctx, "\n", "\n", "\n", 0) 966 return err 967 }) 968 } 969 } 970 971 func TestRepositoriesService_GetBranch_BadJSONResponse(t *testing.T) { 972 t.Parallel() 973 tests := []struct { 974 branch string 975 urlPath string 976 }{ 977 {branch: "b", urlPath: "/repos/o/r/branches/b"}, 978 {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat%2fbranch-50%25"}, 979 } 980 981 for _, test := range tests { 982 t.Run(test.branch, func(t *testing.T) { 983 t.Parallel() 984 client, mux, _ := setup(t) 985 986 mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { 987 testMethod(t, r, "GET") 988 fmt.Fprint(w, `{"name":"n", "commit":{"sha":...truncated`) 989 }) 990 991 ctx := context.Background() 992 if _, _, err := client.Repositories.GetBranch(ctx, "o", "r", test.branch, 0); err == nil { 993 t.Error("Repositories.GetBranch returned no error; wanted JSON error") 994 } 995 }) 996 } 997 } 998 999 func TestRepositoriesService_GetBranch_StatusMovedPermanently_followRedirects(t *testing.T) { 1000 t.Parallel() 1001 client, mux, serverURL := setup(t) 1002 1003 mux.HandleFunc("/repos/o/r/branches/b", func(w http.ResponseWriter, r *http.Request) { 1004 testMethod(t, r, "GET") 1005 redirectURL, _ := url.Parse(serverURL + baseURLPath + "/repos/o/r/branches/br") 1006 http.Redirect(w, r, redirectURL.String(), http.StatusMovedPermanently) 1007 }) 1008 mux.HandleFunc("/repos/o/r/branches/br", func(w http.ResponseWriter, r *http.Request) { 1009 testMethod(t, r, "GET") 1010 fmt.Fprint(w, `{"name":"n", "commit":{"sha":"s","commit":{"message":"m"}}, "protected":true, "protection":{"required_status_checks":{"contexts":["c"]}}}`) 1011 }) 1012 ctx := context.Background() 1013 branch, resp, err := client.Repositories.GetBranch(ctx, "o", "r", "b", 1) 1014 if err != nil { 1015 t.Errorf("Repositories.GetBranch returned error: %v", err) 1016 } 1017 if resp.StatusCode != http.StatusOK { 1018 t.Errorf("Repositories.GetBranch returned status: %d, want %d", resp.StatusCode, http.StatusOK) 1019 } 1020 1021 want := &Branch{ 1022 Name: Ptr("n"), 1023 Commit: &RepositoryCommit{ 1024 SHA: Ptr("s"), 1025 Commit: &Commit{ 1026 Message: Ptr("m"), 1027 }, 1028 }, 1029 Protected: Ptr(true), 1030 Protection: &Protection{ 1031 RequiredStatusChecks: &RequiredStatusChecks{ 1032 Contexts: &[]string{"c"}, 1033 }, 1034 }, 1035 } 1036 if !cmp.Equal(branch, want) { 1037 t.Errorf("Repositories.GetBranch returned %+v, want %+v", branch, want) 1038 } 1039 } 1040 1041 func TestRepositoriesService_GetBranch_notFound(t *testing.T) { 1042 t.Parallel() 1043 tests := []struct { 1044 branch string 1045 urlPath string 1046 }{ 1047 {branch: "b", urlPath: "/repos/o/r/branches/b"}, 1048 {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat-branch-50%"}, 1049 } 1050 1051 for _, test := range tests { 1052 t.Run(test.branch, func(t *testing.T) { 1053 t.Parallel() 1054 client, mux, _ := setup(t) 1055 1056 mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { 1057 testMethod(t, r, "GET") 1058 http.Error(w, "branch not found", http.StatusNotFound) 1059 }) 1060 ctx := context.Background() 1061 _, resp, err := client.Repositories.GetBranch(ctx, "o", "r", test.branch, 1) 1062 if err == nil { 1063 t.Error("Repositories.GetBranch returned error: nil") 1064 } 1065 if resp.StatusCode != http.StatusNotFound { 1066 t.Errorf("Repositories.GetBranch returned status: %d, want %d", resp.StatusCode, http.StatusNotFound) 1067 } 1068 1069 // Add custom round tripper 1070 client.client.Transport = roundTripperFunc(func(*http.Request) (*http.Response, error) { 1071 return nil, errors.New("failed to get branch") 1072 }) 1073 1074 const methodName = "GetBranch" 1075 testBadOptions(t, methodName, func() (err error) { 1076 _, _, err = client.Repositories.GetBranch(ctx, "\n", "\n", "\n", 1) 1077 return err 1078 }) 1079 }) 1080 } 1081 } 1082 1083 func TestRepositoriesService_RenameBranch(t *testing.T) { 1084 t.Parallel() 1085 tests := []struct { 1086 branch string 1087 urlPath string 1088 }{ 1089 {branch: "b", urlPath: "/repos/o/r/branches/b/rename"}, 1090 {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat%2fbranch-50%25/rename"}, 1091 } 1092 1093 for _, test := range tests { 1094 t.Run(test.branch, func(t *testing.T) { 1095 t.Parallel() 1096 client, mux, _ := setup(t) 1097 1098 renameBranchReq := "nn" 1099 1100 mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { 1101 v := new(renameBranchRequest) 1102 assertNilError(t, json.NewDecoder(r.Body).Decode(v)) 1103 1104 testMethod(t, r, "POST") 1105 want := &renameBranchRequest{NewName: renameBranchReq} 1106 if !cmp.Equal(v, want) { 1107 t.Errorf("Request body = %+v, want %+v", v, want) 1108 } 1109 1110 fmt.Fprint(w, `{"protected":true,"name":"nn"}`) 1111 }) 1112 1113 ctx := context.Background() 1114 got, _, err := client.Repositories.RenameBranch(ctx, "o", "r", test.branch, renameBranchReq) 1115 if err != nil { 1116 t.Errorf("Repositories.RenameBranch returned error: %v", err) 1117 } 1118 1119 want := &Branch{Name: Ptr("nn"), Protected: Ptr(true)} 1120 if !cmp.Equal(got, want) { 1121 t.Errorf("Repositories.RenameBranch returned %+v, want %+v", got, want) 1122 } 1123 1124 const methodName = "RenameBranch" 1125 testBadOptions(t, methodName, func() (err error) { 1126 _, _, err = client.Repositories.RenameBranch(ctx, "\n", "\n", "\n", renameBranchReq) 1127 return err 1128 }) 1129 1130 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 1131 got, resp, err := client.Repositories.RenameBranch(ctx, "o", "r", test.branch, renameBranchReq) 1132 if got != nil { 1133 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 1134 } 1135 return resp, err 1136 }) 1137 }) 1138 } 1139 } 1140 1141 func TestRepositoriesService_GetBranchProtection(t *testing.T) { 1142 t.Parallel() 1143 tests := []struct { 1144 branch string 1145 urlPath string 1146 enforceAdminsURLPath string 1147 }{ 1148 {branch: "b", urlPath: "/repos/o/r/branches/b/protection", enforceAdminsURLPath: "/repos/o/r/branches/b/protection/enforce_admins"}, 1149 {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat%2fbranch-50%25/protection", enforceAdminsURLPath: "/repos/o/r/branches/feat%2fbranch-50%25/protection/enforce_admins"}, 1150 } 1151 1152 for _, test := range tests { 1153 t.Run(test.branch, func(t *testing.T) { 1154 t.Parallel() 1155 client, mux, _ := setup(t) 1156 1157 mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { 1158 testMethod(t, r, "GET") 1159 // TODO: remove custom Accept header when this API fully launches 1160 testHeader(t, r, "Accept", mediaTypeRequiredApprovingReviewsPreview) 1161 fmt.Fprintf(w, `{ 1162 "required_status_checks":{ 1163 "strict":true, 1164 "contexts":["continuous-integration"], 1165 "checks": [ 1166 { 1167 "context": "continuous-integration", 1168 "app_id": null 1169 } 1170 ] 1171 }, 1172 "required_pull_request_reviews":{ 1173 "dismissal_restrictions":{ 1174 "users":[{ 1175 "id":3, 1176 "login":"u" 1177 }], 1178 "teams":[{ 1179 "id":4, 1180 "slug":"t" 1181 }], 1182 "apps":[{ 1183 "id":5, 1184 "slug":"a" 1185 }] 1186 }, 1187 "dismiss_stale_reviews":true, 1188 "require_code_owner_reviews":true, 1189 "require_last_push_approval":false, 1190 "required_approving_review_count":1 1191 }, 1192 "enforce_admins":{ 1193 "url":"%s", 1194 "enabled":true 1195 }, 1196 "restrictions":{ 1197 "users":[{"id":1,"login":"u"}], 1198 "teams":[{"id":2,"slug":"t"}], 1199 "apps":[{"id":3,"slug":"a"}] 1200 }, 1201 "required_conversation_resolution": { 1202 "enabled": true 1203 }, 1204 "block_creations": { 1205 "enabled": false 1206 }, 1207 "lock_branch": { 1208 "enabled": false 1209 }, 1210 "allow_fork_syncing": { 1211 "enabled": false 1212 } 1213 }`, test.enforceAdminsURLPath) 1214 }) 1215 1216 ctx := context.Background() 1217 protection, _, err := client.Repositories.GetBranchProtection(ctx, "o", "r", test.branch) 1218 if err != nil { 1219 t.Errorf("Repositories.GetBranchProtection returned error: %v", err) 1220 } 1221 1222 want := &Protection{ 1223 RequiredStatusChecks: &RequiredStatusChecks{ 1224 Strict: true, 1225 Contexts: &[]string{"continuous-integration"}, 1226 Checks: &[]*RequiredStatusCheck{ 1227 { 1228 Context: "continuous-integration", 1229 }, 1230 }, 1231 }, 1232 RequiredPullRequestReviews: &PullRequestReviewsEnforcement{ 1233 DismissStaleReviews: true, 1234 DismissalRestrictions: &DismissalRestrictions{ 1235 Users: []*User{ 1236 {Login: Ptr("u"), ID: Ptr(int64(3))}, 1237 }, 1238 Teams: []*Team{ 1239 {Slug: Ptr("t"), ID: Ptr(int64(4))}, 1240 }, 1241 Apps: []*App{ 1242 {Slug: Ptr("a"), ID: Ptr(int64(5))}, 1243 }, 1244 }, 1245 RequireCodeOwnerReviews: true, 1246 RequiredApprovingReviewCount: 1, 1247 RequireLastPushApproval: false, 1248 }, 1249 EnforceAdmins: &AdminEnforcement{ 1250 URL: Ptr(test.enforceAdminsURLPath), 1251 Enabled: true, 1252 }, 1253 Restrictions: &BranchRestrictions{ 1254 Users: []*User{ 1255 {Login: Ptr("u"), ID: Ptr(int64(1))}, 1256 }, 1257 Teams: []*Team{ 1258 {Slug: Ptr("t"), ID: Ptr(int64(2))}, 1259 }, 1260 Apps: []*App{ 1261 {Slug: Ptr("a"), ID: Ptr(int64(3))}, 1262 }, 1263 }, 1264 RequiredConversationResolution: &RequiredConversationResolution{ 1265 Enabled: true, 1266 }, 1267 BlockCreations: &BlockCreations{ 1268 Enabled: Ptr(false), 1269 }, 1270 LockBranch: &LockBranch{ 1271 Enabled: Ptr(false), 1272 }, 1273 AllowForkSyncing: &AllowForkSyncing{ 1274 Enabled: Ptr(false), 1275 }, 1276 } 1277 if !cmp.Equal(protection, want) { 1278 t.Errorf("Repositories.GetBranchProtection returned %+v, want %+v", protection, want) 1279 } 1280 1281 const methodName = "GetBranchProtection" 1282 testBadOptions(t, methodName, func() (err error) { 1283 _, _, err = client.Repositories.GetBranchProtection(ctx, "\n", "\n", "\n") 1284 return err 1285 }) 1286 1287 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 1288 got, resp, err := client.Repositories.GetBranchProtection(ctx, "o", "r", test.branch) 1289 if got != nil { 1290 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 1291 } 1292 return resp, err 1293 }) 1294 }) 1295 } 1296 } 1297 1298 func TestRepositoriesService_GetBranchProtection_noDismissalRestrictions(t *testing.T) { 1299 t.Parallel() 1300 client, mux, _ := setup(t) 1301 1302 tests := []struct { 1303 branch string 1304 urlPath string 1305 enforceAdminsURLPath string 1306 }{ 1307 {branch: "b", urlPath: "/repos/o/r/branches/b/protection", enforceAdminsURLPath: "/repos/o/r/branches/b/protection/enforce_admins"}, 1308 {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat%2fbranch-50%25/protection", enforceAdminsURLPath: "/repos/o/r/branches/feat%2fbranch-50%25/protection/enforce_admins"}, 1309 } 1310 1311 for _, test := range tests { 1312 mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { 1313 testMethod(t, r, "GET") 1314 // TODO: remove custom Accept header when this API fully launches 1315 testHeader(t, r, "Accept", mediaTypeRequiredApprovingReviewsPreview) 1316 fmt.Fprintf(w, `{ 1317 "required_status_checks":{ 1318 "strict":true, 1319 "contexts":["continuous-integration"], 1320 "checks": [ 1321 { 1322 "context": "continuous-integration", 1323 "app_id": null 1324 } 1325 ] 1326 }, 1327 "required_pull_request_reviews":{ 1328 "dismiss_stale_reviews":true, 1329 "require_code_owner_reviews":true, 1330 "required_approving_review_count":1 1331 }, 1332 "enforce_admins":{ 1333 "url":"%s", 1334 "enabled":true 1335 }, 1336 "restrictions":{ 1337 "users":[{"id":1,"login":"u"}], 1338 "teams":[{"id":2,"slug":"t"}] 1339 } 1340 }`, test.enforceAdminsURLPath) 1341 }) 1342 1343 ctx := context.Background() 1344 protection, _, err := client.Repositories.GetBranchProtection(ctx, "o", "r", test.branch) 1345 if err != nil { 1346 t.Errorf("Repositories.GetBranchProtection returned error: %v", err) 1347 } 1348 1349 want := &Protection{ 1350 RequiredStatusChecks: &RequiredStatusChecks{ 1351 Strict: true, 1352 Contexts: &[]string{"continuous-integration"}, 1353 Checks: &[]*RequiredStatusCheck{ 1354 { 1355 Context: "continuous-integration", 1356 }, 1357 }, 1358 }, 1359 RequiredPullRequestReviews: &PullRequestReviewsEnforcement{ 1360 DismissStaleReviews: true, 1361 DismissalRestrictions: nil, 1362 RequireCodeOwnerReviews: true, 1363 RequiredApprovingReviewCount: 1, 1364 }, 1365 EnforceAdmins: &AdminEnforcement{ 1366 URL: Ptr(test.enforceAdminsURLPath), 1367 Enabled: true, 1368 }, 1369 Restrictions: &BranchRestrictions{ 1370 Users: []*User{ 1371 {Login: Ptr("u"), ID: Ptr(int64(1))}, 1372 }, 1373 Teams: []*Team{ 1374 {Slug: Ptr("t"), ID: Ptr(int64(2))}, 1375 }, 1376 }, 1377 } 1378 if !cmp.Equal(protection, want) { 1379 t.Errorf("Repositories.GetBranchProtection returned %+v, want %+v", protection, want) 1380 } 1381 } 1382 } 1383 1384 func TestRepositoriesService_GetBranchProtection_branchNotProtected(t *testing.T) { 1385 t.Parallel() 1386 tests := []struct { 1387 branch string 1388 urlPath string 1389 }{ 1390 {branch: "b", urlPath: "/repos/o/r/branches/b/protection"}, 1391 {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat%2fbranch-50%25/protection"}, 1392 } 1393 1394 for _, test := range tests { 1395 t.Run(test.branch, func(t *testing.T) { 1396 t.Parallel() 1397 client, mux, _ := setup(t) 1398 1399 mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { 1400 testMethod(t, r, "GET") 1401 1402 w.WriteHeader(http.StatusBadRequest) 1403 fmt.Fprintf(w, `{ 1404 "message": %q, 1405 "documentation_url": "https://docs.github.com/rest/repos#get-branch-protection" 1406 }`, githubBranchNotProtected) 1407 }) 1408 1409 ctx := context.Background() 1410 protection, _, err := client.Repositories.GetBranchProtection(ctx, "o", "r", test.branch) 1411 1412 if protection != nil { 1413 t.Error("Repositories.GetBranchProtection returned non-nil protection data") 1414 } 1415 1416 if err != ErrBranchNotProtected { 1417 t.Errorf("Repositories.GetBranchProtection returned an invalid error: %v", err) 1418 } 1419 }) 1420 } 1421 } 1422 1423 func TestRepositoriesService_UpdateBranchProtection_Contexts(t *testing.T) { 1424 t.Parallel() 1425 tests := []struct { 1426 branch string 1427 urlPath string 1428 }{ 1429 {branch: "b", urlPath: "/repos/o/r/branches/b/protection"}, 1430 {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat%2fbranch-50%25/protection"}, 1431 } 1432 1433 for _, test := range tests { 1434 t.Run(test.branch, func(t *testing.T) { 1435 t.Parallel() 1436 client, mux, _ := setup(t) 1437 1438 input := &ProtectionRequest{ 1439 RequiredStatusChecks: &RequiredStatusChecks{ 1440 Strict: true, 1441 Contexts: &[]string{"continuous-integration"}, 1442 }, 1443 RequiredPullRequestReviews: &PullRequestReviewsEnforcementRequest{ 1444 DismissStaleReviews: true, 1445 DismissalRestrictionsRequest: &DismissalRestrictionsRequest{ 1446 Users: &[]string{"uu"}, 1447 Teams: &[]string{"tt"}, 1448 Apps: &[]string{"aa"}, 1449 }, 1450 BypassPullRequestAllowancesRequest: &BypassPullRequestAllowancesRequest{ 1451 Users: []string{"uuu"}, 1452 Teams: []string{"ttt"}, 1453 Apps: []string{"aaa"}, 1454 }, 1455 }, 1456 Restrictions: &BranchRestrictionsRequest{ 1457 Users: []string{"u"}, 1458 Teams: []string{"t"}, 1459 Apps: []string{"a"}, 1460 }, 1461 BlockCreations: Ptr(true), 1462 LockBranch: Ptr(true), 1463 AllowForkSyncing: Ptr(true), 1464 } 1465 1466 mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { 1467 v := new(ProtectionRequest) 1468 assertNilError(t, json.NewDecoder(r.Body).Decode(v)) 1469 1470 testMethod(t, r, "PUT") 1471 if !cmp.Equal(v, input) { 1472 t.Errorf("Request body = %+v, want %+v", v, input) 1473 } 1474 1475 // TODO: remove custom Accept header when this API fully launches 1476 testHeader(t, r, "Accept", mediaTypeRequiredApprovingReviewsPreview) 1477 fmt.Fprint(w, `{ 1478 "required_status_checks":{ 1479 "strict":true, 1480 "contexts":["continuous-integration"], 1481 "checks": [ 1482 { 1483 "context": "continuous-integration", 1484 "app_id": null 1485 } 1486 ] 1487 }, 1488 "required_pull_request_reviews":{ 1489 "dismissal_restrictions":{ 1490 "users":[{ 1491 "id":3, 1492 "login":"uu" 1493 }], 1494 "teams":[{ 1495 "id":4, 1496 "slug":"tt" 1497 }], 1498 "apps":[{ 1499 "id":5, 1500 "slug":"aa" 1501 }] 1502 }, 1503 "dismiss_stale_reviews":true, 1504 "require_code_owner_reviews":true, 1505 "bypass_pull_request_allowances": { 1506 "users":[{"id":10,"login":"uuu"}], 1507 "teams":[{"id":20,"slug":"ttt"}], 1508 "apps":[{"id":30,"slug":"aaa"}] 1509 } 1510 }, 1511 "restrictions":{ 1512 "users":[{"id":1,"login":"u"}], 1513 "teams":[{"id":2,"slug":"t"}], 1514 "apps":[{"id":3,"slug":"a"}] 1515 }, 1516 "block_creations": { 1517 "enabled": true 1518 }, 1519 "lock_branch": { 1520 "enabled": true 1521 }, 1522 "allow_fork_syncing": { 1523 "enabled": true 1524 } 1525 }`) 1526 }) 1527 1528 ctx := context.Background() 1529 protection, _, err := client.Repositories.UpdateBranchProtection(ctx, "o", "r", test.branch, input) 1530 if err != nil { 1531 t.Errorf("Repositories.UpdateBranchProtection returned error: %v", err) 1532 } 1533 1534 want := &Protection{ 1535 RequiredStatusChecks: &RequiredStatusChecks{ 1536 Strict: true, 1537 Contexts: &[]string{"continuous-integration"}, 1538 Checks: &[]*RequiredStatusCheck{ 1539 { 1540 Context: "continuous-integration", 1541 }, 1542 }, 1543 }, 1544 RequiredPullRequestReviews: &PullRequestReviewsEnforcement{ 1545 DismissStaleReviews: true, 1546 DismissalRestrictions: &DismissalRestrictions{ 1547 Users: []*User{ 1548 {Login: Ptr("uu"), ID: Ptr(int64(3))}, 1549 }, 1550 Teams: []*Team{ 1551 {Slug: Ptr("tt"), ID: Ptr(int64(4))}, 1552 }, 1553 Apps: []*App{ 1554 {Slug: Ptr("aa"), ID: Ptr(int64(5))}, 1555 }, 1556 }, 1557 RequireCodeOwnerReviews: true, 1558 BypassPullRequestAllowances: &BypassPullRequestAllowances{ 1559 Users: []*User{ 1560 {Login: Ptr("uuu"), ID: Ptr(int64(10))}, 1561 }, 1562 Teams: []*Team{ 1563 {Slug: Ptr("ttt"), ID: Ptr(int64(20))}, 1564 }, 1565 Apps: []*App{ 1566 {Slug: Ptr("aaa"), ID: Ptr(int64(30))}, 1567 }, 1568 }, 1569 }, 1570 Restrictions: &BranchRestrictions{ 1571 Users: []*User{ 1572 {Login: Ptr("u"), ID: Ptr(int64(1))}, 1573 }, 1574 Teams: []*Team{ 1575 {Slug: Ptr("t"), ID: Ptr(int64(2))}, 1576 }, 1577 Apps: []*App{ 1578 {Slug: Ptr("a"), ID: Ptr(int64(3))}, 1579 }, 1580 }, 1581 BlockCreations: &BlockCreations{ 1582 Enabled: Ptr(true), 1583 }, 1584 LockBranch: &LockBranch{ 1585 Enabled: Ptr(true), 1586 }, 1587 AllowForkSyncing: &AllowForkSyncing{ 1588 Enabled: Ptr(true), 1589 }, 1590 } 1591 if !cmp.Equal(protection, want) { 1592 t.Errorf("Repositories.UpdateBranchProtection returned %+v, want %+v", protection, want) 1593 } 1594 1595 const methodName = "UpdateBranchProtection" 1596 testBadOptions(t, methodName, func() (err error) { 1597 _, _, err = client.Repositories.UpdateBranchProtection(ctx, "\n", "\n", "\n", input) 1598 return err 1599 }) 1600 1601 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 1602 got, resp, err := client.Repositories.UpdateBranchProtection(ctx, "o", "r", test.branch, input) 1603 if got != nil { 1604 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 1605 } 1606 return resp, err 1607 }) 1608 }) 1609 } 1610 } 1611 1612 func TestRepositoriesService_UpdateBranchProtection_EmptyContexts(t *testing.T) { 1613 t.Parallel() 1614 tests := []struct { 1615 branch string 1616 urlPath string 1617 }{ 1618 {branch: "b", urlPath: "/repos/o/r/branches/b/protection"}, 1619 {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat%2fbranch-50%25/protection"}, 1620 } 1621 1622 for _, test := range tests { 1623 t.Run(test.branch, func(t *testing.T) { 1624 t.Parallel() 1625 client, mux, _ := setup(t) 1626 1627 input := &ProtectionRequest{ 1628 RequiredStatusChecks: &RequiredStatusChecks{ 1629 Strict: true, 1630 Contexts: &[]string{}, 1631 }, 1632 RequiredPullRequestReviews: &PullRequestReviewsEnforcementRequest{ 1633 DismissStaleReviews: true, 1634 DismissalRestrictionsRequest: &DismissalRestrictionsRequest{ 1635 Users: &[]string{"uu"}, 1636 Teams: &[]string{"tt"}, 1637 Apps: &[]string{"aa"}, 1638 }, 1639 BypassPullRequestAllowancesRequest: &BypassPullRequestAllowancesRequest{ 1640 Users: []string{"uuu"}, 1641 Teams: []string{"ttt"}, 1642 Apps: []string{"aaa"}, 1643 }, 1644 }, 1645 Restrictions: &BranchRestrictionsRequest{ 1646 Users: []string{"u"}, 1647 Teams: []string{"t"}, 1648 Apps: []string{"a"}, 1649 }, 1650 BlockCreations: Ptr(true), 1651 LockBranch: Ptr(true), 1652 AllowForkSyncing: Ptr(true), 1653 } 1654 1655 mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { 1656 v := new(ProtectionRequest) 1657 assertNilError(t, json.NewDecoder(r.Body).Decode(v)) 1658 1659 testMethod(t, r, "PUT") 1660 if !cmp.Equal(v, input) { 1661 t.Errorf("Request body = %+v, want %+v", v, input) 1662 } 1663 1664 // TODO: remove custom Accept header when this API fully launches 1665 testHeader(t, r, "Accept", mediaTypeRequiredApprovingReviewsPreview) 1666 fmt.Fprint(w, `{ 1667 "required_status_checks":{ 1668 "strict":true, 1669 "contexts":[], 1670 "checks": null 1671 }, 1672 "required_pull_request_reviews":{ 1673 "dismissal_restrictions":{ 1674 "users":[{ 1675 "id":3, 1676 "login":"uu" 1677 }], 1678 "teams":[{ 1679 "id":4, 1680 "slug":"tt" 1681 }], 1682 "apps":[{ 1683 "id":5, 1684 "slug":"aa" 1685 }] 1686 }, 1687 "dismiss_stale_reviews":true, 1688 "require_code_owner_reviews":true, 1689 "bypass_pull_request_allowances": { 1690 "users":[{"id":10,"login":"uuu"}], 1691 "teams":[{"id":20,"slug":"ttt"}], 1692 "apps":[{"id":30,"slug":"aaa"}] 1693 } 1694 }, 1695 "restrictions":{ 1696 "users":[{"id":1,"login":"u"}], 1697 "teams":[{"id":2,"slug":"t"}], 1698 "apps":[{"id":3,"slug":"a"}] 1699 }, 1700 "block_creations": { 1701 "enabled": true 1702 }, 1703 "lock_branch": { 1704 "enabled": true 1705 }, 1706 "allow_fork_syncing": { 1707 "enabled": true 1708 } 1709 }`) 1710 }) 1711 1712 ctx := context.Background() 1713 protection, _, err := client.Repositories.UpdateBranchProtection(ctx, "o", "r", test.branch, input) 1714 if err != nil { 1715 t.Errorf("Repositories.UpdateBranchProtection returned error: %v", err) 1716 } 1717 1718 want := &Protection{ 1719 RequiredStatusChecks: &RequiredStatusChecks{ 1720 Strict: true, 1721 Contexts: &[]string{}, 1722 }, 1723 RequiredPullRequestReviews: &PullRequestReviewsEnforcement{ 1724 DismissStaleReviews: true, 1725 DismissalRestrictions: &DismissalRestrictions{ 1726 Users: []*User{ 1727 {Login: Ptr("uu"), ID: Ptr(int64(3))}, 1728 }, 1729 Teams: []*Team{ 1730 {Slug: Ptr("tt"), ID: Ptr(int64(4))}, 1731 }, 1732 Apps: []*App{ 1733 {Slug: Ptr("aa"), ID: Ptr(int64(5))}, 1734 }, 1735 }, 1736 RequireCodeOwnerReviews: true, 1737 BypassPullRequestAllowances: &BypassPullRequestAllowances{ 1738 Users: []*User{ 1739 {Login: Ptr("uuu"), ID: Ptr(int64(10))}, 1740 }, 1741 Teams: []*Team{ 1742 {Slug: Ptr("ttt"), ID: Ptr(int64(20))}, 1743 }, 1744 Apps: []*App{ 1745 {Slug: Ptr("aaa"), ID: Ptr(int64(30))}, 1746 }, 1747 }, 1748 }, 1749 Restrictions: &BranchRestrictions{ 1750 Users: []*User{ 1751 {Login: Ptr("u"), ID: Ptr(int64(1))}, 1752 }, 1753 Teams: []*Team{ 1754 {Slug: Ptr("t"), ID: Ptr(int64(2))}, 1755 }, 1756 Apps: []*App{ 1757 {Slug: Ptr("a"), ID: Ptr(int64(3))}, 1758 }, 1759 }, 1760 BlockCreations: &BlockCreations{ 1761 Enabled: Ptr(true), 1762 }, 1763 LockBranch: &LockBranch{ 1764 Enabled: Ptr(true), 1765 }, 1766 AllowForkSyncing: &AllowForkSyncing{ 1767 Enabled: Ptr(true), 1768 }, 1769 } 1770 if !cmp.Equal(protection, want) { 1771 t.Errorf("Repositories.UpdateBranchProtection returned %+v, want %+v", protection, want) 1772 } 1773 1774 const methodName = "UpdateBranchProtection" 1775 testBadOptions(t, methodName, func() (err error) { 1776 _, _, err = client.Repositories.UpdateBranchProtection(ctx, "\n", "\n", "\n", input) 1777 return err 1778 }) 1779 1780 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 1781 got, resp, err := client.Repositories.UpdateBranchProtection(ctx, "o", "r", test.branch, input) 1782 if got != nil { 1783 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 1784 } 1785 return resp, err 1786 }) 1787 }) 1788 } 1789 } 1790 1791 func TestRepositoriesService_UpdateBranchProtection_Checks(t *testing.T) { 1792 t.Parallel() 1793 tests := []struct { 1794 branch string 1795 urlPath string 1796 }{ 1797 {branch: "b", urlPath: "/repos/o/r/branches/b/protection"}, 1798 {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat%2fbranch-50%25/protection"}, 1799 } 1800 1801 for _, test := range tests { 1802 t.Run(test.branch, func(t *testing.T) { 1803 t.Parallel() 1804 client, mux, _ := setup(t) 1805 1806 input := &ProtectionRequest{ 1807 RequiredStatusChecks: &RequiredStatusChecks{ 1808 Strict: true, 1809 Checks: &[]*RequiredStatusCheck{ 1810 { 1811 Context: "continuous-integration", 1812 }, 1813 }, 1814 }, 1815 RequiredPullRequestReviews: &PullRequestReviewsEnforcementRequest{ 1816 DismissStaleReviews: true, 1817 DismissalRestrictionsRequest: &DismissalRestrictionsRequest{ 1818 Users: &[]string{"uu"}, 1819 Teams: &[]string{"tt"}, 1820 Apps: &[]string{"aa"}, 1821 }, 1822 BypassPullRequestAllowancesRequest: &BypassPullRequestAllowancesRequest{ 1823 Users: []string{"uuu"}, 1824 Teams: []string{"ttt"}, 1825 Apps: []string{"aaa"}, 1826 }, 1827 }, 1828 Restrictions: &BranchRestrictionsRequest{ 1829 Users: []string{"u"}, 1830 Teams: []string{"t"}, 1831 Apps: []string{"a"}, 1832 }, 1833 } 1834 1835 mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { 1836 v := new(ProtectionRequest) 1837 assertNilError(t, json.NewDecoder(r.Body).Decode(v)) 1838 1839 testMethod(t, r, "PUT") 1840 if !cmp.Equal(v, input) { 1841 t.Errorf("Request body = %+v, want %+v", v, input) 1842 } 1843 1844 // TODO: remove custom Accept header when this API fully launches 1845 testHeader(t, r, "Accept", mediaTypeRequiredApprovingReviewsPreview) 1846 fmt.Fprint(w, `{ 1847 "required_status_checks":{ 1848 "strict":true, 1849 "contexts":["continuous-integration"], 1850 "checks": [ 1851 { 1852 "context": "continuous-integration", 1853 "app_id": null 1854 } 1855 ] 1856 }, 1857 "required_pull_request_reviews":{ 1858 "dismissal_restrictions":{ 1859 "users":[{ 1860 "id":3, 1861 "login":"uu" 1862 }], 1863 "teams":[{ 1864 "id":4, 1865 "slug":"tt" 1866 }], 1867 "apps":[{ 1868 "id":5, 1869 "slug":"aa" 1870 }] 1871 }, 1872 "dismiss_stale_reviews":true, 1873 "require_code_owner_reviews":true, 1874 "bypass_pull_request_allowances": { 1875 "users":[{"id":10,"login":"uuu"}], 1876 "teams":[{"id":20,"slug":"ttt"}], 1877 "apps":[{"id":30,"slug":"aaa"}] 1878 } 1879 }, 1880 "restrictions":{ 1881 "users":[{"id":1,"login":"u"}], 1882 "teams":[{"id":2,"slug":"t"}], 1883 "apps":[{"id":3,"slug":"a"}] 1884 } 1885 }`) 1886 }) 1887 1888 ctx := context.Background() 1889 protection, _, err := client.Repositories.UpdateBranchProtection(ctx, "o", "r", test.branch, input) 1890 if err != nil { 1891 t.Errorf("Repositories.UpdateBranchProtection returned error: %v", err) 1892 } 1893 1894 want := &Protection{ 1895 RequiredStatusChecks: &RequiredStatusChecks{ 1896 Strict: true, 1897 Contexts: &[]string{"continuous-integration"}, 1898 Checks: &[]*RequiredStatusCheck{ 1899 { 1900 Context: "continuous-integration", 1901 }, 1902 }, 1903 }, 1904 RequiredPullRequestReviews: &PullRequestReviewsEnforcement{ 1905 DismissStaleReviews: true, 1906 DismissalRestrictions: &DismissalRestrictions{ 1907 Users: []*User{ 1908 {Login: Ptr("uu"), ID: Ptr(int64(3))}, 1909 }, 1910 Teams: []*Team{ 1911 {Slug: Ptr("tt"), ID: Ptr(int64(4))}, 1912 }, 1913 Apps: []*App{ 1914 {Slug: Ptr("aa"), ID: Ptr(int64(5))}, 1915 }, 1916 }, 1917 RequireCodeOwnerReviews: true, 1918 BypassPullRequestAllowances: &BypassPullRequestAllowances{ 1919 Users: []*User{ 1920 {Login: Ptr("uuu"), ID: Ptr(int64(10))}, 1921 }, 1922 Teams: []*Team{ 1923 {Slug: Ptr("ttt"), ID: Ptr(int64(20))}, 1924 }, 1925 Apps: []*App{ 1926 {Slug: Ptr("aaa"), ID: Ptr(int64(30))}, 1927 }, 1928 }, 1929 }, 1930 Restrictions: &BranchRestrictions{ 1931 Users: []*User{ 1932 {Login: Ptr("u"), ID: Ptr(int64(1))}, 1933 }, 1934 Teams: []*Team{ 1935 {Slug: Ptr("t"), ID: Ptr(int64(2))}, 1936 }, 1937 Apps: []*App{ 1938 {Slug: Ptr("a"), ID: Ptr(int64(3))}, 1939 }, 1940 }, 1941 } 1942 if !cmp.Equal(protection, want) { 1943 t.Errorf("Repositories.UpdateBranchProtection returned %+v, want %+v", protection, want) 1944 } 1945 }) 1946 } 1947 } 1948 1949 func TestRepositoriesService_UpdateBranchProtection_EmptyChecks(t *testing.T) { 1950 t.Parallel() 1951 tests := []struct { 1952 branch string 1953 urlPath string 1954 }{ 1955 {branch: "b", urlPath: "/repos/o/r/branches/b/protection"}, 1956 {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat%2fbranch-50%25/protection"}, 1957 } 1958 1959 for _, test := range tests { 1960 t.Run(test.branch, func(t *testing.T) { 1961 t.Parallel() 1962 client, mux, _ := setup(t) 1963 1964 input := &ProtectionRequest{ 1965 RequiredStatusChecks: &RequiredStatusChecks{ 1966 Strict: true, 1967 Checks: &[]*RequiredStatusCheck{}, 1968 }, 1969 RequiredPullRequestReviews: &PullRequestReviewsEnforcementRequest{ 1970 DismissStaleReviews: true, 1971 DismissalRestrictionsRequest: &DismissalRestrictionsRequest{ 1972 Users: &[]string{"uu"}, 1973 Teams: &[]string{"tt"}, 1974 Apps: &[]string{"aa"}, 1975 }, 1976 BypassPullRequestAllowancesRequest: &BypassPullRequestAllowancesRequest{ 1977 Users: []string{"uuu"}, 1978 Teams: []string{"ttt"}, 1979 Apps: []string{"aaa"}, 1980 }, 1981 }, 1982 Restrictions: &BranchRestrictionsRequest{ 1983 Users: []string{"u"}, 1984 Teams: []string{"t"}, 1985 Apps: []string{"a"}, 1986 }, 1987 } 1988 1989 mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { 1990 v := new(ProtectionRequest) 1991 assertNilError(t, json.NewDecoder(r.Body).Decode(v)) 1992 1993 testMethod(t, r, "PUT") 1994 if !cmp.Equal(v, input) { 1995 t.Errorf("Request body = %+v, want %+v", v, input) 1996 } 1997 1998 // TODO: remove custom Accept header when this API fully launches 1999 testHeader(t, r, "Accept", mediaTypeRequiredApprovingReviewsPreview) 2000 fmt.Fprint(w, `{ 2001 "required_status_checks":{ 2002 "strict":true, 2003 "contexts":null, 2004 "checks": [] 2005 }, 2006 "required_pull_request_reviews":{ 2007 "dismissal_restrictions":{ 2008 "users":[{ 2009 "id":3, 2010 "login":"uu" 2011 }], 2012 "teams":[{ 2013 "id":4, 2014 "slug":"tt" 2015 }], 2016 "apps":[{ 2017 "id":5, 2018 "slug":"aa" 2019 }] 2020 }, 2021 "dismiss_stale_reviews":true, 2022 "require_code_owner_reviews":true, 2023 "bypass_pull_request_allowances": { 2024 "users":[{"id":10,"login":"uuu"}], 2025 "teams":[{"id":20,"slug":"ttt"}], 2026 "apps":[{"id":30,"slug":"aaa"}] 2027 } 2028 }, 2029 "restrictions":{ 2030 "users":[{"id":1,"login":"u"}], 2031 "teams":[{"id":2,"slug":"t"}], 2032 "apps":[{"id":3,"slug":"a"}] 2033 } 2034 }`) 2035 }) 2036 2037 ctx := context.Background() 2038 protection, _, err := client.Repositories.UpdateBranchProtection(ctx, "o", "r", test.branch, input) 2039 if err != nil { 2040 t.Errorf("Repositories.UpdateBranchProtection returned error: %v", err) 2041 } 2042 2043 want := &Protection{ 2044 RequiredStatusChecks: &RequiredStatusChecks{ 2045 Strict: true, 2046 Checks: &[]*RequiredStatusCheck{}, 2047 }, 2048 RequiredPullRequestReviews: &PullRequestReviewsEnforcement{ 2049 DismissStaleReviews: true, 2050 DismissalRestrictions: &DismissalRestrictions{ 2051 Users: []*User{ 2052 {Login: Ptr("uu"), ID: Ptr(int64(3))}, 2053 }, 2054 Teams: []*Team{ 2055 {Slug: Ptr("tt"), ID: Ptr(int64(4))}, 2056 }, 2057 Apps: []*App{ 2058 {Slug: Ptr("aa"), ID: Ptr(int64(5))}, 2059 }, 2060 }, 2061 RequireCodeOwnerReviews: true, 2062 BypassPullRequestAllowances: &BypassPullRequestAllowances{ 2063 Users: []*User{ 2064 {Login: Ptr("uuu"), ID: Ptr(int64(10))}, 2065 }, 2066 Teams: []*Team{ 2067 {Slug: Ptr("ttt"), ID: Ptr(int64(20))}, 2068 }, 2069 Apps: []*App{ 2070 {Slug: Ptr("aaa"), ID: Ptr(int64(30))}, 2071 }, 2072 }, 2073 }, 2074 Restrictions: &BranchRestrictions{ 2075 Users: []*User{ 2076 {Login: Ptr("u"), ID: Ptr(int64(1))}, 2077 }, 2078 Teams: []*Team{ 2079 {Slug: Ptr("t"), ID: Ptr(int64(2))}, 2080 }, 2081 Apps: []*App{ 2082 {Slug: Ptr("a"), ID: Ptr(int64(3))}, 2083 }, 2084 }, 2085 } 2086 if !cmp.Equal(protection, want) { 2087 t.Errorf("Repositories.UpdateBranchProtection returned %+v, want %+v", protection, want) 2088 } 2089 }) 2090 } 2091 } 2092 2093 func TestRepositoriesService_UpdateBranchProtection_StrictNoChecks(t *testing.T) { 2094 t.Parallel() 2095 tests := []struct { 2096 branch string 2097 urlPath string 2098 }{ 2099 {branch: "b", urlPath: "/repos/o/r/branches/b/protection"}, 2100 {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat%2fbranch-50%25/protection"}, 2101 } 2102 2103 for _, test := range tests { 2104 t.Run(test.branch, func(t *testing.T) { 2105 t.Parallel() 2106 client, mux, _ := setup(t) 2107 2108 input := &ProtectionRequest{ 2109 RequiredStatusChecks: &RequiredStatusChecks{ 2110 Strict: true, 2111 }, 2112 RequiredPullRequestReviews: &PullRequestReviewsEnforcementRequest{ 2113 DismissStaleReviews: true, 2114 DismissalRestrictionsRequest: &DismissalRestrictionsRequest{ 2115 Users: &[]string{"uu"}, 2116 Teams: &[]string{"tt"}, 2117 Apps: &[]string{"aa"}, 2118 }, 2119 BypassPullRequestAllowancesRequest: &BypassPullRequestAllowancesRequest{ 2120 Users: []string{"uuu"}, 2121 Teams: []string{"ttt"}, 2122 Apps: []string{"aaa"}, 2123 }, 2124 }, 2125 Restrictions: &BranchRestrictionsRequest{ 2126 Users: []string{"u"}, 2127 Teams: []string{"t"}, 2128 Apps: []string{"a"}, 2129 }, 2130 } 2131 2132 mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { 2133 v := new(ProtectionRequest) 2134 assertNilError(t, json.NewDecoder(r.Body).Decode(v)) 2135 2136 testMethod(t, r, "PUT") 2137 if !cmp.Equal(v, input) { 2138 t.Errorf("Request body = %+v, want %+v", v, input) 2139 } 2140 2141 // TODO: remove custom Accept header when this API fully launches 2142 testHeader(t, r, "Accept", mediaTypeRequiredApprovingReviewsPreview) 2143 fmt.Fprint(w, `{ 2144 "required_status_checks":{ 2145 "strict":true, 2146 "contexts":[] 2147 }, 2148 "required_pull_request_reviews":{ 2149 "dismissal_restrictions":{ 2150 "users":[{ 2151 "id":3, 2152 "login":"uu" 2153 }], 2154 "teams":[{ 2155 "id":4, 2156 "slug":"tt" 2157 }], 2158 "apps":[{ 2159 "id":5, 2160 "slug":"aa" 2161 }] 2162 }, 2163 "dismiss_stale_reviews":true, 2164 "require_code_owner_reviews":true, 2165 "require_last_push_approval":false, 2166 "bypass_pull_request_allowances": { 2167 "users":[{"id":10,"login":"uuu"}], 2168 "teams":[{"id":20,"slug":"ttt"}], 2169 "apps":[{"id":30,"slug":"aaa"}] 2170 } 2171 }, 2172 "restrictions":{ 2173 "users":[{"id":1,"login":"u"}], 2174 "teams":[{"id":2,"slug":"t"}], 2175 "apps":[{"id":3,"slug":"a"}] 2176 } 2177 }`) 2178 }) 2179 2180 ctx := context.Background() 2181 protection, _, err := client.Repositories.UpdateBranchProtection(ctx, "o", "r", test.branch, input) 2182 if err != nil { 2183 t.Errorf("Repositories.UpdateBranchProtection returned error: %v", err) 2184 } 2185 2186 want := &Protection{ 2187 RequiredStatusChecks: &RequiredStatusChecks{ 2188 Strict: true, 2189 Contexts: &[]string{}, 2190 }, 2191 RequiredPullRequestReviews: &PullRequestReviewsEnforcement{ 2192 DismissStaleReviews: true, 2193 DismissalRestrictions: &DismissalRestrictions{ 2194 Users: []*User{ 2195 {Login: Ptr("uu"), ID: Ptr(int64(3))}, 2196 }, 2197 Teams: []*Team{ 2198 {Slug: Ptr("tt"), ID: Ptr(int64(4))}, 2199 }, 2200 Apps: []*App{ 2201 {Slug: Ptr("aa"), ID: Ptr(int64(5))}, 2202 }, 2203 }, 2204 RequireCodeOwnerReviews: true, 2205 BypassPullRequestAllowances: &BypassPullRequestAllowances{ 2206 Users: []*User{ 2207 {Login: Ptr("uuu"), ID: Ptr(int64(10))}, 2208 }, 2209 Teams: []*Team{ 2210 {Slug: Ptr("ttt"), ID: Ptr(int64(20))}, 2211 }, 2212 Apps: []*App{ 2213 {Slug: Ptr("aaa"), ID: Ptr(int64(30))}, 2214 }, 2215 }, 2216 }, 2217 Restrictions: &BranchRestrictions{ 2218 Users: []*User{ 2219 {Login: Ptr("u"), ID: Ptr(int64(1))}, 2220 }, 2221 Teams: []*Team{ 2222 {Slug: Ptr("t"), ID: Ptr(int64(2))}, 2223 }, 2224 Apps: []*App{ 2225 {Slug: Ptr("a"), ID: Ptr(int64(3))}, 2226 }, 2227 }, 2228 } 2229 if !cmp.Equal(protection, want) { 2230 t.Errorf("Repositories.UpdateBranchProtection returned %+v, want %+v", protection, want) 2231 } 2232 }) 2233 } 2234 } 2235 2236 func TestRepositoriesService_UpdateBranchProtection_RequireLastPushApproval(t *testing.T) { 2237 t.Parallel() 2238 tests := []struct { 2239 branch string 2240 urlPath string 2241 }{ 2242 {branch: "b", urlPath: "/repos/o/r/branches/b/protection"}, 2243 {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat%2fbranch-50%25/protection"}, 2244 } 2245 2246 for _, test := range tests { 2247 t.Run(test.branch, func(t *testing.T) { 2248 t.Parallel() 2249 client, mux, _ := setup(t) 2250 2251 input := &ProtectionRequest{ 2252 RequiredPullRequestReviews: &PullRequestReviewsEnforcementRequest{ 2253 RequireLastPushApproval: Ptr(true), 2254 }, 2255 } 2256 2257 mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { 2258 v := new(ProtectionRequest) 2259 assertNilError(t, json.NewDecoder(r.Body).Decode(v)) 2260 2261 testMethod(t, r, "PUT") 2262 if !cmp.Equal(v, input) { 2263 t.Errorf("Request body = %+v, want %+v", v, input) 2264 } 2265 2266 fmt.Fprint(w, `{ 2267 "required_pull_request_reviews":{ 2268 "require_last_push_approval":true 2269 } 2270 }`) 2271 }) 2272 2273 ctx := context.Background() 2274 protection, _, err := client.Repositories.UpdateBranchProtection(ctx, "o", "r", test.branch, input) 2275 if err != nil { 2276 t.Errorf("Repositories.UpdateBranchProtection returned error: %v", err) 2277 } 2278 2279 want := &Protection{ 2280 RequiredPullRequestReviews: &PullRequestReviewsEnforcement{ 2281 RequireLastPushApproval: true, 2282 }, 2283 } 2284 if !cmp.Equal(protection, want) { 2285 t.Errorf("Repositories.UpdateBranchProtection returned %+v, want %+v", protection, want) 2286 } 2287 }) 2288 } 2289 } 2290 2291 func TestRepositoriesService_RemoveBranchProtection(t *testing.T) { 2292 t.Parallel() 2293 tests := []struct { 2294 branch string 2295 urlPath string 2296 }{ 2297 {branch: "b", urlPath: "/repos/o/r/branches/b/protection"}, 2298 {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat%2fbranch-50%25/protection"}, 2299 } 2300 2301 for _, test := range tests { 2302 t.Run(test.branch, func(t *testing.T) { 2303 t.Parallel() 2304 client, mux, _ := setup(t) 2305 2306 mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { 2307 testMethod(t, r, "DELETE") 2308 w.WriteHeader(http.StatusNoContent) 2309 }) 2310 2311 ctx := context.Background() 2312 _, err := client.Repositories.RemoveBranchProtection(ctx, "o", "r", test.branch) 2313 if err != nil { 2314 t.Errorf("Repositories.RemoveBranchProtection returned error: %v", err) 2315 } 2316 2317 const methodName = "RemoveBranchProtection" 2318 testBadOptions(t, methodName, func() (err error) { 2319 _, err = client.Repositories.RemoveBranchProtection(ctx, "\n", "\n", "\n") 2320 return err 2321 }) 2322 2323 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 2324 return client.Repositories.RemoveBranchProtection(ctx, "o", "r", test.branch) 2325 }) 2326 }) 2327 } 2328 } 2329 2330 func TestRepositoriesService_ListLanguages_invalidOwner(t *testing.T) { 2331 t.Parallel() 2332 client, _, _ := setup(t) 2333 2334 ctx := context.Background() 2335 _, _, err := client.Repositories.ListLanguages(ctx, "%", "%") 2336 testURLParseError(t, err) 2337 } 2338 2339 func TestRepositoriesService_License(t *testing.T) { 2340 t.Parallel() 2341 client, mux, _ := setup(t) 2342 2343 mux.HandleFunc("/repos/o/r/license", func(w http.ResponseWriter, r *http.Request) { 2344 testMethod(t, r, "GET") 2345 fmt.Fprint(w, `{"name": "LICENSE", "path": "LICENSE", "license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","featured":true}}`) 2346 }) 2347 2348 ctx := context.Background() 2349 got, _, err := client.Repositories.License(ctx, "o", "r") 2350 if err != nil { 2351 t.Errorf("Repositories.License returned error: %v", err) 2352 } 2353 2354 want := &RepositoryLicense{ 2355 Name: Ptr("LICENSE"), 2356 Path: Ptr("LICENSE"), 2357 License: &License{ 2358 Name: Ptr("MIT License"), 2359 Key: Ptr("mit"), 2360 SPDXID: Ptr("MIT"), 2361 URL: Ptr("https://api.github.com/licenses/mit"), 2362 Featured: Ptr(true), 2363 }, 2364 } 2365 2366 if !cmp.Equal(got, want) { 2367 t.Errorf("Repositories.License returned %+v, want %+v", got, want) 2368 } 2369 2370 const methodName = "License" 2371 testBadOptions(t, methodName, func() (err error) { 2372 _, _, err = client.Repositories.License(ctx, "\n", "\n") 2373 return err 2374 }) 2375 2376 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 2377 got, resp, err := client.Repositories.License(ctx, "o", "r") 2378 if got != nil { 2379 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 2380 } 2381 return resp, err 2382 }) 2383 } 2384 2385 func TestRepositoriesService_GetRequiredStatusChecks(t *testing.T) { 2386 t.Parallel() 2387 tests := []struct { 2388 branch string 2389 urlPath string 2390 }{ 2391 {branch: "b", urlPath: "/repos/o/r/branches/b/protection/required_status_checks"}, 2392 {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat%2fbranch-50%25/protection/required_status_checks"}, 2393 } 2394 2395 for _, test := range tests { 2396 t.Run(test.branch, func(t *testing.T) { 2397 t.Parallel() 2398 client, mux, _ := setup(t) 2399 2400 mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { 2401 testMethod(t, r, "GET") 2402 fmt.Fprint(w, `{ 2403 "strict": true, 2404 "contexts": ["x","y","z"], 2405 "checks": [ 2406 { 2407 "context": "x", 2408 "app_id": null 2409 }, 2410 { 2411 "context": "y", 2412 "app_id": null 2413 }, 2414 { 2415 "context": "z", 2416 "app_id": null 2417 } 2418 ] 2419 }`) 2420 }) 2421 2422 ctx := context.Background() 2423 checks, _, err := client.Repositories.GetRequiredStatusChecks(ctx, "o", "r", test.branch) 2424 if err != nil { 2425 t.Errorf("Repositories.GetRequiredStatusChecks returned error: %v", err) 2426 } 2427 2428 want := &RequiredStatusChecks{ 2429 Strict: true, 2430 Contexts: &[]string{"x", "y", "z"}, 2431 Checks: &[]*RequiredStatusCheck{ 2432 { 2433 Context: "x", 2434 }, 2435 { 2436 Context: "y", 2437 }, 2438 { 2439 Context: "z", 2440 }, 2441 }, 2442 } 2443 if !cmp.Equal(checks, want) { 2444 t.Errorf("Repositories.GetRequiredStatusChecks returned %+v, want %+v", checks, want) 2445 } 2446 2447 const methodName = "GetRequiredStatusChecks" 2448 testBadOptions(t, methodName, func() (err error) { 2449 _, _, err = client.Repositories.GetRequiredStatusChecks(ctx, "\n", "\n", "\n") 2450 return err 2451 }) 2452 2453 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 2454 got, resp, err := client.Repositories.GetRequiredStatusChecks(ctx, "o", "r", test.branch) 2455 if got != nil { 2456 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 2457 } 2458 return resp, err 2459 }) 2460 }) 2461 } 2462 } 2463 2464 func TestRepositoriesService_GetRequiredStatusChecks_branchNotProtected(t *testing.T) { 2465 t.Parallel() 2466 tests := []struct { 2467 branch string 2468 urlPath string 2469 }{ 2470 {branch: "b", urlPath: "/repos/o/r/branches/b/protection/required_status_checks"}, 2471 {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat%2fbranch-50%25/protection/required_status_checks"}, 2472 } 2473 2474 for _, test := range tests { 2475 t.Run(test.branch, func(t *testing.T) { 2476 t.Parallel() 2477 client, mux, _ := setup(t) 2478 2479 mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { 2480 testMethod(t, r, "GET") 2481 2482 w.WriteHeader(http.StatusBadRequest) 2483 fmt.Fprintf(w, `{ 2484 "message": %q, 2485 "documentation_url": "https://docs.github.com/rest/repos#get-branch-protection" 2486 }`, githubBranchNotProtected) 2487 }) 2488 2489 ctx := context.Background() 2490 checks, _, err := client.Repositories.GetRequiredStatusChecks(ctx, "o", "r", test.branch) 2491 2492 if checks != nil { 2493 t.Error("Repositories.GetRequiredStatusChecks returned non-nil status-checks data") 2494 } 2495 2496 if err != ErrBranchNotProtected { 2497 t.Errorf("Repositories.GetRequiredStatusChecks returned an invalid error: %v", err) 2498 } 2499 }) 2500 } 2501 } 2502 2503 func TestRepositoriesService_UpdateRequiredStatusChecks_Contexts(t *testing.T) { 2504 t.Parallel() 2505 tests := []struct { 2506 branch string 2507 urlPath string 2508 }{ 2509 {branch: "b", urlPath: "/repos/o/r/branches/b/protection/required_status_checks"}, 2510 {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat%2fbranch-50%25/protection/required_status_checks"}, 2511 } 2512 2513 for _, test := range tests { 2514 t.Run(test.branch, func(t *testing.T) { 2515 t.Parallel() 2516 client, mux, _ := setup(t) 2517 2518 input := &RequiredStatusChecksRequest{ 2519 Strict: Ptr(true), 2520 Contexts: []string{"continuous-integration"}, 2521 } 2522 2523 mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { 2524 v := new(RequiredStatusChecksRequest) 2525 assertNilError(t, json.NewDecoder(r.Body).Decode(v)) 2526 2527 testMethod(t, r, "PATCH") 2528 if !cmp.Equal(v, input) { 2529 t.Errorf("Request body = %+v, want %+v", v, input) 2530 } 2531 testHeader(t, r, "Accept", mediaTypeV3) 2532 fmt.Fprint(w, `{ 2533 "strict":true, 2534 "contexts":["continuous-integration"], 2535 "checks": [ 2536 { 2537 "context": "continuous-integration", 2538 "app_id": null 2539 } 2540 ] 2541 }`) 2542 }) 2543 2544 ctx := context.Background() 2545 statusChecks, _, err := client.Repositories.UpdateRequiredStatusChecks(ctx, "o", "r", test.branch, input) 2546 if err != nil { 2547 t.Errorf("Repositories.UpdateRequiredStatusChecks returned error: %v", err) 2548 } 2549 2550 want := &RequiredStatusChecks{ 2551 Strict: true, 2552 Contexts: &[]string{"continuous-integration"}, 2553 Checks: &[]*RequiredStatusCheck{ 2554 { 2555 Context: "continuous-integration", 2556 }, 2557 }, 2558 } 2559 if !cmp.Equal(statusChecks, want) { 2560 t.Errorf("Repositories.UpdateRequiredStatusChecks returned %+v, want %+v", statusChecks, want) 2561 } 2562 2563 const methodName = "UpdateRequiredStatusChecks" 2564 testBadOptions(t, methodName, func() (err error) { 2565 _, _, err = client.Repositories.UpdateRequiredStatusChecks(ctx, "\n", "\n", "\n", input) 2566 return err 2567 }) 2568 2569 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 2570 got, resp, err := client.Repositories.UpdateRequiredStatusChecks(ctx, "o", "r", test.branch, input) 2571 if got != nil { 2572 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 2573 } 2574 return resp, err 2575 }) 2576 }) 2577 } 2578 } 2579 2580 func TestRepositoriesService_UpdateRequiredStatusChecks_Checks(t *testing.T) { 2581 t.Parallel() 2582 tests := []struct { 2583 branch string 2584 urlPath string 2585 }{ 2586 {branch: "b", urlPath: "/repos/o/r/branches/b/protection/required_status_checks"}, 2587 {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat%2fbranch-50%25/protection/required_status_checks"}, 2588 } 2589 2590 for _, test := range tests { 2591 t.Run(test.branch, func(t *testing.T) { 2592 t.Parallel() 2593 client, mux, _ := setup(t) 2594 2595 appID := int64(123) 2596 noAppID := int64(-1) 2597 input := &RequiredStatusChecksRequest{ 2598 Strict: Ptr(true), 2599 Checks: []*RequiredStatusCheck{ 2600 { 2601 Context: "continuous-integration", 2602 }, 2603 { 2604 Context: "continuous-integration2", 2605 AppID: &appID, 2606 }, 2607 { 2608 Context: "continuous-integration3", 2609 AppID: &noAppID, 2610 }, 2611 }, 2612 } 2613 2614 mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { 2615 v := new(RequiredStatusChecksRequest) 2616 assertNilError(t, json.NewDecoder(r.Body).Decode(v)) 2617 2618 testMethod(t, r, "PATCH") 2619 if !cmp.Equal(v, input) { 2620 t.Errorf("Request body = %+v, want %+v", v, input) 2621 } 2622 testHeader(t, r, "Accept", mediaTypeV3) 2623 fmt.Fprint(w, `{ 2624 "strict":true, 2625 "contexts":["continuous-integration"], 2626 "checks": [ 2627 { 2628 "context": "continuous-integration", 2629 "app_id": null 2630 }, 2631 { 2632 "context": "continuous-integration2", 2633 "app_id": 123 2634 }, 2635 { 2636 "context": "continuous-integration3", 2637 "app_id": null 2638 } 2639 ] 2640 }`) 2641 }) 2642 2643 ctx := context.Background() 2644 statusChecks, _, err := client.Repositories.UpdateRequiredStatusChecks(ctx, "o", "r", test.branch, input) 2645 if err != nil { 2646 t.Errorf("Repositories.UpdateRequiredStatusChecks returned error: %v", err) 2647 } 2648 2649 want := &RequiredStatusChecks{ 2650 Strict: true, 2651 Contexts: &[]string{"continuous-integration"}, 2652 Checks: &[]*RequiredStatusCheck{ 2653 { 2654 Context: "continuous-integration", 2655 }, 2656 { 2657 Context: "continuous-integration2", 2658 AppID: &appID, 2659 }, 2660 { 2661 Context: "continuous-integration3", 2662 }, 2663 }, 2664 } 2665 if !cmp.Equal(statusChecks, want) { 2666 t.Errorf("Repositories.UpdateRequiredStatusChecks returned %+v, want %+v", statusChecks, want) 2667 } 2668 }) 2669 } 2670 } 2671 2672 func TestRepositoriesService_RemoveRequiredStatusChecks(t *testing.T) { 2673 t.Parallel() 2674 tests := []struct { 2675 branch string 2676 urlPath string 2677 }{ 2678 {branch: "b", urlPath: "/repos/o/r/branches/b/protection/required_status_checks"}, 2679 {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat%2fbranch-50%25/protection/required_status_checks"}, 2680 } 2681 2682 for _, test := range tests { 2683 t.Run(test.branch, func(t *testing.T) { 2684 t.Parallel() 2685 client, mux, _ := setup(t) 2686 2687 mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { 2688 testMethod(t, r, "DELETE") 2689 testHeader(t, r, "Accept", mediaTypeV3) 2690 w.WriteHeader(http.StatusNoContent) 2691 }) 2692 2693 ctx := context.Background() 2694 _, err := client.Repositories.RemoveRequiredStatusChecks(ctx, "o", "r", test.branch) 2695 if err != nil { 2696 t.Errorf("Repositories.RemoveRequiredStatusChecks returned error: %v", err) 2697 } 2698 2699 const methodName = "RemoveRequiredStatusChecks" 2700 testBadOptions(t, methodName, func() (err error) { 2701 _, err = client.Repositories.RemoveRequiredStatusChecks(ctx, "\n", "\n", "\n") 2702 return err 2703 }) 2704 2705 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 2706 return client.Repositories.RemoveRequiredStatusChecks(ctx, "o", "r", test.branch) 2707 }) 2708 }) 2709 } 2710 } 2711 2712 func TestRepositoriesService_ListRequiredStatusChecksContexts(t *testing.T) { 2713 t.Parallel() 2714 tests := []struct { 2715 branch string 2716 urlPath string 2717 }{ 2718 {branch: "b", urlPath: "/repos/o/r/branches/b/protection/required_status_checks/contexts"}, 2719 {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat%2fbranch-50%25/protection/required_status_checks/contexts"}, 2720 } 2721 2722 for _, test := range tests { 2723 t.Run(test.branch, func(t *testing.T) { 2724 t.Parallel() 2725 client, mux, _ := setup(t) 2726 2727 mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { 2728 testMethod(t, r, "GET") 2729 fmt.Fprint(w, `["x", "y", "z"]`) 2730 }) 2731 2732 ctx := context.Background() 2733 contexts, _, err := client.Repositories.ListRequiredStatusChecksContexts(ctx, "o", "r", test.branch) 2734 if err != nil { 2735 t.Errorf("Repositories.ListRequiredStatusChecksContexts returned error: %v", err) 2736 } 2737 2738 want := []string{"x", "y", "z"} 2739 if !cmp.Equal(contexts, want) { 2740 t.Errorf("Repositories.ListRequiredStatusChecksContexts returned %+v, want %+v", contexts, want) 2741 } 2742 2743 const methodName = "ListRequiredStatusChecksContexts" 2744 testBadOptions(t, methodName, func() (err error) { 2745 _, _, err = client.Repositories.ListRequiredStatusChecksContexts(ctx, "\n", "\n", "\n") 2746 return err 2747 }) 2748 2749 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 2750 got, resp, err := client.Repositories.ListRequiredStatusChecksContexts(ctx, "o", "r", test.branch) 2751 if got != nil { 2752 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 2753 } 2754 return resp, err 2755 }) 2756 }) 2757 } 2758 } 2759 2760 func TestRepositoriesService_ListRequiredStatusChecksContexts_branchNotProtected(t *testing.T) { 2761 t.Parallel() 2762 tests := []struct { 2763 branch string 2764 urlPath string 2765 }{ 2766 {branch: "b", urlPath: "/repos/o/r/branches/b/protection/required_status_checks/contexts"}, 2767 {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat%2fbranch-50%25/protection/required_status_checks/contexts"}, 2768 } 2769 2770 for _, test := range tests { 2771 t.Run(test.branch, func(t *testing.T) { 2772 t.Parallel() 2773 client, mux, _ := setup(t) 2774 2775 mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { 2776 testMethod(t, r, "GET") 2777 2778 w.WriteHeader(http.StatusBadRequest) 2779 fmt.Fprintf(w, `{ 2780 "message": %q, 2781 "documentation_url": "https://docs.github.com/rest/repos#get-branch-protection" 2782 }`, githubBranchNotProtected) 2783 }) 2784 2785 ctx := context.Background() 2786 contexts, _, err := client.Repositories.ListRequiredStatusChecksContexts(ctx, "o", "r", test.branch) 2787 2788 if contexts != nil { 2789 t.Error("Repositories.ListRequiredStatusChecksContexts returned non-nil contexts data") 2790 } 2791 2792 if err != ErrBranchNotProtected { 2793 t.Errorf("Repositories.ListRequiredStatusChecksContexts returned an invalid error: %v", err) 2794 } 2795 }) 2796 } 2797 } 2798 2799 func TestRepositoriesService_GetPullRequestReviewEnforcement(t *testing.T) { 2800 t.Parallel() 2801 tests := []struct { 2802 branch string 2803 urlPath string 2804 }{ 2805 {branch: "b", urlPath: "/repos/o/r/branches/b/protection/required_pull_request_reviews"}, 2806 {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat%2fbranch-50%25/protection/required_pull_request_reviews"}, 2807 } 2808 2809 for _, test := range tests { 2810 t.Run(test.branch, func(t *testing.T) { 2811 t.Parallel() 2812 client, mux, _ := setup(t) 2813 2814 mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { 2815 testMethod(t, r, "GET") 2816 // TODO: remove custom Accept header when this API fully launches 2817 testHeader(t, r, "Accept", mediaTypeRequiredApprovingReviewsPreview) 2818 fmt.Fprint(w, `{ 2819 "dismissal_restrictions":{ 2820 "users":[{"id":1,"login":"u"}], 2821 "teams":[{"id":2,"slug":"t"}], 2822 "apps":[{"id":3,"slug":"a"}] 2823 }, 2824 "dismiss_stale_reviews":true, 2825 "require_code_owner_reviews":true, 2826 "required_approving_review_count":1 2827 }`) 2828 }) 2829 2830 ctx := context.Background() 2831 enforcement, _, err := client.Repositories.GetPullRequestReviewEnforcement(ctx, "o", "r", test.branch) 2832 if err != nil { 2833 t.Errorf("Repositories.GetPullRequestReviewEnforcement returned error: %v", err) 2834 } 2835 2836 want := &PullRequestReviewsEnforcement{ 2837 DismissStaleReviews: true, 2838 DismissalRestrictions: &DismissalRestrictions{ 2839 Users: []*User{ 2840 {Login: Ptr("u"), ID: Ptr(int64(1))}, 2841 }, 2842 Teams: []*Team{ 2843 {Slug: Ptr("t"), ID: Ptr(int64(2))}, 2844 }, 2845 Apps: []*App{ 2846 {Slug: Ptr("a"), ID: Ptr(int64(3))}, 2847 }, 2848 }, 2849 RequireCodeOwnerReviews: true, 2850 RequiredApprovingReviewCount: 1, 2851 } 2852 2853 if !cmp.Equal(enforcement, want) { 2854 t.Errorf("Repositories.GetPullRequestReviewEnforcement returned %+v, want %+v", enforcement, want) 2855 } 2856 2857 const methodName = "GetPullRequestReviewEnforcement" 2858 testBadOptions(t, methodName, func() (err error) { 2859 _, _, err = client.Repositories.GetPullRequestReviewEnforcement(ctx, "\n", "\n", "\n") 2860 return err 2861 }) 2862 2863 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 2864 got, resp, err := client.Repositories.GetPullRequestReviewEnforcement(ctx, "o", "r", test.branch) 2865 if got != nil { 2866 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 2867 } 2868 return resp, err 2869 }) 2870 }) 2871 } 2872 } 2873 2874 func TestRepositoriesService_UpdatePullRequestReviewEnforcement(t *testing.T) { 2875 t.Parallel() 2876 tests := []struct { 2877 branch string 2878 urlPath string 2879 }{ 2880 {branch: "b", urlPath: "/repos/o/r/branches/b/protection/required_pull_request_reviews"}, 2881 {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat%2fbranch-50%25/protection/required_pull_request_reviews"}, 2882 } 2883 2884 for _, test := range tests { 2885 t.Run(test.branch, func(t *testing.T) { 2886 t.Parallel() 2887 client, mux, _ := setup(t) 2888 2889 input := &PullRequestReviewsEnforcementUpdate{ 2890 DismissalRestrictionsRequest: &DismissalRestrictionsRequest{ 2891 Users: &[]string{"u"}, 2892 Teams: &[]string{"t"}, 2893 Apps: &[]string{"a"}, 2894 }, 2895 } 2896 2897 mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { 2898 v := new(PullRequestReviewsEnforcementUpdate) 2899 assertNilError(t, json.NewDecoder(r.Body).Decode(v)) 2900 2901 testMethod(t, r, "PATCH") 2902 if !cmp.Equal(v, input) { 2903 t.Errorf("Request body = %+v, want %+v", v, input) 2904 } 2905 // TODO: remove custom Accept header when this API fully launches 2906 testHeader(t, r, "Accept", mediaTypeRequiredApprovingReviewsPreview) 2907 fmt.Fprint(w, `{ 2908 "dismissal_restrictions":{ 2909 "users":[{"id":1,"login":"u"}], 2910 "teams":[{"id":2,"slug":"t"}], 2911 "apps":[{"id":3,"slug":"a"}] 2912 }, 2913 "dismiss_stale_reviews":true, 2914 "require_code_owner_reviews":true, 2915 "required_approving_review_count":3 2916 }`) 2917 }) 2918 2919 ctx := context.Background() 2920 enforcement, _, err := client.Repositories.UpdatePullRequestReviewEnforcement(ctx, "o", "r", test.branch, input) 2921 if err != nil { 2922 t.Errorf("Repositories.UpdatePullRequestReviewEnforcement returned error: %v", err) 2923 } 2924 2925 want := &PullRequestReviewsEnforcement{ 2926 DismissStaleReviews: true, 2927 DismissalRestrictions: &DismissalRestrictions{ 2928 Users: []*User{ 2929 {Login: Ptr("u"), ID: Ptr(int64(1))}, 2930 }, 2931 Teams: []*Team{ 2932 {Slug: Ptr("t"), ID: Ptr(int64(2))}, 2933 }, 2934 Apps: []*App{ 2935 {Slug: Ptr("a"), ID: Ptr(int64(3))}, 2936 }, 2937 }, 2938 RequireCodeOwnerReviews: true, 2939 RequiredApprovingReviewCount: 3, 2940 } 2941 if !cmp.Equal(enforcement, want) { 2942 t.Errorf("Repositories.UpdatePullRequestReviewEnforcement returned %+v, want %+v", enforcement, want) 2943 } 2944 2945 const methodName = "UpdatePullRequestReviewEnforcement" 2946 testBadOptions(t, methodName, func() (err error) { 2947 _, _, err = client.Repositories.UpdatePullRequestReviewEnforcement(ctx, "\n", "\n", "\n", input) 2948 return err 2949 }) 2950 2951 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 2952 got, resp, err := client.Repositories.UpdatePullRequestReviewEnforcement(ctx, "o", "r", test.branch, input) 2953 if got != nil { 2954 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 2955 } 2956 return resp, err 2957 }) 2958 }) 2959 } 2960 } 2961 2962 func TestRepositoriesService_DisableDismissalRestrictions(t *testing.T) { 2963 t.Parallel() 2964 tests := []struct { 2965 branch string 2966 urlPath string 2967 }{ 2968 {branch: "b", urlPath: "/repos/o/r/branches/b/protection/required_pull_request_reviews"}, 2969 {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat%2fbranch-50%25/protection/required_pull_request_reviews"}, 2970 } 2971 2972 for _, test := range tests { 2973 t.Run(test.branch, func(t *testing.T) { 2974 t.Parallel() 2975 client, mux, _ := setup(t) 2976 2977 mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { 2978 testMethod(t, r, "PATCH") 2979 // TODO: remove custom Accept header when this API fully launches 2980 testHeader(t, r, "Accept", mediaTypeRequiredApprovingReviewsPreview) 2981 testBody(t, r, `{"dismissal_restrictions":{}}`+"\n") 2982 fmt.Fprint(w, `{"dismiss_stale_reviews":true,"require_code_owner_reviews":true,"required_approving_review_count":1}`) 2983 }) 2984 2985 ctx := context.Background() 2986 enforcement, _, err := client.Repositories.DisableDismissalRestrictions(ctx, "o", "r", test.branch) 2987 if err != nil { 2988 t.Errorf("Repositories.DisableDismissalRestrictions returned error: %v", err) 2989 } 2990 2991 want := &PullRequestReviewsEnforcement{ 2992 DismissStaleReviews: true, 2993 DismissalRestrictions: nil, 2994 RequireCodeOwnerReviews: true, 2995 RequiredApprovingReviewCount: 1, 2996 } 2997 if !cmp.Equal(enforcement, want) { 2998 t.Errorf("Repositories.DisableDismissalRestrictions returned %+v, want %+v", enforcement, want) 2999 } 3000 3001 const methodName = "DisableDismissalRestrictions" 3002 testBadOptions(t, methodName, func() (err error) { 3003 _, _, err = client.Repositories.DisableDismissalRestrictions(ctx, "\n", "\n", "\n") 3004 return err 3005 }) 3006 3007 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 3008 got, resp, err := client.Repositories.DisableDismissalRestrictions(ctx, "o", "r", test.branch) 3009 if got != nil { 3010 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 3011 } 3012 return resp, err 3013 }) 3014 }) 3015 } 3016 } 3017 3018 func TestRepositoriesService_RemovePullRequestReviewEnforcement(t *testing.T) { 3019 t.Parallel() 3020 tests := []struct { 3021 branch string 3022 urlPath string 3023 }{ 3024 {branch: "b", urlPath: "/repos/o/r/branches/b/protection/required_pull_request_reviews"}, 3025 {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat%2fbranch-50%25/protection/required_pull_request_reviews"}, 3026 } 3027 3028 for _, test := range tests { 3029 t.Run(test.branch, func(t *testing.T) { 3030 t.Parallel() 3031 client, mux, _ := setup(t) 3032 3033 mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { 3034 testMethod(t, r, "DELETE") 3035 w.WriteHeader(http.StatusNoContent) 3036 }) 3037 3038 ctx := context.Background() 3039 _, err := client.Repositories.RemovePullRequestReviewEnforcement(ctx, "o", "r", test.branch) 3040 if err != nil { 3041 t.Errorf("Repositories.RemovePullRequestReviewEnforcement returned error: %v", err) 3042 } 3043 3044 const methodName = "RemovePullRequestReviewEnforcement" 3045 testBadOptions(t, methodName, func() (err error) { 3046 _, err = client.Repositories.RemovePullRequestReviewEnforcement(ctx, "\n", "\n", "\n") 3047 return err 3048 }) 3049 3050 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 3051 return client.Repositories.RemovePullRequestReviewEnforcement(ctx, "o", "r", test.branch) 3052 }) 3053 }) 3054 } 3055 } 3056 3057 func TestRepositoriesService_GetAdminEnforcement(t *testing.T) { 3058 t.Parallel() 3059 tests := []struct { 3060 branch string 3061 urlPath string 3062 }{ 3063 {branch: "b", urlPath: "/repos/o/r/branches/b/protection/enforce_admins"}, 3064 {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat%2fbranch-50%25/protection/enforce_admins"}, 3065 } 3066 3067 for _, test := range tests { 3068 t.Run(test.branch, func(t *testing.T) { 3069 t.Parallel() 3070 client, mux, _ := setup(t) 3071 3072 mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { 3073 testMethod(t, r, "GET") 3074 fmt.Fprint(w, `{"url":"/repos/o/r/branches/b/protection/enforce_admins","enabled":true}`) 3075 }) 3076 3077 ctx := context.Background() 3078 enforcement, _, err := client.Repositories.GetAdminEnforcement(ctx, "o", "r", test.branch) 3079 if err != nil { 3080 t.Errorf("Repositories.GetAdminEnforcement returned error: %v", err) 3081 } 3082 3083 want := &AdminEnforcement{ 3084 URL: Ptr("/repos/o/r/branches/b/protection/enforce_admins"), 3085 Enabled: true, 3086 } 3087 3088 if !cmp.Equal(enforcement, want) { 3089 t.Errorf("Repositories.GetAdminEnforcement returned %+v, want %+v", enforcement, want) 3090 } 3091 3092 const methodName = "GetAdminEnforcement" 3093 testBadOptions(t, methodName, func() (err error) { 3094 _, _, err = client.Repositories.GetAdminEnforcement(ctx, "\n", "\n", "\n") 3095 return err 3096 }) 3097 3098 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 3099 got, resp, err := client.Repositories.GetAdminEnforcement(ctx, "o", "r", test.branch) 3100 if got != nil { 3101 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 3102 } 3103 return resp, err 3104 }) 3105 }) 3106 } 3107 } 3108 3109 func TestRepositoriesService_AddAdminEnforcement(t *testing.T) { 3110 t.Parallel() 3111 tests := []struct { 3112 branch string 3113 urlPath string 3114 }{ 3115 {branch: "b", urlPath: "/repos/o/r/branches/b/protection/enforce_admins"}, 3116 {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat%2fbranch-50%25/protection/enforce_admins"}, 3117 } 3118 3119 for _, test := range tests { 3120 t.Run(test.branch, func(t *testing.T) { 3121 t.Parallel() 3122 client, mux, _ := setup(t) 3123 3124 mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { 3125 testMethod(t, r, "POST") 3126 fmt.Fprint(w, `{"url":"/repos/o/r/branches/b/protection/enforce_admins","enabled":true}`) 3127 }) 3128 3129 ctx := context.Background() 3130 enforcement, _, err := client.Repositories.AddAdminEnforcement(ctx, "o", "r", test.branch) 3131 if err != nil { 3132 t.Errorf("Repositories.AddAdminEnforcement returned error: %v", err) 3133 } 3134 3135 want := &AdminEnforcement{ 3136 URL: Ptr("/repos/o/r/branches/b/protection/enforce_admins"), 3137 Enabled: true, 3138 } 3139 if !cmp.Equal(enforcement, want) { 3140 t.Errorf("Repositories.AddAdminEnforcement returned %+v, want %+v", enforcement, want) 3141 } 3142 3143 const methodName = "AddAdminEnforcement" 3144 testBadOptions(t, methodName, func() (err error) { 3145 _, _, err = client.Repositories.AddAdminEnforcement(ctx, "\n", "\n", "\n") 3146 return err 3147 }) 3148 3149 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 3150 got, resp, err := client.Repositories.AddAdminEnforcement(ctx, "o", "r", test.branch) 3151 if got != nil { 3152 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 3153 } 3154 return resp, err 3155 }) 3156 }) 3157 } 3158 } 3159 3160 func TestRepositoriesService_RemoveAdminEnforcement(t *testing.T) { 3161 t.Parallel() 3162 tests := []struct { 3163 branch string 3164 urlPath string 3165 }{ 3166 {branch: "b", urlPath: "/repos/o/r/branches/b/protection/enforce_admins"}, 3167 {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat%2fbranch-50%25/protection/enforce_admins"}, 3168 } 3169 3170 for _, test := range tests { 3171 t.Run(test.branch, func(t *testing.T) { 3172 t.Parallel() 3173 client, mux, _ := setup(t) 3174 3175 mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { 3176 testMethod(t, r, "DELETE") 3177 w.WriteHeader(http.StatusNoContent) 3178 }) 3179 3180 ctx := context.Background() 3181 _, err := client.Repositories.RemoveAdminEnforcement(ctx, "o", "r", test.branch) 3182 if err != nil { 3183 t.Errorf("Repositories.RemoveAdminEnforcement returned error: %v", err) 3184 } 3185 3186 const methodName = "RemoveAdminEnforcement" 3187 testBadOptions(t, methodName, func() (err error) { 3188 _, err = client.Repositories.RemoveAdminEnforcement(ctx, "\n", "\n", "\n") 3189 return err 3190 }) 3191 3192 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 3193 return client.Repositories.RemoveAdminEnforcement(ctx, "o", "r", test.branch) 3194 }) 3195 }) 3196 } 3197 } 3198 3199 func TestRepositoriesService_GetSignaturesProtectedBranch(t *testing.T) { 3200 t.Parallel() 3201 tests := []struct { 3202 branch string 3203 urlPath string 3204 }{ 3205 {branch: "b", urlPath: "/repos/o/r/branches/b/protection/required_signatures"}, 3206 {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat%2fbranch-50%25/protection/required_signatures"}, 3207 } 3208 3209 for _, test := range tests { 3210 t.Run(test.branch, func(t *testing.T) { 3211 t.Parallel() 3212 client, mux, _ := setup(t) 3213 3214 mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { 3215 testMethod(t, r, "GET") 3216 testHeader(t, r, "Accept", mediaTypeSignaturePreview) 3217 fmt.Fprint(w, `{"url":"/repos/o/r/branches/b/protection/required_signatures","enabled":false}`) 3218 }) 3219 3220 ctx := context.Background() 3221 signature, _, err := client.Repositories.GetSignaturesProtectedBranch(ctx, "o", "r", test.branch) 3222 if err != nil { 3223 t.Errorf("Repositories.GetSignaturesProtectedBranch returned error: %v", err) 3224 } 3225 3226 want := &SignaturesProtectedBranch{ 3227 URL: Ptr("/repos/o/r/branches/b/protection/required_signatures"), 3228 Enabled: Ptr(false), 3229 } 3230 3231 if !cmp.Equal(signature, want) { 3232 t.Errorf("Repositories.GetSignaturesProtectedBranch returned %+v, want %+v", signature, want) 3233 } 3234 3235 const methodName = "GetSignaturesProtectedBranch" 3236 testBadOptions(t, methodName, func() (err error) { 3237 _, _, err = client.Repositories.GetSignaturesProtectedBranch(ctx, "\n", "\n", "\n") 3238 return err 3239 }) 3240 3241 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 3242 got, resp, err := client.Repositories.GetSignaturesProtectedBranch(ctx, "o", "r", test.branch) 3243 if got != nil { 3244 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 3245 } 3246 return resp, err 3247 }) 3248 }) 3249 } 3250 } 3251 3252 func TestRepositoriesService_RequireSignaturesOnProtectedBranch(t *testing.T) { 3253 t.Parallel() 3254 tests := []struct { 3255 branch string 3256 urlPath string 3257 }{ 3258 {branch: "b", urlPath: "/repos/o/r/branches/b/protection/required_signatures"}, 3259 {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat%2fbranch-50%25/protection/required_signatures"}, 3260 } 3261 3262 for _, test := range tests { 3263 t.Run(test.branch, func(t *testing.T) { 3264 t.Parallel() 3265 client, mux, _ := setup(t) 3266 3267 mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { 3268 testMethod(t, r, "POST") 3269 testHeader(t, r, "Accept", mediaTypeSignaturePreview) 3270 fmt.Fprint(w, `{"url":"/repos/o/r/branches/b/protection/required_signatures","enabled":true}`) 3271 }) 3272 3273 ctx := context.Background() 3274 signature, _, err := client.Repositories.RequireSignaturesOnProtectedBranch(ctx, "o", "r", test.branch) 3275 if err != nil { 3276 t.Errorf("Repositories.RequireSignaturesOnProtectedBranch returned error: %v", err) 3277 } 3278 3279 want := &SignaturesProtectedBranch{ 3280 URL: Ptr("/repos/o/r/branches/b/protection/required_signatures"), 3281 Enabled: Ptr(true), 3282 } 3283 3284 if !cmp.Equal(signature, want) { 3285 t.Errorf("Repositories.RequireSignaturesOnProtectedBranch returned %+v, want %+v", signature, want) 3286 } 3287 3288 const methodName = "RequireSignaturesOnProtectedBranch" 3289 testBadOptions(t, methodName, func() (err error) { 3290 _, _, err = client.Repositories.RequireSignaturesOnProtectedBranch(ctx, "\n", "\n", "\n") 3291 return err 3292 }) 3293 3294 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 3295 got, resp, err := client.Repositories.RequireSignaturesOnProtectedBranch(ctx, "o", "r", test.branch) 3296 if got != nil { 3297 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 3298 } 3299 return resp, err 3300 }) 3301 }) 3302 } 3303 } 3304 3305 func TestRepositoriesService_OptionalSignaturesOnProtectedBranch(t *testing.T) { 3306 t.Parallel() 3307 tests := []struct { 3308 branch string 3309 urlPath string 3310 }{ 3311 {branch: "b", urlPath: "/repos/o/r/branches/b/protection/required_signatures"}, 3312 {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat%2fbranch-50%25/protection/required_signatures"}, 3313 } 3314 3315 for _, test := range tests { 3316 t.Run(test.branch, func(t *testing.T) { 3317 t.Parallel() 3318 client, mux, _ := setup(t) 3319 3320 mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { 3321 testMethod(t, r, "DELETE") 3322 testHeader(t, r, "Accept", mediaTypeSignaturePreview) 3323 w.WriteHeader(http.StatusNoContent) 3324 }) 3325 3326 ctx := context.Background() 3327 _, err := client.Repositories.OptionalSignaturesOnProtectedBranch(ctx, "o", "r", test.branch) 3328 if err != nil { 3329 t.Errorf("Repositories.OptionalSignaturesOnProtectedBranch returned error: %v", err) 3330 } 3331 3332 const methodName = "OptionalSignaturesOnProtectedBranch" 3333 testBadOptions(t, methodName, func() (err error) { 3334 _, err = client.Repositories.OptionalSignaturesOnProtectedBranch(ctx, "\n", "\n", "\n") 3335 return err 3336 }) 3337 3338 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 3339 return client.Repositories.OptionalSignaturesOnProtectedBranch(ctx, "o", "r", test.branch) 3340 }) 3341 }) 3342 } 3343 } 3344 3345 func TestPullRequestReviewsEnforcementRequest_MarshalJSON_nilDismissalRestrictions(t *testing.T) { 3346 t.Parallel() 3347 req := PullRequestReviewsEnforcementRequest{} 3348 3349 got, err := json.Marshal(req) 3350 if err != nil { 3351 t.Errorf("PullRequestReviewsEnforcementRequest.MarshalJSON returned error: %v", err) 3352 } 3353 3354 want := `{"dismiss_stale_reviews":false,"require_code_owner_reviews":false,"required_approving_review_count":0}` 3355 if want != string(got) { 3356 t.Errorf("PullRequestReviewsEnforcementRequest.MarshalJSON returned %+v, want %+v", string(got), want) 3357 } 3358 3359 req = PullRequestReviewsEnforcementRequest{ 3360 DismissalRestrictionsRequest: &DismissalRestrictionsRequest{}, 3361 } 3362 3363 got, err = json.Marshal(req) 3364 if err != nil { 3365 t.Errorf("PullRequestReviewsEnforcementRequest.MarshalJSON returned error: %v", err) 3366 } 3367 3368 want = `{"dismissal_restrictions":{},"dismiss_stale_reviews":false,"require_code_owner_reviews":false,"required_approving_review_count":0}` 3369 if want != string(got) { 3370 t.Errorf("PullRequestReviewsEnforcementRequest.MarshalJSON returned %+v, want %+v", string(got), want) 3371 } 3372 3373 req = PullRequestReviewsEnforcementRequest{ 3374 DismissalRestrictionsRequest: &DismissalRestrictionsRequest{ 3375 Users: &[]string{}, 3376 Teams: &[]string{}, 3377 Apps: &[]string{}, 3378 }, 3379 RequireLastPushApproval: Ptr(true), 3380 } 3381 3382 got, err = json.Marshal(req) 3383 if err != nil { 3384 t.Errorf("PullRequestReviewsEnforcementRequest.MarshalJSON returned error: %v", err) 3385 } 3386 3387 want = `{"dismissal_restrictions":{"users":[],"teams":[],"apps":[]},"dismiss_stale_reviews":false,"require_code_owner_reviews":false,"required_approving_review_count":0,"require_last_push_approval":true}` 3388 if want != string(got) { 3389 t.Errorf("PullRequestReviewsEnforcementRequest.MarshalJSON returned %+v, want %+v", string(got), want) 3390 } 3391 } 3392 3393 func TestRepositoriesService_ListAllTopics(t *testing.T) { 3394 t.Parallel() 3395 client, mux, _ := setup(t) 3396 3397 mux.HandleFunc("/repos/o/r/topics", func(w http.ResponseWriter, r *http.Request) { 3398 testMethod(t, r, "GET") 3399 testHeader(t, r, "Accept", mediaTypeTopicsPreview) 3400 fmt.Fprint(w, `{"names":["go", "go-github", "github"]}`) 3401 }) 3402 3403 ctx := context.Background() 3404 got, _, err := client.Repositories.ListAllTopics(ctx, "o", "r") 3405 if err != nil { 3406 t.Fatalf("Repositories.ListAllTopics returned error: %v", err) 3407 } 3408 3409 want := []string{"go", "go-github", "github"} 3410 if !cmp.Equal(got, want) { 3411 t.Errorf("Repositories.ListAllTopics returned %+v, want %+v", got, want) 3412 } 3413 3414 const methodName = "ListAllTopics" 3415 testBadOptions(t, methodName, func() (err error) { 3416 _, _, err = client.Repositories.ListAllTopics(ctx, "\n", "\n") 3417 return err 3418 }) 3419 3420 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 3421 got, resp, err := client.Repositories.ListAllTopics(ctx, "o", "r") 3422 if got != nil { 3423 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 3424 } 3425 return resp, err 3426 }) 3427 } 3428 3429 func TestRepositoriesService_ListAllTopics_emptyTopics(t *testing.T) { 3430 t.Parallel() 3431 client, mux, _ := setup(t) 3432 3433 mux.HandleFunc("/repos/o/r/topics", func(w http.ResponseWriter, r *http.Request) { 3434 testMethod(t, r, "GET") 3435 testHeader(t, r, "Accept", mediaTypeTopicsPreview) 3436 fmt.Fprint(w, `{"names":[]}`) 3437 }) 3438 3439 ctx := context.Background() 3440 got, _, err := client.Repositories.ListAllTopics(ctx, "o", "r") 3441 if err != nil { 3442 t.Fatalf("Repositories.ListAllTopics returned error: %v", err) 3443 } 3444 3445 want := []string{} 3446 if !cmp.Equal(got, want) { 3447 t.Errorf("Repositories.ListAllTopics returned %+v, want %+v", got, want) 3448 } 3449 } 3450 3451 func TestRepositoriesService_ReplaceAllTopics(t *testing.T) { 3452 t.Parallel() 3453 client, mux, _ := setup(t) 3454 3455 mux.HandleFunc("/repos/o/r/topics", func(w http.ResponseWriter, r *http.Request) { 3456 testMethod(t, r, "PUT") 3457 testHeader(t, r, "Accept", mediaTypeTopicsPreview) 3458 fmt.Fprint(w, `{"names":["go", "go-github", "github"]}`) 3459 }) 3460 3461 ctx := context.Background() 3462 got, _, err := client.Repositories.ReplaceAllTopics(ctx, "o", "r", []string{"go", "go-github", "github"}) 3463 if err != nil { 3464 t.Fatalf("Repositories.ReplaceAllTopics returned error: %v", err) 3465 } 3466 3467 want := []string{"go", "go-github", "github"} 3468 if !cmp.Equal(got, want) { 3469 t.Errorf("Repositories.ReplaceAllTopics returned %+v, want %+v", got, want) 3470 } 3471 3472 const methodName = "ReplaceAllTopics" 3473 testBadOptions(t, methodName, func() (err error) { 3474 _, _, err = client.Repositories.ReplaceAllTopics(ctx, "\n", "\n", []string{"\n", "\n", "\n"}) 3475 return err 3476 }) 3477 3478 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 3479 got, resp, err := client.Repositories.ReplaceAllTopics(ctx, "o", "r", []string{"go", "go-github", "github"}) 3480 if got != nil { 3481 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 3482 } 3483 return resp, err 3484 }) 3485 } 3486 3487 func TestRepositoriesService_ReplaceAllTopics_nilSlice(t *testing.T) { 3488 t.Parallel() 3489 client, mux, _ := setup(t) 3490 3491 mux.HandleFunc("/repos/o/r/topics", func(w http.ResponseWriter, r *http.Request) { 3492 testMethod(t, r, "PUT") 3493 testHeader(t, r, "Accept", mediaTypeTopicsPreview) 3494 testBody(t, r, `{"names":[]}`+"\n") 3495 fmt.Fprint(w, `{"names":[]}`) 3496 }) 3497 3498 ctx := context.Background() 3499 got, _, err := client.Repositories.ReplaceAllTopics(ctx, "o", "r", nil) 3500 if err != nil { 3501 t.Fatalf("Repositories.ReplaceAllTopics returned error: %v", err) 3502 } 3503 3504 want := []string{} 3505 if !cmp.Equal(got, want) { 3506 t.Errorf("Repositories.ReplaceAllTopics returned %+v, want %+v", got, want) 3507 } 3508 } 3509 3510 func TestRepositoriesService_ReplaceAllTopics_emptySlice(t *testing.T) { 3511 t.Parallel() 3512 client, mux, _ := setup(t) 3513 3514 mux.HandleFunc("/repos/o/r/topics", func(w http.ResponseWriter, r *http.Request) { 3515 testMethod(t, r, "PUT") 3516 testHeader(t, r, "Accept", mediaTypeTopicsPreview) 3517 testBody(t, r, `{"names":[]}`+"\n") 3518 fmt.Fprint(w, `{"names":[]}`) 3519 }) 3520 3521 ctx := context.Background() 3522 got, _, err := client.Repositories.ReplaceAllTopics(ctx, "o", "r", []string{}) 3523 if err != nil { 3524 t.Fatalf("Repositories.ReplaceAllTopics returned error: %v", err) 3525 } 3526 3527 want := []string{} 3528 if !cmp.Equal(got, want) { 3529 t.Errorf("Repositories.ReplaceAllTopics returned %+v, want %+v", got, want) 3530 } 3531 } 3532 3533 func TestRepositoriesService_ListAppRestrictions(t *testing.T) { 3534 t.Parallel() 3535 tests := []struct { 3536 branch string 3537 urlPath string 3538 }{ 3539 {branch: "b", urlPath: "/repos/o/r/branches/b/protection/restrictions/apps"}, 3540 {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat%2fbranch-50%25/protection/restrictions/apps"}, 3541 } 3542 3543 for _, test := range tests { 3544 t.Run(test.branch, func(t *testing.T) { 3545 t.Parallel() 3546 client, mux, _ := setup(t) 3547 3548 mux.HandleFunc(test.urlPath, func(_ http.ResponseWriter, r *http.Request) { 3549 testMethod(t, r, "GET") 3550 }) 3551 3552 ctx := context.Background() 3553 _, _, err := client.Repositories.ListAppRestrictions(ctx, "o", "r", test.branch) 3554 if err != nil { 3555 t.Errorf("Repositories.ListAppRestrictions returned error: %v", err) 3556 } 3557 3558 const methodName = "ListAppRestrictions" 3559 testBadOptions(t, methodName, func() (err error) { 3560 _, _, err = client.Repositories.ListAppRestrictions(ctx, "\n", "\n", "\n") 3561 return err 3562 }) 3563 3564 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 3565 got, resp, err := client.Repositories.ListAppRestrictions(ctx, "o", "r", test.branch) 3566 if got != nil { 3567 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 3568 } 3569 return resp, err 3570 }) 3571 }) 3572 } 3573 } 3574 3575 func TestRepositoriesService_ReplaceAppRestrictions(t *testing.T) { 3576 t.Parallel() 3577 tests := []struct { 3578 branch string 3579 urlPath string 3580 }{ 3581 {branch: "b", urlPath: "/repos/o/r/branches/b/protection/restrictions/apps"}, 3582 {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat%2fbranch-50%25/protection/restrictions/apps"}, 3583 } 3584 3585 for _, test := range tests { 3586 t.Run(test.branch, func(t *testing.T) { 3587 t.Parallel() 3588 client, mux, _ := setup(t) 3589 3590 mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { 3591 testMethod(t, r, "PUT") 3592 fmt.Fprint(w, `[{ 3593 "name": "octocat" 3594 }]`) 3595 }) 3596 input := []string{"octocat"} 3597 ctx := context.Background() 3598 got, _, err := client.Repositories.ReplaceAppRestrictions(ctx, "o", "r", test.branch, input) 3599 if err != nil { 3600 t.Errorf("Repositories.ReplaceAppRestrictions returned error: %v", err) 3601 } 3602 want := []*App{ 3603 {Name: Ptr("octocat")}, 3604 } 3605 if !cmp.Equal(got, want) { 3606 t.Errorf("Repositories.ReplaceAppRestrictions returned %+v, want %+v", got, want) 3607 } 3608 3609 const methodName = "ReplaceAppRestrictions" 3610 testBadOptions(t, methodName, func() (err error) { 3611 _, _, err = client.Repositories.ReplaceAppRestrictions(ctx, "\n", "\n", "\n", input) 3612 return err 3613 }) 3614 3615 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 3616 got, resp, err := client.Repositories.ReplaceAppRestrictions(ctx, "o", "r", test.branch, input) 3617 if got != nil { 3618 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 3619 } 3620 return resp, err 3621 }) 3622 }) 3623 } 3624 } 3625 3626 func TestRepositoriesService_AddAppRestrictions(t *testing.T) { 3627 t.Parallel() 3628 tests := []struct { 3629 branch string 3630 urlPath string 3631 }{ 3632 {branch: "b", urlPath: "/repos/o/r/branches/b/protection/restrictions/apps"}, 3633 {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat%2fbranch-50%25/protection/restrictions/apps"}, 3634 } 3635 3636 for _, test := range tests { 3637 t.Run(test.branch, func(t *testing.T) { 3638 t.Parallel() 3639 client, mux, _ := setup(t) 3640 3641 mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { 3642 testMethod(t, r, "POST") 3643 fmt.Fprint(w, `[{ 3644 "name": "octocat" 3645 }]`) 3646 }) 3647 input := []string{"octocat"} 3648 ctx := context.Background() 3649 got, _, err := client.Repositories.AddAppRestrictions(ctx, "o", "r", test.branch, input) 3650 if err != nil { 3651 t.Errorf("Repositories.AddAppRestrictions returned error: %v", err) 3652 } 3653 want := []*App{ 3654 {Name: Ptr("octocat")}, 3655 } 3656 if !cmp.Equal(got, want) { 3657 t.Errorf("Repositories.AddAppRestrictions returned %+v, want %+v", got, want) 3658 } 3659 3660 const methodName = "AddAppRestrictions" 3661 testBadOptions(t, methodName, func() (err error) { 3662 _, _, err = client.Repositories.AddAppRestrictions(ctx, "\n", "\n", "\n", input) 3663 return err 3664 }) 3665 3666 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 3667 got, resp, err := client.Repositories.AddAppRestrictions(ctx, "o", "r", test.branch, input) 3668 if got != nil { 3669 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 3670 } 3671 return resp, err 3672 }) 3673 }) 3674 } 3675 } 3676 3677 func TestRepositoriesService_RemoveAppRestrictions(t *testing.T) { 3678 t.Parallel() 3679 tests := []struct { 3680 branch string 3681 urlPath string 3682 }{ 3683 {branch: "b", urlPath: "/repos/o/r/branches/b/protection/restrictions/apps"}, 3684 {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat%2fbranch-50%25/protection/restrictions/apps"}, 3685 } 3686 3687 for _, test := range tests { 3688 t.Run(test.branch, func(t *testing.T) { 3689 t.Parallel() 3690 client, mux, _ := setup(t) 3691 3692 mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { 3693 testMethod(t, r, "DELETE") 3694 fmt.Fprint(w, `[]`) 3695 }) 3696 input := []string{"octocat"} 3697 ctx := context.Background() 3698 got, _, err := client.Repositories.RemoveAppRestrictions(ctx, "o", "r", test.branch, input) 3699 if err != nil { 3700 t.Errorf("Repositories.RemoveAppRestrictions returned error: %v", err) 3701 } 3702 want := []*App{} 3703 if !cmp.Equal(got, want) { 3704 t.Errorf("Repositories.RemoveAppRestrictions returned %+v, want %+v", got, want) 3705 } 3706 3707 const methodName = "RemoveAppRestrictions" 3708 testBadOptions(t, methodName, func() (err error) { 3709 _, _, err = client.Repositories.RemoveAppRestrictions(ctx, "\n", "\n", "\n", input) 3710 return err 3711 }) 3712 3713 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 3714 got, resp, err := client.Repositories.RemoveAppRestrictions(ctx, "o", "r", test.branch, input) 3715 if got != nil { 3716 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 3717 } 3718 return resp, err 3719 }) 3720 }) 3721 } 3722 } 3723 3724 func TestRepositoriesService_ListTeamRestrictions(t *testing.T) { 3725 t.Parallel() 3726 tests := []struct { 3727 branch string 3728 urlPath string 3729 }{ 3730 {branch: "b", urlPath: "/repos/o/r/branches/b/protection/restrictions/teams"}, 3731 {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat%2fbranch-50%25/protection/restrictions/teams"}, 3732 } 3733 3734 for _, test := range tests { 3735 t.Run(test.branch, func(t *testing.T) { 3736 t.Parallel() 3737 client, mux, _ := setup(t) 3738 3739 mux.HandleFunc(test.urlPath, func(_ http.ResponseWriter, r *http.Request) { 3740 testMethod(t, r, "GET") 3741 }) 3742 3743 ctx := context.Background() 3744 _, _, err := client.Repositories.ListTeamRestrictions(ctx, "o", "r", test.branch) 3745 if err != nil { 3746 t.Errorf("Repositories.ListTeamRestrictions returned error: %v", err) 3747 } 3748 3749 const methodName = "ListTeamRestrictions" 3750 testBadOptions(t, methodName, func() (err error) { 3751 _, _, err = client.Repositories.ListTeamRestrictions(ctx, "\n", "\n", "\n") 3752 return err 3753 }) 3754 3755 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 3756 got, resp, err := client.Repositories.ListTeamRestrictions(ctx, "o", "r", test.branch) 3757 if got != nil { 3758 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 3759 } 3760 return resp, err 3761 }) 3762 }) 3763 } 3764 } 3765 3766 func TestRepositoriesService_ReplaceTeamRestrictions(t *testing.T) { 3767 t.Parallel() 3768 tests := []struct { 3769 branch string 3770 urlPath string 3771 }{ 3772 {branch: "b", urlPath: "/repos/o/r/branches/b/protection/restrictions/teams"}, 3773 {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat%2fbranch-50%25/protection/restrictions/teams"}, 3774 } 3775 3776 for _, test := range tests { 3777 t.Run(test.branch, func(t *testing.T) { 3778 t.Parallel() 3779 client, mux, _ := setup(t) 3780 3781 mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { 3782 testMethod(t, r, "PUT") 3783 fmt.Fprint(w, `[{ 3784 "name": "octocat" 3785 }]`) 3786 }) 3787 input := []string{"octocat"} 3788 ctx := context.Background() 3789 got, _, err := client.Repositories.ReplaceTeamRestrictions(ctx, "o", "r", test.branch, input) 3790 if err != nil { 3791 t.Errorf("Repositories.ReplaceTeamRestrictions returned error: %v", err) 3792 } 3793 want := []*Team{ 3794 {Name: Ptr("octocat")}, 3795 } 3796 if !cmp.Equal(got, want) { 3797 t.Errorf("Repositories.ReplaceTeamRestrictions returned %+v, want %+v", got, want) 3798 } 3799 3800 const methodName = "ReplaceTeamRestrictions" 3801 testBadOptions(t, methodName, func() (err error) { 3802 _, _, err = client.Repositories.ReplaceTeamRestrictions(ctx, "\n", "\n", "\n", input) 3803 return err 3804 }) 3805 3806 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 3807 got, resp, err := client.Repositories.ReplaceTeamRestrictions(ctx, "o", "r", test.branch, input) 3808 if got != nil { 3809 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 3810 } 3811 return resp, err 3812 }) 3813 }) 3814 } 3815 } 3816 3817 func TestRepositoriesService_AddTeamRestrictions(t *testing.T) { 3818 t.Parallel() 3819 tests := []struct { 3820 branch string 3821 urlPath string 3822 }{ 3823 {branch: "b", urlPath: "/repos/o/r/branches/b/protection/restrictions/teams"}, 3824 {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat%2fbranch-50%25/protection/restrictions/teams"}, 3825 } 3826 3827 for _, test := range tests { 3828 t.Run(test.branch, func(t *testing.T) { 3829 t.Parallel() 3830 client, mux, _ := setup(t) 3831 3832 mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { 3833 testMethod(t, r, "POST") 3834 fmt.Fprint(w, `[{ 3835 "name": "octocat" 3836 }]`) 3837 }) 3838 input := []string{"octocat"} 3839 ctx := context.Background() 3840 got, _, err := client.Repositories.AddTeamRestrictions(ctx, "o", "r", test.branch, input) 3841 if err != nil { 3842 t.Errorf("Repositories.AddTeamRestrictions returned error: %v", err) 3843 } 3844 want := []*Team{ 3845 {Name: Ptr("octocat")}, 3846 } 3847 if !cmp.Equal(got, want) { 3848 t.Errorf("Repositories.AddTeamRestrictions returned %+v, want %+v", got, want) 3849 } 3850 3851 const methodName = "AddTeamRestrictions" 3852 testBadOptions(t, methodName, func() (err error) { 3853 _, _, err = client.Repositories.AddTeamRestrictions(ctx, "\n", "\n", "\n", input) 3854 return err 3855 }) 3856 3857 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 3858 got, resp, err := client.Repositories.AddTeamRestrictions(ctx, "o", "r", test.branch, input) 3859 if got != nil { 3860 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 3861 } 3862 return resp, err 3863 }) 3864 }) 3865 } 3866 } 3867 3868 func TestRepositoriesService_RemoveTeamRestrictions(t *testing.T) { 3869 t.Parallel() 3870 tests := []struct { 3871 branch string 3872 urlPath string 3873 }{ 3874 {branch: "b", urlPath: "/repos/o/r/branches/b/protection/restrictions/teams"}, 3875 {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat%2fbranch-50%25/protection/restrictions/teams"}, 3876 } 3877 3878 for _, test := range tests { 3879 t.Run(test.branch, func(t *testing.T) { 3880 t.Parallel() 3881 client, mux, _ := setup(t) 3882 3883 mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { 3884 testMethod(t, r, "DELETE") 3885 fmt.Fprint(w, `[]`) 3886 }) 3887 input := []string{"octocat"} 3888 ctx := context.Background() 3889 got, _, err := client.Repositories.RemoveTeamRestrictions(ctx, "o", "r", test.branch, input) 3890 if err != nil { 3891 t.Errorf("Repositories.RemoveTeamRestrictions returned error: %v", err) 3892 } 3893 want := []*Team{} 3894 if !cmp.Equal(got, want) { 3895 t.Errorf("Repositories.RemoveTeamRestrictions returned %+v, want %+v", got, want) 3896 } 3897 3898 const methodName = "RemoveTeamRestrictions" 3899 testBadOptions(t, methodName, func() (err error) { 3900 _, _, err = client.Repositories.RemoveTeamRestrictions(ctx, "\n", "\n", "\n", input) 3901 return err 3902 }) 3903 3904 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 3905 got, resp, err := client.Repositories.RemoveTeamRestrictions(ctx, "o", "r", test.branch, input) 3906 if got != nil { 3907 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 3908 } 3909 return resp, err 3910 }) 3911 }) 3912 } 3913 } 3914 3915 func TestRepositoriesService_ListUserRestrictions(t *testing.T) { 3916 t.Parallel() 3917 tests := []struct { 3918 branch string 3919 urlPath string 3920 }{ 3921 {branch: "b", urlPath: "/repos/o/r/branches/b/protection/restrictions/users"}, 3922 {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat%2fbranch-50%25/protection/restrictions/users"}, 3923 } 3924 3925 for _, test := range tests { 3926 t.Run(test.branch, func(t *testing.T) { 3927 t.Parallel() 3928 client, mux, _ := setup(t) 3929 3930 mux.HandleFunc(test.urlPath, func(_ http.ResponseWriter, r *http.Request) { 3931 testMethod(t, r, "GET") 3932 }) 3933 3934 ctx := context.Background() 3935 _, _, err := client.Repositories.ListUserRestrictions(ctx, "o", "r", test.branch) 3936 if err != nil { 3937 t.Errorf("Repositories.ListUserRestrictions returned error: %v", err) 3938 } 3939 3940 const methodName = "ListUserRestrictions" 3941 testBadOptions(t, methodName, func() (err error) { 3942 _, _, err = client.Repositories.ListUserRestrictions(ctx, "\n", "\n", "\n") 3943 return err 3944 }) 3945 3946 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 3947 got, resp, err := client.Repositories.ListUserRestrictions(ctx, "o", "r", test.branch) 3948 if got != nil { 3949 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 3950 } 3951 return resp, err 3952 }) 3953 }) 3954 } 3955 } 3956 3957 func TestRepositoriesService_ReplaceUserRestrictions(t *testing.T) { 3958 t.Parallel() 3959 tests := []struct { 3960 branch string 3961 urlPath string 3962 }{ 3963 {branch: "b", urlPath: "/repos/o/r/branches/b/protection/restrictions/users"}, 3964 {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat%2fbranch-50%25/protection/restrictions/users"}, 3965 } 3966 3967 for _, test := range tests { 3968 t.Run(test.branch, func(t *testing.T) { 3969 t.Parallel() 3970 client, mux, _ := setup(t) 3971 3972 mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { 3973 testMethod(t, r, "PUT") 3974 fmt.Fprint(w, `[{ 3975 "name": "octocat" 3976 }]`) 3977 }) 3978 input := []string{"octocat"} 3979 ctx := context.Background() 3980 got, _, err := client.Repositories.ReplaceUserRestrictions(ctx, "o", "r", test.branch, input) 3981 if err != nil { 3982 t.Errorf("Repositories.ReplaceUserRestrictions returned error: %v", err) 3983 } 3984 want := []*User{ 3985 {Name: Ptr("octocat")}, 3986 } 3987 if !cmp.Equal(got, want) { 3988 t.Errorf("Repositories.ReplaceUserRestrictions returned %+v, want %+v", got, want) 3989 } 3990 3991 const methodName = "ReplaceUserRestrictions" 3992 testBadOptions(t, methodName, func() (err error) { 3993 _, _, err = client.Repositories.ReplaceUserRestrictions(ctx, "\n", "\n", "\n", input) 3994 return err 3995 }) 3996 3997 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 3998 got, resp, err := client.Repositories.ReplaceUserRestrictions(ctx, "o", "r", test.branch, input) 3999 if got != nil { 4000 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 4001 } 4002 return resp, err 4003 }) 4004 }) 4005 } 4006 } 4007 4008 func TestRepositoriesService_AddUserRestrictions(t *testing.T) { 4009 t.Parallel() 4010 tests := []struct { 4011 branch string 4012 urlPath string 4013 }{ 4014 {branch: "b", urlPath: "/repos/o/r/branches/b/protection/restrictions/users"}, 4015 {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat%2fbranch-50%25/protection/restrictions/users"}, 4016 } 4017 4018 for _, test := range tests { 4019 t.Run(test.branch, func(t *testing.T) { 4020 t.Parallel() 4021 client, mux, _ := setup(t) 4022 4023 mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { 4024 testMethod(t, r, "POST") 4025 fmt.Fprint(w, `[{ 4026 "name": "octocat" 4027 }]`) 4028 }) 4029 input := []string{"octocat"} 4030 ctx := context.Background() 4031 got, _, err := client.Repositories.AddUserRestrictions(ctx, "o", "r", test.branch, input) 4032 if err != nil { 4033 t.Errorf("Repositories.AddUserRestrictions returned error: %v", err) 4034 } 4035 want := []*User{ 4036 {Name: Ptr("octocat")}, 4037 } 4038 if !cmp.Equal(got, want) { 4039 t.Errorf("Repositories.AddUserRestrictions returned %+v, want %+v", got, want) 4040 } 4041 4042 const methodName = "AddUserRestrictions" 4043 testBadOptions(t, methodName, func() (err error) { 4044 _, _, err = client.Repositories.AddUserRestrictions(ctx, "\n", "\n", "\n", input) 4045 return err 4046 }) 4047 4048 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 4049 got, resp, err := client.Repositories.AddUserRestrictions(ctx, "o", "r", test.branch, input) 4050 if got != nil { 4051 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 4052 } 4053 return resp, err 4054 }) 4055 }) 4056 } 4057 } 4058 4059 func TestRepositoriesService_RemoveUserRestrictions(t *testing.T) { 4060 t.Parallel() 4061 tests := []struct { 4062 branch string 4063 urlPath string 4064 }{ 4065 {branch: "b", urlPath: "/repos/o/r/branches/b/protection/restrictions/users"}, 4066 {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat%2fbranch-50%25/protection/restrictions/users"}, 4067 } 4068 4069 for _, test := range tests { 4070 t.Run(test.branch, func(t *testing.T) { 4071 t.Parallel() 4072 client, mux, _ := setup(t) 4073 4074 mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { 4075 testMethod(t, r, "DELETE") 4076 fmt.Fprint(w, `[]`) 4077 }) 4078 input := []string{"octocat"} 4079 ctx := context.Background() 4080 got, _, err := client.Repositories.RemoveUserRestrictions(ctx, "o", "r", test.branch, input) 4081 if err != nil { 4082 t.Errorf("Repositories.RemoveUserRestrictions returned error: %v", err) 4083 } 4084 want := []*User{} 4085 if !cmp.Equal(got, want) { 4086 t.Errorf("Repositories.RemoveUserRestrictions returned %+v, want %+v", got, want) 4087 } 4088 4089 const methodName = "RemoveUserRestrictions" 4090 testBadOptions(t, methodName, func() (err error) { 4091 _, _, err = client.Repositories.RemoveUserRestrictions(ctx, "\n", "\n", "\n", input) 4092 return err 4093 }) 4094 4095 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 4096 got, resp, err := client.Repositories.RemoveUserRestrictions(ctx, "o", "r", test.branch, input) 4097 if got != nil { 4098 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 4099 } 4100 return resp, err 4101 }) 4102 }) 4103 } 4104 } 4105 4106 func TestRepositoriesService_Transfer(t *testing.T) { 4107 t.Parallel() 4108 client, mux, _ := setup(t) 4109 4110 input := TransferRequest{NewOwner: "a", NewName: Ptr("b"), TeamID: []int64{123}} 4111 4112 mux.HandleFunc("/repos/o/r/transfer", func(w http.ResponseWriter, r *http.Request) { 4113 var v TransferRequest 4114 assertNilError(t, json.NewDecoder(r.Body).Decode(&v)) 4115 4116 testMethod(t, r, "POST") 4117 if !cmp.Equal(v, input) { 4118 t.Errorf("Request body = %+v, want %+v", v, input) 4119 } 4120 4121 fmt.Fprint(w, `{"owner":{"login":"a"}}`) 4122 }) 4123 4124 ctx := context.Background() 4125 got, _, err := client.Repositories.Transfer(ctx, "o", "r", input) 4126 if err != nil { 4127 t.Errorf("Repositories.Transfer returned error: %v", err) 4128 } 4129 4130 want := &Repository{Owner: &User{Login: Ptr("a")}} 4131 if !cmp.Equal(got, want) { 4132 t.Errorf("Repositories.Transfer returned %+v, want %+v", got, want) 4133 } 4134 4135 const methodName = "Transfer" 4136 testBadOptions(t, methodName, func() (err error) { 4137 _, _, err = client.Repositories.Transfer(ctx, "\n", "\n", input) 4138 return err 4139 }) 4140 4141 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 4142 got, resp, err := client.Repositories.Transfer(ctx, "o", "r", input) 4143 if got != nil { 4144 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 4145 } 4146 return resp, err 4147 }) 4148 } 4149 4150 func TestRepositoriesService_Dispatch(t *testing.T) { 4151 t.Parallel() 4152 client, mux, _ := setup(t) 4153 4154 var input DispatchRequestOptions 4155 4156 mux.HandleFunc("/repos/o/r/dispatches", func(w http.ResponseWriter, r *http.Request) { 4157 var v DispatchRequestOptions 4158 assertNilError(t, json.NewDecoder(r.Body).Decode(&v)) 4159 4160 testMethod(t, r, "POST") 4161 if !cmp.Equal(v, input) { 4162 t.Errorf("Request body = %+v, want %+v", v, input) 4163 } 4164 4165 fmt.Fprint(w, `{"owner":{"login":"a"}}`) 4166 }) 4167 4168 ctx := context.Background() 4169 4170 testCases := []any{ 4171 nil, 4172 struct { 4173 Foo string 4174 }{ 4175 Foo: "test", 4176 }, 4177 struct { 4178 Bar int 4179 }{ 4180 Bar: 42, 4181 }, 4182 struct { 4183 Foo string 4184 Bar int 4185 Baz bool 4186 }{ 4187 Foo: "test", 4188 Bar: 42, 4189 Baz: false, 4190 }, 4191 } 4192 4193 for _, tc := range testCases { 4194 if tc == nil { 4195 input = DispatchRequestOptions{EventType: "go"} 4196 } else { 4197 bytes, _ := json.Marshal(tc) 4198 payload := json.RawMessage(bytes) 4199 input = DispatchRequestOptions{EventType: "go", ClientPayload: &payload} 4200 } 4201 4202 got, _, err := client.Repositories.Dispatch(ctx, "o", "r", input) 4203 if err != nil { 4204 t.Errorf("Repositories.Dispatch returned error: %v", err) 4205 } 4206 4207 want := &Repository{Owner: &User{Login: Ptr("a")}} 4208 if !cmp.Equal(got, want) { 4209 t.Errorf("Repositories.Dispatch returned %+v, want %+v", got, want) 4210 } 4211 } 4212 4213 const methodName = "Dispatch" 4214 testBadOptions(t, methodName, func() (err error) { 4215 _, _, err = client.Repositories.Dispatch(ctx, "\n", "\n", input) 4216 return err 4217 }) 4218 4219 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 4220 got, resp, err := client.Repositories.Dispatch(ctx, "o", "r", input) 4221 if got != nil { 4222 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 4223 } 4224 return resp, err 4225 }) 4226 } 4227 4228 func TestAdvancedSecurity_Marshal(t *testing.T) { 4229 t.Parallel() 4230 testJSONMarshal(t, &AdvancedSecurity{}, "{}") 4231 4232 u := &AdvancedSecurity{ 4233 Status: Ptr("status"), 4234 } 4235 4236 want := `{ 4237 "status": "status" 4238 }` 4239 4240 testJSONMarshal(t, u, want) 4241 } 4242 4243 func TestAuthorizedActorsOnly_Marshal(t *testing.T) { 4244 t.Parallel() 4245 testJSONMarshal(t, &AuthorizedActorsOnly{}, "{}") 4246 4247 u := &AuthorizedActorsOnly{ 4248 From: Ptr(true), 4249 } 4250 4251 want := `{ 4252 "from" : true 4253 }` 4254 4255 testJSONMarshal(t, u, want) 4256 } 4257 4258 func TestDispatchRequestOptions_Marshal(t *testing.T) { 4259 t.Parallel() 4260 testJSONMarshal(t, &DispatchRequestOptions{}, "{}") 4261 4262 cp := json.RawMessage(`{"testKey":"testValue"}`) 4263 u := &DispatchRequestOptions{ 4264 EventType: "test_event_type", 4265 ClientPayload: &cp, 4266 } 4267 4268 want := `{ 4269 "event_type": "test_event_type", 4270 "client_payload": { 4271 "testKey": "testValue" 4272 } 4273 }` 4274 4275 testJSONMarshal(t, u, want) 4276 } 4277 4278 func TestTransferRequest_Marshal(t *testing.T) { 4279 t.Parallel() 4280 testJSONMarshal(t, &TransferRequest{}, "{}") 4281 4282 u := &TransferRequest{ 4283 NewOwner: "testOwner", 4284 NewName: Ptr("testName"), 4285 TeamID: []int64{1, 2}, 4286 } 4287 4288 want := `{ 4289 "new_owner": "testOwner", 4290 "new_name": "testName", 4291 "team_ids": [1,2] 4292 }` 4293 4294 testJSONMarshal(t, u, want) 4295 } 4296 4297 func TestSignaturesProtectedBranch_Marshal(t *testing.T) { 4298 t.Parallel() 4299 testJSONMarshal(t, &SignaturesProtectedBranch{}, "{}") 4300 4301 u := &SignaturesProtectedBranch{ 4302 URL: Ptr("https://www.testURL.in"), 4303 Enabled: Ptr(false), 4304 } 4305 4306 want := `{ 4307 "url": "https://www.testURL.in", 4308 "enabled": false 4309 }` 4310 4311 testJSONMarshal(t, u, want) 4312 4313 u2 := &SignaturesProtectedBranch{ 4314 URL: Ptr("testURL"), 4315 Enabled: Ptr(true), 4316 } 4317 4318 want2 := `{ 4319 "url": "testURL", 4320 "enabled": true 4321 }` 4322 4323 testJSONMarshal(t, u2, want2) 4324 } 4325 4326 func TestDismissalRestrictionsRequest_Marshal(t *testing.T) { 4327 t.Parallel() 4328 testJSONMarshal(t, &DismissalRestrictionsRequest{}, "{}") 4329 4330 u := &DismissalRestrictionsRequest{ 4331 Users: &[]string{"user1", "user2"}, 4332 Teams: &[]string{"team1", "team2"}, 4333 Apps: &[]string{"app1", "app2"}, 4334 } 4335 4336 want := `{ 4337 "users": ["user1","user2"], 4338 "teams": ["team1","team2"], 4339 "apps": ["app1","app2"] 4340 }` 4341 4342 testJSONMarshal(t, u, want) 4343 } 4344 4345 func TestAdminEnforcement_Marshal(t *testing.T) { 4346 t.Parallel() 4347 testJSONMarshal(t, &AdminEnforcement{}, "{}") 4348 4349 u := &AdminEnforcement{ 4350 URL: Ptr("https://www.test-url.in"), 4351 Enabled: false, 4352 } 4353 4354 want := `{ 4355 "url": "https://www.test-url.in", 4356 "enabled": false 4357 }` 4358 4359 testJSONMarshal(t, u, want) 4360 } 4361 4362 func TestPullRequestReviewsEnforcementUpdate_Marshal(t *testing.T) { 4363 t.Parallel() 4364 testJSONMarshal(t, &PullRequestReviewsEnforcementUpdate{}, "{}") 4365 4366 u := &PullRequestReviewsEnforcementUpdate{ 4367 BypassPullRequestAllowancesRequest: &BypassPullRequestAllowancesRequest{ 4368 Users: []string{"user1", "user2"}, 4369 Teams: []string{"team1", "team2"}, 4370 Apps: []string{"app1", "app2"}, 4371 }, 4372 DismissStaleReviews: Ptr(false), 4373 RequireCodeOwnerReviews: Ptr(true), 4374 RequiredApprovingReviewCount: 2, 4375 } 4376 4377 want := `{ 4378 "bypass_pull_request_allowances": { 4379 "users": ["user1","user2"], 4380 "teams": ["team1","team2"], 4381 "apps": ["app1","app2"] 4382 }, 4383 "dismiss_stale_reviews": false, 4384 "require_code_owner_reviews": true, 4385 "required_approving_review_count": 2 4386 }` 4387 4388 testJSONMarshal(t, u, want) 4389 } 4390 4391 func TestRequiredStatusCheck_Marshal(t *testing.T) { 4392 t.Parallel() 4393 testJSONMarshal(t, &RequiredStatusCheck{}, "{}") 4394 4395 u := &RequiredStatusCheck{ 4396 Context: "ctx", 4397 AppID: Ptr(int64(1)), 4398 } 4399 4400 want := `{ 4401 "context": "ctx", 4402 "app_id": 1 4403 }` 4404 4405 testJSONMarshal(t, u, want) 4406 } 4407 4408 func TestRepositoryTag_Marshal(t *testing.T) { 4409 t.Parallel() 4410 testJSONMarshal(t, &RepositoryTag{}, "{}") 4411 4412 u := &RepositoryTag{ 4413 Name: Ptr("v0.1"), 4414 Commit: &Commit{ 4415 SHA: Ptr("sha"), 4416 URL: Ptr("url"), 4417 }, 4418 ZipballURL: Ptr("zball"), 4419 TarballURL: Ptr("tball"), 4420 } 4421 4422 want := `{ 4423 "name": "v0.1", 4424 "commit": { 4425 "sha": "sha", 4426 "url": "url" 4427 }, 4428 "zipball_url": "zball", 4429 "tarball_url": "tball" 4430 }` 4431 4432 testJSONMarshal(t, u, want) 4433 } 4434 4435 func TestRepositoriesService_EnablePrivateReporting(t *testing.T) { 4436 t.Parallel() 4437 client, mux, _ := setup(t) 4438 4439 mux.HandleFunc("/repos/owner/repo/private-vulnerability-reporting", func(w http.ResponseWriter, r *http.Request) { 4440 testMethod(t, r, "PUT") 4441 w.WriteHeader(http.StatusNoContent) 4442 }) 4443 4444 ctx := context.Background() 4445 _, err := client.Repositories.EnablePrivateReporting(ctx, "owner", "repo") 4446 if err != nil { 4447 t.Errorf("Repositories.EnablePrivateReporting returned error: %v", err) 4448 } 4449 4450 const methodName = "EnablePrivateReporting" 4451 testBadOptions(t, methodName, func() (err error) { 4452 _, err = client.Repositories.EnablePrivateReporting(ctx, "\n", "\n") 4453 return err 4454 }) 4455 4456 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 4457 return client.Repositories.EnablePrivateReporting(ctx, "owner", "repo") 4458 }) 4459 } 4460 4461 func TestRepositoriesService_DisablePrivateReporting(t *testing.T) { 4462 t.Parallel() 4463 client, mux, _ := setup(t) 4464 4465 mux.HandleFunc("/repos/owner/repo/private-vulnerability-reporting", func(w http.ResponseWriter, r *http.Request) { 4466 testMethod(t, r, "DELETE") 4467 w.WriteHeader(http.StatusNoContent) 4468 }) 4469 4470 ctx := context.Background() 4471 _, err := client.Repositories.DisablePrivateReporting(ctx, "owner", "repo") 4472 if err != nil { 4473 t.Errorf("Repositories.DisablePrivateReporting returned error: %v", err) 4474 } 4475 4476 const methodName = "DisablePrivateReporting" 4477 testBadOptions(t, methodName, func() (err error) { 4478 _, err = client.Repositories.DisablePrivateReporting(ctx, "\n", "\n") 4479 return err 4480 }) 4481 4482 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 4483 return client.Repositories.DisablePrivateReporting(ctx, "owner", "repo") 4484 }) 4485 } 4486 4487 func TestRepositoriesService_IsPrivateReportingEnabled(t *testing.T) { 4488 t.Parallel() 4489 client, mux, _ := setup(t) 4490 4491 mux.HandleFunc("/repos/owner/repo/private-vulnerability-reporting", func(w http.ResponseWriter, r *http.Request) { 4492 testMethod(t, r, "GET") 4493 fmt.Fprint(w, `{"enabled": true}`) 4494 }) 4495 4496 ctx := context.Background() 4497 enabled, _, err := client.Repositories.IsPrivateReportingEnabled(ctx, "owner", "repo") 4498 if err != nil { 4499 t.Errorf("Repositories.IsPrivateReportingEnabled returned error: %v", err) 4500 } 4501 if want := true; enabled != want { 4502 t.Errorf("Repositories.IsPrivateReportingEnabled returned %+v, want %+v", enabled, want) 4503 } 4504 4505 const methodName = "IsPrivateReportingEnabled" 4506 testBadOptions(t, methodName, func() (err error) { 4507 _, _, err = client.Repositories.IsPrivateReportingEnabled(ctx, "\n", "\n") 4508 return err 4509 }) 4510 4511 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 4512 got, resp, err := client.Repositories.IsPrivateReportingEnabled(ctx, "owner", "repo") 4513 if got { 4514 t.Errorf("testNewRequestAndDoFailure %v = %#v, want false", methodName, got) 4515 } 4516 return resp, err 4517 }) 4518 } 4519 4520 func TestRepository_UnmarshalJSON(t *testing.T) { 4521 t.Parallel() 4522 var testCases = map[string]struct { 4523 data []byte 4524 wantRepository Repository 4525 wantErr bool 4526 }{ 4527 "Empty": { 4528 data: []byte("{}"), 4529 wantRepository: Repository{}, 4530 wantErr: false, 4531 }, 4532 "Invalid JSON": { 4533 data: []byte("{"), 4534 wantRepository: Repository{}, 4535 wantErr: true, 4536 }, 4537 "Partial project": { 4538 data: []byte(`{"id":10270722,"name":"go-github","private":false,"owner":{"login":"google"},"created_at":"2013-05-24T16:42:58Z","license":{},"topics":["github"],"permissions":{"pull":true},"custom_properties":{},"organization":{"login":"google"}}`), 4539 wantRepository: Repository{ID: Ptr(int64(10270722)), Name: Ptr("go-github"), Private: Ptr(false), Owner: &User{Login: Ptr("google")}, CreatedAt: &Timestamp{time.Date(2013, 5, 24, 16, 42, 58, 0, time.UTC)}, License: &License{}, Topics: []string{"github"}, Permissions: map[string]bool{"pull": true}, CustomProperties: map[string]any{}, Organization: &Organization{Login: Ptr("google")}}, 4540 wantErr: false, 4541 }, 4542 "With custom properties": { 4543 data: []byte(`{"custom_properties":{"boolean":"false","text":"a","single-select":"a","multi-select":["a","b","c"]}}`), 4544 wantRepository: Repository{CustomProperties: map[string]any{"boolean": "false", "text": "a", "single-select": "a", "multi-select": []any{"a", "b", "c"}}}, 4545 wantErr: false, 4546 }, 4547 } 4548 4549 for name, tt := range testCases { 4550 t.Run(name, func(t *testing.T) { 4551 t.Parallel() 4552 pk := Repository{} 4553 err := json.Unmarshal(tt.data, &pk) 4554 if err == nil && tt.wantErr { 4555 t.Error("Repository.UnmarshalJSON returned nil instead of an error") 4556 } 4557 if err != nil && !tt.wantErr { 4558 t.Errorf("Repository.UnmarshalJSON returned an unexpected error: %+v", err) 4559 } 4560 if !cmp.Equal(tt.wantRepository, pk) { 4561 t.Errorf("Repository.UnmarshalJSON expected repository %+v, got %+v", tt.wantRepository, pk) 4562 } 4563 }) 4564 } 4565 }