Skip to content

[Issue#617] Update Protected Branches API preview #637

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Jun 28, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions github/github-accessors.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

243 changes: 227 additions & 16 deletions github/repos.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ package github

import (
"context"
"encoding/json"
"fmt"
"strings"
)
Expand Down Expand Up @@ -509,37 +510,78 @@ type Branch struct {

// Protection represents a repository branch's protection.
type Protection struct {
RequiredStatusChecks *RequiredStatusChecks `json:"required_status_checks"`
RequiredPullRequestReviews *RequiredPullRequestReviews `json:"required_pull_request_reviews"`
EnforceAdmins *AdminEnforcement `json:"enforce_admins"`
Restrictions *BranchRestrictions `json:"restrictions"`
RequiredStatusChecks *RequiredStatusChecks `json:"required_status_checks"`
RequiredPullRequestReviews *PullRequestReviewsEnforcement `json:"required_pull_request_reviews"`
EnforceAdmins *AdminEnforcement `json:"enforce_admins"`
Restrictions *BranchRestrictions `json:"restrictions"`
}

// ProtectionRequest represents a request to create/edit a branch's protection.
type ProtectionRequest struct {
RequiredStatusChecks *RequiredStatusChecks `json:"required_status_checks"`
RequiredPullRequestReviews *RequiredPullRequestReviews `json:"required_pull_request_reviews"`
EnforceAdmins bool `json:"enforce_admins"`
Restrictions *BranchRestrictionsRequest `json:"restrictions"`
RequiredStatusChecks *RequiredStatusChecks `json:"required_status_checks"`
RequiredPullRequestReviews *PullRequestReviewsEnforcementRequest `json:"required_pull_request_reviews"`
EnforceAdmins bool `json:"enforce_admins"`
Restrictions *BranchRestrictionsRequest `json:"restrictions"`
}

// RequiredStatusChecks represents the protection status of a individual branch.
type RequiredStatusChecks struct {
// Enforce required status checks for repository administrators. (Required.)
// Deprecated: Use EnforceAdmins instead.
IncludeAdmins bool `json:"include_admins"`
// Require branches to be up to date before merging. (Required.)
Strict bool `json:"strict"`
// The list of status checks to require in order to merge into this
// branch. (Required; use []string{} instead of nil for empty list.)
Contexts []string `json:"contexts"`
}

// RequiredPullRequestReviews represents the protection configuration for pull requests.
type RequiredPullRequestReviews struct {
// Enforce pull request reviews for repository administrators. (Required.)
// Deprecated: Use EnforceAdmins instead.
IncludeAdmins bool `json:"include_admins"`
// PullRequestReviewsEnforcement represents the pull request reviews enforcement of a protected branch.
type PullRequestReviewsEnforcement struct {
// Specifies which users and teams can dismiss pull requets reviews.
DismissalRestrictions DismissalRestrictions `json:"dismissal_restrictions"`
// Specifies if approved reviews are dismissed automatically, when a new commit is pushed.
DismissStaleReviews bool `json:"dismiss_stale_reviews"`
}

// PullRequestReviewsEnforcementRequest represents request to set the pull request review
// enforcement of a protected branch. It is separate from PullRequestReviewsEnforcement above
// because the request structure is different from the response structure.
type PullRequestReviewsEnforcementRequest struct {
// Specifies which users and teams should be allowed to dismiss pull requets reviews. Can be nil to disable the restrictions.
DismissalRestrictionsRequest *DismissalRestrictionsRequest `json:"dismissal_restrictions"`
// Specifies if approved reviews can be dismissed automatically, when a new commit is pushed. (Required)
DismissStaleReviews bool `json:"dismiss_stale_reviews"`
}

// MarshalJSON implements the json.Marshaler interface.
// Converts nil value of PullRequestReviewsEnforcementRequest.DismissalRestrictionsRequest to empty array
func (req PullRequestReviewsEnforcementRequest) MarshalJSON() ([]byte, error) {
if req.DismissalRestrictionsRequest == nil {
newReq := struct {
R []interface{} `json:"dismissal_restrictions"`
D bool `json:"dismiss_stale_reviews"`
}{
R: []interface{}{},
D: req.DismissStaleReviews,
}
return json.Marshal(newReq)
}
newReq := struct {
R *DismissalRestrictionsRequest `json:"dismissal_restrictions"`
D bool `json:"dismiss_stale_reviews"`
}{
R: req.DismissalRestrictionsRequest,
D: req.DismissStaleReviews,
}
return json.Marshal(newReq)
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a really cool solution to work around the GitHub API weirdness. Nice idea! 👍


// PullRequestReviewsEnforcementUpdate represents request to patch the pull request review
// enforcement of a protected branch. It is separate from PullRequestReviewsEnforcementRequest above
// because the patch request does not require all fields to be initialized.
type PullRequestReviewsEnforcementUpdate struct {
// Specifies which users and teams can dismiss pull requets reviews. Can be ommitted.
DismissalRestrictionsRequest *DismissalRestrictionsRequest `json:"dismissal_restrictions,omitempty"`
// Specifies if approved reviews can be dismissed automatically, when a new commit is pushed. Can be ommited.
DismissStaleReviews *bool `json:"dismiss_stale_reviews,omitempty"`
}

// AdminEnforcement represents the configuration to enforce required status checks for repository administrators.
Expand Down Expand Up @@ -568,6 +610,25 @@ type BranchRestrictionsRequest struct {
Teams []string `json:"teams"`
}

// DismissalRestrictions specifies which users and teams can dismiss pull request reviews.
type DismissalRestrictions struct {
// The list of users who can dimiss pull request reviews.
Users []*User `json:"users"`
// The list of teams which can dismiss pull request reviews.
Teams []*Team `json:"teams"`
}

// DismissalRestrictionsRequest represents the request to create/edit the
// restriction to allows only specific users or teams to dimiss pull request reviews. It is
// separate from DismissalRestrictions above because the request structure is
// different from the response structure.
type DismissalRestrictionsRequest struct {
// The list of user logins who can dismiss pull request reviews. (Required; use []string{} instead of nil for empty list.)
Users []string `json:"users"`
// The list of team slugs which can dismiss pull request reviews. (Required; use []string{} instead of nil for empty list.)
Teams []string `json:"teams"`
}

// ListBranches lists branches for the specified repository.
//
// GitHub API docs: https://developer.github.com/v3/repos/#list-branches
Expand Down Expand Up @@ -738,3 +799,153 @@ func (s *RepositoriesService) License(ctx context.Context, owner, repo string) (

return r, resp, nil
}

// GetPullRequestReviewEnforcement gets pull request review enforcement of a protected branch.
//
// GitHub API docs: https://developer.github.com/v3/repos/branches/#get-pull-request-review-enforcement-of-protected-branch
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)
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}

// TODO: remove custom Accept header when this API fully launches
req.Header.Set("Accept", mediaTypeProtectedBranchesPreview)

r := new(PullRequestReviewsEnforcement)
resp, err := s.client.Do(ctx, req, r)
if err != nil {
return nil, resp, err
}

return r, resp, nil
}

// UpdatePullRequestReviewEnforcement patches pull request review enforcement of a protected branch.
// It requires admin access and branch protection to be enabled.
//
// GitHub API docs: https://developer.github.com/v3/repos/branches/#update-pull-request-review-enforcement-of-protected-branch
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)
req, err := s.client.NewRequest("PATCH", u, patch)
if err != nil {
return nil, nil, err
}

