mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2024-11-27 12:53:57 +01: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:
parent
908f8952be
commit
9ff4e1d2d9
10 changed files with 1352 additions and 28 deletions
|
@ -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": {
|
||||
|
|
Loading…
Reference in a new issue