* 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>tags/v1.10.5
@@ -30,6 +30,54 @@ func testAPIGetBranch(t *testing.T, branchName string, exists bool) { | |||
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) { | |||
for _, test := range []struct { | |||
BranchName string | |||
@@ -43,3 +91,23 @@ func TestAPIGetBranch(t *testing.T) { | |||
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) | |||
} | |||
// 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. | |||
func getOwnerTeam(e Engine, orgID int64) (*Team, error) { | |||
return getTeam(e, orgID, ownerTeamName) | |||
@@ -574,6 +591,22 @@ func GetTeamByID(teamID int64) (*Team, error) { | |||
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. | |||
func UpdateTeam(t *Team, authChanged bool, includeAllChanged bool) (err error) { | |||
if len(t.Name) == 0 { |
@@ -1386,6 +1386,17 @@ func GetMaileableUsersByIDs(ids []int64) ([]*User, error) { | |||
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. | |||
func GetUsersByIDs(ids []int64) ([]*User, error) { | |||
ous := make([]*User, 0, len(ids)) |
@@ -30,28 +30,86 @@ func ToEmail(email *models.EmailAddress) *api.Email { | |||
} | |||
// 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 { | |||
return &api.Branch{ | |||
Name: b.Name, | |||
Commit: ToCommit(repo, c), | |||
Protected: false, | |||
RequiredApprovals: 0, | |||
EnableStatusCheck: false, | |||
StatusCheckContexts: []string{}, | |||
UserCanPush: true, | |||
UserCanMerge: true, | |||
Name: b.Name, | |||
Commit: ToCommit(repo, c), | |||
Protected: false, | |||
RequiredApprovals: 0, | |||
EnableStatusCheck: false, | |||
StatusCheckContexts: []string{}, | |||
UserCanPush: true, | |||
UserCanMerge: true, | |||
EffectiveBranchProtectionName: "", | |||
} | |||
} | |||
branchProtectionName := "" | |||
if isRepoAdmin { | |||
branchProtectionName = bp.BranchName | |||
} | |||
return &api.Branch{ | |||
Name: b.Name, | |||
Commit: ToCommit(repo, c), | |||
Protected: true, | |||
RequiredApprovals: bp.RequiredApprovals, | |||
EnableStatusCheck: bp.EnableStatusCheck, | |||
StatusCheckContexts: bp.StatusCheckContexts, | |||
UserCanPush: bp.CanUserPush(user.ID), | |||
UserCanMerge: bp.IsUserMergeWhitelisted(user.ID), | |||
Name: b.Name, | |||
Commit: ToCommit(repo, c), | |||
Protected: true, | |||
RequiredApprovals: bp.RequiredApprovals, | |||
EnableStatusCheck: bp.EnableStatusCheck, | |||
StatusCheckContexts: bp.StatusCheckContexts, | |||
UserCanPush: bp.CanUserPush(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,14 +4,88 @@ | |||
package structs | |||
import ( | |||
"time" | |||
) | |||
// Branch represents a repository branch | |||
type Branch struct { | |||
Name string `json:"name"` | |||
Commit *PayloadCommit `json:"commit"` | |||
Protected bool `json:"protected"` | |||
RequiredApprovals int64 `json:"required_approvals"` | |||
EnableStatusCheck bool `json:"enable_status_check"` | |||
StatusCheckContexts []string `json:"status_check_contexts"` | |||
UserCanPush bool `json:"user_can_push"` | |||
UserCanMerge bool `json:"user_can_merge"` | |||
Name string `json:"name"` | |||
Commit *PayloadCommit `json:"commit"` | |||
Protected bool `json:"protected"` | |||
RequiredApprovals int64 `json:"required_approvals"` | |||
EnableStatusCheck bool `json:"enable_status_check"` | |||
StatusCheckContexts []string `json:"status_check_contexts"` | |||
UserCanPush bool `json:"user_can_push"` | |||
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("/*", context.RepoRefByType(context.RepoRefBranch), repo.GetBranch) | |||
}, 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.Get("", repo.ListTags) | |||
}, reqRepoReader(models.UnitTypeCode), context.ReferencesGitRepo(true)) |
@@ -8,6 +8,7 @@ package repo | |||
import ( | |||
"net/http" | |||
"code.gitea.io/gitea/models" | |||
"code.gitea.io/gitea/modules/context" | |||
"code.gitea.io/gitea/modules/convert" | |||
"code.gitea.io/gitea/modules/git" | |||
@@ -71,7 +72,7 @@ func GetBranch(ctx *context.APIContext) { | |||
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 | |||
@@ -114,8 +115,509 @@ func ListBranches(ctx *context.APIContext) { | |||
ctx.Error(http.StatusInternalServerError, "GetBranchProtection", err) | |||
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) | |||
} | |||
// 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 | |||
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"` | |||
} | |||
// 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 | |||
// swagger:response TagList | |||
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": { | |||
"get": { | |||
"produces": [ | |||
@@ -9394,6 +9615,10 @@ | |||
"commit": { | |||
"$ref": "#/definitions/PayloadCommit" | |||
}, | |||
"effective_branch_protection_name": { | |||
"type": "string", | |||
"x-go-name": "EffectiveBranchProtectionName" | |||
}, | |||
"enable_status_check": { | |||
"type": "boolean", | |||
"x-go-name": "EnableStatusCheck" | |||
@@ -9429,6 +9654,117 @@ | |||
}, | |||
"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": { | |||
"description": "Comment represents a comment on a commit or issue", | |||
"type": "object", | |||
@@ -9634,6 +9970,107 @@ | |||
}, | |||
"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": { | |||
"description": "CreateEmailOption options when creating email addresses", | |||
"type": "object", | |||
@@ -10318,6 +10755,103 @@ | |||
}, | |||
"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": { | |||
"description": "EditDeadlineOption options for creating a deadline", | |||
"type": "object", | |||
@@ -12880,6 +13414,21 @@ | |||
} | |||
} | |||
}, | |||
"BranchProtection": { | |||
"description": "BranchProtection", | |||
"schema": { | |||
"$ref": "#/definitions/BranchProtection" | |||
} | |||
}, | |||
"BranchProtectionList": { | |||
"description": "BranchProtectionList", | |||
"schema": { | |||
"type": "array", | |||
"items": { | |||
"$ref": "#/definitions/BranchProtection" | |||
} | |||
} | |||
}, | |||
"Comment": { | |||
"description": "Comment", | |||
"schema": { | |||
@@ -13410,7 +13959,7 @@ | |||
"parameterBodies": { | |||
"description": "parameterBodies", | |||
"schema": { | |||
"$ref": "#/definitions/EditReactionOption" | |||
"$ref": "#/definitions/EditBranchProtectionOption" | |||
} | |||
}, | |||
"redirect": { |