// TODO: remove custom Accept header when this API fully launches
req.Header.Set("Accept", mediaTypeProtectedBranchesPreview)

r := new(PullRequestReviewsEnforcement)
resp, err := s.client.Do(ctx, req, r)
if err != nil {
return nil, resp, err
}

return r, resp, err
}

// DisableDismissalRestrictions disables dismissal restrictions of a protected branch.
// It requires admin access and branch protection to be enabled.
//
// GitHub API docs: https://developer.github.com/v3/repos/branches/#update-pull-request-review-enforcement-of-protected-branch
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)

data := struct {
R []interface{} `json:"dismissal_restrictions"`
}{[]interface{}{}}

req, err := s.client.NewRequest("PATCH", u, data)
if err != nil {
return nil, nil, err
}

// TODO: remove custom Accept header when this API fully launches
req.Header.Set("Accept", mediaTypeProtectedBranchesPreview)

r := new(PullRequestReviewsEnforcement)
resp, err := s.client.Do(ctx, req, r)
if err != nil {
return nil, resp, err
}

return r, resp, err
}

// RemovePullRequestReviewEnforcement removes pull request enforcement of a protected branch.
//
// GitHub API docs: https://developer.github.com/v3/repos/branches/#remove-pull-request-review-enforcement-of-protected-branch
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)
req, err := s.client.NewRequest("DELETE", u, nil)
if err != nil {
return nil, err
}

// TODO: remove custom Accept header when this API fully launches
req.Header.Set("Accept", mediaTypeProtectedBranchesPreview)

return s.client.Do(ctx, req, nil)
}

// GetAdminEnforcement gets admin enforcement information of a protected branch.
//
// GitHub API docs: https://developer.github.com/v3/repos/branches/#get-admin-enforcement-of-protected-branch
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)
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}

// TODO: remove custom Accept header when this API fully launches
req.Header.Set("Accept", mediaTypeProtectedBranchesPreview)

r := new(AdminEnforcement)
resp, err := s.client.Do(ctx, req, r)
if err != nil {
return nil, resp, err
}

return r, resp, nil
}

// AddAdminEnforcement adds admin enforcement to a protected branch.
// It requires admin access and branch protection to be enabled.
//
// GitHub API docs: https://developer.github.com/v3/repos/branches/#add-admin-enforcement-of-protected-branch
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)
req, err := s.client.NewRequest("POST", u, nil)
if err != nil {
return nil, nil, err
}

// TODO: remove custom Accept header when this API fully launches
req.Header.Set("Accept", mediaTypeProtectedBranchesPreview)

r := new(AdminEnforcement)
resp, err := s.client.Do(ctx, req, r)
if err != nil {
return nil, resp, err
}

return r, resp, err
}

// RemoveAdminEnforcement removes admin enforcement from a protected branch.
//
// GitHub API docs: https://developer.github.com/v3/repos/branches/#remove-admin-enforcement-of-protected-branch
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)
req, err := s.client.NewRequest("DELETE", u, nil)
if err != nil {
return nil, err
}

// TODO: remove custom Accept header when this API fully launches
req.Header.Set("Accept", mediaTypeProtectedBranchesPreview)

return s.client.Do(ctx, req, nil)
}
Loading