diff --git a/github/repos.go b/github/repos.go index e09971abea..f2059926ec 100644 --- a/github/repos.go +++ b/github/repos.go @@ -11,6 +11,7 @@ import ( "errors" "fmt" "net/http" + "net/url" "strings" ) @@ -1273,9 +1274,11 @@ func (s *RepositoriesService) ListBranches(ctx context.Context, owner string, re // GetBranch gets the specified branch for a repository. // +// Note: the branch name is URL path escaped for you. See: https://pkg.go.dev/net/url#PathEscape . +// // GitHub API docs: https://docs.github.com/en/rest/branches/branches#get-a-branch func (s *RepositoriesService) GetBranch(ctx context.Context, owner, repo, branch string, maxRedirects int) (*Branch, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v", owner, repo, branch) + u := fmt.Sprintf("repos/%v/%v/branches/%v", owner, repo, url.PathEscape(branch)) resp, err := s.client.roundTripWithOptionalFollowRedirect(ctx, u, maxRedirects) if err != nil { @@ -1302,9 +1305,11 @@ type renameBranchRequest struct { // To rename a non-default branch: Users must have push access. GitHub Apps must have the `contents:write` repository permission. // To rename the default branch: Users must have admin or owner permissions. GitHub Apps must have the `administration:write` repository permission. // +// Note: the branch name is URL path escaped for you. See: https://pkg.go.dev/net/url#PathEscape . +// // GitHub API docs: https://docs.github.com/en/rest/branches/branches#rename-a-branch func (s *RepositoriesService) RenameBranch(ctx context.Context, owner, repo, branch, newName string) (*Branch, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/rename", owner, repo, branch) + u := fmt.Sprintf("repos/%v/%v/branches/%v/rename", owner, repo, url.PathEscape(branch)) r := &renameBranchRequest{NewName: newName} req, err := s.client.NewRequest("POST", u, r) if err != nil { @@ -1322,9 +1327,11 @@ func (s *RepositoriesService) RenameBranch(ctx context.Context, owner, repo, bra // GetBranchProtection gets the protection of a given branch. // +// Note: the branch name is URL path escaped for you. See: https://pkg.go.dev/net/url#PathEscape . +// // GitHub API docs: https://docs.github.com/en/rest/branches/branch-protection#get-branch-protection func (s *RepositoriesService) GetBranchProtection(ctx context.Context, owner, repo, branch string) (*Protection, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection", owner, repo, branch) + u := fmt.Sprintf("repos/%v/%v/branches/%v/protection", owner, repo, url.PathEscape(branch)) req, err := s.client.NewRequest("GET", u, nil) if err != nil { return nil, nil, err @@ -1347,9 +1354,11 @@ func (s *RepositoriesService) GetBranchProtection(ctx context.Context, owner, re // GetRequiredStatusChecks gets the required status checks for a given protected branch. // +// Note: the branch name is URL path escaped for you. See: https://pkg.go.dev/net/url#PathEscape . +// // GitHub API docs: https://docs.github.com/en/rest/branches/branch-protection#get-status-checks-protection func (s *RepositoriesService) GetRequiredStatusChecks(ctx context.Context, owner, repo, branch string) (*RequiredStatusChecks, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/required_status_checks", owner, repo, branch) + u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/required_status_checks", owner, repo, url.PathEscape(branch)) req, err := s.client.NewRequest("GET", u, nil) if err != nil { return nil, nil, err @@ -1369,9 +1378,11 @@ func (s *RepositoriesService) GetRequiredStatusChecks(ctx context.Context, owner // ListRequiredStatusChecksContexts lists the required status checks contexts for a given protected branch. // +// Note: the branch name is URL path escaped for you. See: https://pkg.go.dev/net/url#PathEscape . +// // GitHub API docs: https://docs.github.com/en/rest/branches/branch-protection#get-all-status-check-contexts func (s *RepositoriesService) ListRequiredStatusChecksContexts(ctx context.Context, owner, repo, branch string) (contexts []string, resp *Response, err error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/required_status_checks/contexts", owner, repo, branch) + u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/required_status_checks/contexts", owner, repo, url.PathEscape(branch)) req, err := s.client.NewRequest("GET", u, nil) if err != nil { return nil, nil, err @@ -1390,9 +1401,11 @@ func (s *RepositoriesService) ListRequiredStatusChecksContexts(ctx context.Conte // UpdateBranchProtection updates the protection of a given branch. // +// Note: the branch name is URL path escaped for you. See: https://pkg.go.dev/net/url#PathEscape . +// // GitHub API docs: https://docs.github.com/en/rest/branches/branch-protection#update-branch-protection func (s *RepositoriesService) UpdateBranchProtection(ctx context.Context, owner, repo, branch string, preq *ProtectionRequest) (*Protection, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection", owner, repo, branch) + u := fmt.Sprintf("repos/%v/%v/branches/%v/protection", owner, repo, url.PathEscape(branch)) req, err := s.client.NewRequest("PUT", u, preq) if err != nil { return nil, nil, err @@ -1412,9 +1425,11 @@ func (s *RepositoriesService) UpdateBranchProtection(ctx context.Context, owner, // RemoveBranchProtection removes the protection of a given branch. // +// Note: the branch name is URL path escaped for you. See: https://pkg.go.dev/net/url#PathEscape . +// // GitHub API docs: https://docs.github.com/en/rest/branches/branch-protection#delete-branch-protection func (s *RepositoriesService) RemoveBranchProtection(ctx context.Context, owner, repo, branch string) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection", owner, repo, branch) + u := fmt.Sprintf("repos/%v/%v/branches/%v/protection", owner, repo, url.PathEscape(branch)) req, err := s.client.NewRequest("DELETE", u, nil) if err != nil { return nil, err @@ -1425,9 +1440,11 @@ func (s *RepositoriesService) RemoveBranchProtection(ctx context.Context, owner, // GetSignaturesProtectedBranch gets required signatures of protected branch. // +// Note: the branch name is URL path escaped for you. See: https://pkg.go.dev/net/url#PathEscape . +// // GitHub API docs: https://docs.github.com/en/rest/branches/branch-protection#get-commit-signature-protection func (s *RepositoriesService) GetSignaturesProtectedBranch(ctx context.Context, owner, repo, branch string) (*SignaturesProtectedBranch, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/required_signatures", owner, repo, branch) + u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/required_signatures", owner, repo, url.PathEscape(branch)) req, err := s.client.NewRequest("GET", u, nil) if err != nil { return nil, nil, err @@ -1448,9 +1465,11 @@ func (s *RepositoriesService) GetSignaturesProtectedBranch(ctx context.Context, // RequireSignaturesOnProtectedBranch makes signed commits required on a protected branch. // It requires admin access and branch protection to be enabled. // +// Note: the branch name is URL path escaped for you. See: https://pkg.go.dev/net/url#PathEscape . +// // GitHub API docs: https://docs.github.com/en/rest/branches/branch-protection#create-commit-signature-protection func (s *RepositoriesService) RequireSignaturesOnProtectedBranch(ctx context.Context, owner, repo, branch string) (*SignaturesProtectedBranch, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/required_signatures", owner, repo, branch) + u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/required_signatures", owner, repo, url.PathEscape(branch)) req, err := s.client.NewRequest("POST", u, nil) if err != nil { return nil, nil, err @@ -1470,9 +1489,11 @@ func (s *RepositoriesService) RequireSignaturesOnProtectedBranch(ctx context.Con // OptionalSignaturesOnProtectedBranch removes required signed commits on a given branch. // +// Note: the branch name is URL path escaped for you. See: https://pkg.go.dev/net/url#PathEscape . +// // GitHub API docs: https://docs.github.com/en/rest/branches/branch-protection#delete-commit-signature-protection func (s *RepositoriesService) OptionalSignaturesOnProtectedBranch(ctx context.Context, owner, repo, branch string) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/required_signatures", owner, repo, branch) + u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/required_signatures", owner, repo, url.PathEscape(branch)) req, err := s.client.NewRequest("DELETE", u, nil) if err != nil { return nil, err @@ -1486,9 +1507,11 @@ func (s *RepositoriesService) OptionalSignaturesOnProtectedBranch(ctx context.Co // UpdateRequiredStatusChecks updates the required status checks for a given protected branch. // +// Note: the branch name is URL path escaped for you. See: https://pkg.go.dev/net/url#PathEscape . +// // GitHub API docs: https://docs.github.com/en/rest/branches/branch-protection#update-status-check-protection func (s *RepositoriesService) UpdateRequiredStatusChecks(ctx context.Context, owner, repo, branch string, sreq *RequiredStatusChecksRequest) (*RequiredStatusChecks, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/required_status_checks", owner, repo, branch) + u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/required_status_checks", owner, repo, url.PathEscape(branch)) req, err := s.client.NewRequest("PATCH", u, sreq) if err != nil { return nil, nil, err @@ -1505,9 +1528,11 @@ func (s *RepositoriesService) UpdateRequiredStatusChecks(ctx context.Context, ow // RemoveRequiredStatusChecks removes the required status checks for a given protected branch. // +// Note: the branch name is URL path escaped for you. See: https://pkg.go.dev/net/url#PathEscape . +// // GitHub API docs: https://docs.github.com/en/rest/branches/branch-protection#remove-status-check-protection func (s *RepositoriesService) RemoveRequiredStatusChecks(ctx context.Context, owner, repo, branch string) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/required_status_checks", owner, repo, branch) + u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/required_status_checks", owner, repo, url.PathEscape(branch)) req, err := s.client.NewRequest("DELETE", u, nil) if err != nil { return nil, err @@ -1537,9 +1562,11 @@ func (s *RepositoriesService) License(ctx context.Context, owner, repo string) ( // GetPullRequestReviewEnforcement gets pull request review enforcement of a protected branch. // +// Note: the branch name is URL path escaped for you. See: https://pkg.go.dev/net/url#PathEscape . +// // GitHub API docs: https://docs.github.com/en/rest/branches/branch-protection#get-pull-request-review-protection func (s *RepositoriesService) GetPullRequestReviewEnforcement(ctx context.Context, owner, repo, branch string) (*PullRequestReviewsEnforcement, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/required_pull_request_reviews", owner, repo, branch) + u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/required_pull_request_reviews", owner, repo, url.PathEscape(branch)) req, err := s.client.NewRequest("GET", u, nil) if err != nil { return nil, nil, err @@ -1560,9 +1587,11 @@ func (s *RepositoriesService) GetPullRequestReviewEnforcement(ctx context.Contex // UpdatePullRequestReviewEnforcement patches pull request review enforcement of a protected branch. // It requires admin access and branch protection to be enabled. // +// Note: the branch name is URL path escaped for you. See: https://pkg.go.dev/net/url#PathEscape . +// // GitHub API docs: https://docs.github.com/en/rest/branches/branch-protection#update-pull-request-review-protection func (s *RepositoriesService) UpdatePullRequestReviewEnforcement(ctx context.Context, owner, repo, branch string, patch *PullRequestReviewsEnforcementUpdate) (*PullRequestReviewsEnforcement, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/required_pull_request_reviews", owner, repo, branch) + u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/required_pull_request_reviews", owner, repo, url.PathEscape(branch)) req, err := s.client.NewRequest("PATCH", u, patch) if err != nil { return nil, nil, err @@ -1583,9 +1612,11 @@ func (s *RepositoriesService) UpdatePullRequestReviewEnforcement(ctx context.Con // DisableDismissalRestrictions disables dismissal restrictions of a protected branch. // It requires admin access and branch protection to be enabled. // +// Note: the branch name is URL path escaped for you. See: https://pkg.go.dev/net/url#PathEscape . +// // GitHub API docs: https://docs.github.com/en/rest/branches/branch-protection#update-pull-request-review-protection func (s *RepositoriesService) DisableDismissalRestrictions(ctx context.Context, owner, repo, branch string) (*PullRequestReviewsEnforcement, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/required_pull_request_reviews", owner, repo, branch) + u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/required_pull_request_reviews", owner, repo, url.PathEscape(branch)) data := new(struct { DismissalRestrictionsRequest `json:"dismissal_restrictions"` @@ -1610,9 +1641,11 @@ func (s *RepositoriesService) DisableDismissalRestrictions(ctx context.Context, // RemovePullRequestReviewEnforcement removes pull request enforcement of a protected branch. // +// Note: the branch name is URL path escaped for you. See: https://pkg.go.dev/net/url#PathEscape . +// // GitHub API docs: https://docs.github.com/en/rest/branches/branch-protection#delete-pull-request-review-protection func (s *RepositoriesService) RemovePullRequestReviewEnforcement(ctx context.Context, owner, repo, branch string) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/required_pull_request_reviews", owner, repo, branch) + u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/required_pull_request_reviews", owner, repo, url.PathEscape(branch)) req, err := s.client.NewRequest("DELETE", u, nil) if err != nil { return nil, err @@ -1623,9 +1656,11 @@ func (s *RepositoriesService) RemovePullRequestReviewEnforcement(ctx context.Con // GetAdminEnforcement gets admin enforcement information of a protected branch. // +// Note: the branch name is URL path escaped for you. See: https://pkg.go.dev/net/url#PathEscape . +// // GitHub API docs: https://docs.github.com/en/rest/branches/branch-protection#get-admin-branch-protection func (s *RepositoriesService) GetAdminEnforcement(ctx context.Context, owner, repo, branch string) (*AdminEnforcement, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/enforce_admins", owner, repo, branch) + u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/enforce_admins", owner, repo, url.PathEscape(branch)) req, err := s.client.NewRequest("GET", u, nil) if err != nil { return nil, nil, err @@ -1643,9 +1678,11 @@ func (s *RepositoriesService) GetAdminEnforcement(ctx context.Context, owner, re // AddAdminEnforcement adds admin enforcement to a protected branch. // It requires admin access and branch protection to be enabled. // +// Note: the branch name is URL path escaped for you. See: https://pkg.go.dev/net/url#PathEscape . +// // GitHub API docs: https://docs.github.com/en/rest/branches/branch-protection#set-admin-branch-protection func (s *RepositoriesService) AddAdminEnforcement(ctx context.Context, owner, repo, branch string) (*AdminEnforcement, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/enforce_admins", owner, repo, branch) + u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/enforce_admins", owner, repo, url.PathEscape(branch)) req, err := s.client.NewRequest("POST", u, nil) if err != nil { return nil, nil, err @@ -1662,9 +1699,11 @@ func (s *RepositoriesService) AddAdminEnforcement(ctx context.Context, owner, re // RemoveAdminEnforcement removes admin enforcement from a protected branch. // +// Note: the branch name is URL path escaped for you. See: https://pkg.go.dev/net/url#PathEscape . +// // GitHub API docs: https://docs.github.com/en/rest/branches/branch-protection#delete-admin-branch-protection func (s *RepositoriesService) RemoveAdminEnforcement(ctx context.Context, owner, repo, branch string) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/enforce_admins", owner, repo, branch) + u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/enforce_admins", owner, repo, url.PathEscape(branch)) req, err := s.client.NewRequest("DELETE", u, nil) if err != nil { return nil, err @@ -1731,11 +1770,13 @@ func (s *RepositoriesService) ReplaceAllTopics(ctx context.Context, owner, repo // ListApps lists the GitHub apps that have push access to a given protected branch. // It requires the GitHub apps to have `write` access to the `content` permission. // +// Note: the branch name is URL path escaped for you. See: https://pkg.go.dev/net/url#PathEscape . +// // GitHub API docs: https://docs.github.com/en/rest/branches/branch-protection#get-apps-with-access-to-the-protected-branch // // Deprecated: Please use ListAppRestrictions instead. func (s *RepositoriesService) ListApps(ctx context.Context, owner, repo, branch string) ([]*App, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/restrictions/apps", owner, repo, branch) + u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/restrictions/apps", owner, repo, url.PathEscape(branch)) req, err := s.client.NewRequest("GET", u, nil) if err != nil { return nil, nil, err @@ -1766,9 +1807,11 @@ func (s *RepositoriesService) ListAppRestrictions(ctx context.Context, owner, re // // Note: The list of users, apps, and teams in total is limited to 100 items. // +// Note: the branch name is URL path escaped for you. See: https://pkg.go.dev/net/url#PathEscape . +// // GitHub API docs: https://docs.github.com/en/rest/branches/branch-protection#set-app-access-restrictions func (s *RepositoriesService) ReplaceAppRestrictions(ctx context.Context, owner, repo, branch string, apps []string) ([]*App, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/restrictions/apps", owner, repo, branch) + u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/restrictions/apps", owner, repo, url.PathEscape(branch)) req, err := s.client.NewRequest("PUT", u, apps) if err != nil { return nil, nil, err @@ -1788,9 +1831,11 @@ func (s *RepositoriesService) ReplaceAppRestrictions(ctx context.Context, owner, // // Note: The list of users, apps, and teams in total is limited to 100 items. // +// Note: the branch name is URL path escaped for you. See: https://pkg.go.dev/net/url#PathEscape . +// // GitHub API docs: https://docs.github.com/en/rest/branches/branch-protection#add-app-access-restrictions func (s *RepositoriesService) AddAppRestrictions(ctx context.Context, owner, repo, branch string, apps []string) ([]*App, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/restrictions/apps", owner, repo, branch) + u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/restrictions/apps", owner, repo, url.PathEscape(branch)) req, err := s.client.NewRequest("POST", u, apps) if err != nil { return nil, nil, err @@ -1810,9 +1855,11 @@ func (s *RepositoriesService) AddAppRestrictions(ctx context.Context, owner, rep // // Note: The list of users, apps, and teams in total is limited to 100 items. // +// Note: the branch name is URL path escaped for you. See: https://pkg.go.dev/net/url#PathEscape . +// // GitHub API docs: https://docs.github.com/en/rest/branches/branch-protection#remove-app-access-restrictions func (s *RepositoriesService) RemoveAppRestrictions(ctx context.Context, owner, repo, branch string, apps []string) ([]*App, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/restrictions/apps", owner, repo, branch) + u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/restrictions/apps", owner, repo, url.PathEscape(branch)) req, err := s.client.NewRequest("DELETE", u, apps) if err != nil { return nil, nil, err @@ -1830,9 +1877,11 @@ func (s *RepositoriesService) RemoveAppRestrictions(ctx context.Context, owner, // ListTeamRestrictions lists the GitHub teams that have push access to a given protected branch. // It requires the GitHub teams to have `write` access to the `content` permission. // +// Note: the branch name is URL path escaped for you. See: https://pkg.go.dev/net/url#PathEscape . +// // GitHub API docs: https://docs.github.com/en/rest/branches/branch-protection#get-teams-with-access-to-the-protected-branch func (s *RepositoriesService) ListTeamRestrictions(ctx context.Context, owner, repo, branch string) ([]*Team, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/restrictions/teams", owner, repo, branch) + u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/restrictions/teams", owner, repo, url.PathEscape(branch)) req, err := s.client.NewRequest("GET", u, nil) if err != nil { return nil, nil, err @@ -1853,9 +1902,11 @@ func (s *RepositoriesService) ListTeamRestrictions(ctx context.Context, owner, r // // Note: The list of users, apps, and teams in total is limited to 100 items. // +// Note: the branch name is URL path escaped for you. See: https://pkg.go.dev/net/url#PathEscape . +// // GitHub API docs: https://docs.github.com/en/rest/branches/branch-protection#set-team-access-restrictions func (s *RepositoriesService) ReplaceTeamRestrictions(ctx context.Context, owner, repo, branch string, teams []string) ([]*Team, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/restrictions/teams", owner, repo, branch) + u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/restrictions/teams", owner, repo, url.PathEscape(branch)) req, err := s.client.NewRequest("PUT", u, teams) if err != nil { return nil, nil, err @@ -1875,9 +1926,11 @@ func (s *RepositoriesService) ReplaceTeamRestrictions(ctx context.Context, owner // // Note: The list of users, apps, and teams in total is limited to 100 items. // +// Note: the branch name is URL path escaped for you. See: https://pkg.go.dev/net/url#PathEscape . +// // GitHub API docs: https://docs.github.com/en/rest/branches/branch-protection#add-team-access-restrictions func (s *RepositoriesService) AddTeamRestrictions(ctx context.Context, owner, repo, branch string, teams []string) ([]*Team, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/restrictions/teams", owner, repo, branch) + u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/restrictions/teams", owner, repo, url.PathEscape(branch)) req, err := s.client.NewRequest("POST", u, teams) if err != nil { return nil, nil, err @@ -1897,9 +1950,11 @@ func (s *RepositoriesService) AddTeamRestrictions(ctx context.Context, owner, re // // Note: The list of users, apps, and teams in total is limited to 100 items. // +// Note: the branch name is URL path escaped for you. See: https://pkg.go.dev/net/url#PathEscape . +// // GitHub API docs: https://docs.github.com/en/rest/branches/branch-protection#remove-team-access-restrictions func (s *RepositoriesService) RemoveTeamRestrictions(ctx context.Context, owner, repo, branch string, teams []string) ([]*Team, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/restrictions/teams", owner, repo, branch) + u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/restrictions/teams", owner, repo, url.PathEscape(branch)) req, err := s.client.NewRequest("DELETE", u, teams) if err != nil { return nil, nil, err @@ -1917,9 +1972,11 @@ func (s *RepositoriesService) RemoveTeamRestrictions(ctx context.Context, owner, // ListUserRestrictions lists the GitHub users that have push access to a given protected branch. // It requires the GitHub users to have `write` access to the `content` permission. // +// Note: the branch name is URL path escaped for you. See: https://pkg.go.dev/net/url#PathEscape . +// // GitHub API docs: https://docs.github.com/en/rest/branches/branch-protection#get-users-with-access-to-the-protected-branch func (s *RepositoriesService) ListUserRestrictions(ctx context.Context, owner, repo, branch string) ([]*User, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/restrictions/users", owner, repo, branch) + u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/restrictions/users", owner, repo, url.PathEscape(branch)) req, err := s.client.NewRequest("GET", u, nil) if err != nil { return nil, nil, err @@ -1940,9 +1997,11 @@ func (s *RepositoriesService) ListUserRestrictions(ctx context.Context, owner, r // // Note: The list of users, apps, and teams in total is limited to 100 items. // +// Note: the branch name is URL path escaped for you. See: https://pkg.go.dev/net/url#PathEscape . +// // GitHub API docs: https://docs.github.com/en/rest/branches/branch-protection#set-team-access-restrictions func (s *RepositoriesService) ReplaceUserRestrictions(ctx context.Context, owner, repo, branch string, users []string) ([]*User, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/restrictions/users", owner, repo, branch) + u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/restrictions/users", owner, repo, url.PathEscape(branch)) req, err := s.client.NewRequest("PUT", u, users) if err != nil { return nil, nil, err @@ -1962,9 +2021,11 @@ func (s *RepositoriesService) ReplaceUserRestrictions(ctx context.Context, owner // // Note: The list of users, apps, and teams in total is limited to 100 items. // +// Note: the branch name is URL path escaped for you. See: https://pkg.go.dev/net/url#PathEscape . +// // GitHub API docs: https://docs.github.com/en/rest/branches/branch-protection#add-team-access-restrictions func (s *RepositoriesService) AddUserRestrictions(ctx context.Context, owner, repo, branch string, users []string) ([]*User, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/restrictions/users", owner, repo, branch) + u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/restrictions/users", owner, repo, url.PathEscape(branch)) req, err := s.client.NewRequest("POST", u, users) if err != nil { return nil, nil, err @@ -1984,9 +2045,11 @@ func (s *RepositoriesService) AddUserRestrictions(ctx context.Context, owner, re // // Note: The list of users, apps, and teams in total is limited to 100 items. // +// Note: the branch name is URL path escaped for you. See: https://pkg.go.dev/net/url#PathEscape . +// // GitHub API docs: https://docs.github.com/en/rest/branches/branch-protection#remove-team-access-restrictions func (s *RepositoriesService) RemoveUserRestrictions(ctx context.Context, owner, repo, branch string, users []string) ([]*User, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/restrictions/users", owner, repo, branch) + u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/restrictions/users", owner, repo, url.PathEscape(branch)) req, err := s.client.NewRequest("DELETE", u, users) if err != nil { return nil, nil, err diff --git a/github/repos_test.go b/github/repos_test.go index 6aba962a91..7486e488fe 100644 --- a/github/repos_test.go +++ b/github/repos_test.go @@ -919,51 +919,73 @@ func TestRepositoriesService_GetBranch(t *testing.T) { client, mux, _, teardown := setup() defer teardown() - mux.HandleFunc("/repos/o/r/branches/b", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "GET") - fmt.Fprint(w, `{"name":"n", "commit":{"sha":"s","commit":{"message":"m"}}, "protected":true}`) - }) + tests := []struct { + branch string + urlPath string + }{ + {branch: "b", urlPath: "/repos/o/r/branches/b"}, + {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat/branch-50%"}, + } + + for _, test := range tests { + mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + fmt.Fprint(w, `{"name":"n", "commit":{"sha":"s","commit":{"message":"m"}}, "protected":true}`) + }) - ctx := context.Background() - branch, _, err := client.Repositories.GetBranch(ctx, "o", "r", "b", 0) - if err != nil { - t.Errorf("Repositories.GetBranch returned error: %v", err) - } + ctx := context.Background() + branch, _, err := client.Repositories.GetBranch(ctx, "o", "r", test.branch, 0) + if err != nil { + t.Errorf("Repositories.GetBranch returned error: %v", err) + } - want := &Branch{ - Name: String("n"), - Commit: &RepositoryCommit{ - SHA: String("s"), - Commit: &Commit{ - Message: String("m"), + want := &Branch{ + Name: String("n"), + Commit: &RepositoryCommit{ + SHA: String("s"), + Commit: &Commit{ + Message: String("m"), + }, }, - }, - Protected: Bool(true), - } + Protected: Bool(true), + } - if !cmp.Equal(branch, want) { - t.Errorf("Repositories.GetBranch returned %+v, want %+v", branch, want) - } + if !cmp.Equal(branch, want) { + t.Errorf("Repositories.GetBranch returned %+v, want %+v", branch, want) + } - const methodName = "GetBranch" - testBadOptions(t, methodName, func() (err error) { - _, _, err = client.Repositories.GetBranch(ctx, "\n", "\n", "\n", 0) - return err - }) + const methodName = "GetBranch" + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.Repositories.GetBranch(ctx, "\n", "\n", "\n", 0) + return err + }) + } } func TestRepositoriesService_GetBranch_BadJSONResponse(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() - - mux.HandleFunc("/repos/o/r/branches/b", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "GET") - fmt.Fprint(w, `{"name":"n", "commit":{"sha":...truncated`) - }) - - ctx := context.Background() - if _, _, err := client.Repositories.GetBranch(ctx, "o", "r", "b", 0); err == nil { - t.Error("Repositories.GetBranch returned no error; wanted JSON error") + tests := []struct { + branch string + urlPath string + }{ + {branch: "b", urlPath: "/repos/o/r/branches/b"}, + {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat/branch-50%"}, + } + + for _, test := range tests { + t.Run(test.branch, func(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + fmt.Fprint(w, `{"name":"n", "commit":{"sha":...truncated`) + }) + + ctx := context.Background() + if _, _, err := client.Repositories.GetBranch(ctx, "o", "r", test.branch, 0); err == nil { + t.Error("Repositories.GetBranch returned no error; wanted JSON error") + } + }) } } @@ -1005,492 +1027,1013 @@ func TestRepositoriesService_GetBranch_StatusMovedPermanently_followRedirects(t } func TestRepositoriesService_GetBranch_notFound(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() + tests := []struct { + branch string + urlPath string + }{ + {branch: "b", urlPath: "/repos/o/r/branches/b"}, + {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat-branch-50%"}, + } + + for _, test := range tests { + t.Run(test.branch, func(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + http.Error(w, "branch not found", http.StatusNotFound) + }) + ctx := context.Background() + _, resp, err := client.Repositories.GetBranch(ctx, "o", "r", test.branch, 1) + if err == nil { + t.Error("Repositories.GetBranch returned error: nil") + } + if resp.StatusCode != http.StatusNotFound { + t.Errorf("Repositories.GetBranch returned status: %d, want %d", resp.StatusCode, http.StatusNotFound) + } - mux.HandleFunc("/repos/o/r/branches/b", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "GET") - http.Error(w, "branch not found", http.StatusNotFound) - }) - ctx := context.Background() - _, resp, err := client.Repositories.GetBranch(ctx, "o", "r", "b", 1) - if err == nil { - t.Error("Repositories.GetBranch returned error: nil") + // Add custom round tripper + client.client.Transport = roundTripperFunc(func(r *http.Request) (*http.Response, error) { + return nil, errors.New("failed to get branch") + }) + + const methodName = "GetBranch" + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.Repositories.GetBranch(ctx, "\n", "\n", "\n", 1) + return err + }) + }) } - if resp.StatusCode != http.StatusNotFound { - t.Errorf("Repositories.GetBranch returned status: %d, want %d", resp.StatusCode, http.StatusNotFound) +} + +func TestRepositoriesService_RenameBranch(t *testing.T) { + tests := []struct { + branch string + urlPath string + }{ + {branch: "b", urlPath: "/repos/o/r/branches/b/rename"}, + {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat/branch-50%/rename"}, } - // Add custom round tripper - client.client.Transport = roundTripperFunc(func(r *http.Request) (*http.Response, error) { - return nil, errors.New("failed to get branch") - }) + for _, test := range tests { + t.Run(test.branch, func(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() - const methodName = "GetBranch" - testBadOptions(t, methodName, func() (err error) { - _, _, err = client.Repositories.GetBranch(ctx, "\n", "\n", "\n", 1) - return err - }) -} + renameBranchReq := "nn" -func TestRepositoriesService_RenameBranch(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() + mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { + v := new(renameBranchRequest) + assertNilError(t, json.NewDecoder(r.Body).Decode(v)) - renameBranchReq := "nn" + testMethod(t, r, "POST") + want := &renameBranchRequest{NewName: renameBranchReq} + if !cmp.Equal(v, want) { + t.Errorf("Request body = %+v, want %+v", v, want) + } - mux.HandleFunc("/repos/o/r/branches/b/rename", func(w http.ResponseWriter, r *http.Request) { - v := new(renameBranchRequest) - assertNilError(t, json.NewDecoder(r.Body).Decode(v)) + fmt.Fprint(w, `{"protected":true,"name":"nn"}`) + }) - testMethod(t, r, "POST") - want := &renameBranchRequest{NewName: "nn"} - if !cmp.Equal(v, want) { - t.Errorf("Request body = %+v, want %+v", v, want) - } + ctx := context.Background() + got, _, err := client.Repositories.RenameBranch(ctx, "o", "r", test.branch, renameBranchReq) + if err != nil { + t.Errorf("Repositories.RenameBranch returned error: %v", err) + } - fmt.Fprint(w, `{"protected":true,"name":"nn"}`) - }) + want := &Branch{Name: String("nn"), Protected: Bool(true)} + if !cmp.Equal(got, want) { + t.Errorf("Repositories.RenameBranch returned %+v, want %+v", got, want) + } - ctx := context.Background() - got, _, err := client.Repositories.RenameBranch(ctx, "o", "r", "b", renameBranchReq) - if err != nil { - t.Errorf("Repositories.RenameBranch returned error: %v", err) - } + const methodName = "RenameBranch" + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.Repositories.RenameBranch(ctx, "\n", "\n", "\n", renameBranchReq) + return err + }) - want := &Branch{Name: String("nn"), Protected: Bool(true)} - if !cmp.Equal(got, want) { - t.Errorf("Repositories.RenameBranch returned %+v, want %+v", got, want) + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Repositories.RenameBranch(ctx, "o", "r", test.branch, renameBranchReq) + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) + }) } +} - const methodName = "RenameBranch" - testBadOptions(t, methodName, func() (err error) { - _, _, err = client.Repositories.RenameBranch(ctx, "\n", "\n", "\n", renameBranchReq) - return err - }) +func TestRepositoriesService_GetBranchProtection(t *testing.T) { + tests := []struct { + branch string + urlPath string + enforceAdminsURLPath string + }{ + {branch: "b", urlPath: "/repos/o/r/branches/b/protection", enforceAdminsURLPath: "/repos/o/r/branches/b/protection/enforce_admins"}, + {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat/branch-50%/protection", enforceAdminsURLPath: "/repos/o/r/branches/feat/branch-50%/protection/enforce_admins"}, + } + + for _, test := range tests { + t.Run(test.branch, func(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + // TODO: remove custom Accept header when this API fully launches + testHeader(t, r, "Accept", mediaTypeRequiredApprovingReviewsPreview) + fmt.Fprintf(w, `{ + "required_status_checks":{ + "strict":true, + "contexts":["continuous-integration"], + "checks": [ + { + "context": "continuous-integration", + "app_id": null + } + ] + }, + "required_pull_request_reviews":{ + "dismissal_restrictions":{ + "users":[{ + "id":3, + "login":"u" + }], + "teams":[{ + "id":4, + "slug":"t" + }], + "apps":[{ + "id":5, + "slug":"a" + }] + }, + "dismiss_stale_reviews":true, + "require_code_owner_reviews":true, + "require_last_push_approval":false, + "required_approving_review_count":1 + }, + "enforce_admins":{ + "url":"%s", + "enabled":true + }, + "restrictions":{ + "users":[{"id":1,"login":"u"}], + "teams":[{"id":2,"slug":"t"}], + "apps":[{"id":3,"slug":"a"}] + }, + "required_conversation_resolution": { + "enabled": true + }, + "block_creations": { + "enabled": false + }, + "lock_branch": { + "enabled": false + }, + "allow_fork_syncing": { + "enabled": false + } + }`, test.enforceAdminsURLPath) + }) + + ctx := context.Background() + protection, _, err := client.Repositories.GetBranchProtection(ctx, "o", "r", test.branch) + if err != nil { + t.Errorf("Repositories.GetBranchProtection returned error: %v", err) + } - testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { - got, resp, err := client.Repositories.RenameBranch(ctx, "o", "r", "b", renameBranchReq) - if got != nil { - t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) - } - return resp, err - }) + want := &Protection{ + RequiredStatusChecks: &RequiredStatusChecks{ + Strict: true, + Contexts: []string{"continuous-integration"}, + Checks: []*RequiredStatusCheck{ + { + Context: "continuous-integration", + }, + }, + }, + RequiredPullRequestReviews: &PullRequestReviewsEnforcement{ + DismissStaleReviews: true, + DismissalRestrictions: &DismissalRestrictions{ + Users: []*User{ + {Login: String("u"), ID: Int64(3)}, + }, + Teams: []*Team{ + {Slug: String("t"), ID: Int64(4)}, + }, + Apps: []*App{ + {Slug: String("a"), ID: Int64(5)}, + }, + }, + RequireCodeOwnerReviews: true, + RequiredApprovingReviewCount: 1, + RequireLastPushApproval: false, + }, + EnforceAdmins: &AdminEnforcement{ + URL: String(test.enforceAdminsURLPath), + Enabled: true, + }, + Restrictions: &BranchRestrictions{ + Users: []*User{ + {Login: String("u"), ID: Int64(1)}, + }, + Teams: []*Team{ + {Slug: String("t"), ID: Int64(2)}, + }, + Apps: []*App{ + {Slug: String("a"), ID: Int64(3)}, + }, + }, + RequiredConversationResolution: &RequiredConversationResolution{ + Enabled: true, + }, + BlockCreations: &BlockCreations{ + Enabled: Bool(false), + }, + LockBranch: &LockBranch{ + Enabled: Bool(false), + }, + AllowForkSyncing: &AllowForkSyncing{ + Enabled: Bool(false), + }, + } + if !cmp.Equal(protection, want) { + t.Errorf("Repositories.GetBranchProtection returned %+v, want %+v", protection, want) + } + + const methodName = "GetBranchProtection" + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.Repositories.GetBranchProtection(ctx, "\n", "\n", "\n") + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Repositories.GetBranchProtection(ctx, "o", "r", test.branch) + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) + }) + } } -func TestRepositoriesService_GetBranchProtection(t *testing.T) { +func TestRepositoriesService_GetBranchProtection_noDismissalRestrictions(t *testing.T) { client, mux, _, teardown := setup() defer teardown() - mux.HandleFunc("/repos/o/r/branches/b/protection", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "GET") - // TODO: remove custom Accept header when this API fully launches - testHeader(t, r, "Accept", mediaTypeRequiredApprovingReviewsPreview) - fmt.Fprintf(w, `{ - "required_status_checks":{ - "strict":true, - "contexts":["continuous-integration"], - "checks": [ - { - "context": "continuous-integration", - "app_id": null + tests := []struct { + branch string + urlPath string + enforceAdminsURLPath string + }{ + {branch: "b", urlPath: "/repos/o/r/branches/b/protection", enforceAdminsURLPath: "/repos/o/r/branches/b/protection/enforce_admins"}, + {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat/branch-50%/protection", enforceAdminsURLPath: "/repos/o/r/branches/feat/branch-50%/protection/enforce_admins"}, + } + + for _, test := range tests { + mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + // TODO: remove custom Accept header when this API fully launches + testHeader(t, r, "Accept", mediaTypeRequiredApprovingReviewsPreview) + fmt.Fprintf(w, `{ + "required_status_checks":{ + "strict":true, + "contexts":["continuous-integration"], + "checks": [ + { + "context": "continuous-integration", + "app_id": null + } + ] + }, + "required_pull_request_reviews":{ + "dismiss_stale_reviews":true, + "require_code_owner_reviews":true, + "required_approving_review_count":1 + }, + "enforce_admins":{ + "url":"%s", + "enabled":true + }, + "restrictions":{ + "users":[{"id":1,"login":"u"}], + "teams":[{"id":2,"slug":"t"}] } - ] + }`, test.enforceAdminsURLPath) + }) + + ctx := context.Background() + protection, _, err := client.Repositories.GetBranchProtection(ctx, "o", "r", test.branch) + if err != nil { + t.Errorf("Repositories.GetBranchProtection returned error: %v", err) + } + + want := &Protection{ + RequiredStatusChecks: &RequiredStatusChecks{ + Strict: true, + Contexts: []string{"continuous-integration"}, + Checks: []*RequiredStatusCheck{ + { + Context: "continuous-integration", + }, }, - "required_pull_request_reviews":{ - "dismissal_restrictions":{ - "users":[{ - "id":3, - "login":"u" - }], - "teams":[{ - "id":4, - "slug":"t" - }], - "apps":[{ - "id":5, - "slug":"a" - }] + }, + RequiredPullRequestReviews: &PullRequestReviewsEnforcement{ + DismissStaleReviews: true, + DismissalRestrictions: nil, + RequireCodeOwnerReviews: true, + RequiredApprovingReviewCount: 1, + }, + EnforceAdmins: &AdminEnforcement{ + URL: String(test.enforceAdminsURLPath), + Enabled: true, + }, + Restrictions: &BranchRestrictions{ + Users: []*User{ + {Login: String("u"), ID: Int64(1)}, + }, + Teams: []*Team{ + {Slug: String("t"), ID: Int64(2)}, + }, + }, + } + if !cmp.Equal(protection, want) { + t.Errorf("Repositories.GetBranchProtection returned %+v, want %+v", protection, want) + } + } +} + +func TestRepositoriesService_GetBranchProtection_branchNotProtected(t *testing.T) { + tests := []struct { + branch string + urlPath string + }{ + {branch: "b", urlPath: "/repos/o/r/branches/b/protection"}, + {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat/branch-50%/protection"}, + } + + for _, test := range tests { + t.Run(test.branch, func(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + + w.WriteHeader(http.StatusBadRequest) + fmt.Fprintf(w, `{ + "message": %q, + "documentation_url": "https://docs.github.com/rest/repos#get-branch-protection" + }`, githubBranchNotProtected) + }) + + ctx := context.Background() + protection, _, err := client.Repositories.GetBranchProtection(ctx, "o", "r", test.branch) + + if protection != nil { + t.Errorf("Repositories.GetBranchProtection returned non-nil protection data") + } + + if err != ErrBranchNotProtected { + t.Errorf("Repositories.GetBranchProtection returned an invalid error: %v", err) + } + }) + } +} + +func TestRepositoriesService_UpdateBranchProtection_Contexts(t *testing.T) { + tests := []struct { + branch string + urlPath string + }{ + {branch: "b", urlPath: "/repos/o/r/branches/b/protection"}, + {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat/branch-50%/protection"}, + } + + for _, test := range tests { + t.Run(test.branch, func(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + input := &ProtectionRequest{ + RequiredStatusChecks: &RequiredStatusChecks{ + Strict: true, + Contexts: []string{"continuous-integration"}, + }, + RequiredPullRequestReviews: &PullRequestReviewsEnforcementRequest{ + DismissStaleReviews: true, + DismissalRestrictionsRequest: &DismissalRestrictionsRequest{ + Users: &[]string{"uu"}, + Teams: &[]string{"tt"}, + Apps: &[]string{"aa"}, }, - "dismiss_stale_reviews":true, - "require_code_owner_reviews":true, - "require_last_push_approval":false, - "required_approving_review_count":1 + BypassPullRequestAllowancesRequest: &BypassPullRequestAllowancesRequest{ + Users: []string{"uuu"}, + Teams: []string{"ttt"}, + Apps: []string{"aaa"}, + }, + }, + Restrictions: &BranchRestrictionsRequest{ + Users: []string{"u"}, + Teams: []string{"t"}, + Apps: []string{"a"}, + }, + BlockCreations: Bool(true), + LockBranch: Bool(true), + AllowForkSyncing: Bool(true), + } + + mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { + v := new(ProtectionRequest) + assertNilError(t, json.NewDecoder(r.Body).Decode(v)) + + testMethod(t, r, "PUT") + if !cmp.Equal(v, input) { + t.Errorf("Request body = %+v, want %+v", v, input) + } + + // TODO: remove custom Accept header when this API fully launches + testHeader(t, r, "Accept", mediaTypeRequiredApprovingReviewsPreview) + fmt.Fprintf(w, `{ + "required_status_checks":{ + "strict":true, + "contexts":["continuous-integration"], + "checks": [ + { + "context": "continuous-integration", + "app_id": null + } + ] }, - "enforce_admins":{ - "url":"/repos/o/r/branches/b/protection/enforce_admins", - "enabled":true + "required_pull_request_reviews":{ + "dismissal_restrictions":{ + "users":[{ + "id":3, + "login":"uu" + }], + "teams":[{ + "id":4, + "slug":"tt" + }], + "apps":[{ + "id":5, + "slug":"aa" + }] + }, + "dismiss_stale_reviews":true, + "require_code_owner_reviews":true, + "bypass_pull_request_allowances": { + "users":[{"id":10,"login":"uuu"}], + "teams":[{"id":20,"slug":"ttt"}], + "apps":[{"id":30,"slug":"aaa"}] + } }, "restrictions":{ "users":[{"id":1,"login":"u"}], "teams":[{"id":2,"slug":"t"}], "apps":[{"id":3,"slug":"a"}] }, - "required_conversation_resolution": { - "enabled": true - }, "block_creations": { - "enabled": false + "enabled": true }, "lock_branch": { - "enabled": false + "enabled": true }, "allow_fork_syncing": { - "enabled": false + "enabled": true } }`) - }) + }) - ctx := context.Background() - protection, _, err := client.Repositories.GetBranchProtection(ctx, "o", "r", "b") - if err != nil { - t.Errorf("Repositories.GetBranchProtection returned error: %v", err) - } + ctx := context.Background() + protection, _, err := client.Repositories.UpdateBranchProtection(ctx, "o", "r", test.branch, input) + if err != nil { + t.Errorf("Repositories.UpdateBranchProtection returned error: %v", err) + } - want := &Protection{ - RequiredStatusChecks: &RequiredStatusChecks{ - Strict: true, - Contexts: []string{"continuous-integration"}, - Checks: []*RequiredStatusCheck{ - { - Context: "continuous-integration", + want := &Protection{ + RequiredStatusChecks: &RequiredStatusChecks{ + Strict: true, + Contexts: []string{"continuous-integration"}, + Checks: []*RequiredStatusCheck{ + { + Context: "continuous-integration", + }, + }, }, - }, - }, - RequiredPullRequestReviews: &PullRequestReviewsEnforcement{ - DismissStaleReviews: true, - DismissalRestrictions: &DismissalRestrictions{ - Users: []*User{ - {Login: String("u"), ID: Int64(3)}, + RequiredPullRequestReviews: &PullRequestReviewsEnforcement{ + DismissStaleReviews: true, + DismissalRestrictions: &DismissalRestrictions{ + Users: []*User{ + {Login: String("uu"), ID: Int64(3)}, + }, + Teams: []*Team{ + {Slug: String("tt"), ID: Int64(4)}, + }, + Apps: []*App{ + {Slug: String("aa"), ID: Int64(5)}, + }, + }, + RequireCodeOwnerReviews: true, + BypassPullRequestAllowances: &BypassPullRequestAllowances{ + Users: []*User{ + {Login: String("uuu"), ID: Int64(10)}, + }, + Teams: []*Team{ + {Slug: String("ttt"), ID: Int64(20)}, + }, + Apps: []*App{ + {Slug: String("aaa"), ID: Int64(30)}, + }, + }, }, - Teams: []*Team{ - {Slug: String("t"), ID: Int64(4)}, + Restrictions: &BranchRestrictions{ + Users: []*User{ + {Login: String("u"), ID: Int64(1)}, + }, + Teams: []*Team{ + {Slug: String("t"), ID: Int64(2)}, + }, + Apps: []*App{ + {Slug: String("a"), ID: Int64(3)}, + }, }, - Apps: []*App{ - {Slug: String("a"), ID: Int64(5)}, + BlockCreations: &BlockCreations{ + Enabled: Bool(true), }, - }, - RequireCodeOwnerReviews: true, - RequiredApprovingReviewCount: 1, - RequireLastPushApproval: false, - }, - EnforceAdmins: &AdminEnforcement{ - URL: String("/repos/o/r/branches/b/protection/enforce_admins"), - Enabled: true, - }, - Restrictions: &BranchRestrictions{ - Users: []*User{ - {Login: String("u"), ID: Int64(1)}, - }, - Teams: []*Team{ - {Slug: String("t"), ID: Int64(2)}, - }, - Apps: []*App{ - {Slug: String("a"), ID: Int64(3)}, - }, - }, - RequiredConversationResolution: &RequiredConversationResolution{ - Enabled: true, - }, - BlockCreations: &BlockCreations{ - Enabled: Bool(false), - }, - LockBranch: &LockBranch{ - Enabled: Bool(false), - }, - AllowForkSyncing: &AllowForkSyncing{ - Enabled: Bool(false), - }, - } - if !cmp.Equal(protection, want) { - t.Errorf("Repositories.GetBranchProtection returned %+v, want %+v", protection, want) - } + LockBranch: &LockBranch{ + Enabled: Bool(true), + }, + AllowForkSyncing: &AllowForkSyncing{ + Enabled: Bool(true), + }, + } + if !cmp.Equal(protection, want) { + t.Errorf("Repositories.UpdateBranchProtection returned %+v, want %+v", protection, want) + } - const methodName = "GetBranchProtection" - testBadOptions(t, methodName, func() (err error) { - _, _, err = client.Repositories.GetBranchProtection(ctx, "\n", "\n", "\n") - return err - }) + const methodName = "UpdateBranchProtection" + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.Repositories.UpdateBranchProtection(ctx, "\n", "\n", "\n", input) + return err + }) - testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { - got, resp, err := client.Repositories.GetBranchProtection(ctx, "o", "r", "b") - if got != nil { - t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) - } - return resp, err - }) + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Repositories.UpdateBranchProtection(ctx, "o", "r", test.branch, input) + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) + }) + } } -func TestRepositoriesService_GetBranchProtection_noDismissalRestrictions(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() - - mux.HandleFunc("/repos/o/r/branches/b/protection", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "GET") - // TODO: remove custom Accept header when this API fully launches - testHeader(t, r, "Accept", mediaTypeRequiredApprovingReviewsPreview) - fmt.Fprintf(w, `{ - "required_status_checks":{ - "strict":true, - "contexts":["continuous-integration"], - "checks": [ +func TestRepositoriesService_UpdateBranchProtection_Checks(t *testing.T) { + tests := []struct { + branch string + urlPath string + }{ + {branch: "b", urlPath: "/repos/o/r/branches/b/protection"}, + {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat/branch-50%/protection"}, + } + + for _, test := range tests { + t.Run(test.branch, func(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + input := &ProtectionRequest{ + RequiredStatusChecks: &RequiredStatusChecks{ + Strict: true, + Checks: []*RequiredStatusCheck{ { - "context": "continuous-integration", - "app_id": null - } - ] + Context: "continuous-integration", + }, + }, }, - "required_pull_request_reviews":{ - "dismiss_stale_reviews":true, - "require_code_owner_reviews":true, - "required_approving_review_count":1 + RequiredPullRequestReviews: &PullRequestReviewsEnforcementRequest{ + DismissStaleReviews: true, + DismissalRestrictionsRequest: &DismissalRestrictionsRequest{ + Users: &[]string{"uu"}, + Teams: &[]string{"tt"}, + Apps: &[]string{"aa"}, + }, + BypassPullRequestAllowancesRequest: &BypassPullRequestAllowancesRequest{ + Users: []string{"uuu"}, + Teams: []string{"ttt"}, + Apps: []string{"aaa"}, + }, + }, + Restrictions: &BranchRestrictionsRequest{ + Users: []string{"u"}, + Teams: []string{"t"}, + Apps: []string{"a"}, + }, + } + + mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { + v := new(ProtectionRequest) + assertNilError(t, json.NewDecoder(r.Body).Decode(v)) + + testMethod(t, r, "PUT") + if !cmp.Equal(v, input) { + t.Errorf("Request body = %+v, want %+v", v, input) + } + + // TODO: remove custom Accept header when this API fully launches + testHeader(t, r, "Accept", mediaTypeRequiredApprovingReviewsPreview) + fmt.Fprintf(w, `{ + "required_status_checks":{ + "strict":true, + "contexts":["continuous-integration"], + "checks": [ + { + "context": "continuous-integration", + "app_id": null + } + ] }, - "enforce_admins":{ - "url":"/repos/o/r/branches/b/protection/enforce_admins", - "enabled":true + "required_pull_request_reviews":{ + "dismissal_restrictions":{ + "users":[{ + "id":3, + "login":"uu" + }], + "teams":[{ + "id":4, + "slug":"tt" + }], + "apps":[{ + "id":5, + "slug":"aa" + }] + }, + "dismiss_stale_reviews":true, + "require_code_owner_reviews":true, + "bypass_pull_request_allowances": { + "users":[{"id":10,"login":"uuu"}], + "teams":[{"id":20,"slug":"ttt"}], + "apps":[{"id":30,"slug":"aaa"}] + } }, "restrictions":{ "users":[{"id":1,"login":"u"}], - "teams":[{"id":2,"slug":"t"}] + "teams":[{"id":2,"slug":"t"}], + "apps":[{"id":3,"slug":"a"}] } }`) - }) + }) - ctx := context.Background() - protection, _, err := client.Repositories.GetBranchProtection(ctx, "o", "r", "b") - if err != nil { - t.Errorf("Repositories.GetBranchProtection returned error: %v", err) - } + ctx := context.Background() + protection, _, err := client.Repositories.UpdateBranchProtection(ctx, "o", "r", test.branch, input) + if err != nil { + t.Errorf("Repositories.UpdateBranchProtection returned error: %v", err) + } - want := &Protection{ - RequiredStatusChecks: &RequiredStatusChecks{ - Strict: true, - Contexts: []string{"continuous-integration"}, - Checks: []*RequiredStatusCheck{ - { - Context: "continuous-integration", + want := &Protection{ + RequiredStatusChecks: &RequiredStatusChecks{ + Strict: true, + Contexts: []string{"continuous-integration"}, + Checks: []*RequiredStatusCheck{ + { + Context: "continuous-integration", + }, + }, }, - }, - }, - RequiredPullRequestReviews: &PullRequestReviewsEnforcement{ - DismissStaleReviews: true, - DismissalRestrictions: nil, - RequireCodeOwnerReviews: true, - RequiredApprovingReviewCount: 1, - }, - EnforceAdmins: &AdminEnforcement{ - URL: String("/repos/o/r/branches/b/protection/enforce_admins"), - Enabled: true, - }, - Restrictions: &BranchRestrictions{ - Users: []*User{ - {Login: String("u"), ID: Int64(1)}, - }, - Teams: []*Team{ - {Slug: String("t"), ID: Int64(2)}, - }, - }, - } - if !cmp.Equal(protection, want) { - t.Errorf("Repositories.GetBranchProtection returned %+v, want %+v", protection, want) + RequiredPullRequestReviews: &PullRequestReviewsEnforcement{ + DismissStaleReviews: true, + DismissalRestrictions: &DismissalRestrictions{ + Users: []*User{ + {Login: String("uu"), ID: Int64(3)}, + }, + Teams: []*Team{ + {Slug: String("tt"), ID: Int64(4)}, + }, + Apps: []*App{ + {Slug: String("aa"), ID: Int64(5)}, + }, + }, + RequireCodeOwnerReviews: true, + BypassPullRequestAllowances: &BypassPullRequestAllowances{ + Users: []*User{ + {Login: String("uuu"), ID: Int64(10)}, + }, + Teams: []*Team{ + {Slug: String("ttt"), ID: Int64(20)}, + }, + Apps: []*App{ + {Slug: String("aaa"), ID: Int64(30)}, + }, + }, + }, + Restrictions: &BranchRestrictions{ + Users: []*User{ + {Login: String("u"), ID: Int64(1)}, + }, + Teams: []*Team{ + {Slug: String("t"), ID: Int64(2)}, + }, + Apps: []*App{ + {Slug: String("a"), ID: Int64(3)}, + }, + }, + } + if !cmp.Equal(protection, want) { + t.Errorf("Repositories.UpdateBranchProtection returned %+v, want %+v", protection, want) + } + }) } } -func TestRepositoriesService_GetBranchProtection_branchNotProtected(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() +func TestRepositoriesService_UpdateBranchProtection_StrictNoChecks(t *testing.T) { + tests := []struct { + branch string + urlPath string + }{ + {branch: "b", urlPath: "/repos/o/r/branches/b/protection"}, + {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat/branch-50%/protection"}, + } + + for _, test := range tests { + t.Run(test.branch, func(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + input := &ProtectionRequest{ + RequiredStatusChecks: &RequiredStatusChecks{ + Strict: true, + Checks: []*RequiredStatusCheck{}, + }, + RequiredPullRequestReviews: &PullRequestReviewsEnforcementRequest{ + DismissStaleReviews: true, + DismissalRestrictionsRequest: &DismissalRestrictionsRequest{ + Users: &[]string{"uu"}, + Teams: &[]string{"tt"}, + Apps: &[]string{"aa"}, + }, + BypassPullRequestAllowancesRequest: &BypassPullRequestAllowancesRequest{ + Users: []string{"uuu"}, + Teams: []string{"ttt"}, + Apps: []string{"aaa"}, + }, + }, + Restrictions: &BranchRestrictionsRequest{ + Users: []string{"u"}, + Teams: []string{"t"}, + Apps: []string{"a"}, + }, + } - mux.HandleFunc("/repos/o/r/branches/b/protection", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "GET") + mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { + v := new(ProtectionRequest) + assertNilError(t, json.NewDecoder(r.Body).Decode(v)) - w.WriteHeader(http.StatusBadRequest) - fmt.Fprintf(w, `{ - "message": %q, - "documentation_url": "https://docs.github.com/rest/repos#get-branch-protection" - }`, githubBranchNotProtected) - }) + testMethod(t, r, "PUT") + if !cmp.Equal(v, input) { + t.Errorf("Request body = %+v, want %+v", v, input) + } - ctx := context.Background() - protection, _, err := client.Repositories.GetBranchProtection(ctx, "o", "r", "b") + // TODO: remove custom Accept header when this API fully launches + testHeader(t, r, "Accept", mediaTypeRequiredApprovingReviewsPreview) + fmt.Fprintf(w, `{ + "required_status_checks":{ + "strict":true, + "contexts":[], + "checks": [] + }, + "required_pull_request_reviews":{ + "dismissal_restrictions":{ + "users":[{ + "id":3, + "login":"uu" + }], + "teams":[{ + "id":4, + "slug":"tt" + }], + "apps":[{ + "id":5, + "slug":"aa" + }] + }, + "dismiss_stale_reviews":true, + "require_code_owner_reviews":true, + "require_last_push_approval":false, + "bypass_pull_request_allowances": { + "users":[{"id":10,"login":"uuu"}], + "teams":[{"id":20,"slug":"ttt"}], + "apps":[{"id":30,"slug":"aaa"}] + } + }, + "restrictions":{ + "users":[{"id":1,"login":"u"}], + "teams":[{"id":2,"slug":"t"}], + "apps":[{"id":3,"slug":"a"}] + } + }`) + }) - if protection != nil { - t.Errorf("Repositories.GetBranchProtection returned non-nil protection data") - } + ctx := context.Background() + protection, _, err := client.Repositories.UpdateBranchProtection(ctx, "o", "r", test.branch, input) + if err != nil { + t.Errorf("Repositories.UpdateBranchProtection returned error: %v", err) + } - if err != ErrBranchNotProtected { - t.Errorf("Repositories.GetBranchProtection returned an invalid error: %v", err) + want := &Protection{ + RequiredStatusChecks: &RequiredStatusChecks{ + Strict: true, + Contexts: []string{}, + Checks: []*RequiredStatusCheck{}, + }, + RequiredPullRequestReviews: &PullRequestReviewsEnforcement{ + DismissStaleReviews: true, + DismissalRestrictions: &DismissalRestrictions{ + Users: []*User{ + {Login: String("uu"), ID: Int64(3)}, + }, + Teams: []*Team{ + {Slug: String("tt"), ID: Int64(4)}, + }, + Apps: []*App{ + {Slug: String("aa"), ID: Int64(5)}, + }, + }, + RequireCodeOwnerReviews: true, + BypassPullRequestAllowances: &BypassPullRequestAllowances{ + Users: []*User{ + {Login: String("uuu"), ID: Int64(10)}, + }, + Teams: []*Team{ + {Slug: String("ttt"), ID: Int64(20)}, + }, + Apps: []*App{ + {Slug: String("aaa"), ID: Int64(30)}, + }, + }, + }, + Restrictions: &BranchRestrictions{ + Users: []*User{ + {Login: String("u"), ID: Int64(1)}, + }, + Teams: []*Team{ + {Slug: String("t"), ID: Int64(2)}, + }, + Apps: []*App{ + {Slug: String("a"), ID: Int64(3)}, + }, + }, + } + if !cmp.Equal(protection, want) { + t.Errorf("Repositories.UpdateBranchProtection returned %+v, want %+v", protection, want) + } + }) } } -func TestRepositoriesService_UpdateBranchProtection_Contexts(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() - - input := &ProtectionRequest{ - RequiredStatusChecks: &RequiredStatusChecks{ - Strict: true, - Contexts: []string{"continuous-integration"}, - }, - RequiredPullRequestReviews: &PullRequestReviewsEnforcementRequest{ - DismissStaleReviews: true, - DismissalRestrictionsRequest: &DismissalRestrictionsRequest{ - Users: &[]string{"uu"}, - Teams: &[]string{"tt"}, - Apps: &[]string{"aa"}, - }, - BypassPullRequestAllowancesRequest: &BypassPullRequestAllowancesRequest{ - Users: []string{"uuu"}, - Teams: []string{"ttt"}, - Apps: []string{"aaa"}, - }, - }, - Restrictions: &BranchRestrictionsRequest{ - Users: []string{"u"}, - Teams: []string{"t"}, - Apps: []string{"a"}, - }, - BlockCreations: Bool(true), - LockBranch: Bool(true), - AllowForkSyncing: Bool(true), - } +func TestRepositoriesService_UpdateBranchProtection_RequireLastPushApproval(t *testing.T) { + tests := []struct { + branch string + urlPath string + }{ + {branch: "b", urlPath: "/repos/o/r/branches/b/protection"}, + {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat/branch-50%/protection"}, + } + + for _, test := range tests { + t.Run(test.branch, func(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + input := &ProtectionRequest{ + RequiredPullRequestReviews: &PullRequestReviewsEnforcementRequest{ + RequireLastPushApproval: Bool(true), + }, + } - mux.HandleFunc("/repos/o/r/branches/b/protection", func(w http.ResponseWriter, r *http.Request) { - v := new(ProtectionRequest) - assertNilError(t, json.NewDecoder(r.Body).Decode(v)) + mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { + v := new(ProtectionRequest) + assertNilError(t, json.NewDecoder(r.Body).Decode(v)) - testMethod(t, r, "PUT") - if !cmp.Equal(v, input) { - t.Errorf("Request body = %+v, want %+v", v, input) - } + testMethod(t, r, "PUT") + if !cmp.Equal(v, input) { + t.Errorf("Request body = %+v, want %+v", v, input) + } - // TODO: remove custom Accept header when this API fully launches - testHeader(t, r, "Accept", mediaTypeRequiredApprovingReviewsPreview) - fmt.Fprintf(w, `{ - "required_status_checks":{ - "strict":true, - "contexts":["continuous-integration"], - "checks": [ - { - "context": "continuous-integration", - "app_id": null + fmt.Fprintf(w, `{ + "required_pull_request_reviews":{ + "require_last_push_approval":true } - ] - }, - "required_pull_request_reviews":{ - "dismissal_restrictions":{ - "users":[{ - "id":3, - "login":"uu" - }], - "teams":[{ - "id":4, - "slug":"tt" - }], - "apps":[{ - "id":5, - "slug":"aa" - }] + }`) + }) + + ctx := context.Background() + protection, _, err := client.Repositories.UpdateBranchProtection(ctx, "o", "r", test.branch, input) + if err != nil { + t.Errorf("Repositories.UpdateBranchProtection returned error: %v", err) + } + + want := &Protection{ + RequiredPullRequestReviews: &PullRequestReviewsEnforcement{ + RequireLastPushApproval: true, }, - "dismiss_stale_reviews":true, - "require_code_owner_reviews":true, - "bypass_pull_request_allowances": { - "users":[{"id":10,"login":"uuu"}], - "teams":[{"id":20,"slug":"ttt"}], - "apps":[{"id":30,"slug":"aaa"}] - } - }, - "restrictions":{ - "users":[{"id":1,"login":"u"}], - "teams":[{"id":2,"slug":"t"}], - "apps":[{"id":3,"slug":"a"}] - }, - "block_creations": { - "enabled": true - }, - "lock_branch": { - "enabled": true - }, - "allow_fork_syncing": { - "enabled": true } - }`) + if !cmp.Equal(protection, want) { + t.Errorf("Repositories.UpdateBranchProtection returned %+v, want %+v", protection, want) + } + }) + } +} + +func TestRepositoriesService_RemoveBranchProtection(t *testing.T) { + tests := []struct { + branch string + urlPath string + }{ + {branch: "b", urlPath: "/repos/o/r/branches/b/protection"}, + {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat/branch-50%/protection"}, + } + + for _, test := range tests { + t.Run(test.branch, func(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "DELETE") + w.WriteHeader(http.StatusNoContent) + }) + + ctx := context.Background() + _, err := client.Repositories.RemoveBranchProtection(ctx, "o", "r", test.branch) + if err != nil { + t.Errorf("Repositories.RemoveBranchProtection returned error: %v", err) + } + + const methodName = "RemoveBranchProtection" + testBadOptions(t, methodName, func() (err error) { + _, err = client.Repositories.RemoveBranchProtection(ctx, "\n", "\n", "\n") + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + return client.Repositories.RemoveBranchProtection(ctx, "o", "r", test.branch) + }) + }) + } +} + +func TestRepositoriesService_ListLanguages_invalidOwner(t *testing.T) { + client, _, _, teardown := setup() + defer teardown() + + ctx := context.Background() + _, _, err := client.Repositories.ListLanguages(ctx, "%", "%") + testURLParseError(t, err) +} + +func TestRepositoriesService_License(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/repos/o/r/license", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + 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}}`) }) ctx := context.Background() - protection, _, err := client.Repositories.UpdateBranchProtection(ctx, "o", "r", "b", input) + got, _, err := client.Repositories.License(ctx, "o", "r") if err != nil { - t.Errorf("Repositories.UpdateBranchProtection returned error: %v", err) + t.Errorf("Repositories.License returned error: %v", err) } - want := &Protection{ - RequiredStatusChecks: &RequiredStatusChecks{ - Strict: true, - Contexts: []string{"continuous-integration"}, - Checks: []*RequiredStatusCheck{ - { - Context: "continuous-integration", - }, - }, - }, - RequiredPullRequestReviews: &PullRequestReviewsEnforcement{ - DismissStaleReviews: true, - DismissalRestrictions: &DismissalRestrictions{ - Users: []*User{ - {Login: String("uu"), ID: Int64(3)}, - }, - Teams: []*Team{ - {Slug: String("tt"), ID: Int64(4)}, - }, - Apps: []*App{ - {Slug: String("aa"), ID: Int64(5)}, - }, - }, - RequireCodeOwnerReviews: true, - BypassPullRequestAllowances: &BypassPullRequestAllowances{ - Users: []*User{ - {Login: String("uuu"), ID: Int64(10)}, - }, - Teams: []*Team{ - {Slug: String("ttt"), ID: Int64(20)}, - }, - Apps: []*App{ - {Slug: String("aaa"), ID: Int64(30)}, - }, - }, - }, - Restrictions: &BranchRestrictions{ - Users: []*User{ - {Login: String("u"), ID: Int64(1)}, - }, - Teams: []*Team{ - {Slug: String("t"), ID: Int64(2)}, - }, - Apps: []*App{ - {Slug: String("a"), ID: Int64(3)}, - }, - }, - BlockCreations: &BlockCreations{ - Enabled: Bool(true), - }, - LockBranch: &LockBranch{ - Enabled: Bool(true), - }, - AllowForkSyncing: &AllowForkSyncing{ - Enabled: Bool(true), + want := &RepositoryLicense{ + Name: String("LICENSE"), + Path: String("LICENSE"), + License: &License{ + Name: String("MIT License"), + Key: String("mit"), + SPDXID: String("MIT"), + URL: String("https://api.github.com/licenses/mit"), + Featured: Bool(true), }, } - if !cmp.Equal(protection, want) { - t.Errorf("Repositories.UpdateBranchProtection returned %+v, want %+v", protection, want) + + if !cmp.Equal(got, want) { + t.Errorf("Repositories.License returned %+v, want %+v", got, want) } - const methodName = "UpdateBranchProtection" + const methodName = "License" testBadOptions(t, methodName, func() (err error) { - _, _, err = client.Repositories.UpdateBranchProtection(ctx, "\n", "\n", "\n", input) + _, _, err = client.Repositories.License(ctx, "\n", "\n") return err }) testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { - got, resp, err := client.Repositories.UpdateBranchProtection(ctx, "o", "r", "b", input) + got, resp, err := client.Repositories.License(ctx, "o", "r") if got != nil { t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) } @@ -1498,1532 +2041,1025 @@ func TestRepositoriesService_UpdateBranchProtection_Contexts(t *testing.T) { }) } -func TestRepositoriesService_UpdateBranchProtection_Checks(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() - - input := &ProtectionRequest{ - RequiredStatusChecks: &RequiredStatusChecks{ - Strict: true, - Checks: []*RequiredStatusCheck{ - { - Context: "continuous-integration", - }, - }, - }, - RequiredPullRequestReviews: &PullRequestReviewsEnforcementRequest{ - DismissStaleReviews: true, - DismissalRestrictionsRequest: &DismissalRestrictionsRequest{ - Users: &[]string{"uu"}, - Teams: &[]string{"tt"}, - Apps: &[]string{"aa"}, - }, - BypassPullRequestAllowancesRequest: &BypassPullRequestAllowancesRequest{ - Users: []string{"uuu"}, - Teams: []string{"ttt"}, - Apps: []string{"aaa"}, - }, - }, - Restrictions: &BranchRestrictionsRequest{ - Users: []string{"u"}, - Teams: []string{"t"}, - Apps: []string{"a"}, - }, - } - - mux.HandleFunc("/repos/o/r/branches/b/protection", func(w http.ResponseWriter, r *http.Request) { - v := new(ProtectionRequest) - assertNilError(t, json.NewDecoder(r.Body).Decode(v)) +func TestRepositoriesService_GetRequiredStatusChecks(t *testing.T) { + tests := []struct { + branch string + urlPath string + }{ + {branch: "b", urlPath: "/repos/o/r/branches/b/protection/required_status_checks"}, + {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat/branch-50%/protection/required_status_checks"}, + } + + for _, test := range tests { + t.Run(test.branch, func(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + fmt.Fprint(w, `{ + "strict": true, + "contexts": ["x","y","z"], + "checks": [ + { + "context": "x", + "app_id": null + }, + { + "context": "y", + "app_id": null + }, + { + "context": "z", + "app_id": null + } + ] + }`) + }) - testMethod(t, r, "PUT") - if !cmp.Equal(v, input) { - t.Errorf("Request body = %+v, want %+v", v, input) - } + ctx := context.Background() + checks, _, err := client.Repositories.GetRequiredStatusChecks(ctx, "o", "r", test.branch) + if err != nil { + t.Errorf("Repositories.GetRequiredStatusChecks returned error: %v", err) + } - // TODO: remove custom Accept header when this API fully launches - testHeader(t, r, "Accept", mediaTypeRequiredApprovingReviewsPreview) - fmt.Fprintf(w, `{ - "required_status_checks":{ - "strict":true, - "contexts":["continuous-integration"], - "checks": [ + want := &RequiredStatusChecks{ + Strict: true, + Contexts: []string{"x", "y", "z"}, + Checks: []*RequiredStatusCheck{ { - "context": "continuous-integration", - "app_id": null - } - ] - }, - "required_pull_request_reviews":{ - "dismissal_restrictions":{ - "users":[{ - "id":3, - "login":"uu" - }], - "teams":[{ - "id":4, - "slug":"tt" - }], - "apps":[{ - "id":5, - "slug":"aa" - }] + Context: "x", + }, + { + Context: "y", + }, + { + Context: "z", + }, }, - "dismiss_stale_reviews":true, - "require_code_owner_reviews":true, - "bypass_pull_request_allowances": { - "users":[{"id":10,"login":"uuu"}], - "teams":[{"id":20,"slug":"ttt"}], - "apps":[{"id":30,"slug":"aaa"}] - } - }, - "restrictions":{ - "users":[{"id":1,"login":"u"}], - "teams":[{"id":2,"slug":"t"}], - "apps":[{"id":3,"slug":"a"}] } - }`) - }) + if !cmp.Equal(checks, want) { + t.Errorf("Repositories.GetRequiredStatusChecks returned %+v, want %+v", checks, want) + } - ctx := context.Background() - protection, _, err := client.Repositories.UpdateBranchProtection(ctx, "o", "r", "b", input) - if err != nil { - t.Errorf("Repositories.UpdateBranchProtection returned error: %v", err) - } + const methodName = "GetRequiredStatusChecks" + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.Repositories.GetRequiredStatusChecks(ctx, "\n", "\n", "\n") + return err + }) - want := &Protection{ - RequiredStatusChecks: &RequiredStatusChecks{ - Strict: true, - Contexts: []string{"continuous-integration"}, - Checks: []*RequiredStatusCheck{ - { - Context: "continuous-integration", - }, - }, - }, - RequiredPullRequestReviews: &PullRequestReviewsEnforcement{ - DismissStaleReviews: true, - DismissalRestrictions: &DismissalRestrictions{ - Users: []*User{ - {Login: String("uu"), ID: Int64(3)}, - }, - Teams: []*Team{ - {Slug: String("tt"), ID: Int64(4)}, - }, - Apps: []*App{ - {Slug: String("aa"), ID: Int64(5)}, - }, - }, - RequireCodeOwnerReviews: true, - BypassPullRequestAllowances: &BypassPullRequestAllowances{ - Users: []*User{ - {Login: String("uuu"), ID: Int64(10)}, - }, - Teams: []*Team{ - {Slug: String("ttt"), ID: Int64(20)}, - }, - Apps: []*App{ - {Slug: String("aaa"), ID: Int64(30)}, - }, - }, - }, - Restrictions: &BranchRestrictions{ - Users: []*User{ - {Login: String("u"), ID: Int64(1)}, - }, - Teams: []*Team{ - {Slug: String("t"), ID: Int64(2)}, - }, - Apps: []*App{ - {Slug: String("a"), ID: Int64(3)}, - }, - }, - } - if !cmp.Equal(protection, want) { - t.Errorf("Repositories.UpdateBranchProtection returned %+v, want %+v", protection, want) + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Repositories.GetRequiredStatusChecks(ctx, "o", "r", test.branch) + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) + }) } } -func TestRepositoriesService_UpdateBranchProtection_StrictNoChecks(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() - - input := &ProtectionRequest{ - RequiredStatusChecks: &RequiredStatusChecks{ - Strict: true, - Checks: []*RequiredStatusCheck{}, - }, - RequiredPullRequestReviews: &PullRequestReviewsEnforcementRequest{ - DismissStaleReviews: true, - DismissalRestrictionsRequest: &DismissalRestrictionsRequest{ - Users: &[]string{"uu"}, - Teams: &[]string{"tt"}, - Apps: &[]string{"aa"}, - }, - BypassPullRequestAllowancesRequest: &BypassPullRequestAllowancesRequest{ - Users: []string{"uuu"}, - Teams: []string{"ttt"}, - Apps: []string{"aaa"}, - }, - }, - Restrictions: &BranchRestrictionsRequest{ - Users: []string{"u"}, - Teams: []string{"t"}, - Apps: []string{"a"}, - }, +func TestRepositoriesService_GetRequiredStatusChecks_branchNotProtected(t *testing.T) { + tests := []struct { + branch string + urlPath string + }{ + {branch: "b", urlPath: "/repos/o/r/branches/b/protection/required_status_checks"}, + {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat/branch-50%/protection/required_status_checks"}, } - mux.HandleFunc("/repos/o/r/branches/b/protection", func(w http.ResponseWriter, r *http.Request) { - v := new(ProtectionRequest) - assertNilError(t, json.NewDecoder(r.Body).Decode(v)) + for _, test := range tests { + t.Run(test.branch, func(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() - testMethod(t, r, "PUT") - if !cmp.Equal(v, input) { - t.Errorf("Request body = %+v, want %+v", v, input) - } + mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") - // TODO: remove custom Accept header when this API fully launches - testHeader(t, r, "Accept", mediaTypeRequiredApprovingReviewsPreview) - fmt.Fprintf(w, `{ - "required_status_checks":{ - "strict":true, - "contexts":[], - "checks": [] - }, - "required_pull_request_reviews":{ - "dismissal_restrictions":{ - "users":[{ - "id":3, - "login":"uu" - }], - "teams":[{ - "id":4, - "slug":"tt" - }], - "apps":[{ - "id":5, - "slug":"aa" - }] - }, - "dismiss_stale_reviews":true, - "require_code_owner_reviews":true, - "require_last_push_approval":false, - "bypass_pull_request_allowances": { - "users":[{"id":10,"login":"uuu"}], - "teams":[{"id":20,"slug":"ttt"}], - "apps":[{"id":30,"slug":"aaa"}] - } - }, - "restrictions":{ - "users":[{"id":1,"login":"u"}], - "teams":[{"id":2,"slug":"t"}], - "apps":[{"id":3,"slug":"a"}] - } - }`) - }) + w.WriteHeader(http.StatusBadRequest) + fmt.Fprintf(w, `{ + "message": %q, + "documentation_url": "https://docs.github.com/rest/repos#get-branch-protection" + }`, githubBranchNotProtected) + }) - ctx := context.Background() - protection, _, err := client.Repositories.UpdateBranchProtection(ctx, "o", "r", "b", input) - if err != nil { - t.Errorf("Repositories.UpdateBranchProtection returned error: %v", err) - } + ctx := context.Background() + checks, _, err := client.Repositories.GetRequiredStatusChecks(ctx, "o", "r", test.branch) - want := &Protection{ - RequiredStatusChecks: &RequiredStatusChecks{ - Strict: true, - Contexts: []string{}, - Checks: []*RequiredStatusCheck{}, - }, - RequiredPullRequestReviews: &PullRequestReviewsEnforcement{ - DismissStaleReviews: true, - DismissalRestrictions: &DismissalRestrictions{ - Users: []*User{ - {Login: String("uu"), ID: Int64(3)}, - }, - Teams: []*Team{ - {Slug: String("tt"), ID: Int64(4)}, - }, - Apps: []*App{ - {Slug: String("aa"), ID: Int64(5)}, - }, - }, - RequireCodeOwnerReviews: true, - BypassPullRequestAllowances: &BypassPullRequestAllowances{ - Users: []*User{ - {Login: String("uuu"), ID: Int64(10)}, - }, - Teams: []*Team{ - {Slug: String("ttt"), ID: Int64(20)}, - }, - Apps: []*App{ - {Slug: String("aaa"), ID: Int64(30)}, - }, - }, - }, - Restrictions: &BranchRestrictions{ - Users: []*User{ - {Login: String("u"), ID: Int64(1)}, - }, - Teams: []*Team{ - {Slug: String("t"), ID: Int64(2)}, - }, - Apps: []*App{ - {Slug: String("a"), ID: Int64(3)}, - }, - }, - } - if !cmp.Equal(protection, want) { - t.Errorf("Repositories.UpdateBranchProtection returned %+v, want %+v", protection, want) + if checks != nil { + t.Errorf("Repositories.GetRequiredStatusChecks returned non-nil status-checks data") + } + + if err != ErrBranchNotProtected { + t.Errorf("Repositories.GetRequiredStatusChecks returned an invalid error: %v", err) + } + }) } } -func TestRepositoriesService_UpdateBranchProtection_RequireLastPushApproval(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() +func TestRepositoriesService_UpdateRequiredStatusChecks_Contexts(t *testing.T) { + tests := []struct { + branch string + urlPath string + }{ + {branch: "b", urlPath: "/repos/o/r/branches/b/protection/required_status_checks"}, + {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat/branch-50%/protection/required_status_checks"}, + } + + for _, test := range tests { + t.Run(test.branch, func(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + input := &RequiredStatusChecksRequest{ + Strict: Bool(true), + Contexts: []string{"continuous-integration"}, + } - input := &ProtectionRequest{ - RequiredPullRequestReviews: &PullRequestReviewsEnforcementRequest{ - RequireLastPushApproval: Bool(true), - }, - } + mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { + v := new(RequiredStatusChecksRequest) + assertNilError(t, json.NewDecoder(r.Body).Decode(v)) - mux.HandleFunc("/repos/o/r/branches/b/protection", func(w http.ResponseWriter, r *http.Request) { - v := new(ProtectionRequest) - assertNilError(t, json.NewDecoder(r.Body).Decode(v)) + testMethod(t, r, "PATCH") + if !cmp.Equal(v, input) { + t.Errorf("Request body = %+v, want %+v", v, input) + } + testHeader(t, r, "Accept", mediaTypeV3) + fmt.Fprintf(w, `{ + "strict":true, + "contexts":["continuous-integration"], + "checks": [ + { + "context": "continuous-integration", + "app_id": null + } + ] + }`) + }) - testMethod(t, r, "PUT") - if !cmp.Equal(v, input) { - t.Errorf("Request body = %+v, want %+v", v, input) - } + ctx := context.Background() + statusChecks, _, err := client.Repositories.UpdateRequiredStatusChecks(ctx, "o", "r", test.branch, input) + if err != nil { + t.Errorf("Repositories.UpdateRequiredStatusChecks returned error: %v", err) + } - fmt.Fprintf(w, `{ - "required_pull_request_reviews":{ - "require_last_push_approval":true + want := &RequiredStatusChecks{ + Strict: true, + Contexts: []string{"continuous-integration"}, + Checks: []*RequiredStatusCheck{ + { + Context: "continuous-integration", + }, + }, + } + if !cmp.Equal(statusChecks, want) { + t.Errorf("Repositories.UpdateRequiredStatusChecks returned %+v, want %+v", statusChecks, want) } - }`) - }) - ctx := context.Background() - protection, _, err := client.Repositories.UpdateBranchProtection(ctx, "o", "r", "b", input) - if err != nil { - t.Errorf("Repositories.UpdateBranchProtection returned error: %v", err) - } + const methodName = "UpdateRequiredStatusChecks" + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.Repositories.UpdateRequiredStatusChecks(ctx, "\n", "\n", "\n", input) + return err + }) - want := &Protection{ - RequiredPullRequestReviews: &PullRequestReviewsEnforcement{ - RequireLastPushApproval: true, - }, - } - if !cmp.Equal(protection, want) { - t.Errorf("Repositories.UpdateBranchProtection returned %+v, want %+v", protection, want) + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Repositories.UpdateRequiredStatusChecks(ctx, "o", "r", test.branch, input) + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) + }) } } -func TestRepositoriesService_RemoveBranchProtection(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() - - mux.HandleFunc("/repos/o/r/branches/b/protection", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "DELETE") - w.WriteHeader(http.StatusNoContent) - }) - - ctx := context.Background() - _, err := client.Repositories.RemoveBranchProtection(ctx, "o", "r", "b") - if err != nil { - t.Errorf("Repositories.RemoveBranchProtection returned error: %v", err) - } +func TestRepositoriesService_UpdateRequiredStatusChecks_Checks(t *testing.T) { + tests := []struct { + branch string + urlPath string + }{ + {branch: "b", urlPath: "/repos/o/r/branches/b/protection/required_status_checks"}, + {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat/branch-50%/protection/required_status_checks"}, + } + + for _, test := range tests { + t.Run(test.branch, func(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + appID := int64(123) + noAppID := int64(-1) + input := &RequiredStatusChecksRequest{ + Strict: Bool(true), + Checks: []*RequiredStatusCheck{ + { + Context: "continuous-integration", + }, + { + Context: "continuous-integration2", + AppID: &appID, + }, + { + Context: "continuous-integration3", + AppID: &noAppID, + }, + }, + } - const methodName = "RemoveBranchProtection" - testBadOptions(t, methodName, func() (err error) { - _, err = client.Repositories.RemoveBranchProtection(ctx, "\n", "\n", "\n") - return err - }) + mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { + v := new(RequiredStatusChecksRequest) + assertNilError(t, json.NewDecoder(r.Body).Decode(v)) - testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { - return client.Repositories.RemoveBranchProtection(ctx, "o", "r", "b") - }) -} + testMethod(t, r, "PATCH") + if !cmp.Equal(v, input) { + t.Errorf("Request body = %+v, want %+v", v, input) + } + testHeader(t, r, "Accept", mediaTypeV3) + fmt.Fprintf(w, `{ + "strict":true, + "contexts":["continuous-integration"], + "checks": [ + { + "context": "continuous-integration", + "app_id": null + }, + { + "context": "continuous-integration2", + "app_id": 123 + }, + { + "context": "continuous-integration3", + "app_id": null + } + ] + }`) + }) -func TestRepositoriesService_ListLanguages_invalidOwner(t *testing.T) { - client, _, _, teardown := setup() - defer teardown() + ctx := context.Background() + statusChecks, _, err := client.Repositories.UpdateRequiredStatusChecks(ctx, "o", "r", test.branch, input) + if err != nil { + t.Errorf("Repositories.UpdateRequiredStatusChecks returned error: %v", err) + } - ctx := context.Background() - _, _, err := client.Repositories.ListLanguages(ctx, "%", "%") - testURLParseError(t, err) + want := &RequiredStatusChecks{ + Strict: true, + Contexts: []string{"continuous-integration"}, + Checks: []*RequiredStatusCheck{ + { + Context: "continuous-integration", + }, + { + Context: "continuous-integration2", + AppID: &appID, + }, + { + Context: "continuous-integration3", + }, + }, + } + if !cmp.Equal(statusChecks, want) { + t.Errorf("Repositories.UpdateRequiredStatusChecks returned %+v, want %+v", statusChecks, want) + } + }) + } } -func TestRepositoriesService_License(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() - - mux.HandleFunc("/repos/o/r/license", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "GET") - 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}}`) - }) - - ctx := context.Background() - got, _, err := client.Repositories.License(ctx, "o", "r") - if err != nil { - t.Errorf("Repositories.License returned error: %v", err) - } +func TestRepositoriesService_RemoveRequiredStatusChecks(t *testing.T) { + tests := []struct { + branch string + urlPath string + }{ + {branch: "b", urlPath: "/repos/o/r/branches/b/protection/required_status_checks"}, + {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat/branch-50%/protection/required_status_checks"}, + } + + for _, test := range tests { + t.Run(test.branch, func(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "DELETE") + testHeader(t, r, "Accept", mediaTypeV3) + w.WriteHeader(http.StatusNoContent) + }) + + ctx := context.Background() + _, err := client.Repositories.RemoveRequiredStatusChecks(ctx, "o", "r", test.branch) + if err != nil { + t.Errorf("Repositories.RemoveRequiredStatusChecks returned error: %v", err) + } - want := &RepositoryLicense{ - Name: String("LICENSE"), - Path: String("LICENSE"), - License: &License{ - Name: String("MIT License"), - Key: String("mit"), - SPDXID: String("MIT"), - URL: String("https://api.github.com/licenses/mit"), - Featured: Bool(true), - }, - } + const methodName = "RemoveRequiredStatusChecks" + testBadOptions(t, methodName, func() (err error) { + _, err = client.Repositories.RemoveRequiredStatusChecks(ctx, "\n", "\n", "\n") + return err + }) - if !cmp.Equal(got, want) { - t.Errorf("Repositories.License returned %+v, want %+v", got, want) + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + return client.Repositories.RemoveRequiredStatusChecks(ctx, "o", "r", test.branch) + }) + }) } +} - const methodName = "License" - testBadOptions(t, methodName, func() (err error) { - _, _, err = client.Repositories.License(ctx, "\n", "\n") - return err - }) +func TestRepositoriesService_ListRequiredStatusChecksContexts(t *testing.T) { + tests := []struct { + branch string + urlPath string + }{ + {branch: "b", urlPath: "/repos/o/r/branches/b/protection/required_status_checks/contexts"}, + {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat/branch-50%/protection/required_status_checks/contexts"}, + } + + for _, test := range tests { + t.Run(test.branch, func(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + fmt.Fprint(w, `["x", "y", "z"]`) + }) + + ctx := context.Background() + contexts, _, err := client.Repositories.ListRequiredStatusChecksContexts(ctx, "o", "r", test.branch) + if err != nil { + t.Errorf("Repositories.ListRequiredStatusChecksContexts returned error: %v", err) + } - testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { - got, resp, err := client.Repositories.License(ctx, "o", "r") - if got != nil { - t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) - } - return resp, err - }) -} + want := []string{"x", "y", "z"} + if !cmp.Equal(contexts, want) { + t.Errorf("Repositories.ListRequiredStatusChecksContexts returned %+v, want %+v", contexts, want) + } -func TestRepositoriesService_GetRequiredStatusChecks(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() + const methodName = "ListRequiredStatusChecksContexts" + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.Repositories.ListRequiredStatusChecksContexts(ctx, "\n", "\n", "\n") + return err + }) - mux.HandleFunc("/repos/o/r/branches/b/protection/required_status_checks", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "GET") - fmt.Fprint(w, `{ - "strict": true, - "contexts": ["x","y","z"], - "checks": [ - { - "context": "x", - "app_id": null - }, - { - "context": "y", - "app_id": null - }, - { - "context": "z", - "app_id": null + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Repositories.ListRequiredStatusChecksContexts(ctx, "o", "r", test.branch) + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) } - ] - }`) - }) - - ctx := context.Background() - checks, _, err := client.Repositories.GetRequiredStatusChecks(ctx, "o", "r", "b") - if err != nil { - t.Errorf("Repositories.GetRequiredStatusChecks returned error: %v", err) + return resp, err + }) + }) } +} - want := &RequiredStatusChecks{ - Strict: true, - Contexts: []string{"x", "y", "z"}, - Checks: []*RequiredStatusCheck{ - { - Context: "x", - }, - { - Context: "y", - }, - { - Context: "z", - }, - }, - } - if !cmp.Equal(checks, want) { - t.Errorf("Repositories.GetRequiredStatusChecks returned %+v, want %+v", checks, want) +func TestRepositoriesService_ListRequiredStatusChecksContexts_branchNotProtected(t *testing.T) { + tests := []struct { + branch string + urlPath string + }{ + {branch: "b", urlPath: "/repos/o/r/branches/b/protection/required_status_checks/contexts"}, + {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat/branch-50%/protection/required_status_checks/contexts"}, } - const methodName = "GetRequiredStatusChecks" - testBadOptions(t, methodName, func() (err error) { - _, _, err = client.Repositories.GetRequiredStatusChecks(ctx, "\n", "\n", "\n") - return err - }) - - testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { - got, resp, err := client.Repositories.GetRequiredStatusChecks(ctx, "o", "r", "b") - if got != nil { - t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) - } - return resp, err - }) -} - -func TestRepositoriesService_GetRequiredStatusChecks_branchNotProtected(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() + for _, test := range tests { + t.Run(test.branch, func(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() - mux.HandleFunc("/repos/o/r/branches/b/protection/required_status_checks", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "GET") + mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") - w.WriteHeader(http.StatusBadRequest) - fmt.Fprintf(w, `{ + w.WriteHeader(http.StatusBadRequest) + fmt.Fprintf(w, `{ "message": %q, "documentation_url": "https://docs.github.com/rest/repos#get-branch-protection" }`, githubBranchNotProtected) - }) + }) - ctx := context.Background() - checks, _, err := client.Repositories.GetRequiredStatusChecks(ctx, "o", "r", "b") + ctx := context.Background() + contexts, _, err := client.Repositories.ListRequiredStatusChecksContexts(ctx, "o", "r", test.branch) - if checks != nil { - t.Errorf("Repositories.GetRequiredStatusChecks returned non-nil status-checks data") - } + if contexts != nil { + t.Errorf("Repositories.ListRequiredStatusChecksContexts returned non-nil contexts data") + } - if err != ErrBranchNotProtected { - t.Errorf("Repositories.GetRequiredStatusChecks returned an invalid error: %v", err) + if err != ErrBranchNotProtected { + t.Errorf("Repositories.ListRequiredStatusChecksContexts returned an invalid error: %v", err) + } + }) } } -func TestRepositoriesService_UpdateRequiredStatusChecks_Contexts(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() +func TestRepositoriesService_GetPullRequestReviewEnforcement(t *testing.T) { + tests := []struct { + branch string + urlPath string + }{ + {branch: "b", urlPath: "/repos/o/r/branches/b/protection/required_pull_request_reviews"}, + {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat/branch-50%/protection/required_pull_request_reviews"}, + } + + for _, test := range tests { + t.Run(test.branch, func(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + // TODO: remove custom Accept header when this API fully launches + testHeader(t, r, "Accept", mediaTypeRequiredApprovingReviewsPreview) + fmt.Fprintf(w, `{ + "dismissal_restrictions":{ + "users":[{"id":1,"login":"u"}], + "teams":[{"id":2,"slug":"t"}], + "apps":[{"id":3,"slug":"a"}] + }, + "dismiss_stale_reviews":true, + "require_code_owner_reviews":true, + "required_approving_review_count":1 + }`) + }) - input := &RequiredStatusChecksRequest{ - Strict: Bool(true), - Contexts: []string{"continuous-integration"}, - } + ctx := context.Background() + enforcement, _, err := client.Repositories.GetPullRequestReviewEnforcement(ctx, "o", "r", test.branch) + if err != nil { + t.Errorf("Repositories.GetPullRequestReviewEnforcement returned error: %v", err) + } - mux.HandleFunc("/repos/o/r/branches/b/protection/required_status_checks", func(w http.ResponseWriter, r *http.Request) { - v := new(RequiredStatusChecksRequest) - assertNilError(t, json.NewDecoder(r.Body).Decode(v)) + want := &PullRequestReviewsEnforcement{ + DismissStaleReviews: true, + DismissalRestrictions: &DismissalRestrictions{ + Users: []*User{ + {Login: String("u"), ID: Int64(1)}, + }, + Teams: []*Team{ + {Slug: String("t"), ID: Int64(2)}, + }, + Apps: []*App{ + {Slug: String("a"), ID: Int64(3)}, + }, + }, + RequireCodeOwnerReviews: true, + RequiredApprovingReviewCount: 1, + } - testMethod(t, r, "PATCH") - if !cmp.Equal(v, input) { - t.Errorf("Request body = %+v, want %+v", v, input) - } - testHeader(t, r, "Accept", mediaTypeV3) - fmt.Fprintf(w, `{ - "strict":true, - "contexts":["continuous-integration"], - "checks": [ - { - "context": "continuous-integration", - "app_id": null - } - ] - }`) - }) + if !cmp.Equal(enforcement, want) { + t.Errorf("Repositories.GetPullRequestReviewEnforcement returned %+v, want %+v", enforcement, want) + } - ctx := context.Background() - statusChecks, _, err := client.Repositories.UpdateRequiredStatusChecks(ctx, "o", "r", "b", input) - if err != nil { - t.Errorf("Repositories.UpdateRequiredStatusChecks returned error: %v", err) - } + const methodName = "GetPullRequestReviewEnforcement" + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.Repositories.GetPullRequestReviewEnforcement(ctx, "\n", "\n", "\n") + return err + }) - want := &RequiredStatusChecks{ - Strict: true, - Contexts: []string{"continuous-integration"}, - Checks: []*RequiredStatusCheck{ - { - Context: "continuous-integration", - }, - }, - } - if !cmp.Equal(statusChecks, want) { - t.Errorf("Repositories.UpdateRequiredStatusChecks returned %+v, want %+v", statusChecks, want) + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Repositories.GetPullRequestReviewEnforcement(ctx, "o", "r", test.branch) + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) + }) } +} - const methodName = "UpdateRequiredStatusChecks" - testBadOptions(t, methodName, func() (err error) { - _, _, err = client.Repositories.UpdateRequiredStatusChecks(ctx, "\n", "\n", "\n", input) - return err - }) +func TestRepositoriesService_UpdatePullRequestReviewEnforcement(t *testing.T) { + tests := []struct { + branch string + urlPath string + }{ + {branch: "b", urlPath: "/repos/o/r/branches/b/protection/required_pull_request_reviews"}, + {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat/branch-50%/protection/required_pull_request_reviews"}, + } + + for _, test := range tests { + t.Run(test.branch, func(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + input := &PullRequestReviewsEnforcementUpdate{ + DismissalRestrictionsRequest: &DismissalRestrictionsRequest{ + Users: &[]string{"u"}, + Teams: &[]string{"t"}, + Apps: &[]string{"a"}, + }, + } - testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { - got, resp, err := client.Repositories.UpdateRequiredStatusChecks(ctx, "o", "r", "b", input) - if got != nil { - t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) - } - return resp, err - }) -} + mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { + v := new(PullRequestReviewsEnforcementUpdate) + assertNilError(t, json.NewDecoder(r.Body).Decode(v)) -func TestRepositoriesService_UpdateRequiredStatusChecks_Checks(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() - - appID := int64(123) - noAppID := int64(-1) - input := &RequiredStatusChecksRequest{ - Strict: Bool(true), - Checks: []*RequiredStatusCheck{ - { - Context: "continuous-integration", - }, - { - Context: "continuous-integration2", - AppID: &appID, - }, - { - Context: "continuous-integration3", - AppID: &noAppID, - }, - }, - } - - mux.HandleFunc("/repos/o/r/branches/b/protection/required_status_checks", func(w http.ResponseWriter, r *http.Request) { - v := new(RequiredStatusChecksRequest) - assertNilError(t, json.NewDecoder(r.Body).Decode(v)) - - testMethod(t, r, "PATCH") - if !cmp.Equal(v, input) { - t.Errorf("Request body = %+v, want %+v", v, input) - } - testHeader(t, r, "Accept", mediaTypeV3) - fmt.Fprintf(w, `{ - "strict":true, - "contexts":["continuous-integration"], - "checks": [ - { - "context": "continuous-integration", - "app_id": null - }, - { - "context": "continuous-integration2", - "app_id": 123 - }, - { - "context": "continuous-integration3", - "app_id": null + testMethod(t, r, "PATCH") + if !cmp.Equal(v, input) { + t.Errorf("Request body = %+v, want %+v", v, input) } - ] - }`) - }) - - ctx := context.Background() - statusChecks, _, err := client.Repositories.UpdateRequiredStatusChecks(ctx, "o", "r", "b", input) - if err != nil { - t.Errorf("Repositories.UpdateRequiredStatusChecks returned error: %v", err) - } - - want := &RequiredStatusChecks{ - Strict: true, - Contexts: []string{"continuous-integration"}, - Checks: []*RequiredStatusCheck{ - { - Context: "continuous-integration", - }, - { - Context: "continuous-integration2", - AppID: &appID, - }, - { - Context: "continuous-integration3", - }, - }, - } - if !cmp.Equal(statusChecks, want) { - t.Errorf("Repositories.UpdateRequiredStatusChecks returned %+v, want %+v", statusChecks, want) - } -} - -func TestRepositoriesService_RemoveRequiredStatusChecks(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() - - mux.HandleFunc("/repos/o/r/branches/b/protection/required_status_checks", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "DELETE") - testHeader(t, r, "Accept", mediaTypeV3) - w.WriteHeader(http.StatusNoContent) - }) - - ctx := context.Background() - _, err := client.Repositories.RemoveRequiredStatusChecks(ctx, "o", "r", "b") - if err != nil { - t.Errorf("Repositories.RemoveRequiredStatusChecks returned error: %v", err) - } - - const methodName = "RemoveRequiredStatusChecks" - testBadOptions(t, methodName, func() (err error) { - _, err = client.Repositories.RemoveRequiredStatusChecks(ctx, "\n", "\n", "\n") - return err - }) - - testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { - return client.Repositories.RemoveRequiredStatusChecks(ctx, "o", "r", "b") - }) -} - -func TestRepositoriesService_ListRequiredStatusChecksContexts(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() - - mux.HandleFunc("/repos/o/r/branches/b/protection/required_status_checks/contexts", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "GET") - fmt.Fprint(w, `["x", "y", "z"]`) - }) - - ctx := context.Background() - contexts, _, err := client.Repositories.ListRequiredStatusChecksContexts(ctx, "o", "r", "b") - if err != nil { - t.Errorf("Repositories.ListRequiredStatusChecksContexts returned error: %v", err) - } - - want := []string{"x", "y", "z"} - if !cmp.Equal(contexts, want) { - t.Errorf("Repositories.ListRequiredStatusChecksContexts returned %+v, want %+v", contexts, want) - } - - const methodName = "ListRequiredStatusChecksContexts" - testBadOptions(t, methodName, func() (err error) { - _, _, err = client.Repositories.ListRequiredStatusChecksContexts(ctx, "\n", "\n", "\n") - return err - }) - - testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { - got, resp, err := client.Repositories.ListRequiredStatusChecksContexts(ctx, "o", "r", "b") - if got != nil { - t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) - } - return resp, err - }) -} - -func TestRepositoriesService_ListRequiredStatusChecksContexts_branchNotProtected(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() - - mux.HandleFunc("/repos/o/r/branches/b/protection/required_status_checks/contexts", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "GET") - - w.WriteHeader(http.StatusBadRequest) - fmt.Fprintf(w, `{ - "message": %q, - "documentation_url": "https://docs.github.com/rest/repos#get-branch-protection" - }`, githubBranchNotProtected) - }) - - ctx := context.Background() - contexts, _, err := client.Repositories.ListRequiredStatusChecksContexts(ctx, "o", "r", "b") - - if contexts != nil { - t.Errorf("Repositories.ListRequiredStatusChecksContexts returned non-nil contexts data") - } - - if err != ErrBranchNotProtected { - t.Errorf("Repositories.ListRequiredStatusChecksContexts returned an invalid error: %v", err) - } -} - -func TestRepositoriesService_GetPullRequestReviewEnforcement(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() - - mux.HandleFunc("/repos/o/r/branches/b/protection/required_pull_request_reviews", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "GET") - // TODO: remove custom Accept header when this API fully launches - testHeader(t, r, "Accept", mediaTypeRequiredApprovingReviewsPreview) - fmt.Fprintf(w, `{ - "dismissal_restrictions":{ - "users":[{"id":1,"login":"u"}], - "teams":[{"id":2,"slug":"t"}], - "apps":[{"id":3,"slug":"a"}] - }, - "dismiss_stale_reviews":true, - "require_code_owner_reviews":true, - "required_approving_review_count":1 - }`) - }) - - ctx := context.Background() - enforcement, _, err := client.Repositories.GetPullRequestReviewEnforcement(ctx, "o", "r", "b") - if err != nil { - t.Errorf("Repositories.GetPullRequestReviewEnforcement returned error: %v", err) - } - - want := &PullRequestReviewsEnforcement{ - DismissStaleReviews: true, - DismissalRestrictions: &DismissalRestrictions{ - Users: []*User{ - {Login: String("u"), ID: Int64(1)}, - }, - Teams: []*Team{ - {Slug: String("t"), ID: Int64(2)}, - }, - Apps: []*App{ - {Slug: String("a"), ID: Int64(3)}, - }, - }, - RequireCodeOwnerReviews: true, - RequiredApprovingReviewCount: 1, - } - - if !cmp.Equal(enforcement, want) { - t.Errorf("Repositories.GetPullRequestReviewEnforcement returned %+v, want %+v", enforcement, want) - } - - const methodName = "GetPullRequestReviewEnforcement" - testBadOptions(t, methodName, func() (err error) { - _, _, err = client.Repositories.GetPullRequestReviewEnforcement(ctx, "\n", "\n", "\n") - return err - }) - - testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { - got, resp, err := client.Repositories.GetPullRequestReviewEnforcement(ctx, "o", "r", "b") - if got != nil { - t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) - } - return resp, err - }) -} - -func TestRepositoriesService_UpdatePullRequestReviewEnforcement(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() - - input := &PullRequestReviewsEnforcementUpdate{ - DismissalRestrictionsRequest: &DismissalRestrictionsRequest{ - Users: &[]string{"u"}, - Teams: &[]string{"t"}, - Apps: &[]string{"a"}, - }, - } - - mux.HandleFunc("/repos/o/r/branches/b/protection/required_pull_request_reviews", func(w http.ResponseWriter, r *http.Request) { - v := new(PullRequestReviewsEnforcementUpdate) - assertNilError(t, json.NewDecoder(r.Body).Decode(v)) - - testMethod(t, r, "PATCH") - if !cmp.Equal(v, input) { - t.Errorf("Request body = %+v, want %+v", v, input) - } - // TODO: remove custom Accept header when this API fully launches - testHeader(t, r, "Accept", mediaTypeRequiredApprovingReviewsPreview) - fmt.Fprintf(w, `{ - "dismissal_restrictions":{ - "users":[{"id":1,"login":"u"}], - "teams":[{"id":2,"slug":"t"}], - "apps":[{"id":3,"slug":"a"}] - }, - "dismiss_stale_reviews":true, - "require_code_owner_reviews":true, - "required_approving_review_count":3 - }`) - }) - - ctx := context.Background() - enforcement, _, err := client.Repositories.UpdatePullRequestReviewEnforcement(ctx, "o", "r", "b", input) - if err != nil { - t.Errorf("Repositories.UpdatePullRequestReviewEnforcement returned error: %v", err) - } - - want := &PullRequestReviewsEnforcement{ - DismissStaleReviews: true, - DismissalRestrictions: &DismissalRestrictions{ - Users: []*User{ - {Login: String("u"), ID: Int64(1)}, - }, - Teams: []*Team{ - {Slug: String("t"), ID: Int64(2)}, - }, - Apps: []*App{ - {Slug: String("a"), ID: Int64(3)}, - }, - }, - RequireCodeOwnerReviews: true, - RequiredApprovingReviewCount: 3, - } - if !cmp.Equal(enforcement, want) { - t.Errorf("Repositories.UpdatePullRequestReviewEnforcement returned %+v, want %+v", enforcement, want) - } - - const methodName = "UpdatePullRequestReviewEnforcement" - testBadOptions(t, methodName, func() (err error) { - _, _, err = client.Repositories.UpdatePullRequestReviewEnforcement(ctx, "\n", "\n", "\n", input) - return err - }) - - testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { - got, resp, err := client.Repositories.UpdatePullRequestReviewEnforcement(ctx, "o", "r", "b", input) - if got != nil { - t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) - } - return resp, err - }) -} - -func TestRepositoriesService_DisableDismissalRestrictions(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() - - mux.HandleFunc("/repos/o/r/branches/b/protection/required_pull_request_reviews", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "PATCH") - // TODO: remove custom Accept header when this API fully launches - testHeader(t, r, "Accept", mediaTypeRequiredApprovingReviewsPreview) - testBody(t, r, `{"dismissal_restrictions":{}}`+"\n") - fmt.Fprintf(w, `{"dismiss_stale_reviews":true,"require_code_owner_reviews":true,"required_approving_review_count":1}`) - }) - - ctx := context.Background() - enforcement, _, err := client.Repositories.DisableDismissalRestrictions(ctx, "o", "r", "b") - if err != nil { - t.Errorf("Repositories.DisableDismissalRestrictions returned error: %v", err) - } - - want := &PullRequestReviewsEnforcement{ - DismissStaleReviews: true, - DismissalRestrictions: nil, - RequireCodeOwnerReviews: true, - RequiredApprovingReviewCount: 1, - } - if !cmp.Equal(enforcement, want) { - t.Errorf("Repositories.DisableDismissalRestrictions returned %+v, want %+v", enforcement, want) - } - - const methodName = "DisableDismissalRestrictions" - testBadOptions(t, methodName, func() (err error) { - _, _, err = client.Repositories.DisableDismissalRestrictions(ctx, "\n", "\n", "\n") - return err - }) - - testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { - got, resp, err := client.Repositories.DisableDismissalRestrictions(ctx, "o", "r", "b") - if got != nil { - t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) - } - return resp, err - }) -} - -func TestRepositoriesService_RemovePullRequestReviewEnforcement(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() - - mux.HandleFunc("/repos/o/r/branches/b/protection/required_pull_request_reviews", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "DELETE") - w.WriteHeader(http.StatusNoContent) - }) - - ctx := context.Background() - _, err := client.Repositories.RemovePullRequestReviewEnforcement(ctx, "o", "r", "b") - if err != nil { - t.Errorf("Repositories.RemovePullRequestReviewEnforcement returned error: %v", err) - } - - const methodName = "RemovePullRequestReviewEnforcement" - testBadOptions(t, methodName, func() (err error) { - _, err = client.Repositories.RemovePullRequestReviewEnforcement(ctx, "\n", "\n", "\n") - return err - }) - - testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { - return client.Repositories.RemovePullRequestReviewEnforcement(ctx, "o", "r", "b") - }) -} - -func TestRepositoriesService_GetAdminEnforcement(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() - - mux.HandleFunc("/repos/o/r/branches/b/protection/enforce_admins", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "GET") - fmt.Fprintf(w, `{"url":"/repos/o/r/branches/b/protection/enforce_admins","enabled":true}`) - }) - - ctx := context.Background() - enforcement, _, err := client.Repositories.GetAdminEnforcement(ctx, "o", "r", "b") - if err != nil { - t.Errorf("Repositories.GetAdminEnforcement returned error: %v", err) - } - - want := &AdminEnforcement{ - URL: String("/repos/o/r/branches/b/protection/enforce_admins"), - Enabled: true, - } - - if !cmp.Equal(enforcement, want) { - t.Errorf("Repositories.GetAdminEnforcement returned %+v, want %+v", enforcement, want) - } - - const methodName = "GetAdminEnforcement" - testBadOptions(t, methodName, func() (err error) { - _, _, err = client.Repositories.GetAdminEnforcement(ctx, "\n", "\n", "\n") - return err - }) - - testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { - got, resp, err := client.Repositories.GetAdminEnforcement(ctx, "o", "r", "b") - if got != nil { - t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) - } - return resp, err - }) -} - -func TestRepositoriesService_AddAdminEnforcement(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() - - mux.HandleFunc("/repos/o/r/branches/b/protection/enforce_admins", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "POST") - fmt.Fprintf(w, `{"url":"/repos/o/r/branches/b/protection/enforce_admins","enabled":true}`) - }) - - ctx := context.Background() - enforcement, _, err := client.Repositories.AddAdminEnforcement(ctx, "o", "r", "b") - if err != nil { - t.Errorf("Repositories.AddAdminEnforcement returned error: %v", err) - } - - want := &AdminEnforcement{ - URL: String("/repos/o/r/branches/b/protection/enforce_admins"), - Enabled: true, - } - if !cmp.Equal(enforcement, want) { - t.Errorf("Repositories.AddAdminEnforcement returned %+v, want %+v", enforcement, want) - } - - const methodName = "AddAdminEnforcement" - testBadOptions(t, methodName, func() (err error) { - _, _, err = client.Repositories.AddAdminEnforcement(ctx, "\n", "\n", "\n") - return err - }) - - testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { - got, resp, err := client.Repositories.AddAdminEnforcement(ctx, "o", "r", "b") - if got != nil { - t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) - } - return resp, err - }) -} - -func TestRepositoriesService_RemoveAdminEnforcement(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() - - mux.HandleFunc("/repos/o/r/branches/b/protection/enforce_admins", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "DELETE") - w.WriteHeader(http.StatusNoContent) - }) - - ctx := context.Background() - _, err := client.Repositories.RemoveAdminEnforcement(ctx, "o", "r", "b") - if err != nil { - t.Errorf("Repositories.RemoveAdminEnforcement returned error: %v", err) - } - - const methodName = "RemoveAdminEnforcement" - testBadOptions(t, methodName, func() (err error) { - _, err = client.Repositories.RemoveAdminEnforcement(ctx, "\n", "\n", "\n") - return err - }) - - testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { - return client.Repositories.RemoveAdminEnforcement(ctx, "o", "r", "b") - }) -} - -func TestRepositoriesService_GetSignaturesProtectedBranch(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() - - mux.HandleFunc("/repos/o/r/branches/b/protection/required_signatures", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "GET") - testHeader(t, r, "Accept", mediaTypeSignaturePreview) - fmt.Fprintf(w, `{"url":"/repos/o/r/branches/b/protection/required_signatures","enabled":false}`) - }) - - ctx := context.Background() - signature, _, err := client.Repositories.GetSignaturesProtectedBranch(ctx, "o", "r", "b") - if err != nil { - t.Errorf("Repositories.GetSignaturesProtectedBranch returned error: %v", err) - } - - want := &SignaturesProtectedBranch{ - URL: String("/repos/o/r/branches/b/protection/required_signatures"), - Enabled: Bool(false), - } - - if !cmp.Equal(signature, want) { - t.Errorf("Repositories.GetSignaturesProtectedBranch returned %+v, want %+v", signature, want) - } - - const methodName = "GetSignaturesProtectedBranch" - testBadOptions(t, methodName, func() (err error) { - _, _, err = client.Repositories.GetSignaturesProtectedBranch(ctx, "\n", "\n", "\n") - return err - }) - - testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { - got, resp, err := client.Repositories.GetSignaturesProtectedBranch(ctx, "o", "r", "b") - if got != nil { - t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) - } - return resp, err - }) -} - -func TestRepositoriesService_RequireSignaturesOnProtectedBranch(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() - - mux.HandleFunc("/repos/o/r/branches/b/protection/required_signatures", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "POST") - testHeader(t, r, "Accept", mediaTypeSignaturePreview) - fmt.Fprintf(w, `{"url":"/repos/o/r/branches/b/protection/required_signatures","enabled":true}`) - }) - - ctx := context.Background() - signature, _, err := client.Repositories.RequireSignaturesOnProtectedBranch(ctx, "o", "r", "b") - if err != nil { - t.Errorf("Repositories.RequireSignaturesOnProtectedBranch returned error: %v", err) - } - - want := &SignaturesProtectedBranch{ - URL: String("/repos/o/r/branches/b/protection/required_signatures"), - Enabled: Bool(true), - } - - if !cmp.Equal(signature, want) { - t.Errorf("Repositories.RequireSignaturesOnProtectedBranch returned %+v, want %+v", signature, want) - } - - const methodName = "RequireSignaturesOnProtectedBranch" - testBadOptions(t, methodName, func() (err error) { - _, _, err = client.Repositories.RequireSignaturesOnProtectedBranch(ctx, "\n", "\n", "\n") - return err - }) - - testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { - got, resp, err := client.Repositories.RequireSignaturesOnProtectedBranch(ctx, "o", "r", "b") - if got != nil { - t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) - } - return resp, err - }) -} - -func TestRepositoriesService_OptionalSignaturesOnProtectedBranch(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() - - mux.HandleFunc("/repos/o/r/branches/b/protection/required_signatures", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "DELETE") - testHeader(t, r, "Accept", mediaTypeSignaturePreview) - w.WriteHeader(http.StatusNoContent) - }) - - ctx := context.Background() - _, err := client.Repositories.OptionalSignaturesOnProtectedBranch(ctx, "o", "r", "b") - if err != nil { - t.Errorf("Repositories.OptionalSignaturesOnProtectedBranch returned error: %v", err) - } - - const methodName = "OptionalSignaturesOnProtectedBranch" - testBadOptions(t, methodName, func() (err error) { - _, err = client.Repositories.OptionalSignaturesOnProtectedBranch(ctx, "\n", "\n", "\n") - return err - }) - - testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { - return client.Repositories.OptionalSignaturesOnProtectedBranch(ctx, "o", "r", "b") - }) -} - -func TestPullRequestReviewsEnforcementRequest_MarshalJSON_nilDismissalRestirctions(t *testing.T) { - req := PullRequestReviewsEnforcementRequest{} - - got, err := json.Marshal(req) - if err != nil { - t.Errorf("PullRequestReviewsEnforcementRequest.MarshalJSON returned error: %v", err) - } - - want := `{"dismiss_stale_reviews":false,"require_code_owner_reviews":false,"required_approving_review_count":0}` - if want != string(got) { - t.Errorf("PullRequestReviewsEnforcementRequest.MarshalJSON returned %+v, want %+v", string(got), want) - } - - req = PullRequestReviewsEnforcementRequest{ - DismissalRestrictionsRequest: &DismissalRestrictionsRequest{}, - } - - got, err = json.Marshal(req) - if err != nil { - t.Errorf("PullRequestReviewsEnforcementRequest.MarshalJSON returned error: %v", err) - } - - want = `{"dismissal_restrictions":{},"dismiss_stale_reviews":false,"require_code_owner_reviews":false,"required_approving_review_count":0}` - if want != string(got) { - t.Errorf("PullRequestReviewsEnforcementRequest.MarshalJSON returned %+v, want %+v", string(got), want) - } - - req = PullRequestReviewsEnforcementRequest{ - DismissalRestrictionsRequest: &DismissalRestrictionsRequest{ - Users: &[]string{}, - Teams: &[]string{}, - Apps: &[]string{}, - }, - RequireLastPushApproval: Bool(true), - } - - got, err = json.Marshal(req) - if err != nil { - t.Errorf("PullRequestReviewsEnforcementRequest.MarshalJSON returned error: %v", err) - } - - 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}` - if want != string(got) { - t.Errorf("PullRequestReviewsEnforcementRequest.MarshalJSON returned %+v, want %+v", string(got), want) - } -} - -func TestRepositoriesService_ListAllTopics(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() - - mux.HandleFunc("/repos/o/r/topics", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "GET") - testHeader(t, r, "Accept", mediaTypeTopicsPreview) - fmt.Fprint(w, `{"names":["go", "go-github", "github"]}`) - }) - - ctx := context.Background() - got, _, err := client.Repositories.ListAllTopics(ctx, "o", "r") - if err != nil { - t.Fatalf("Repositories.ListAllTopics returned error: %v", err) - } - - want := []string{"go", "go-github", "github"} - if !cmp.Equal(got, want) { - t.Errorf("Repositories.ListAllTopics returned %+v, want %+v", got, want) - } - - const methodName = "ListAllTopics" - testBadOptions(t, methodName, func() (err error) { - _, _, err = client.Repositories.ListAllTopics(ctx, "\n", "\n") - return err - }) - - testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { - got, resp, err := client.Repositories.ListAllTopics(ctx, "o", "r") - if got != nil { - t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) - } - return resp, err - }) -} + // TODO: remove custom Accept header when this API fully launches + testHeader(t, r, "Accept", mediaTypeRequiredApprovingReviewsPreview) + fmt.Fprintf(w, `{ + "dismissal_restrictions":{ + "users":[{"id":1,"login":"u"}], + "teams":[{"id":2,"slug":"t"}], + "apps":[{"id":3,"slug":"a"}] + }, + "dismiss_stale_reviews":true, + "require_code_owner_reviews":true, + "required_approving_review_count":3 + }`) + }) -func TestRepositoriesService_ListAllTopics_emptyTopics(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() + ctx := context.Background() + enforcement, _, err := client.Repositories.UpdatePullRequestReviewEnforcement(ctx, "o", "r", test.branch, input) + if err != nil { + t.Errorf("Repositories.UpdatePullRequestReviewEnforcement returned error: %v", err) + } - mux.HandleFunc("/repos/o/r/topics", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "GET") - testHeader(t, r, "Accept", mediaTypeTopicsPreview) - fmt.Fprint(w, `{"names":[]}`) - }) + want := &PullRequestReviewsEnforcement{ + DismissStaleReviews: true, + DismissalRestrictions: &DismissalRestrictions{ + Users: []*User{ + {Login: String("u"), ID: Int64(1)}, + }, + Teams: []*Team{ + {Slug: String("t"), ID: Int64(2)}, + }, + Apps: []*App{ + {Slug: String("a"), ID: Int64(3)}, + }, + }, + RequireCodeOwnerReviews: true, + RequiredApprovingReviewCount: 3, + } + if !cmp.Equal(enforcement, want) { + t.Errorf("Repositories.UpdatePullRequestReviewEnforcement returned %+v, want %+v", enforcement, want) + } - ctx := context.Background() - got, _, err := client.Repositories.ListAllTopics(ctx, "o", "r") - if err != nil { - t.Fatalf("Repositories.ListAllTopics returned error: %v", err) - } + const methodName = "UpdatePullRequestReviewEnforcement" + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.Repositories.UpdatePullRequestReviewEnforcement(ctx, "\n", "\n", "\n", input) + return err + }) - want := []string{} - if !cmp.Equal(got, want) { - t.Errorf("Repositories.ListAllTopics returned %+v, want %+v", got, want) + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Repositories.UpdatePullRequestReviewEnforcement(ctx, "o", "r", test.branch, input) + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) + }) } } -func TestRepositoriesService_ReplaceAllTopics(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() +func TestRepositoriesService_DisableDismissalRestrictions(t *testing.T) { + tests := []struct { + branch string + urlPath string + }{ + {branch: "b", urlPath: "/repos/o/r/branches/b/protection/required_pull_request_reviews"}, + {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat/branch-50%/protection/required_pull_request_reviews"}, + } + + for _, test := range tests { + t.Run(test.branch, func(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "PATCH") + // TODO: remove custom Accept header when this API fully launches + testHeader(t, r, "Accept", mediaTypeRequiredApprovingReviewsPreview) + testBody(t, r, `{"dismissal_restrictions":{}}`+"\n") + fmt.Fprintf(w, `{"dismiss_stale_reviews":true,"require_code_owner_reviews":true,"required_approving_review_count":1}`) + }) + + ctx := context.Background() + enforcement, _, err := client.Repositories.DisableDismissalRestrictions(ctx, "o", "r", test.branch) + if err != nil { + t.Errorf("Repositories.DisableDismissalRestrictions returned error: %v", err) + } - mux.HandleFunc("/repos/o/r/topics", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "PUT") - testHeader(t, r, "Accept", mediaTypeTopicsPreview) - fmt.Fprint(w, `{"names":["go", "go-github", "github"]}`) - }) + want := &PullRequestReviewsEnforcement{ + DismissStaleReviews: true, + DismissalRestrictions: nil, + RequireCodeOwnerReviews: true, + RequiredApprovingReviewCount: 1, + } + if !cmp.Equal(enforcement, want) { + t.Errorf("Repositories.DisableDismissalRestrictions returned %+v, want %+v", enforcement, want) + } - ctx := context.Background() - got, _, err := client.Repositories.ReplaceAllTopics(ctx, "o", "r", []string{"go", "go-github", "github"}) - if err != nil { - t.Fatalf("Repositories.ReplaceAllTopics returned error: %v", err) - } + const methodName = "DisableDismissalRestrictions" + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.Repositories.DisableDismissalRestrictions(ctx, "\n", "\n", "\n") + return err + }) - want := []string{"go", "go-github", "github"} - if !cmp.Equal(got, want) { - t.Errorf("Repositories.ReplaceAllTopics returned %+v, want %+v", got, want) + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Repositories.DisableDismissalRestrictions(ctx, "o", "r", test.branch) + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) + }) } +} - const methodName = "ReplaceAllTopics" - testBadOptions(t, methodName, func() (err error) { - _, _, err = client.Repositories.ReplaceAllTopics(ctx, "\n", "\n", []string{"\n", "\n", "\n"}) - return err - }) +func TestRepositoriesService_RemovePullRequestReviewEnforcement(t *testing.T) { + tests := []struct { + branch string + urlPath string + }{ + {branch: "b", urlPath: "/repos/o/r/branches/b/protection/required_pull_request_reviews"}, + {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat/branch-50%/protection/required_pull_request_reviews"}, + } + + for _, test := range tests { + t.Run(test.branch, func(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "DELETE") + w.WriteHeader(http.StatusNoContent) + }) + + ctx := context.Background() + _, err := client.Repositories.RemovePullRequestReviewEnforcement(ctx, "o", "r", test.branch) + if err != nil { + t.Errorf("Repositories.RemovePullRequestReviewEnforcement returned error: %v", err) + } - testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { - got, resp, err := client.Repositories.ReplaceAllTopics(ctx, "o", "r", []string{"go", "go-github", "github"}) - if got != nil { - t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) - } - return resp, err - }) + const methodName = "RemovePullRequestReviewEnforcement" + testBadOptions(t, methodName, func() (err error) { + _, err = client.Repositories.RemovePullRequestReviewEnforcement(ctx, "\n", "\n", "\n") + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + return client.Repositories.RemovePullRequestReviewEnforcement(ctx, "o", "r", test.branch) + }) + }) + } } -func TestRepositoriesService_ReplaceAllTopics_nilSlice(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() +func TestRepositoriesService_GetAdminEnforcement(t *testing.T) { + tests := []struct { + branch string + urlPath string + }{ + {branch: "b", urlPath: "/repos/o/r/branches/b/protection/enforce_admins"}, + {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat/branch-50%/protection/enforce_admins"}, + } + + for _, test := range tests { + t.Run(test.branch, func(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + fmt.Fprintf(w, `{"url":"/repos/o/r/branches/b/protection/enforce_admins","enabled":true}`) + }) + + ctx := context.Background() + enforcement, _, err := client.Repositories.GetAdminEnforcement(ctx, "o", "r", test.branch) + if err != nil { + t.Errorf("Repositories.GetAdminEnforcement returned error: %v", err) + } - mux.HandleFunc("/repos/o/r/topics", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "PUT") - testHeader(t, r, "Accept", mediaTypeTopicsPreview) - testBody(t, r, `{"names":[]}`+"\n") - fmt.Fprint(w, `{"names":[]}`) - }) + want := &AdminEnforcement{ + URL: String("/repos/o/r/branches/b/protection/enforce_admins"), + Enabled: true, + } - ctx := context.Background() - got, _, err := client.Repositories.ReplaceAllTopics(ctx, "o", "r", nil) - if err != nil { - t.Fatalf("Repositories.ReplaceAllTopics returned error: %v", err) - } + if !cmp.Equal(enforcement, want) { + t.Errorf("Repositories.GetAdminEnforcement returned %+v, want %+v", enforcement, want) + } - want := []string{} - if !cmp.Equal(got, want) { - t.Errorf("Repositories.ReplaceAllTopics returned %+v, want %+v", got, want) + const methodName = "GetAdminEnforcement" + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.Repositories.GetAdminEnforcement(ctx, "\n", "\n", "\n") + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Repositories.GetAdminEnforcement(ctx, "o", "r", test.branch) + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) + }) } } -func TestRepositoriesService_ReplaceAllTopics_emptySlice(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() +func TestRepositoriesService_AddAdminEnforcement(t *testing.T) { + tests := []struct { + branch string + urlPath string + }{ + {branch: "b", urlPath: "/repos/o/r/branches/b/protection/enforce_admins"}, + {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat/branch-50%/protection/enforce_admins"}, + } + + for _, test := range tests { + t.Run(test.branch, func(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "POST") + fmt.Fprintf(w, `{"url":"/repos/o/r/branches/b/protection/enforce_admins","enabled":true}`) + }) + + ctx := context.Background() + enforcement, _, err := client.Repositories.AddAdminEnforcement(ctx, "o", "r", test.branch) + if err != nil { + t.Errorf("Repositories.AddAdminEnforcement returned error: %v", err) + } - mux.HandleFunc("/repos/o/r/topics", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "PUT") - testHeader(t, r, "Accept", mediaTypeTopicsPreview) - testBody(t, r, `{"names":[]}`+"\n") - fmt.Fprint(w, `{"names":[]}`) - }) + want := &AdminEnforcement{ + URL: String("/repos/o/r/branches/b/protection/enforce_admins"), + Enabled: true, + } + if !cmp.Equal(enforcement, want) { + t.Errorf("Repositories.AddAdminEnforcement returned %+v, want %+v", enforcement, want) + } - ctx := context.Background() - got, _, err := client.Repositories.ReplaceAllTopics(ctx, "o", "r", []string{}) - if err != nil { - t.Fatalf("Repositories.ReplaceAllTopics returned error: %v", err) - } + const methodName = "AddAdminEnforcement" + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.Repositories.AddAdminEnforcement(ctx, "\n", "\n", "\n") + return err + }) - want := []string{} - if !cmp.Equal(got, want) { - t.Errorf("Repositories.ReplaceAllTopics returned %+v, want %+v", got, want) + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Repositories.AddAdminEnforcement(ctx, "o", "r", test.branch) + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) + }) } } -func TestRepositoriesService_ListAppRestrictions(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() +func TestRepositoriesService_RemoveAdminEnforcement(t *testing.T) { + tests := []struct { + branch string + urlPath string + }{ + {branch: "b", urlPath: "/repos/o/r/branches/b/protection/enforce_admins"}, + {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat/branch-50%/protection/enforce_admins"}, + } + + for _, test := range tests { + t.Run(test.branch, func(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "DELETE") + w.WriteHeader(http.StatusNoContent) + }) + + ctx := context.Background() + _, err := client.Repositories.RemoveAdminEnforcement(ctx, "o", "r", test.branch) + if err != nil { + t.Errorf("Repositories.RemoveAdminEnforcement returned error: %v", err) + } - mux.HandleFunc("/repos/o/r/branches/b/protection/restrictions/apps", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "GET") - }) + const methodName = "RemoveAdminEnforcement" + testBadOptions(t, methodName, func() (err error) { + _, err = client.Repositories.RemoveAdminEnforcement(ctx, "\n", "\n", "\n") + return err + }) - ctx := context.Background() - _, _, err := client.Repositories.ListAppRestrictions(ctx, "o", "r", "b") - if err != nil { - t.Errorf("Repositories.ListAppRestrictions returned error: %v", err) + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + return client.Repositories.RemoveAdminEnforcement(ctx, "o", "r", test.branch) + }) + }) } +} - const methodName = "ListAppRestrictions" - testBadOptions(t, methodName, func() (err error) { - _, _, err = client.Repositories.ListAppRestrictions(ctx, "\n", "\n", "\n") - return err - }) +func TestRepositoriesService_GetSignaturesProtectedBranch(t *testing.T) { + tests := []struct { + branch string + urlPath string + }{ + {branch: "b", urlPath: "/repos/o/r/branches/b/protection/required_signatures"}, + {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat/branch-50%/protection/required_signatures"}, + } + + for _, test := range tests { + t.Run(test.branch, func(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + testHeader(t, r, "Accept", mediaTypeSignaturePreview) + fmt.Fprintf(w, `{"url":"/repos/o/r/branches/b/protection/required_signatures","enabled":false}`) + }) + + ctx := context.Background() + signature, _, err := client.Repositories.GetSignaturesProtectedBranch(ctx, "o", "r", test.branch) + if err != nil { + t.Errorf("Repositories.GetSignaturesProtectedBranch returned error: %v", err) + } - testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { - got, resp, err := client.Repositories.ListAppRestrictions(ctx, "o", "r", "b") - if got != nil { - t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) - } - return resp, err - }) -} + want := &SignaturesProtectedBranch{ + URL: String("/repos/o/r/branches/b/protection/required_signatures"), + Enabled: Bool(false), + } -func TestRepositoriesService_ReplaceAppRestrictions(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() + if !cmp.Equal(signature, want) { + t.Errorf("Repositories.GetSignaturesProtectedBranch returned %+v, want %+v", signature, want) + } - mux.HandleFunc("/repos/o/r/branches/b/protection/restrictions/apps", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "PUT") - fmt.Fprint(w, `[{ - "name": "octocat" - }]`) - }) - input := []string{"octocat"} - ctx := context.Background() - got, _, err := client.Repositories.ReplaceAppRestrictions(ctx, "o", "r", "b", input) - if err != nil { - t.Errorf("Repositories.ReplaceAppRestrictions returned error: %v", err) - } - want := []*App{ - {Name: String("octocat")}, - } - if !cmp.Equal(got, want) { - t.Errorf("Repositories.ReplaceAppRestrictions returned %+v, want %+v", got, want) + const methodName = "GetSignaturesProtectedBranch" + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.Repositories.GetSignaturesProtectedBranch(ctx, "\n", "\n", "\n") + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Repositories.GetSignaturesProtectedBranch(ctx, "o", "r", test.branch) + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) + }) } +} - const methodName = "ReplaceAppRestrictions" - testBadOptions(t, methodName, func() (err error) { - _, _, err = client.Repositories.ReplaceAppRestrictions(ctx, "\n", "\n", "\n", input) - return err - }) +func TestRepositoriesService_RequireSignaturesOnProtectedBranch(t *testing.T) { + tests := []struct { + branch string + urlPath string + }{ + {branch: "b", urlPath: "/repos/o/r/branches/b/protection/required_signatures"}, + {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat/branch-50%/protection/required_signatures"}, + } + + for _, test := range tests { + t.Run(test.branch, func(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "POST") + testHeader(t, r, "Accept", mediaTypeSignaturePreview) + fmt.Fprintf(w, `{"url":"/repos/o/r/branches/b/protection/required_signatures","enabled":true}`) + }) + + ctx := context.Background() + signature, _, err := client.Repositories.RequireSignaturesOnProtectedBranch(ctx, "o", "r", test.branch) + if err != nil { + t.Errorf("Repositories.RequireSignaturesOnProtectedBranch returned error: %v", err) + } - testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { - got, resp, err := client.Repositories.ReplaceAppRestrictions(ctx, "o", "r", "b", input) - if got != nil { - t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) - } - return resp, err - }) -} + want := &SignaturesProtectedBranch{ + URL: String("/repos/o/r/branches/b/protection/required_signatures"), + Enabled: Bool(true), + } -func TestRepositoriesService_AddAppRestrictions(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() + if !cmp.Equal(signature, want) { + t.Errorf("Repositories.RequireSignaturesOnProtectedBranch returned %+v, want %+v", signature, want) + } - mux.HandleFunc("/repos/o/r/branches/b/protection/restrictions/apps", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "POST") - fmt.Fprint(w, `[{ - "name": "octocat" - }]`) - }) - input := []string{"octocat"} - ctx := context.Background() - got, _, err := client.Repositories.AddAppRestrictions(ctx, "o", "r", "b", input) - if err != nil { - t.Errorf("Repositories.AddAppRestrictions returned error: %v", err) - } - want := []*App{ - {Name: String("octocat")}, - } - if !cmp.Equal(got, want) { - t.Errorf("Repositories.AddAppRestrictions returned %+v, want %+v", got, want) + const methodName = "RequireSignaturesOnProtectedBranch" + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.Repositories.RequireSignaturesOnProtectedBranch(ctx, "\n", "\n", "\n") + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Repositories.RequireSignaturesOnProtectedBranch(ctx, "o", "r", test.branch) + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) + }) } +} - const methodName = "AddAppRestrictions" - testBadOptions(t, methodName, func() (err error) { - _, _, err = client.Repositories.AddAppRestrictions(ctx, "\n", "\n", "\n", input) - return err - }) +func TestRepositoriesService_OptionalSignaturesOnProtectedBranch(t *testing.T) { + tests := []struct { + branch string + urlPath string + }{ + {branch: "b", urlPath: "/repos/o/r/branches/b/protection/required_signatures"}, + {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat/branch-50%/protection/required_signatures"}, + } + + for _, test := range tests { + t.Run(test.branch, func(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "DELETE") + testHeader(t, r, "Accept", mediaTypeSignaturePreview) + w.WriteHeader(http.StatusNoContent) + }) + + ctx := context.Background() + _, err := client.Repositories.OptionalSignaturesOnProtectedBranch(ctx, "o", "r", test.branch) + if err != nil { + t.Errorf("Repositories.OptionalSignaturesOnProtectedBranch returned error: %v", err) + } - testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { - got, resp, err := client.Repositories.AddAppRestrictions(ctx, "o", "r", "b", input) - if got != nil { - t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) - } - return resp, err - }) + const methodName = "OptionalSignaturesOnProtectedBranch" + testBadOptions(t, methodName, func() (err error) { + _, err = client.Repositories.OptionalSignaturesOnProtectedBranch(ctx, "\n", "\n", "\n") + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + return client.Repositories.OptionalSignaturesOnProtectedBranch(ctx, "o", "r", test.branch) + }) + }) + } } -func TestRepositoriesService_RemoveAppRestrictions(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() +func TestPullRequestReviewsEnforcementRequest_MarshalJSON_nilDismissalRestirctions(t *testing.T) { + req := PullRequestReviewsEnforcementRequest{} - mux.HandleFunc("/repos/o/r/branches/b/protection/restrictions/apps", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "DELETE") - fmt.Fprint(w, `[]`) - }) - input := []string{"octocat"} - ctx := context.Background() - got, _, err := client.Repositories.RemoveAppRestrictions(ctx, "o", "r", "b", input) + got, err := json.Marshal(req) if err != nil { - t.Errorf("Repositories.RemoveAppRestrictions returned error: %v", err) + t.Errorf("PullRequestReviewsEnforcementRequest.MarshalJSON returned error: %v", err) } - want := []*App{} - if !cmp.Equal(got, want) { - t.Errorf("Repositories.RemoveAppRestrictions returned %+v, want %+v", got, want) + + want := `{"dismiss_stale_reviews":false,"require_code_owner_reviews":false,"required_approving_review_count":0}` + if want != string(got) { + t.Errorf("PullRequestReviewsEnforcementRequest.MarshalJSON returned %+v, want %+v", string(got), want) } - const methodName = "RemoveAppRestrictions" - testBadOptions(t, methodName, func() (err error) { - _, _, err = client.Repositories.RemoveAppRestrictions(ctx, "\n", "\n", "\n", input) - return err - }) + req = PullRequestReviewsEnforcementRequest{ + DismissalRestrictionsRequest: &DismissalRestrictionsRequest{}, + } - testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { - got, resp, err := client.Repositories.RemoveAppRestrictions(ctx, "o", "r", "b", input) - if got != nil { - t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) - } - return resp, err - }) -} + got, err = json.Marshal(req) + if err != nil { + t.Errorf("PullRequestReviewsEnforcementRequest.MarshalJSON returned error: %v", err) + } -func TestRepositoriesService_ListTeamRestrictions(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() + want = `{"dismissal_restrictions":{},"dismiss_stale_reviews":false,"require_code_owner_reviews":false,"required_approving_review_count":0}` + if want != string(got) { + t.Errorf("PullRequestReviewsEnforcementRequest.MarshalJSON returned %+v, want %+v", string(got), want) + } - mux.HandleFunc("/repos/o/r/branches/b/protection/restrictions/teams", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "GET") - }) + req = PullRequestReviewsEnforcementRequest{ + DismissalRestrictionsRequest: &DismissalRestrictionsRequest{ + Users: &[]string{}, + Teams: &[]string{}, + Apps: &[]string{}, + }, + RequireLastPushApproval: Bool(true), + } - ctx := context.Background() - _, _, err := client.Repositories.ListTeamRestrictions(ctx, "o", "r", "b") + got, err = json.Marshal(req) if err != nil { - t.Errorf("Repositories.ListTeamRestrictions returned error: %v", err) + t.Errorf("PullRequestReviewsEnforcementRequest.MarshalJSON returned error: %v", err) } - const methodName = "ListTeamRestrictions" - testBadOptions(t, methodName, func() (err error) { - _, _, err = client.Repositories.ListTeamRestrictions(ctx, "\n", "\n", "\n") - return err - }) - - testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { - got, resp, err := client.Repositories.ListTeamRestrictions(ctx, "o", "r", "b") - if got != nil { - t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) - } - return resp, err - }) + 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}` + if want != string(got) { + t.Errorf("PullRequestReviewsEnforcementRequest.MarshalJSON returned %+v, want %+v", string(got), want) + } } -func TestRepositoriesService_ReplaceTeamRestrictions(t *testing.T) { +func TestRepositoriesService_ListAllTopics(t *testing.T) { client, mux, _, teardown := setup() defer teardown() - - mux.HandleFunc("/repos/o/r/branches/b/protection/restrictions/teams", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "PUT") - fmt.Fprint(w, `[{ - "name": "octocat" - }]`) + + mux.HandleFunc("/repos/o/r/topics", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + testHeader(t, r, "Accept", mediaTypeTopicsPreview) + fmt.Fprint(w, `{"names":["go", "go-github", "github"]}`) }) - input := []string{"octocat"} + ctx := context.Background() - got, _, err := client.Repositories.ReplaceTeamRestrictions(ctx, "o", "r", "b", input) + got, _, err := client.Repositories.ListAllTopics(ctx, "o", "r") if err != nil { - t.Errorf("Repositories.ReplaceTeamRestrictions returned error: %v", err) - } - want := []*Team{ - {Name: String("octocat")}, + t.Fatalf("Repositories.ListAllTopics returned error: %v", err) } + + want := []string{"go", "go-github", "github"} if !cmp.Equal(got, want) { - t.Errorf("Repositories.ReplaceTeamRestrictions returned %+v, want %+v", got, want) + t.Errorf("Repositories.ListAllTopics returned %+v, want %+v", got, want) } - const methodName = "ReplaceTeamRestrictions" + const methodName = "ListAllTopics" testBadOptions(t, methodName, func() (err error) { - _, _, err = client.Repositories.ReplaceTeamRestrictions(ctx, "\n", "\n", "\n", input) + _, _, err = client.Repositories.ListAllTopics(ctx, "\n", "\n") return err }) testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { - got, resp, err := client.Repositories.ReplaceTeamRestrictions(ctx, "o", "r", "b", input) + got, resp, err := client.Repositories.ListAllTopics(ctx, "o", "r") if got != nil { t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) } @@ -3031,71 +3067,57 @@ func TestRepositoriesService_ReplaceTeamRestrictions(t *testing.T) { }) } -func TestRepositoriesService_AddTeamRestrictions(t *testing.T) { +func TestRepositoriesService_ListAllTopics_emptyTopics(t *testing.T) { client, mux, _, teardown := setup() defer teardown() - mux.HandleFunc("/repos/o/r/branches/b/protection/restrictions/teams", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "POST") - fmt.Fprint(w, `[{ - "name": "octocat" - }]`) + mux.HandleFunc("/repos/o/r/topics", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + testHeader(t, r, "Accept", mediaTypeTopicsPreview) + fmt.Fprint(w, `{"names":[]}`) }) - input := []string{"octocat"} + ctx := context.Background() - got, _, err := client.Repositories.AddTeamRestrictions(ctx, "o", "r", "b", input) + got, _, err := client.Repositories.ListAllTopics(ctx, "o", "r") if err != nil { - t.Errorf("Repositories.AddTeamRestrictions returned error: %v", err) - } - want := []*Team{ - {Name: String("octocat")}, + t.Fatalf("Repositories.ListAllTopics returned error: %v", err) } + + want := []string{} if !cmp.Equal(got, want) { - t.Errorf("Repositories.AddTeamRestrictions returned %+v, want %+v", got, want) + t.Errorf("Repositories.ListAllTopics returned %+v, want %+v", got, want) } - - const methodName = "AddTeamRestrictions" - testBadOptions(t, methodName, func() (err error) { - _, _, err = client.Repositories.AddTeamRestrictions(ctx, "\n", "\n", "\n", input) - return err - }) - - testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { - got, resp, err := client.Repositories.AddTeamRestrictions(ctx, "o", "r", "b", input) - if got != nil { - t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) - } - return resp, err - }) } -func TestRepositoriesService_RemoveTeamRestrictions(t *testing.T) { +func TestRepositoriesService_ReplaceAllTopics(t *testing.T) { client, mux, _, teardown := setup() defer teardown() - mux.HandleFunc("/repos/o/r/branches/b/protection/restrictions/teams", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "DELETE") - fmt.Fprint(w, `[]`) + mux.HandleFunc("/repos/o/r/topics", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "PUT") + testHeader(t, r, "Accept", mediaTypeTopicsPreview) + fmt.Fprint(w, `{"names":["go", "go-github", "github"]}`) }) - input := []string{"octocat"} + ctx := context.Background() - got, _, err := client.Repositories.RemoveTeamRestrictions(ctx, "o", "r", "b", input) + got, _, err := client.Repositories.ReplaceAllTopics(ctx, "o", "r", []string{"go", "go-github", "github"}) if err != nil { - t.Errorf("Repositories.RemoveTeamRestrictions returned error: %v", err) + t.Fatalf("Repositories.ReplaceAllTopics returned error: %v", err) } - want := []*Team{} + + want := []string{"go", "go-github", "github"} if !cmp.Equal(got, want) { - t.Errorf("Repositories.RemoveTeamRestrictions returned %+v, want %+v", got, want) + t.Errorf("Repositories.ReplaceAllTopics returned %+v, want %+v", got, want) } - const methodName = "RemoveTeamRestrictions" + const methodName = "ReplaceAllTopics" testBadOptions(t, methodName, func() (err error) { - _, _, err = client.Repositories.RemoveTeamRestrictions(ctx, "\n", "\n", "\n", input) + _, _, err = client.Repositories.ReplaceAllTopics(ctx, "\n", "\n", []string{"\n", "\n", "\n"}) return err }) testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { - got, resp, err := client.Repositories.RemoveTeamRestrictions(ctx, "o", "r", "b", input) + got, resp, err := client.Repositories.ReplaceAllTopics(ctx, "o", "r", []string{"go", "go-github", "github"}) if got != nil { t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) } @@ -3103,143 +3125,611 @@ func TestRepositoriesService_RemoveTeamRestrictions(t *testing.T) { }) } -func TestRepositoriesService_ListUserRestrictions(t *testing.T) { +func TestRepositoriesService_ReplaceAllTopics_nilSlice(t *testing.T) { client, mux, _, teardown := setup() defer teardown() - mux.HandleFunc("/repos/o/r/branches/b/protection/restrictions/users", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "GET") + mux.HandleFunc("/repos/o/r/topics", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "PUT") + testHeader(t, r, "Accept", mediaTypeTopicsPreview) + testBody(t, r, `{"names":[]}`+"\n") + fmt.Fprint(w, `{"names":[]}`) }) ctx := context.Background() - _, _, err := client.Repositories.ListUserRestrictions(ctx, "o", "r", "b") + got, _, err := client.Repositories.ReplaceAllTopics(ctx, "o", "r", nil) if err != nil { - t.Errorf("Repositories.ListUserRestrictions returned error: %v", err) + t.Fatalf("Repositories.ReplaceAllTopics returned error: %v", err) } - const methodName = "ListUserRestrictions" - testBadOptions(t, methodName, func() (err error) { - _, _, err = client.Repositories.ListUserRestrictions(ctx, "\n", "\n", "\n") - return err - }) - - testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { - got, resp, err := client.Repositories.ListUserRestrictions(ctx, "o", "r", "b") - if got != nil { - t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) - } - return resp, err - }) + want := []string{} + if !cmp.Equal(got, want) { + t.Errorf("Repositories.ReplaceAllTopics returned %+v, want %+v", got, want) + } } -func TestRepositoriesService_ReplaceUserRestrictions(t *testing.T) { +func TestRepositoriesService_ReplaceAllTopics_emptySlice(t *testing.T) { client, mux, _, teardown := setup() defer teardown() - mux.HandleFunc("/repos/o/r/branches/b/protection/restrictions/users", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/repos/o/r/topics", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "PUT") - fmt.Fprint(w, `[{ - "name": "octocat" - }]`) + testHeader(t, r, "Accept", mediaTypeTopicsPreview) + testBody(t, r, `{"names":[]}`+"\n") + fmt.Fprint(w, `{"names":[]}`) }) - input := []string{"octocat"} + ctx := context.Background() - got, _, err := client.Repositories.ReplaceUserRestrictions(ctx, "o", "r", "b", input) + got, _, err := client.Repositories.ReplaceAllTopics(ctx, "o", "r", []string{}) if err != nil { - t.Errorf("Repositories.ReplaceUserRestrictions returned error: %v", err) - } - want := []*User{ - {Name: String("octocat")}, + t.Fatalf("Repositories.ReplaceAllTopics returned error: %v", err) } + + want := []string{} if !cmp.Equal(got, want) { - t.Errorf("Repositories.ReplaceUserRestrictions returned %+v, want %+v", got, want) + t.Errorf("Repositories.ReplaceAllTopics returned %+v, want %+v", got, want) } +} - const methodName = "ReplaceUserRestrictions" - testBadOptions(t, methodName, func() (err error) { - _, _, err = client.Repositories.ReplaceUserRestrictions(ctx, "\n", "\n", "\n", input) - return err - }) +func TestRepositoriesService_ListAppRestrictions(t *testing.T) { + tests := []struct { + branch string + urlPath string + }{ + {branch: "b", urlPath: "/repos/o/r/branches/b/protection/restrictions/apps"}, + {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat/branch-50%/protection/restrictions/apps"}, + } + + for _, test := range tests { + t.Run(test.branch, func(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + }) + + ctx := context.Background() + _, _, err := client.Repositories.ListAppRestrictions(ctx, "o", "r", test.branch) + if err != nil { + t.Errorf("Repositories.ListAppRestrictions returned error: %v", err) + } - testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { - got, resp, err := client.Repositories.ReplaceUserRestrictions(ctx, "o", "r", "b", input) - if got != nil { - t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) - } - return resp, err - }) + const methodName = "ListAppRestrictions" + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.Repositories.ListAppRestrictions(ctx, "\n", "\n", "\n") + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Repositories.ListAppRestrictions(ctx, "o", "r", test.branch) + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) + }) + } } -func TestRepositoriesService_AddUserRestrictions(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() +func TestRepositoriesService_ReplaceAppRestrictions(t *testing.T) { + tests := []struct { + branch string + urlPath string + }{ + {branch: "b", urlPath: "/repos/o/r/branches/b/protection/restrictions/apps"}, + {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat/branch-50%/protection/restrictions/apps"}, + } + + for _, test := range tests { + t.Run(test.branch, func(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "PUT") + fmt.Fprint(w, `[{ + "name": "octocat" + }]`) + }) + input := []string{"octocat"} + ctx := context.Background() + got, _, err := client.Repositories.ReplaceAppRestrictions(ctx, "o", "r", test.branch, input) + if err != nil { + t.Errorf("Repositories.ReplaceAppRestrictions returned error: %v", err) + } + want := []*App{ + {Name: String("octocat")}, + } + if !cmp.Equal(got, want) { + t.Errorf("Repositories.ReplaceAppRestrictions returned %+v, want %+v", got, want) + } - mux.HandleFunc("/repos/o/r/branches/b/protection/restrictions/users", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "POST") - fmt.Fprint(w, `[{ + const methodName = "ReplaceAppRestrictions" + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.Repositories.ReplaceAppRestrictions(ctx, "\n", "\n", "\n", input) + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Repositories.ReplaceAppRestrictions(ctx, "o", "r", test.branch, input) + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) + }) + } +} + +func TestRepositoriesService_AddAppRestrictions(t *testing.T) { + tests := []struct { + branch string + urlPath string + }{ + {branch: "b", urlPath: "/repos/o/r/branches/b/protection/restrictions/apps"}, + {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat/branch-50%/protection/restrictions/apps"}, + } + + for _, test := range tests { + t.Run(test.branch, func(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "POST") + fmt.Fprint(w, `[{ "name": "octocat" }]`) - }) - input := []string{"octocat"} - ctx := context.Background() - got, _, err := client.Repositories.AddUserRestrictions(ctx, "o", "r", "b", input) - if err != nil { - t.Errorf("Repositories.AddUserRestrictions returned error: %v", err) + }) + input := []string{"octocat"} + ctx := context.Background() + got, _, err := client.Repositories.AddAppRestrictions(ctx, "o", "r", test.branch, input) + if err != nil { + t.Errorf("Repositories.AddAppRestrictions returned error: %v", err) + } + want := []*App{ + {Name: String("octocat")}, + } + if !cmp.Equal(got, want) { + t.Errorf("Repositories.AddAppRestrictions returned %+v, want %+v", got, want) + } + + const methodName = "AddAppRestrictions" + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.Repositories.AddAppRestrictions(ctx, "\n", "\n", "\n", input) + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Repositories.AddAppRestrictions(ctx, "o", "r", test.branch, input) + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) + }) } - want := []*User{ - {Name: String("octocat")}, +} + +func TestRepositoriesService_RemoveAppRestrictions(t *testing.T) { + tests := []struct { + branch string + urlPath string + }{ + {branch: "b", urlPath: "/repos/o/r/branches/b/protection/restrictions/apps"}, + {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat/branch-50%/protection/restrictions/apps"}, + } + + for _, test := range tests { + t.Run(test.branch, func(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "DELETE") + fmt.Fprint(w, `[]`) + }) + input := []string{"octocat"} + ctx := context.Background() + got, _, err := client.Repositories.RemoveAppRestrictions(ctx, "o", "r", test.branch, input) + if err != nil { + t.Errorf("Repositories.RemoveAppRestrictions returned error: %v", err) + } + want := []*App{} + if !cmp.Equal(got, want) { + t.Errorf("Repositories.RemoveAppRestrictions returned %+v, want %+v", got, want) + } + + const methodName = "RemoveAppRestrictions" + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.Repositories.RemoveAppRestrictions(ctx, "\n", "\n", "\n", input) + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Repositories.RemoveAppRestrictions(ctx, "o", "r", test.branch, input) + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) + }) } - if !cmp.Equal(got, want) { - t.Errorf("Repositories.AddUserRestrictions returned %+v, want %+v", got, want) +} + +func TestRepositoriesService_ListTeamRestrictions(t *testing.T) { + tests := []struct { + branch string + urlPath string + }{ + {branch: "b", urlPath: "/repos/o/r/branches/b/protection/restrictions/teams"}, + {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat/branch-50%/protection/restrictions/teams"}, + } + + for _, test := range tests { + t.Run(test.branch, func(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + }) + + ctx := context.Background() + _, _, err := client.Repositories.ListTeamRestrictions(ctx, "o", "r", test.branch) + if err != nil { + t.Errorf("Repositories.ListTeamRestrictions returned error: %v", err) + } + + const methodName = "ListTeamRestrictions" + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.Repositories.ListTeamRestrictions(ctx, "\n", "\n", "\n") + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Repositories.ListTeamRestrictions(ctx, "o", "r", test.branch) + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) + }) } +} - const methodName = "AddUserRestrictions" - testBadOptions(t, methodName, func() (err error) { - _, _, err = client.Repositories.AddUserRestrictions(ctx, "\n", "\n", "\n", input) - return err - }) +func TestRepositoriesService_ReplaceTeamRestrictions(t *testing.T) { + tests := []struct { + branch string + urlPath string + }{ + {branch: "b", urlPath: "/repos/o/r/branches/b/protection/restrictions/teams"}, + {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat/branch-50%/protection/restrictions/teams"}, + } + + for _, test := range tests { + t.Run(test.branch, func(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "PUT") + fmt.Fprint(w, `[{ + "name": "octocat" + }]`) + }) + input := []string{"octocat"} + ctx := context.Background() + got, _, err := client.Repositories.ReplaceTeamRestrictions(ctx, "o", "r", test.branch, input) + if err != nil { + t.Errorf("Repositories.ReplaceTeamRestrictions returned error: %v", err) + } + want := []*Team{ + {Name: String("octocat")}, + } + if !cmp.Equal(got, want) { + t.Errorf("Repositories.ReplaceTeamRestrictions returned %+v, want %+v", got, want) + } - testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { - got, resp, err := client.Repositories.AddUserRestrictions(ctx, "o", "r", "b", input) - if got != nil { - t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) - } - return resp, err - }) + const methodName = "ReplaceTeamRestrictions" + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.Repositories.ReplaceTeamRestrictions(ctx, "\n", "\n", "\n", input) + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Repositories.ReplaceTeamRestrictions(ctx, "o", "r", test.branch, input) + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) + }) + } } -func TestRepositoriesService_RemoveUserRestrictions(t *testing.T) { - client, mux, _, teardown := setup() - defer teardown() +func TestRepositoriesService_AddTeamRestrictions(t *testing.T) { + tests := []struct { + branch string + urlPath string + }{ + {branch: "b", urlPath: "/repos/o/r/branches/b/protection/restrictions/teams"}, + {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat/branch-50%/protection/restrictions/teams"}, + } + + for _, test := range tests { + t.Run(test.branch, func(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "POST") + fmt.Fprint(w, `[{ + "name": "octocat" + }]`) + }) + input := []string{"octocat"} + ctx := context.Background() + got, _, err := client.Repositories.AddTeamRestrictions(ctx, "o", "r", test.branch, input) + if err != nil { + t.Errorf("Repositories.AddTeamRestrictions returned error: %v", err) + } + want := []*Team{ + {Name: String("octocat")}, + } + if !cmp.Equal(got, want) { + t.Errorf("Repositories.AddTeamRestrictions returned %+v, want %+v", got, want) + } - mux.HandleFunc("/repos/o/r/branches/b/protection/restrictions/users", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "DELETE") - fmt.Fprint(w, `[]`) - }) - input := []string{"octocat"} - ctx := context.Background() - got, _, err := client.Repositories.RemoveUserRestrictions(ctx, "o", "r", "b", input) - if err != nil { - t.Errorf("Repositories.RemoveUserRestrictions returned error: %v", err) + const methodName = "AddTeamRestrictions" + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.Repositories.AddTeamRestrictions(ctx, "\n", "\n", "\n", input) + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Repositories.AddTeamRestrictions(ctx, "o", "r", test.branch, input) + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) + }) } - want := []*User{} - if !cmp.Equal(got, want) { - t.Errorf("Repositories.RemoveUserRestrictions returned %+v, want %+v", got, want) +} + +func TestRepositoriesService_RemoveTeamRestrictions(t *testing.T) { + tests := []struct { + branch string + urlPath string + }{ + {branch: "b", urlPath: "/repos/o/r/branches/b/protection/restrictions/teams"}, + {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat/branch-50%/protection/restrictions/teams"}, + } + + for _, test := range tests { + t.Run(test.branch, func(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "DELETE") + fmt.Fprint(w, `[]`) + }) + input := []string{"octocat"} + ctx := context.Background() + got, _, err := client.Repositories.RemoveTeamRestrictions(ctx, "o", "r", test.branch, input) + if err != nil { + t.Errorf("Repositories.RemoveTeamRestrictions returned error: %v", err) + } + want := []*Team{} + if !cmp.Equal(got, want) { + t.Errorf("Repositories.RemoveTeamRestrictions returned %+v, want %+v", got, want) + } + + const methodName = "RemoveTeamRestrictions" + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.Repositories.RemoveTeamRestrictions(ctx, "\n", "\n", "\n", input) + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Repositories.RemoveTeamRestrictions(ctx, "o", "r", test.branch, input) + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) + }) } +} - const methodName = "RemoveUserRestrictions" - testBadOptions(t, methodName, func() (err error) { - _, _, err = client.Repositories.RemoveUserRestrictions(ctx, "\n", "\n", "\n", input) - return err - }) +func TestRepositoriesService_ListUserRestrictions(t *testing.T) { + tests := []struct { + branch string + urlPath string + }{ + {branch: "b", urlPath: "/repos/o/r/branches/b/protection/restrictions/users"}, + {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat/branch-50%/protection/restrictions/users"}, + } + + for _, test := range tests { + t.Run(test.branch, func(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + }) + + ctx := context.Background() + _, _, err := client.Repositories.ListUserRestrictions(ctx, "o", "r", test.branch) + if err != nil { + t.Errorf("Repositories.ListUserRestrictions returned error: %v", err) + } - testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { - got, resp, err := client.Repositories.RemoveUserRestrictions(ctx, "o", "r", "b", input) - if got != nil { - t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) - } - return resp, err - }) + const methodName = "ListUserRestrictions" + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.Repositories.ListUserRestrictions(ctx, "\n", "\n", "\n") + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Repositories.ListUserRestrictions(ctx, "o", "r", test.branch) + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) + }) + } +} + +func TestRepositoriesService_ReplaceUserRestrictions(t *testing.T) { + tests := []struct { + branch string + urlPath string + }{ + {branch: "b", urlPath: "/repos/o/r/branches/b/protection/restrictions/users"}, + {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat/branch-50%/protection/restrictions/users"}, + } + + for _, test := range tests { + t.Run(test.branch, func(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "PUT") + fmt.Fprint(w, `[{ + "name": "octocat" + }]`) + }) + input := []string{"octocat"} + ctx := context.Background() + got, _, err := client.Repositories.ReplaceUserRestrictions(ctx, "o", "r", test.branch, input) + if err != nil { + t.Errorf("Repositories.ReplaceUserRestrictions returned error: %v", err) + } + want := []*User{ + {Name: String("octocat")}, + } + if !cmp.Equal(got, want) { + t.Errorf("Repositories.ReplaceUserRestrictions returned %+v, want %+v", got, want) + } + + const methodName = "ReplaceUserRestrictions" + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.Repositories.ReplaceUserRestrictions(ctx, "\n", "\n", "\n", input) + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Repositories.ReplaceUserRestrictions(ctx, "o", "r", test.branch, input) + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) + }) + } +} + +func TestRepositoriesService_AddUserRestrictions(t *testing.T) { + tests := []struct { + branch string + urlPath string + }{ + {branch: "b", urlPath: "/repos/o/r/branches/b/protection/restrictions/users"}, + {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat/branch-50%/protection/restrictions/users"}, + } + + for _, test := range tests { + t.Run(test.branch, func(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "POST") + fmt.Fprint(w, `[{ + "name": "octocat" + }]`) + }) + input := []string{"octocat"} + ctx := context.Background() + got, _, err := client.Repositories.AddUserRestrictions(ctx, "o", "r", test.branch, input) + if err != nil { + t.Errorf("Repositories.AddUserRestrictions returned error: %v", err) + } + want := []*User{ + {Name: String("octocat")}, + } + if !cmp.Equal(got, want) { + t.Errorf("Repositories.AddUserRestrictions returned %+v, want %+v", got, want) + } + + const methodName = "AddUserRestrictions" + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.Repositories.AddUserRestrictions(ctx, "\n", "\n", "\n", input) + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Repositories.AddUserRestrictions(ctx, "o", "r", test.branch, input) + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) + }) + } +} + +func TestRepositoriesService_RemoveUserRestrictions(t *testing.T) { + tests := []struct { + branch string + urlPath string + }{ + {branch: "b", urlPath: "/repos/o/r/branches/b/protection/restrictions/users"}, + {branch: "feat/branch-50%", urlPath: "/repos/o/r/branches/feat/branch-50%/protection/restrictions/users"}, + } + + for _, test := range tests { + t.Run(test.branch, func(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc(test.urlPath, func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "DELETE") + fmt.Fprint(w, `[]`) + }) + input := []string{"octocat"} + ctx := context.Background() + got, _, err := client.Repositories.RemoveUserRestrictions(ctx, "o", "r", test.branch, input) + if err != nil { + t.Errorf("Repositories.RemoveUserRestrictions returned error: %v", err) + } + want := []*User{} + if !cmp.Equal(got, want) { + t.Errorf("Repositories.RemoveUserRestrictions returned %+v, want %+v", got, want) + } + + const methodName = "RemoveUserRestrictions" + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.Repositories.RemoveUserRestrictions(ctx, "\n", "\n", "\n", input) + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Repositories.RemoveUserRestrictions(ctx, "o", "r", test.branch, input) + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) + }) + } } func TestRepositoriesService_Transfer(t *testing.T) {