mirror of
				https://gitee.com/gitea/gitea
				synced 2025-11-04 16:40:24 +08:00 
			
		
		
		
	Add API branch protection endpoint (#9311)
* add API branch protection endpoint * lint * Change to use team names instead of ids. * Status codes. * fix * Fix * Add new branch protection options (BlockOnRejectedReviews, DismissStaleApprovals, RequireSignedCommits) * Do xorm query directly * fix xorm GetUserNamesByIDs * Add some tests * Improved GetTeamNamesByID * http status created for CreateBranchProtection * Correct status code in integration test Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com> Co-authored-by: zeripath <art27@cantab.net>
This commit is contained in:
		@@ -30,6 +30,54 @@ func testAPIGetBranch(t *testing.T, branchName string, exists bool) {
 | 
				
			|||||||
	assert.EqualValues(t, branchName, branch.Name)
 | 
						assert.EqualValues(t, branchName, branch.Name)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func testAPIGetBranchProtection(t *testing.T, branchName string, expectedHTTPStatus int) {
 | 
				
			||||||
 | 
						session := loginUser(t, "user2")
 | 
				
			||||||
 | 
						token := getTokenForLoggedInUser(t, session)
 | 
				
			||||||
 | 
						req := NewRequestf(t, "GET", "/api/v1/repos/user2/repo1/branch_protections/%s?token=%s", branchName, token)
 | 
				
			||||||
 | 
						resp := session.MakeRequest(t, req, expectedHTTPStatus)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if resp.Code == 200 {
 | 
				
			||||||
 | 
							var branchProtection api.BranchProtection
 | 
				
			||||||
 | 
							DecodeJSON(t, resp, &branchProtection)
 | 
				
			||||||
 | 
							assert.EqualValues(t, branchName, branchProtection.BranchName)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func testAPICreateBranchProtection(t *testing.T, branchName string, expectedHTTPStatus int) {
 | 
				
			||||||
 | 
						session := loginUser(t, "user2")
 | 
				
			||||||
 | 
						token := getTokenForLoggedInUser(t, session)
 | 
				
			||||||
 | 
						req := NewRequestWithJSON(t, "POST", "/api/v1/repos/user2/repo1/branch_protections?token="+token, &api.BranchProtection{
 | 
				
			||||||
 | 
							BranchName: branchName,
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						resp := session.MakeRequest(t, req, expectedHTTPStatus)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if resp.Code == 201 {
 | 
				
			||||||
 | 
							var branchProtection api.BranchProtection
 | 
				
			||||||
 | 
							DecodeJSON(t, resp, &branchProtection)
 | 
				
			||||||
 | 
							assert.EqualValues(t, branchName, branchProtection.BranchName)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func testAPIEditBranchProtection(t *testing.T, branchName string, body *api.BranchProtection, expectedHTTPStatus int) {
 | 
				
			||||||
 | 
						session := loginUser(t, "user2")
 | 
				
			||||||
 | 
						token := getTokenForLoggedInUser(t, session)
 | 
				
			||||||
 | 
						req := NewRequestWithJSON(t, "PATCH", "/api/v1/repos/user2/repo1/branch_protections/"+branchName+"?token="+token, body)
 | 
				
			||||||
 | 
						resp := session.MakeRequest(t, req, expectedHTTPStatus)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if resp.Code == 200 {
 | 
				
			||||||
 | 
							var branchProtection api.BranchProtection
 | 
				
			||||||
 | 
							DecodeJSON(t, resp, &branchProtection)
 | 
				
			||||||
 | 
							assert.EqualValues(t, branchName, branchProtection.BranchName)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func testAPIDeleteBranchProtection(t *testing.T, branchName string, expectedHTTPStatus int) {
 | 
				
			||||||
 | 
						session := loginUser(t, "user2")
 | 
				
			||||||
 | 
						token := getTokenForLoggedInUser(t, session)
 | 
				
			||||||
 | 
						req := NewRequestf(t, "DELETE", "/api/v1/repos/user2/repo1/branch_protections/%s?token=%s", branchName, token)
 | 
				
			||||||
 | 
						session.MakeRequest(t, req, expectedHTTPStatus)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestAPIGetBranch(t *testing.T) {
 | 
					func TestAPIGetBranch(t *testing.T) {
 | 
				
			||||||
	for _, test := range []struct {
 | 
						for _, test := range []struct {
 | 
				
			||||||
		BranchName string
 | 
							BranchName string
 | 
				
			||||||
@@ -43,3 +91,23 @@ func TestAPIGetBranch(t *testing.T) {
 | 
				
			|||||||
		testAPIGetBranch(t, test.BranchName, test.Exists)
 | 
							testAPIGetBranch(t, test.BranchName, test.Exists)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestAPIBranchProtection(t *testing.T) {
 | 
				
			||||||
 | 
						defer prepareTestEnv(t)()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Branch protection only on branch that exist
 | 
				
			||||||
 | 
						testAPICreateBranchProtection(t, "master/doesnotexist", http.StatusNotFound)
 | 
				
			||||||
 | 
						// Get branch protection on branch that exist but not branch protection
 | 
				
			||||||
 | 
						testAPIGetBranchProtection(t, "master", http.StatusNotFound)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						testAPICreateBranchProtection(t, "master", http.StatusCreated)
 | 
				
			||||||
 | 
						// Can only create once
 | 
				
			||||||
 | 
						testAPICreateBranchProtection(t, "master", http.StatusForbidden)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						testAPIGetBranchProtection(t, "master", http.StatusOK)
 | 
				
			||||||
 | 
						testAPIEditBranchProtection(t, "master", &api.BranchProtection{
 | 
				
			||||||
 | 
							EnablePush: true,
 | 
				
			||||||
 | 
						}, http.StatusOK)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						testAPIDeleteBranchProtection(t, "master", http.StatusNoContent)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -553,6 +553,23 @@ func GetTeam(orgID int64, name string) (*Team, error) {
 | 
				
			|||||||
	return getTeam(x, orgID, name)
 | 
						return getTeam(x, orgID, name)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GetTeamIDsByNames returns a slice of team ids corresponds to names.
 | 
				
			||||||
 | 
					func GetTeamIDsByNames(orgID int64, names []string, ignoreNonExistent bool) ([]int64, error) {
 | 
				
			||||||
 | 
						ids := make([]int64, 0, len(names))
 | 
				
			||||||
 | 
						for _, name := range names {
 | 
				
			||||||
 | 
							u, err := GetTeam(orgID, name)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								if ignoreNonExistent {
 | 
				
			||||||
 | 
									continue
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									return nil, err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							ids = append(ids, u.ID)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return ids, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// getOwnerTeam returns team by given team name and organization.
 | 
					// getOwnerTeam returns team by given team name and organization.
 | 
				
			||||||
func getOwnerTeam(e Engine, orgID int64) (*Team, error) {
 | 
					func getOwnerTeam(e Engine, orgID int64) (*Team, error) {
 | 
				
			||||||
	return getTeam(e, orgID, ownerTeamName)
 | 
						return getTeam(e, orgID, ownerTeamName)
 | 
				
			||||||
@@ -574,6 +591,22 @@ func GetTeamByID(teamID int64) (*Team, error) {
 | 
				
			|||||||
	return getTeamByID(x, teamID)
 | 
						return getTeamByID(x, teamID)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GetTeamNamesByID returns team's lower name from a list of team ids.
 | 
				
			||||||
 | 
					func GetTeamNamesByID(teamIDs []int64) ([]string, error) {
 | 
				
			||||||
 | 
						if len(teamIDs) == 0 {
 | 
				
			||||||
 | 
							return []string{}, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var teamNames []string
 | 
				
			||||||
 | 
						err := x.Table("team").
 | 
				
			||||||
 | 
							Select("lower_name").
 | 
				
			||||||
 | 
							In("id", teamIDs).
 | 
				
			||||||
 | 
							Asc("name").
 | 
				
			||||||
 | 
							Find(&teamNames)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return teamNames, err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// UpdateTeam updates information of team.
 | 
					// UpdateTeam updates information of team.
 | 
				
			||||||
func UpdateTeam(t *Team, authChanged bool, includeAllChanged bool) (err error) {
 | 
					func UpdateTeam(t *Team, authChanged bool, includeAllChanged bool) (err error) {
 | 
				
			||||||
	if len(t.Name) == 0 {
 | 
						if len(t.Name) == 0 {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1386,6 +1386,17 @@ func GetMaileableUsersByIDs(ids []int64) ([]*User, error) {
 | 
				
			|||||||
		Find(&ous)
 | 
							Find(&ous)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GetUserNamesByIDs returns usernames for all resolved users from a list of Ids.
 | 
				
			||||||
 | 
					func GetUserNamesByIDs(ids []int64) ([]string, error) {
 | 
				
			||||||
 | 
						unames := make([]string, 0, len(ids))
 | 
				
			||||||
 | 
						err := x.In("id", ids).
 | 
				
			||||||
 | 
							Table("user").
 | 
				
			||||||
 | 
							Asc("name").
 | 
				
			||||||
 | 
							Cols("name").
 | 
				
			||||||
 | 
							Find(&unames)
 | 
				
			||||||
 | 
						return unames, err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GetUsersByIDs returns all resolved users from a list of Ids.
 | 
					// GetUsersByIDs returns all resolved users from a list of Ids.
 | 
				
			||||||
func GetUsersByIDs(ids []int64) ([]*User, error) {
 | 
					func GetUsersByIDs(ids []int64) ([]*User, error) {
 | 
				
			||||||
	ous := make([]*User, 0, len(ids))
 | 
						ous := make([]*User, 0, len(ids))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -30,7 +30,7 @@ func ToEmail(email *models.EmailAddress) *api.Email {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ToBranch convert a git.Commit and git.Branch to an api.Branch
 | 
					// ToBranch convert a git.Commit and git.Branch to an api.Branch
 | 
				
			||||||
func ToBranch(repo *models.Repository, b *git.Branch, c *git.Commit, bp *models.ProtectedBranch, user *models.User) *api.Branch {
 | 
					func ToBranch(repo *models.Repository, b *git.Branch, c *git.Commit, bp *models.ProtectedBranch, user *models.User, isRepoAdmin bool) *api.Branch {
 | 
				
			||||||
	if bp == nil {
 | 
						if bp == nil {
 | 
				
			||||||
		return &api.Branch{
 | 
							return &api.Branch{
 | 
				
			||||||
			Name:                          b.Name,
 | 
								Name:                          b.Name,
 | 
				
			||||||
@@ -41,8 +41,14 @@ func ToBranch(repo *models.Repository, b *git.Branch, c *git.Commit, bp *models.
 | 
				
			|||||||
			StatusCheckContexts:           []string{},
 | 
								StatusCheckContexts:           []string{},
 | 
				
			||||||
			UserCanPush:                   true,
 | 
								UserCanPush:                   true,
 | 
				
			||||||
			UserCanMerge:                  true,
 | 
								UserCanMerge:                  true,
 | 
				
			||||||
 | 
								EffectiveBranchProtectionName: "",
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						branchProtectionName := ""
 | 
				
			||||||
 | 
						if isRepoAdmin {
 | 
				
			||||||
 | 
							branchProtectionName = bp.BranchName
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return &api.Branch{
 | 
						return &api.Branch{
 | 
				
			||||||
		Name:                          b.Name,
 | 
							Name:                          b.Name,
 | 
				
			||||||
		Commit:                        ToCommit(repo, c),
 | 
							Commit:                        ToCommit(repo, c),
 | 
				
			||||||
@@ -52,6 +58,58 @@ func ToBranch(repo *models.Repository, b *git.Branch, c *git.Commit, bp *models.
 | 
				
			|||||||
		StatusCheckContexts:           bp.StatusCheckContexts,
 | 
							StatusCheckContexts:           bp.StatusCheckContexts,
 | 
				
			||||||
		UserCanPush:                   bp.CanUserPush(user.ID),
 | 
							UserCanPush:                   bp.CanUserPush(user.ID),
 | 
				
			||||||
		UserCanMerge:                  bp.IsUserMergeWhitelisted(user.ID),
 | 
							UserCanMerge:                  bp.IsUserMergeWhitelisted(user.ID),
 | 
				
			||||||
 | 
							EffectiveBranchProtectionName: branchProtectionName,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ToBranchProtection convert a ProtectedBranch to api.BranchProtection
 | 
				
			||||||
 | 
					func ToBranchProtection(bp *models.ProtectedBranch) *api.BranchProtection {
 | 
				
			||||||
 | 
						pushWhitelistUsernames, err := models.GetUserNamesByIDs(bp.WhitelistUserIDs)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Error("GetUserNamesByIDs (WhitelistUserIDs): %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						mergeWhitelistUsernames, err := models.GetUserNamesByIDs(bp.MergeWhitelistUserIDs)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Error("GetUserNamesByIDs (MergeWhitelistUserIDs): %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						approvalsWhitelistUsernames, err := models.GetUserNamesByIDs(bp.ApprovalsWhitelistUserIDs)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Error("GetUserNamesByIDs (ApprovalsWhitelistUserIDs): %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						pushWhitelistTeams, err := models.GetTeamNamesByID(bp.WhitelistTeamIDs)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Error("GetTeamNamesByID (WhitelistTeamIDs): %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						mergeWhitelistTeams, err := models.GetTeamNamesByID(bp.MergeWhitelistTeamIDs)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Error("GetTeamNamesByID (MergeWhitelistTeamIDs): %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						approvalsWhitelistTeams, err := models.GetTeamNamesByID(bp.ApprovalsWhitelistTeamIDs)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Error("GetTeamNamesByID (ApprovalsWhitelistTeamIDs): %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return &api.BranchProtection{
 | 
				
			||||||
 | 
							BranchName:                  bp.BranchName,
 | 
				
			||||||
 | 
							EnablePush:                  bp.CanPush,
 | 
				
			||||||
 | 
							EnablePushWhitelist:         bp.EnableWhitelist,
 | 
				
			||||||
 | 
							PushWhitelistUsernames:      pushWhitelistUsernames,
 | 
				
			||||||
 | 
							PushWhitelistTeams:          pushWhitelistTeams,
 | 
				
			||||||
 | 
							PushWhitelistDeployKeys:     bp.WhitelistDeployKeys,
 | 
				
			||||||
 | 
							EnableMergeWhitelist:        bp.EnableMergeWhitelist,
 | 
				
			||||||
 | 
							MergeWhitelistUsernames:     mergeWhitelistUsernames,
 | 
				
			||||||
 | 
							MergeWhitelistTeams:         mergeWhitelistTeams,
 | 
				
			||||||
 | 
							EnableStatusCheck:           bp.EnableStatusCheck,
 | 
				
			||||||
 | 
							StatusCheckContexts:         bp.StatusCheckContexts,
 | 
				
			||||||
 | 
							RequiredApprovals:           bp.RequiredApprovals,
 | 
				
			||||||
 | 
							EnableApprovalsWhitelist:    bp.EnableApprovalsWhitelist,
 | 
				
			||||||
 | 
							ApprovalsWhitelistUsernames: approvalsWhitelistUsernames,
 | 
				
			||||||
 | 
							ApprovalsWhitelistTeams:     approvalsWhitelistTeams,
 | 
				
			||||||
 | 
							BlockOnRejectedReviews:      bp.BlockOnRejectedReviews,
 | 
				
			||||||
 | 
							DismissStaleApprovals:       bp.DismissStaleApprovals,
 | 
				
			||||||
 | 
							RequireSignedCommits:        bp.RequireSignedCommits,
 | 
				
			||||||
 | 
							Created:                     bp.CreatedUnix.AsTime(),
 | 
				
			||||||
 | 
							Updated:                     bp.UpdatedUnix.AsTime(),
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,6 +4,10 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
package structs
 | 
					package structs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Branch represents a repository branch
 | 
					// Branch represents a repository branch
 | 
				
			||||||
type Branch struct {
 | 
					type Branch struct {
 | 
				
			||||||
	Name                          string         `json:"name"`
 | 
						Name                          string         `json:"name"`
 | 
				
			||||||
@@ -14,4 +18,74 @@ type Branch struct {
 | 
				
			|||||||
	StatusCheckContexts           []string       `json:"status_check_contexts"`
 | 
						StatusCheckContexts           []string       `json:"status_check_contexts"`
 | 
				
			||||||
	UserCanPush                   bool           `json:"user_can_push"`
 | 
						UserCanPush                   bool           `json:"user_can_push"`
 | 
				
			||||||
	UserCanMerge                  bool           `json:"user_can_merge"`
 | 
						UserCanMerge                  bool           `json:"user_can_merge"`
 | 
				
			||||||
 | 
						EffectiveBranchProtectionName string         `json:"effective_branch_protection_name"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// BranchProtection represents a branch protection for a repository
 | 
				
			||||||
 | 
					type BranchProtection struct {
 | 
				
			||||||
 | 
						BranchName                  string   `json:"branch_name"`
 | 
				
			||||||
 | 
						EnablePush                  bool     `json:"enable_push"`
 | 
				
			||||||
 | 
						EnablePushWhitelist         bool     `json:"enable_push_whitelist"`
 | 
				
			||||||
 | 
						PushWhitelistUsernames      []string `json:"push_whitelist_usernames"`
 | 
				
			||||||
 | 
						PushWhitelistTeams          []string `json:"push_whitelist_teams"`
 | 
				
			||||||
 | 
						PushWhitelistDeployKeys     bool     `json:"push_whitelist_deploy_keys"`
 | 
				
			||||||
 | 
						EnableMergeWhitelist        bool     `json:"enable_merge_whitelist"`
 | 
				
			||||||
 | 
						MergeWhitelistUsernames     []string `json:"merge_whitelist_usernames"`
 | 
				
			||||||
 | 
						MergeWhitelistTeams         []string `json:"merge_whitelist_teams"`
 | 
				
			||||||
 | 
						EnableStatusCheck           bool     `json:"enable_status_check"`
 | 
				
			||||||
 | 
						StatusCheckContexts         []string `json:"status_check_contexts"`
 | 
				
			||||||
 | 
						RequiredApprovals           int64    `json:"required_approvals"`
 | 
				
			||||||
 | 
						EnableApprovalsWhitelist    bool     `json:"enable_approvals_whitelist"`
 | 
				
			||||||
 | 
						ApprovalsWhitelistUsernames []string `json:"approvals_whitelist_username"`
 | 
				
			||||||
 | 
						ApprovalsWhitelistTeams     []string `json:"approvals_whitelist_teams"`
 | 
				
			||||||
 | 
						BlockOnRejectedReviews      bool     `json:"block_on_rejected_reviews"`
 | 
				
			||||||
 | 
						DismissStaleApprovals       bool     `json:"dismiss_stale_approvals"`
 | 
				
			||||||
 | 
						RequireSignedCommits        bool     `json:"require_signed_commits"`
 | 
				
			||||||
 | 
						// swagger:strfmt date-time
 | 
				
			||||||
 | 
						Created time.Time `json:"created_at"`
 | 
				
			||||||
 | 
						// swagger:strfmt date-time
 | 
				
			||||||
 | 
						Updated time.Time `json:"updated_at"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// CreateBranchProtectionOption options for creating a branch protection
 | 
				
			||||||
 | 
					type CreateBranchProtectionOption struct {
 | 
				
			||||||
 | 
						BranchName                  string   `json:"branch_name"`
 | 
				
			||||||
 | 
						EnablePush                  bool     `json:"enable_push"`
 | 
				
			||||||
 | 
						EnablePushWhitelist         bool     `json:"enable_push_whitelist"`
 | 
				
			||||||
 | 
						PushWhitelistUsernames      []string `json:"push_whitelist_usernames"`
 | 
				
			||||||
 | 
						PushWhitelistTeams          []string `json:"push_whitelist_teams"`
 | 
				
			||||||
 | 
						PushWhitelistDeployKeys     bool     `json:"push_whitelist_deploy_keys"`
 | 
				
			||||||
 | 
						EnableMergeWhitelist        bool     `json:"enable_merge_whitelist"`
 | 
				
			||||||
 | 
						MergeWhitelistUsernames     []string `json:"merge_whitelist_usernames"`
 | 
				
			||||||
 | 
						MergeWhitelistTeams         []string `json:"merge_whitelist_teams"`
 | 
				
			||||||
 | 
						EnableStatusCheck           bool     `json:"enable_status_check"`
 | 
				
			||||||
 | 
						StatusCheckContexts         []string `json:"status_check_contexts"`
 | 
				
			||||||
 | 
						RequiredApprovals           int64    `json:"required_approvals"`
 | 
				
			||||||
 | 
						EnableApprovalsWhitelist    bool     `json:"enable_approvals_whitelist"`
 | 
				
			||||||
 | 
						ApprovalsWhitelistUsernames []string `json:"approvals_whitelist_username"`
 | 
				
			||||||
 | 
						ApprovalsWhitelistTeams     []string `json:"approvals_whitelist_teams"`
 | 
				
			||||||
 | 
						BlockOnRejectedReviews      bool     `json:"block_on_rejected_reviews"`
 | 
				
			||||||
 | 
						DismissStaleApprovals       bool     `json:"dismiss_stale_approvals"`
 | 
				
			||||||
 | 
						RequireSignedCommits        bool     `json:"require_signed_commits"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// EditBranchProtectionOption options for editing a branch protection
 | 
				
			||||||
 | 
					type EditBranchProtectionOption struct {
 | 
				
			||||||
 | 
						EnablePush                  *bool    `json:"enable_push"`
 | 
				
			||||||
 | 
						EnablePushWhitelist         *bool    `json:"enable_push_whitelist"`
 | 
				
			||||||
 | 
						PushWhitelistUsernames      []string `json:"push_whitelist_usernames"`
 | 
				
			||||||
 | 
						PushWhitelistTeams          []string `json:"push_whitelist_teams"`
 | 
				
			||||||
 | 
						PushWhitelistDeployKeys     *bool    `json:"push_whitelist_deploy_keys"`
 | 
				
			||||||
 | 
						EnableMergeWhitelist        *bool    `json:"enable_merge_whitelist"`
 | 
				
			||||||
 | 
						MergeWhitelistUsernames     []string `json:"merge_whitelist_usernames"`
 | 
				
			||||||
 | 
						MergeWhitelistTeams         []string `json:"merge_whitelist_teams"`
 | 
				
			||||||
 | 
						EnableStatusCheck           *bool    `json:"enable_status_check"`
 | 
				
			||||||
 | 
						StatusCheckContexts         []string `json:"status_check_contexts"`
 | 
				
			||||||
 | 
						RequiredApprovals           *int64   `json:"required_approvals"`
 | 
				
			||||||
 | 
						EnableApprovalsWhitelist    *bool    `json:"enable_approvals_whitelist"`
 | 
				
			||||||
 | 
						ApprovalsWhitelistUsernames []string `json:"approvals_whitelist_username"`
 | 
				
			||||||
 | 
						ApprovalsWhitelistTeams     []string `json:"approvals_whitelist_teams"`
 | 
				
			||||||
 | 
						BlockOnRejectedReviews      *bool    `json:"block_on_rejected_reviews"`
 | 
				
			||||||
 | 
						DismissStaleApprovals       *bool    `json:"dismiss_stale_approvals"`
 | 
				
			||||||
 | 
						RequireSignedCommits        *bool    `json:"require_signed_commits"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -656,6 +656,15 @@ func RegisterRoutes(m *macaron.Macaron) {
 | 
				
			|||||||
					m.Get("", repo.ListBranches)
 | 
										m.Get("", repo.ListBranches)
 | 
				
			||||||
					m.Get("/*", context.RepoRefByType(context.RepoRefBranch), repo.GetBranch)
 | 
										m.Get("/*", context.RepoRefByType(context.RepoRefBranch), repo.GetBranch)
 | 
				
			||||||
				}, reqRepoReader(models.UnitTypeCode))
 | 
									}, reqRepoReader(models.UnitTypeCode))
 | 
				
			||||||
 | 
									m.Group("/branch_protections", func() {
 | 
				
			||||||
 | 
										m.Get("", repo.ListBranchProtections)
 | 
				
			||||||
 | 
										m.Post("", bind(api.CreateBranchProtectionOption{}), repo.CreateBranchProtection)
 | 
				
			||||||
 | 
										m.Group("/:name", func() {
 | 
				
			||||||
 | 
											m.Get("", repo.GetBranchProtection)
 | 
				
			||||||
 | 
											m.Patch("", bind(api.EditBranchProtectionOption{}), repo.EditBranchProtection)
 | 
				
			||||||
 | 
											m.Delete("", repo.DeleteBranchProtection)
 | 
				
			||||||
 | 
										})
 | 
				
			||||||
 | 
									}, reqToken(), reqAdmin())
 | 
				
			||||||
				m.Group("/tags", func() {
 | 
									m.Group("/tags", func() {
 | 
				
			||||||
					m.Get("", repo.ListTags)
 | 
										m.Get("", repo.ListTags)
 | 
				
			||||||
				}, reqRepoReader(models.UnitTypeCode), context.ReferencesGitRepo(true))
 | 
									}, reqRepoReader(models.UnitTypeCode), context.ReferencesGitRepo(true))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,7 @@ package repo
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/models"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/context"
 | 
						"code.gitea.io/gitea/modules/context"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/convert"
 | 
						"code.gitea.io/gitea/modules/convert"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/git"
 | 
						"code.gitea.io/gitea/modules/git"
 | 
				
			||||||
@@ -71,7 +72,7 @@ func GetBranch(ctx *context.APIContext) {
 | 
				
			|||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ctx.JSON(http.StatusOK, convert.ToBranch(ctx.Repo.Repository, branch, c, branchProtection, ctx.User))
 | 
						ctx.JSON(http.StatusOK, convert.ToBranch(ctx.Repo.Repository, branch, c, branchProtection, ctx.User, ctx.Repo.IsAdmin()))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ListBranches list all the branches of a repository
 | 
					// ListBranches list all the branches of a repository
 | 
				
			||||||
@@ -114,8 +115,509 @@ func ListBranches(ctx *context.APIContext) {
 | 
				
			|||||||
			ctx.Error(http.StatusInternalServerError, "GetBranchProtection", err)
 | 
								ctx.Error(http.StatusInternalServerError, "GetBranchProtection", err)
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		apiBranches[i] = convert.ToBranch(ctx.Repo.Repository, branches[i], c, branchProtection, ctx.User)
 | 
							apiBranches[i] = convert.ToBranch(ctx.Repo.Repository, branches[i], c, branchProtection, ctx.User, ctx.Repo.IsAdmin())
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ctx.JSON(http.StatusOK, &apiBranches)
 | 
						ctx.JSON(http.StatusOK, &apiBranches)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GetBranchProtection gets a branch protection
 | 
				
			||||||
 | 
					func GetBranchProtection(ctx *context.APIContext) {
 | 
				
			||||||
 | 
						// swagger:operation GET /repos/{owner}/{repo}/branch_protections/{name} repository repoGetBranchProtection
 | 
				
			||||||
 | 
						// ---
 | 
				
			||||||
 | 
						// summary: Get a specific branch protection for the repository
 | 
				
			||||||
 | 
						// produces:
 | 
				
			||||||
 | 
						// - application/json
 | 
				
			||||||
 | 
						// parameters:
 | 
				
			||||||
 | 
						// - name: owner
 | 
				
			||||||
 | 
						//   in: path
 | 
				
			||||||
 | 
						//   description: owner of the repo
 | 
				
			||||||
 | 
						//   type: string
 | 
				
			||||||
 | 
						//   required: true
 | 
				
			||||||
 | 
						// - name: repo
 | 
				
			||||||
 | 
						//   in: path
 | 
				
			||||||
 | 
						//   description: name of the repo
 | 
				
			||||||
 | 
						//   type: string
 | 
				
			||||||
 | 
						//   required: true
 | 
				
			||||||
 | 
						// - name: name
 | 
				
			||||||
 | 
						//   in: path
 | 
				
			||||||
 | 
						//   description: name of protected branch
 | 
				
			||||||
 | 
						//   type: string
 | 
				
			||||||
 | 
						//   required: true
 | 
				
			||||||
 | 
						// responses:
 | 
				
			||||||
 | 
						//   "200":
 | 
				
			||||||
 | 
						//     "$ref": "#/responses/BranchProtection"
 | 
				
			||||||
 | 
						//   "404":
 | 
				
			||||||
 | 
						//     "$ref": "#/responses/notFound"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						repo := ctx.Repo.Repository
 | 
				
			||||||
 | 
						bpName := ctx.Params(":name")
 | 
				
			||||||
 | 
						bp, err := models.GetProtectedBranchBy(repo.ID, bpName)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							ctx.Error(http.StatusInternalServerError, "GetProtectedBranchByID", err)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if bp == nil || bp.RepoID != repo.ID {
 | 
				
			||||||
 | 
							ctx.NotFound()
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ctx.JSON(http.StatusOK, convert.ToBranchProtection(bp))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ListBranchProtections list branch protections for a repo
 | 
				
			||||||
 | 
					func ListBranchProtections(ctx *context.APIContext) {
 | 
				
			||||||
 | 
						// swagger:operation GET /repos/{owner}/{repo}/branch_protections repository repoListBranchProtection
 | 
				
			||||||
 | 
						// ---
 | 
				
			||||||
 | 
						// summary: List branch protections for a repository
 | 
				
			||||||
 | 
						// produces:
 | 
				
			||||||
 | 
						// - application/json
 | 
				
			||||||
 | 
						// parameters:
 | 
				
			||||||
 | 
						// - name: owner
 | 
				
			||||||
 | 
						//   in: path
 | 
				
			||||||
 | 
						//   description: owner of the repo
 | 
				
			||||||
 | 
						//   type: string
 | 
				
			||||||
 | 
						//   required: true
 | 
				
			||||||
 | 
						// - name: repo
 | 
				
			||||||
 | 
						//   in: path
 | 
				
			||||||
 | 
						//   description: name of the repo
 | 
				
			||||||
 | 
						//   type: string
 | 
				
			||||||
 | 
						//   required: true
 | 
				
			||||||
 | 
						// responses:
 | 
				
			||||||
 | 
						//   "200":
 | 
				
			||||||
 | 
						//     "$ref": "#/responses/BranchProtectionList"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						repo := ctx.Repo.Repository
 | 
				
			||||||
 | 
						bps, err := repo.GetProtectedBranches()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							ctx.Error(http.StatusInternalServerError, "GetProtectedBranches", err)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						apiBps := make([]*api.BranchProtection, len(bps))
 | 
				
			||||||
 | 
						for i := range bps {
 | 
				
			||||||
 | 
							apiBps[i] = convert.ToBranchProtection(bps[i])
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ctx.JSON(http.StatusOK, apiBps)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// CreateBranchProtection creates a branch protection for a repo
 | 
				
			||||||
 | 
					func CreateBranchProtection(ctx *context.APIContext, form api.CreateBranchProtectionOption) {
 | 
				
			||||||
 | 
						// swagger:operation POST /repos/{owner}/{repo}/branch_protections repository repoCreateBranchProtection
 | 
				
			||||||
 | 
						// ---
 | 
				
			||||||
 | 
						// summary: Create a branch protections for a repository
 | 
				
			||||||
 | 
						// consumes:
 | 
				
			||||||
 | 
						// - application/json
 | 
				
			||||||
 | 
						// produces:
 | 
				
			||||||
 | 
						// - application/json
 | 
				
			||||||
 | 
						// parameters:
 | 
				
			||||||
 | 
						// - name: owner
 | 
				
			||||||
 | 
						//   in: path
 | 
				
			||||||
 | 
						//   description: owner of the repo
 | 
				
			||||||
 | 
						//   type: string
 | 
				
			||||||
 | 
						//   required: true
 | 
				
			||||||
 | 
						// - name: repo
 | 
				
			||||||
 | 
						//   in: path
 | 
				
			||||||
 | 
						//   description: name of the repo
 | 
				
			||||||
 | 
						//   type: string
 | 
				
			||||||
 | 
						//   required: true
 | 
				
			||||||
 | 
						// - name: body
 | 
				
			||||||
 | 
						//   in: body
 | 
				
			||||||
 | 
						//   schema:
 | 
				
			||||||
 | 
						//     "$ref": "#/definitions/CreateBranchProtectionOption"
 | 
				
			||||||
 | 
						// responses:
 | 
				
			||||||
 | 
						//   "201":
 | 
				
			||||||
 | 
						//     "$ref": "#/responses/BranchProtection"
 | 
				
			||||||
 | 
						//   "403":
 | 
				
			||||||
 | 
						//     "$ref": "#/responses/forbidden"
 | 
				
			||||||
 | 
						//   "404":
 | 
				
			||||||
 | 
						//     "$ref": "#/responses/notFound"
 | 
				
			||||||
 | 
						//   "422":
 | 
				
			||||||
 | 
						//     "$ref": "#/responses/validationError"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						repo := ctx.Repo.Repository
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Currently protection must match an actual branch
 | 
				
			||||||
 | 
						if !git.IsBranchExist(ctx.Repo.Repository.RepoPath(), form.BranchName) {
 | 
				
			||||||
 | 
							ctx.NotFound()
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						protectBranch, err := models.GetProtectedBranchBy(repo.ID, form.BranchName)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							ctx.Error(http.StatusInternalServerError, "GetProtectBranchOfRepoByName", err)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						} else if protectBranch != nil {
 | 
				
			||||||
 | 
							ctx.Error(http.StatusForbidden, "Create branch protection", "Branch protection already exist")
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var requiredApprovals int64
 | 
				
			||||||
 | 
						if form.RequiredApprovals > 0 {
 | 
				
			||||||
 | 
							requiredApprovals = form.RequiredApprovals
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						whitelistUsers, err := models.GetUserIDsByNames(form.PushWhitelistUsernames, false)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							if models.IsErrUserNotExist(err) {
 | 
				
			||||||
 | 
								ctx.Error(http.StatusUnprocessableEntity, "User does not exist", err)
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							ctx.Error(http.StatusInternalServerError, "GetUserIDsByNames", err)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						mergeWhitelistUsers, err := models.GetUserIDsByNames(form.MergeWhitelistUsernames, false)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							if models.IsErrUserNotExist(err) {
 | 
				
			||||||
 | 
								ctx.Error(http.StatusUnprocessableEntity, "User does not exist", err)
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							ctx.Error(http.StatusInternalServerError, "GetUserIDsByNames", err)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						approvalsWhitelistUsers, err := models.GetUserIDsByNames(form.ApprovalsWhitelistUsernames, false)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							if models.IsErrUserNotExist(err) {
 | 
				
			||||||
 | 
								ctx.Error(http.StatusUnprocessableEntity, "User does not exist", err)
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							ctx.Error(http.StatusInternalServerError, "GetUserIDsByNames", err)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						var whitelistTeams, mergeWhitelistTeams, approvalsWhitelistTeams []int64
 | 
				
			||||||
 | 
						if repo.Owner.IsOrganization() {
 | 
				
			||||||
 | 
							whitelistTeams, err = models.GetTeamIDsByNames(repo.OwnerID, form.PushWhitelistTeams, false)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								if models.IsErrTeamNotExist(err) {
 | 
				
			||||||
 | 
									ctx.Error(http.StatusUnprocessableEntity, "Team does not exist", err)
 | 
				
			||||||
 | 
									return
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								ctx.Error(http.StatusInternalServerError, "GetTeamIDsByNames", err)
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							mergeWhitelistTeams, err = models.GetTeamIDsByNames(repo.OwnerID, form.MergeWhitelistTeams, false)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								if models.IsErrTeamNotExist(err) {
 | 
				
			||||||
 | 
									ctx.Error(http.StatusUnprocessableEntity, "Team does not exist", err)
 | 
				
			||||||
 | 
									return
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								ctx.Error(http.StatusInternalServerError, "GetTeamIDsByNames", err)
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							approvalsWhitelistTeams, err = models.GetTeamIDsByNames(repo.OwnerID, form.ApprovalsWhitelistTeams, false)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								if models.IsErrTeamNotExist(err) {
 | 
				
			||||||
 | 
									ctx.Error(http.StatusUnprocessableEntity, "Team does not exist", err)
 | 
				
			||||||
 | 
									return
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								ctx.Error(http.StatusInternalServerError, "GetTeamIDsByNames", err)
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						protectBranch = &models.ProtectedBranch{
 | 
				
			||||||
 | 
							RepoID:                   ctx.Repo.Repository.ID,
 | 
				
			||||||
 | 
							BranchName:               form.BranchName,
 | 
				
			||||||
 | 
							CanPush:                  form.EnablePush,
 | 
				
			||||||
 | 
							EnableWhitelist:          form.EnablePush && form.EnablePushWhitelist,
 | 
				
			||||||
 | 
							EnableMergeWhitelist:     form.EnableMergeWhitelist,
 | 
				
			||||||
 | 
							WhitelistDeployKeys:      form.EnablePush && form.EnablePushWhitelist && form.PushWhitelistDeployKeys,
 | 
				
			||||||
 | 
							EnableStatusCheck:        form.EnableStatusCheck,
 | 
				
			||||||
 | 
							StatusCheckContexts:      form.StatusCheckContexts,
 | 
				
			||||||
 | 
							EnableApprovalsWhitelist: form.EnableApprovalsWhitelist,
 | 
				
			||||||
 | 
							RequiredApprovals:        requiredApprovals,
 | 
				
			||||||
 | 
							BlockOnRejectedReviews:   form.BlockOnRejectedReviews,
 | 
				
			||||||
 | 
							DismissStaleApprovals:    form.DismissStaleApprovals,
 | 
				
			||||||
 | 
							RequireSignedCommits:     form.RequireSignedCommits,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = models.UpdateProtectBranch(ctx.Repo.Repository, protectBranch, models.WhitelistOptions{
 | 
				
			||||||
 | 
							UserIDs:          whitelistUsers,
 | 
				
			||||||
 | 
							TeamIDs:          whitelistTeams,
 | 
				
			||||||
 | 
							MergeUserIDs:     mergeWhitelistUsers,
 | 
				
			||||||
 | 
							MergeTeamIDs:     mergeWhitelistTeams,
 | 
				
			||||||
 | 
							ApprovalsUserIDs: approvalsWhitelistUsers,
 | 
				
			||||||
 | 
							ApprovalsTeamIDs: approvalsWhitelistTeams,
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							ctx.Error(http.StatusInternalServerError, "UpdateProtectBranch", err)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Reload from db to get all whitelists
 | 
				
			||||||
 | 
						bp, err := models.GetProtectedBranchBy(ctx.Repo.Repository.ID, form.BranchName)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							ctx.Error(http.StatusInternalServerError, "GetProtectedBranchByID", err)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if bp == nil || bp.RepoID != ctx.Repo.Repository.ID {
 | 
				
			||||||
 | 
							ctx.Error(http.StatusInternalServerError, "New branch protection not found", err)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ctx.JSON(http.StatusCreated, convert.ToBranchProtection(bp))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// EditBranchProtection edits a branch protection for a repo
 | 
				
			||||||
 | 
					func EditBranchProtection(ctx *context.APIContext, form api.EditBranchProtectionOption) {
 | 
				
			||||||
 | 
						// swagger:operation PATCH /repos/{owner}/{repo}/branch_protections/{name} repository repoEditBranchProtection
 | 
				
			||||||
 | 
						// ---
 | 
				
			||||||
 | 
						// summary: Edit a branch protections for a repository. Only fields that are set will be changed
 | 
				
			||||||
 | 
						// consumes:
 | 
				
			||||||
 | 
						// - application/json
 | 
				
			||||||
 | 
						// produces:
 | 
				
			||||||
 | 
						// - application/json
 | 
				
			||||||
 | 
						// parameters:
 | 
				
			||||||
 | 
						// - name: owner
 | 
				
			||||||
 | 
						//   in: path
 | 
				
			||||||
 | 
						//   description: owner of the repo
 | 
				
			||||||
 | 
						//   type: string
 | 
				
			||||||
 | 
						//   required: true
 | 
				
			||||||
 | 
						// - name: repo
 | 
				
			||||||
 | 
						//   in: path
 | 
				
			||||||
 | 
						//   description: name of the repo
 | 
				
			||||||
 | 
						//   type: string
 | 
				
			||||||
 | 
						//   required: true
 | 
				
			||||||
 | 
						// - name: name
 | 
				
			||||||
 | 
						//   in: path
 | 
				
			||||||
 | 
						//   description: name of protected branch
 | 
				
			||||||
 | 
						//   type: string
 | 
				
			||||||
 | 
						//   required: true
 | 
				
			||||||
 | 
						// - name: body
 | 
				
			||||||
 | 
						//   in: body
 | 
				
			||||||
 | 
						//   schema:
 | 
				
			||||||
 | 
						//     "$ref": "#/definitions/EditBranchProtectionOption"
 | 
				
			||||||
 | 
						// responses:
 | 
				
			||||||
 | 
						//   "200":
 | 
				
			||||||
 | 
						//     "$ref": "#/responses/BranchProtection"
 | 
				
			||||||
 | 
						//   "404":
 | 
				
			||||||
 | 
						//     "$ref": "#/responses/notFound"
 | 
				
			||||||
 | 
						//   "422":
 | 
				
			||||||
 | 
						//     "$ref": "#/responses/validationError"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						repo := ctx.Repo.Repository
 | 
				
			||||||
 | 
						bpName := ctx.Params(":name")
 | 
				
			||||||
 | 
						protectBranch, err := models.GetProtectedBranchBy(repo.ID, bpName)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							ctx.Error(http.StatusInternalServerError, "GetProtectedBranchByID", err)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if protectBranch == nil || protectBranch.RepoID != repo.ID {
 | 
				
			||||||
 | 
							ctx.NotFound()
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if form.EnablePush != nil {
 | 
				
			||||||
 | 
							if !*form.EnablePush {
 | 
				
			||||||
 | 
								protectBranch.CanPush = false
 | 
				
			||||||
 | 
								protectBranch.EnableWhitelist = false
 | 
				
			||||||
 | 
								protectBranch.WhitelistDeployKeys = false
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								protectBranch.CanPush = true
 | 
				
			||||||
 | 
								if form.EnablePushWhitelist != nil {
 | 
				
			||||||
 | 
									if !*form.EnablePushWhitelist {
 | 
				
			||||||
 | 
										protectBranch.EnableWhitelist = false
 | 
				
			||||||
 | 
										protectBranch.WhitelistDeployKeys = false
 | 
				
			||||||
 | 
									} else {
 | 
				
			||||||
 | 
										protectBranch.EnableWhitelist = true
 | 
				
			||||||
 | 
										if form.PushWhitelistDeployKeys != nil {
 | 
				
			||||||
 | 
											protectBranch.WhitelistDeployKeys = *form.PushWhitelistDeployKeys
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if form.EnableMergeWhitelist != nil {
 | 
				
			||||||
 | 
							protectBranch.EnableMergeWhitelist = *form.EnableMergeWhitelist
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if form.EnableStatusCheck != nil {
 | 
				
			||||||
 | 
							protectBranch.EnableStatusCheck = *form.EnableStatusCheck
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if protectBranch.EnableStatusCheck {
 | 
				
			||||||
 | 
							protectBranch.StatusCheckContexts = form.StatusCheckContexts
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if form.RequiredApprovals != nil && *form.RequiredApprovals >= 0 {
 | 
				
			||||||
 | 
							protectBranch.RequiredApprovals = *form.RequiredApprovals
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if form.EnableApprovalsWhitelist != nil {
 | 
				
			||||||
 | 
							protectBranch.EnableApprovalsWhitelist = *form.EnableApprovalsWhitelist
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if form.BlockOnRejectedReviews != nil {
 | 
				
			||||||
 | 
							protectBranch.BlockOnRejectedReviews = *form.BlockOnRejectedReviews
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if form.DismissStaleApprovals != nil {
 | 
				
			||||||
 | 
							protectBranch.DismissStaleApprovals = *form.DismissStaleApprovals
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if form.RequireSignedCommits != nil {
 | 
				
			||||||
 | 
							protectBranch.RequireSignedCommits = *form.RequireSignedCommits
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var whitelistUsers []int64
 | 
				
			||||||
 | 
						if form.PushWhitelistUsernames != nil {
 | 
				
			||||||
 | 
							whitelistUsers, err = models.GetUserIDsByNames(form.PushWhitelistUsernames, false)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								if models.IsErrUserNotExist(err) {
 | 
				
			||||||
 | 
									ctx.Error(http.StatusUnprocessableEntity, "User does not exist", err)
 | 
				
			||||||
 | 
									return
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								ctx.Error(http.StatusInternalServerError, "GetUserIDsByNames", err)
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							whitelistUsers = protectBranch.WhitelistUserIDs
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						var mergeWhitelistUsers []int64
 | 
				
			||||||
 | 
						if form.MergeWhitelistUsernames != nil {
 | 
				
			||||||
 | 
							mergeWhitelistUsers, err = models.GetUserIDsByNames(form.MergeWhitelistUsernames, false)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								if models.IsErrUserNotExist(err) {
 | 
				
			||||||
 | 
									ctx.Error(http.StatusUnprocessableEntity, "User does not exist", err)
 | 
				
			||||||
 | 
									return
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								ctx.Error(http.StatusInternalServerError, "GetUserIDsByNames", err)
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							mergeWhitelistUsers = protectBranch.MergeWhitelistUserIDs
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						var approvalsWhitelistUsers []int64
 | 
				
			||||||
 | 
						if form.ApprovalsWhitelistUsernames != nil {
 | 
				
			||||||
 | 
							approvalsWhitelistUsers, err = models.GetUserIDsByNames(form.ApprovalsWhitelistUsernames, false)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								if models.IsErrUserNotExist(err) {
 | 
				
			||||||
 | 
									ctx.Error(http.StatusUnprocessableEntity, "User does not exist", err)
 | 
				
			||||||
 | 
									return
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								ctx.Error(http.StatusInternalServerError, "GetUserIDsByNames", err)
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							approvalsWhitelistUsers = protectBranch.ApprovalsWhitelistUserIDs
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var whitelistTeams, mergeWhitelistTeams, approvalsWhitelistTeams []int64
 | 
				
			||||||
 | 
						if repo.Owner.IsOrganization() {
 | 
				
			||||||
 | 
							if form.PushWhitelistTeams != nil {
 | 
				
			||||||
 | 
								whitelistTeams, err = models.GetTeamIDsByNames(repo.OwnerID, form.PushWhitelistTeams, false)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									if models.IsErrTeamNotExist(err) {
 | 
				
			||||||
 | 
										ctx.Error(http.StatusUnprocessableEntity, "Team does not exist", err)
 | 
				
			||||||
 | 
										return
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									ctx.Error(http.StatusInternalServerError, "GetTeamIDsByNames", err)
 | 
				
			||||||
 | 
									return
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								whitelistTeams = protectBranch.WhitelistTeamIDs
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if form.MergeWhitelistTeams != nil {
 | 
				
			||||||
 | 
								mergeWhitelistTeams, err = models.GetTeamIDsByNames(repo.OwnerID, form.MergeWhitelistTeams, false)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									if models.IsErrTeamNotExist(err) {
 | 
				
			||||||
 | 
										ctx.Error(http.StatusUnprocessableEntity, "Team does not exist", err)
 | 
				
			||||||
 | 
										return
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									ctx.Error(http.StatusInternalServerError, "GetTeamIDsByNames", err)
 | 
				
			||||||
 | 
									return
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								mergeWhitelistTeams = protectBranch.MergeWhitelistTeamIDs
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if form.ApprovalsWhitelistTeams != nil {
 | 
				
			||||||
 | 
								approvalsWhitelistTeams, err = models.GetTeamIDsByNames(repo.OwnerID, form.ApprovalsWhitelistTeams, false)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									if models.IsErrTeamNotExist(err) {
 | 
				
			||||||
 | 
										ctx.Error(http.StatusUnprocessableEntity, "Team does not exist", err)
 | 
				
			||||||
 | 
										return
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									ctx.Error(http.StatusInternalServerError, "GetTeamIDsByNames", err)
 | 
				
			||||||
 | 
									return
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								approvalsWhitelistTeams = protectBranch.ApprovalsWhitelistTeamIDs
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = models.UpdateProtectBranch(ctx.Repo.Repository, protectBranch, models.WhitelistOptions{
 | 
				
			||||||
 | 
							UserIDs:          whitelistUsers,
 | 
				
			||||||
 | 
							TeamIDs:          whitelistTeams,
 | 
				
			||||||
 | 
							MergeUserIDs:     mergeWhitelistUsers,
 | 
				
			||||||
 | 
							MergeTeamIDs:     mergeWhitelistTeams,
 | 
				
			||||||
 | 
							ApprovalsUserIDs: approvalsWhitelistUsers,
 | 
				
			||||||
 | 
							ApprovalsTeamIDs: approvalsWhitelistTeams,
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							ctx.Error(http.StatusInternalServerError, "UpdateProtectBranch", err)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Reload from db to ensure get all whitelists
 | 
				
			||||||
 | 
						bp, err := models.GetProtectedBranchBy(repo.ID, bpName)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							ctx.Error(http.StatusInternalServerError, "GetProtectedBranchBy", err)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if bp == nil || bp.RepoID != ctx.Repo.Repository.ID {
 | 
				
			||||||
 | 
							ctx.Error(http.StatusInternalServerError, "New branch protection not found", err)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ctx.JSON(http.StatusOK, convert.ToBranchProtection(bp))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// DeleteBranchProtection deletes a branch protection for a repo
 | 
				
			||||||
 | 
					func DeleteBranchProtection(ctx *context.APIContext) {
 | 
				
			||||||
 | 
						// swagger:operation DELETE /repos/{owner}/{repo}/branch_protections/{name} repository repoDeleteBranchProtection
 | 
				
			||||||
 | 
						// ---
 | 
				
			||||||
 | 
						// summary: Delete a specific branch protection for the repository
 | 
				
			||||||
 | 
						// produces:
 | 
				
			||||||
 | 
						// - application/json
 | 
				
			||||||
 | 
						// parameters:
 | 
				
			||||||
 | 
						// - name: owner
 | 
				
			||||||
 | 
						//   in: path
 | 
				
			||||||
 | 
						//   description: owner of the repo
 | 
				
			||||||
 | 
						//   type: string
 | 
				
			||||||
 | 
						//   required: true
 | 
				
			||||||
 | 
						// - name: repo
 | 
				
			||||||
 | 
						//   in: path
 | 
				
			||||||
 | 
						//   description: name of the repo
 | 
				
			||||||
 | 
						//   type: string
 | 
				
			||||||
 | 
						//   required: true
 | 
				
			||||||
 | 
						// - name: name
 | 
				
			||||||
 | 
						//   in: path
 | 
				
			||||||
 | 
						//   description: name of protected branch
 | 
				
			||||||
 | 
						//   type: string
 | 
				
			||||||
 | 
						//   required: true
 | 
				
			||||||
 | 
						// responses:
 | 
				
			||||||
 | 
						//   "204":
 | 
				
			||||||
 | 
						//     "$ref": "#/responses/empty"
 | 
				
			||||||
 | 
						//   "404":
 | 
				
			||||||
 | 
						//     "$ref": "#/responses/notFound"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						repo := ctx.Repo.Repository
 | 
				
			||||||
 | 
						bpName := ctx.Params(":name")
 | 
				
			||||||
 | 
						bp, err := models.GetProtectedBranchBy(repo.ID, bpName)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							ctx.Error(http.StatusInternalServerError, "GetProtectedBranchByID", err)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if bp == nil || bp.RepoID != repo.ID {
 | 
				
			||||||
 | 
							ctx.NotFound()
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err := ctx.Repo.Repository.DeleteProtectedBranch(bp.ID); err != nil {
 | 
				
			||||||
 | 
							ctx.Error(http.StatusInternalServerError, "DeleteProtectedBranch", err)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ctx.Status(http.StatusNoContent)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -128,4 +128,10 @@ type swaggerParameterBodies struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	// in:body
 | 
						// in:body
 | 
				
			||||||
	EditReactionOption api.EditReactionOption
 | 
						EditReactionOption api.EditReactionOption
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// in:body
 | 
				
			||||||
 | 
						CreateBranchProtectionOption api.CreateBranchProtectionOption
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// in:body
 | 
				
			||||||
 | 
						EditBranchProtectionOption api.EditBranchProtectionOption
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -36,6 +36,20 @@ type swaggerResponseBranchList struct {
 | 
				
			|||||||
	Body []api.Branch `json:"body"`
 | 
						Body []api.Branch `json:"body"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// BranchProtection
 | 
				
			||||||
 | 
					// swagger:response BranchProtection
 | 
				
			||||||
 | 
					type swaggerResponseBranchProtection struct {
 | 
				
			||||||
 | 
						// in:body
 | 
				
			||||||
 | 
						Body api.BranchProtection `json:"body"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// BranchProtectionList
 | 
				
			||||||
 | 
					// swagger:response BranchProtectionList
 | 
				
			||||||
 | 
					type swaggerResponseBranchProtectionList struct {
 | 
				
			||||||
 | 
						// in:body
 | 
				
			||||||
 | 
						Body []api.BranchProtection `json:"body"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// TagList
 | 
					// TagList
 | 
				
			||||||
// swagger:response TagList
 | 
					// swagger:response TagList
 | 
				
			||||||
type swaggerResponseTagList struct {
 | 
					type swaggerResponseTagList struct {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1797,6 +1797,227 @@
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "/repos/{owner}/{repo}/branch_protections": {
 | 
				
			||||||
 | 
					      "get": {
 | 
				
			||||||
 | 
					        "produces": [
 | 
				
			||||||
 | 
					          "application/json"
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        "tags": [
 | 
				
			||||||
 | 
					          "repository"
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        "summary": "List branch protections for a repository",
 | 
				
			||||||
 | 
					        "operationId": "repoListBranchProtection",
 | 
				
			||||||
 | 
					        "parameters": [
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            "type": "string",
 | 
				
			||||||
 | 
					            "description": "owner of the repo",
 | 
				
			||||||
 | 
					            "name": "owner",
 | 
				
			||||||
 | 
					            "in": "path",
 | 
				
			||||||
 | 
					            "required": true
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            "type": "string",
 | 
				
			||||||
 | 
					            "description": "name of the repo",
 | 
				
			||||||
 | 
					            "name": "repo",
 | 
				
			||||||
 | 
					            "in": "path",
 | 
				
			||||||
 | 
					            "required": true
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        "responses": {
 | 
				
			||||||
 | 
					          "200": {
 | 
				
			||||||
 | 
					            "$ref": "#/responses/BranchProtectionList"
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "post": {
 | 
				
			||||||
 | 
					        "consumes": [
 | 
				
			||||||
 | 
					          "application/json"
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        "produces": [
 | 
				
			||||||
 | 
					          "application/json"
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        "tags": [
 | 
				
			||||||
 | 
					          "repository"
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        "summary": "Create a branch protections for a repository",
 | 
				
			||||||
 | 
					        "operationId": "repoCreateBranchProtection",
 | 
				
			||||||
 | 
					        "parameters": [
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            "type": "string",
 | 
				
			||||||
 | 
					            "description": "owner of the repo",
 | 
				
			||||||
 | 
					            "name": "owner",
 | 
				
			||||||
 | 
					            "in": "path",
 | 
				
			||||||
 | 
					            "required": true
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            "type": "string",
 | 
				
			||||||
 | 
					            "description": "name of the repo",
 | 
				
			||||||
 | 
					            "name": "repo",
 | 
				
			||||||
 | 
					            "in": "path",
 | 
				
			||||||
 | 
					            "required": true
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            "name": "body",
 | 
				
			||||||
 | 
					            "in": "body",
 | 
				
			||||||
 | 
					            "schema": {
 | 
				
			||||||
 | 
					              "$ref": "#/definitions/CreateBranchProtectionOption"
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        "responses": {
 | 
				
			||||||
 | 
					          "201": {
 | 
				
			||||||
 | 
					            "$ref": "#/responses/BranchProtection"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "403": {
 | 
				
			||||||
 | 
					            "$ref": "#/responses/forbidden"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "404": {
 | 
				
			||||||
 | 
					            "$ref": "#/responses/notFound"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "422": {
 | 
				
			||||||
 | 
					            "$ref": "#/responses/validationError"
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "/repos/{owner}/{repo}/branch_protections/{name}": {
 | 
				
			||||||
 | 
					      "get": {
 | 
				
			||||||
 | 
					        "produces": [
 | 
				
			||||||
 | 
					          "application/json"
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        "tags": [
 | 
				
			||||||
 | 
					          "repository"
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        "summary": "Get a specific branch protection for the repository",
 | 
				
			||||||
 | 
					        "operationId": "repoGetBranchProtection",
 | 
				
			||||||
 | 
					        "parameters": [
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            "type": "string",
 | 
				
			||||||
 | 
					            "description": "owner of the repo",
 | 
				
			||||||
 | 
					            "name": "owner",
 | 
				
			||||||
 | 
					            "in": "path",
 | 
				
			||||||
 | 
					            "required": true
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            "type": "string",
 | 
				
			||||||
 | 
					            "description": "name of the repo",
 | 
				
			||||||
 | 
					            "name": "repo",
 | 
				
			||||||
 | 
					            "in": "path",
 | 
				
			||||||
 | 
					            "required": true
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            "type": "string",
 | 
				
			||||||
 | 
					            "description": "name of protected branch",
 | 
				
			||||||
 | 
					            "name": "name",
 | 
				
			||||||
 | 
					            "in": "path",
 | 
				
			||||||
 | 
					            "required": true
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        "responses": {
 | 
				
			||||||
 | 
					          "200": {
 | 
				
			||||||
 | 
					            "$ref": "#/responses/BranchProtection"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "404": {
 | 
				
			||||||
 | 
					            "$ref": "#/responses/notFound"
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "delete": {
 | 
				
			||||||
 | 
					        "produces": [
 | 
				
			||||||
 | 
					          "application/json"
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        "tags": [
 | 
				
			||||||
 | 
					          "repository"
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        "summary": "Delete a specific branch protection for the repository",
 | 
				
			||||||
 | 
					        "operationId": "repoDeleteBranchProtection",
 | 
				
			||||||
 | 
					        "parameters": [
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            "type": "string",
 | 
				
			||||||
 | 
					            "description": "owner of the repo",
 | 
				
			||||||
 | 
					            "name": "owner",
 | 
				
			||||||
 | 
					            "in": "path",
 | 
				
			||||||
 | 
					            "required": true
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            "type": "string",
 | 
				
			||||||
 | 
					            "description": "name of the repo",
 | 
				
			||||||
 | 
					            "name": "repo",
 | 
				
			||||||
 | 
					            "in": "path",
 | 
				
			||||||
 | 
					            "required": true
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            "type": "string",
 | 
				
			||||||
 | 
					            "description": "name of protected branch",
 | 
				
			||||||
 | 
					            "name": "name",
 | 
				
			||||||
 | 
					            "in": "path",
 | 
				
			||||||
 | 
					            "required": true
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        "responses": {
 | 
				
			||||||
 | 
					          "204": {
 | 
				
			||||||
 | 
					            "$ref": "#/responses/empty"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "404": {
 | 
				
			||||||
 | 
					            "$ref": "#/responses/notFound"
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "patch": {
 | 
				
			||||||
 | 
					        "consumes": [
 | 
				
			||||||
 | 
					          "application/json"
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        "produces": [
 | 
				
			||||||
 | 
					          "application/json"
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        "tags": [
 | 
				
			||||||
 | 
					          "repository"
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        "summary": "Edit a branch protections for a repository. Only fields that are set will be changed",
 | 
				
			||||||
 | 
					        "operationId": "repoEditBranchProtection",
 | 
				
			||||||
 | 
					        "parameters": [
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            "type": "string",
 | 
				
			||||||
 | 
					            "description": "owner of the repo",
 | 
				
			||||||
 | 
					            "name": "owner",
 | 
				
			||||||
 | 
					            "in": "path",
 | 
				
			||||||
 | 
					            "required": true
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            "type": "string",
 | 
				
			||||||
 | 
					            "description": "name of the repo",
 | 
				
			||||||
 | 
					            "name": "repo",
 | 
				
			||||||
 | 
					            "in": "path",
 | 
				
			||||||
 | 
					            "required": true
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            "type": "string",
 | 
				
			||||||
 | 
					            "description": "name of protected branch",
 | 
				
			||||||
 | 
					            "name": "name",
 | 
				
			||||||
 | 
					            "in": "path",
 | 
				
			||||||
 | 
					            "required": true
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            "name": "body",
 | 
				
			||||||
 | 
					            "in": "body",
 | 
				
			||||||
 | 
					            "schema": {
 | 
				
			||||||
 | 
					              "$ref": "#/definitions/EditBranchProtectionOption"
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        "responses": {
 | 
				
			||||||
 | 
					          "200": {
 | 
				
			||||||
 | 
					            "$ref": "#/responses/BranchProtection"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "404": {
 | 
				
			||||||
 | 
					            "$ref": "#/responses/notFound"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "422": {
 | 
				
			||||||
 | 
					            "$ref": "#/responses/validationError"
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "/repos/{owner}/{repo}/branches": {
 | 
					    "/repos/{owner}/{repo}/branches": {
 | 
				
			||||||
      "get": {
 | 
					      "get": {
 | 
				
			||||||
        "produces": [
 | 
					        "produces": [
 | 
				
			||||||
@@ -9394,6 +9615,10 @@
 | 
				
			|||||||
        "commit": {
 | 
					        "commit": {
 | 
				
			||||||
          "$ref": "#/definitions/PayloadCommit"
 | 
					          "$ref": "#/definitions/PayloadCommit"
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
 | 
					        "effective_branch_protection_name": {
 | 
				
			||||||
 | 
					          "type": "string",
 | 
				
			||||||
 | 
					          "x-go-name": "EffectiveBranchProtectionName"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
        "enable_status_check": {
 | 
					        "enable_status_check": {
 | 
				
			||||||
          "type": "boolean",
 | 
					          "type": "boolean",
 | 
				
			||||||
          "x-go-name": "EnableStatusCheck"
 | 
					          "x-go-name": "EnableStatusCheck"
 | 
				
			||||||
@@ -9429,6 +9654,117 @@
 | 
				
			|||||||
      },
 | 
					      },
 | 
				
			||||||
      "x-go-package": "code.gitea.io/gitea/modules/structs"
 | 
					      "x-go-package": "code.gitea.io/gitea/modules/structs"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "BranchProtection": {
 | 
				
			||||||
 | 
					      "description": "BranchProtection represents a branch protection for a repository",
 | 
				
			||||||
 | 
					      "type": "object",
 | 
				
			||||||
 | 
					      "properties": {
 | 
				
			||||||
 | 
					        "approvals_whitelist_teams": {
 | 
				
			||||||
 | 
					          "type": "array",
 | 
				
			||||||
 | 
					          "items": {
 | 
				
			||||||
 | 
					            "type": "string"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "x-go-name": "ApprovalsWhitelistTeams"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "approvals_whitelist_username": {
 | 
				
			||||||
 | 
					          "type": "array",
 | 
				
			||||||
 | 
					          "items": {
 | 
				
			||||||
 | 
					            "type": "string"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "x-go-name": "ApprovalsWhitelistUsernames"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "block_on_rejected_reviews": {
 | 
				
			||||||
 | 
					          "type": "boolean",
 | 
				
			||||||
 | 
					          "x-go-name": "BlockOnRejectedReviews"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "branch_name": {
 | 
				
			||||||
 | 
					          "type": "string",
 | 
				
			||||||
 | 
					          "x-go-name": "BranchName"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "created_at": {
 | 
				
			||||||
 | 
					          "type": "string",
 | 
				
			||||||
 | 
					          "format": "date-time",
 | 
				
			||||||
 | 
					          "x-go-name": "Created"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "dismiss_stale_approvals": {
 | 
				
			||||||
 | 
					          "type": "boolean",
 | 
				
			||||||
 | 
					          "x-go-name": "DismissStaleApprovals"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "enable_approvals_whitelist": {
 | 
				
			||||||
 | 
					          "type": "boolean",
 | 
				
			||||||
 | 
					          "x-go-name": "EnableApprovalsWhitelist"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "enable_merge_whitelist": {
 | 
				
			||||||
 | 
					          "type": "boolean",
 | 
				
			||||||
 | 
					          "x-go-name": "EnableMergeWhitelist"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "enable_push": {
 | 
				
			||||||
 | 
					          "type": "boolean",
 | 
				
			||||||
 | 
					          "x-go-name": "EnablePush"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "enable_push_whitelist": {
 | 
				
			||||||
 | 
					          "type": "boolean",
 | 
				
			||||||
 | 
					          "x-go-name": "EnablePushWhitelist"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "enable_status_check": {
 | 
				
			||||||
 | 
					          "type": "boolean",
 | 
				
			||||||
 | 
					          "x-go-name": "EnableStatusCheck"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "merge_whitelist_teams": {
 | 
				
			||||||
 | 
					          "type": "array",
 | 
				
			||||||
 | 
					          "items": {
 | 
				
			||||||
 | 
					            "type": "string"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "x-go-name": "MergeWhitelistTeams"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "merge_whitelist_usernames": {
 | 
				
			||||||
 | 
					          "type": "array",
 | 
				
			||||||
 | 
					          "items": {
 | 
				
			||||||
 | 
					            "type": "string"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "x-go-name": "MergeWhitelistUsernames"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "push_whitelist_deploy_keys": {
 | 
				
			||||||
 | 
					          "type": "boolean",
 | 
				
			||||||
 | 
					          "x-go-name": "PushWhitelistDeployKeys"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "push_whitelist_teams": {
 | 
				
			||||||
 | 
					          "type": "array",
 | 
				
			||||||
 | 
					          "items": {
 | 
				
			||||||
 | 
					            "type": "string"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "x-go-name": "PushWhitelistTeams"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "push_whitelist_usernames": {
 | 
				
			||||||
 | 
					          "type": "array",
 | 
				
			||||||
 | 
					          "items": {
 | 
				
			||||||
 | 
					            "type": "string"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "x-go-name": "PushWhitelistUsernames"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "require_signed_commits": {
 | 
				
			||||||
 | 
					          "type": "boolean",
 | 
				
			||||||
 | 
					          "x-go-name": "RequireSignedCommits"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "required_approvals": {
 | 
				
			||||||
 | 
					          "type": "integer",
 | 
				
			||||||
 | 
					          "format": "int64",
 | 
				
			||||||
 | 
					          "x-go-name": "RequiredApprovals"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "status_check_contexts": {
 | 
				
			||||||
 | 
					          "type": "array",
 | 
				
			||||||
 | 
					          "items": {
 | 
				
			||||||
 | 
					            "type": "string"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "x-go-name": "StatusCheckContexts"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "updated_at": {
 | 
				
			||||||
 | 
					          "type": "string",
 | 
				
			||||||
 | 
					          "format": "date-time",
 | 
				
			||||||
 | 
					          "x-go-name": "Updated"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "x-go-package": "code.gitea.io/gitea/modules/structs"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "Comment": {
 | 
					    "Comment": {
 | 
				
			||||||
      "description": "Comment represents a comment on a commit or issue",
 | 
					      "description": "Comment represents a comment on a commit or issue",
 | 
				
			||||||
      "type": "object",
 | 
					      "type": "object",
 | 
				
			||||||
@@ -9634,6 +9970,107 @@
 | 
				
			|||||||
      },
 | 
					      },
 | 
				
			||||||
      "x-go-package": "code.gitea.io/gitea/modules/structs"
 | 
					      "x-go-package": "code.gitea.io/gitea/modules/structs"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "CreateBranchProtectionOption": {
 | 
				
			||||||
 | 
					      "description": "CreateBranchProtectionOption options for creating a branch protection",
 | 
				
			||||||
 | 
					      "type": "object",
 | 
				
			||||||
 | 
					      "properties": {
 | 
				
			||||||
 | 
					        "approvals_whitelist_teams": {
 | 
				
			||||||
 | 
					          "type": "array",
 | 
				
			||||||
 | 
					          "items": {
 | 
				
			||||||
 | 
					            "type": "string"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "x-go-name": "ApprovalsWhitelistTeams"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "approvals_whitelist_username": {
 | 
				
			||||||
 | 
					          "type": "array",
 | 
				
			||||||
 | 
					          "items": {
 | 
				
			||||||
 | 
					            "type": "string"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "x-go-name": "ApprovalsWhitelistUsernames"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "block_on_rejected_reviews": {
 | 
				
			||||||
 | 
					          "type": "boolean",
 | 
				
			||||||
 | 
					          "x-go-name": "BlockOnRejectedReviews"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "branch_name": {
 | 
				
			||||||
 | 
					          "type": "string",
 | 
				
			||||||
 | 
					          "x-go-name": "BranchName"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "dismiss_stale_approvals": {
 | 
				
			||||||
 | 
					          "type": "boolean",
 | 
				
			||||||
 | 
					          "x-go-name": "DismissStaleApprovals"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "enable_approvals_whitelist": {
 | 
				
			||||||
 | 
					          "type": "boolean",
 | 
				
			||||||
 | 
					          "x-go-name": "EnableApprovalsWhitelist"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "enable_merge_whitelist": {
 | 
				
			||||||
 | 
					          "type": "boolean",
 | 
				
			||||||
 | 
					          "x-go-name": "EnableMergeWhitelist"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "enable_push": {
 | 
				
			||||||
 | 
					          "type": "boolean",
 | 
				
			||||||
 | 
					          "x-go-name": "EnablePush"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "enable_push_whitelist": {
 | 
				
			||||||
 | 
					          "type": "boolean",
 | 
				
			||||||
 | 
					          "x-go-name": "EnablePushWhitelist"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "enable_status_check": {
 | 
				
			||||||
 | 
					          "type": "boolean",
 | 
				
			||||||
 | 
					          "x-go-name": "EnableStatusCheck"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "merge_whitelist_teams": {
 | 
				
			||||||
 | 
					          "type": "array",
 | 
				
			||||||
 | 
					          "items": {
 | 
				
			||||||
 | 
					            "type": "string"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "x-go-name": "MergeWhitelistTeams"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "merge_whitelist_usernames": {
 | 
				
			||||||
 | 
					          "type": "array",
 | 
				
			||||||
 | 
					          "items": {
 | 
				
			||||||
 | 
					            "type": "string"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "x-go-name": "MergeWhitelistUsernames"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "push_whitelist_deploy_keys": {
 | 
				
			||||||
 | 
					          "type": "boolean",
 | 
				
			||||||
 | 
					          "x-go-name": "PushWhitelistDeployKeys"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "push_whitelist_teams": {
 | 
				
			||||||
 | 
					          "type": "array",
 | 
				
			||||||
 | 
					          "items": {
 | 
				
			||||||
 | 
					            "type": "string"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "x-go-name": "PushWhitelistTeams"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "push_whitelist_usernames": {
 | 
				
			||||||
 | 
					          "type": "array",
 | 
				
			||||||
 | 
					          "items": {
 | 
				
			||||||
 | 
					            "type": "string"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "x-go-name": "PushWhitelistUsernames"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "require_signed_commits": {
 | 
				
			||||||
 | 
					          "type": "boolean",
 | 
				
			||||||
 | 
					          "x-go-name": "RequireSignedCommits"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "required_approvals": {
 | 
				
			||||||
 | 
					          "type": "integer",
 | 
				
			||||||
 | 
					          "format": "int64",
 | 
				
			||||||
 | 
					          "x-go-name": "RequiredApprovals"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "status_check_contexts": {
 | 
				
			||||||
 | 
					          "type": "array",
 | 
				
			||||||
 | 
					          "items": {
 | 
				
			||||||
 | 
					            "type": "string"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "x-go-name": "StatusCheckContexts"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "x-go-package": "code.gitea.io/gitea/modules/structs"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "CreateEmailOption": {
 | 
					    "CreateEmailOption": {
 | 
				
			||||||
      "description": "CreateEmailOption options when creating email addresses",
 | 
					      "description": "CreateEmailOption options when creating email addresses",
 | 
				
			||||||
      "type": "object",
 | 
					      "type": "object",
 | 
				
			||||||
@@ -10318,6 +10755,103 @@
 | 
				
			|||||||
      },
 | 
					      },
 | 
				
			||||||
      "x-go-package": "code.gitea.io/gitea/modules/structs"
 | 
					      "x-go-package": "code.gitea.io/gitea/modules/structs"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "EditBranchProtectionOption": {
 | 
				
			||||||
 | 
					      "description": "EditBranchProtectionOption options for editing a branch protection",
 | 
				
			||||||
 | 
					      "type": "object",
 | 
				
			||||||
 | 
					      "properties": {
 | 
				
			||||||
 | 
					        "approvals_whitelist_teams": {
 | 
				
			||||||
 | 
					          "type": "array",
 | 
				
			||||||
 | 
					          "items": {
 | 
				
			||||||
 | 
					            "type": "string"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "x-go-name": "ApprovalsWhitelistTeams"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "approvals_whitelist_username": {
 | 
				
			||||||
 | 
					          "type": "array",
 | 
				
			||||||
 | 
					          "items": {
 | 
				
			||||||
 | 
					            "type": "string"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "x-go-name": "ApprovalsWhitelistUsernames"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "block_on_rejected_reviews": {
 | 
				
			||||||
 | 
					          "type": "boolean",
 | 
				
			||||||
 | 
					          "x-go-name": "BlockOnRejectedReviews"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "dismiss_stale_approvals": {
 | 
				
			||||||
 | 
					          "type": "boolean",
 | 
				
			||||||
 | 
					          "x-go-name": "DismissStaleApprovals"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "enable_approvals_whitelist": {
 | 
				
			||||||
 | 
					          "type": "boolean",
 | 
				
			||||||
 | 
					          "x-go-name": "EnableApprovalsWhitelist"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "enable_merge_whitelist": {
 | 
				
			||||||
 | 
					          "type": "boolean",
 | 
				
			||||||
 | 
					          "x-go-name": "EnableMergeWhitelist"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "enable_push": {
 | 
				
			||||||
 | 
					          "type": "boolean",
 | 
				
			||||||
 | 
					          "x-go-name": "EnablePush"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "enable_push_whitelist": {
 | 
				
			||||||
 | 
					          "type": "boolean",
 | 
				
			||||||
 | 
					          "x-go-name": "EnablePushWhitelist"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "enable_status_check": {
 | 
				
			||||||
 | 
					          "type": "boolean",
 | 
				
			||||||
 | 
					          "x-go-name": "EnableStatusCheck"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "merge_whitelist_teams": {
 | 
				
			||||||
 | 
					          "type": "array",
 | 
				
			||||||
 | 
					          "items": {
 | 
				
			||||||
 | 
					            "type": "string"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "x-go-name": "MergeWhitelistTeams"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "merge_whitelist_usernames": {
 | 
				
			||||||
 | 
					          "type": "array",
 | 
				
			||||||
 | 
					          "items": {
 | 
				
			||||||
 | 
					            "type": "string"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "x-go-name": "MergeWhitelistUsernames"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "push_whitelist_deploy_keys": {
 | 
				
			||||||
 | 
					          "type": "boolean",
 | 
				
			||||||
 | 
					          "x-go-name": "PushWhitelistDeployKeys"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "push_whitelist_teams": {
 | 
				
			||||||
 | 
					          "type": "array",
 | 
				
			||||||
 | 
					          "items": {
 | 
				
			||||||
 | 
					            "type": "string"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "x-go-name": "PushWhitelistTeams"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "push_whitelist_usernames": {
 | 
				
			||||||
 | 
					          "type": "array",
 | 
				
			||||||
 | 
					          "items": {
 | 
				
			||||||
 | 
					            "type": "string"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "x-go-name": "PushWhitelistUsernames"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "require_signed_commits": {
 | 
				
			||||||
 | 
					          "type": "boolean",
 | 
				
			||||||
 | 
					          "x-go-name": "RequireSignedCommits"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "required_approvals": {
 | 
				
			||||||
 | 
					          "type": "integer",
 | 
				
			||||||
 | 
					          "format": "int64",
 | 
				
			||||||
 | 
					          "x-go-name": "RequiredApprovals"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "status_check_contexts": {
 | 
				
			||||||
 | 
					          "type": "array",
 | 
				
			||||||
 | 
					          "items": {
 | 
				
			||||||
 | 
					            "type": "string"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "x-go-name": "StatusCheckContexts"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "x-go-package": "code.gitea.io/gitea/modules/structs"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "EditDeadlineOption": {
 | 
					    "EditDeadlineOption": {
 | 
				
			||||||
      "description": "EditDeadlineOption options for creating a deadline",
 | 
					      "description": "EditDeadlineOption options for creating a deadline",
 | 
				
			||||||
      "type": "object",
 | 
					      "type": "object",
 | 
				
			||||||
@@ -12880,6 +13414,21 @@
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "BranchProtection": {
 | 
				
			||||||
 | 
					      "description": "BranchProtection",
 | 
				
			||||||
 | 
					      "schema": {
 | 
				
			||||||
 | 
					        "$ref": "#/definitions/BranchProtection"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "BranchProtectionList": {
 | 
				
			||||||
 | 
					      "description": "BranchProtectionList",
 | 
				
			||||||
 | 
					      "schema": {
 | 
				
			||||||
 | 
					        "type": "array",
 | 
				
			||||||
 | 
					        "items": {
 | 
				
			||||||
 | 
					          "$ref": "#/definitions/BranchProtection"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "Comment": {
 | 
					    "Comment": {
 | 
				
			||||||
      "description": "Comment",
 | 
					      "description": "Comment",
 | 
				
			||||||
      "schema": {
 | 
					      "schema": {
 | 
				
			||||||
@@ -13410,7 +13959,7 @@
 | 
				
			|||||||
    "parameterBodies": {
 | 
					    "parameterBodies": {
 | 
				
			||||||
      "description": "parameterBodies",
 | 
					      "description": "parameterBodies",
 | 
				
			||||||
      "schema": {
 | 
					      "schema": {
 | 
				
			||||||
        "$ref": "#/definitions/EditReactionOption"
 | 
					        "$ref": "#/definitions/EditBranchProtectionOption"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "redirect": {
 | 
					    "redirect": {
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user