* 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.21.12.1
| @@ -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": { | |||