[API] Add branch delete (#11112)
* use same process as in routers/repo/branch.go/deleteBranch * make sure default branch can not be deleted * remove IsDefaultBranch from UI process - it is worth its own pull * permissions
This commit is contained in:
parent
0ef11ff2c9
commit
3c5a4d094a
4 changed files with 157 additions and 0 deletions
|
@ -80,6 +80,13 @@ func testAPIDeleteBranchProtection(t *testing.T, branchName string, expectedHTTP
|
|||
session.MakeRequest(t, req, expectedHTTPStatus)
|
||||
}
|
||||
|
||||
func testAPIDeleteBranch(t *testing.T, branchName string, expectedHTTPStatus int) {
|
||||
session := loginUser(t, "user2")
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
req := NewRequestf(t, "DELETE", "/api/v1/repos/user2/repo1/branches/%s?token=%s", branchName, token)
|
||||
session.MakeRequest(t, req, expectedHTTPStatus)
|
||||
}
|
||||
|
||||
func TestAPIGetBranch(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
BranchName string
|
||||
|
@ -106,10 +113,17 @@ func TestAPIBranchProtection(t *testing.T) {
|
|||
// Can only create once
|
||||
testAPICreateBranchProtection(t, "master", http.StatusForbidden)
|
||||
|
||||
// Can't delete a protected branch
|
||||
testAPIDeleteBranch(t, "master", http.StatusForbidden)
|
||||
|
||||
testAPIGetBranchProtection(t, "master", http.StatusOK)
|
||||
testAPIEditBranchProtection(t, "master", &api.BranchProtection{
|
||||
EnablePush: true,
|
||||
}, http.StatusOK)
|
||||
|
||||
testAPIDeleteBranchProtection(t, "master", http.StatusNoContent)
|
||||
|
||||
// Test branch deletion
|
||||
testAPIDeleteBranch(t, "master", http.StatusForbidden)
|
||||
testAPIDeleteBranch(t, "branch2", http.StatusNoContent)
|
||||
}
|
||||
|
|
|
@ -664,6 +664,7 @@ func RegisterRoutes(m *macaron.Macaron) {
|
|||
m.Group("/branches", func() {
|
||||
m.Get("", repo.ListBranches)
|
||||
m.Get("/*", context.RepoRefByType(context.RepoRefBranch), repo.GetBranch)
|
||||
m.Delete("/*", reqRepoWriter(models.UnitTypeCode), context.RepoRefByType(context.RepoRefBranch), repo.DeleteBranch)
|
||||
}, reqRepoReader(models.UnitTypeCode))
|
||||
m.Group("/branch_protections", func() {
|
||||
m.Get("", repo.ListBranchProtections)
|
||||
|
|
|
@ -6,12 +6,15 @@
|
|||
package repo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"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"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/repofiles"
|
||||
repo_module "code.gitea.io/gitea/modules/repository"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
)
|
||||
|
@ -81,6 +84,104 @@ func GetBranch(ctx *context.APIContext) {
|
|||
ctx.JSON(http.StatusOK, br)
|
||||
}
|
||||
|
||||
// DeleteBranch get a branch of a repository
|
||||
func DeleteBranch(ctx *context.APIContext) {
|
||||
// swagger:operation DELETE /repos/{owner}/{repo}/branches/{branch} repository repoDeleteBranch
|
||||
// ---
|
||||
// summary: Delete a specific branch from 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
|
||||
// - name: branch
|
||||
// in: path
|
||||
// description: branch to delete
|
||||
// type: string
|
||||
// required: true
|
||||
// responses:
|
||||
// "204":
|
||||
// "$ref": "#/responses/empty"
|
||||
// "403":
|
||||
// "$ref": "#/responses/error"
|
||||
|
||||
if ctx.Repo.TreePath != "" {
|
||||
// if TreePath != "", then URL contained extra slashes
|
||||
// (i.e. "master/subbranch" instead of "master"), so branch does
|
||||
// not exist
|
||||
ctx.NotFound()
|
||||
return
|
||||
}
|
||||
|
||||
if ctx.Repo.Repository.DefaultBranch == ctx.Repo.BranchName {
|
||||
ctx.Error(http.StatusForbidden, "DefaultBranch", fmt.Errorf("can not delete default branch"))
|
||||
return
|
||||
}
|
||||
|
||||
isProtected, err := ctx.Repo.Repository.IsProtectedBranch(ctx.Repo.BranchName, ctx.User)
|
||||
if err != nil {
|
||||
ctx.InternalServerError(err)
|
||||
return
|
||||
}
|
||||
if isProtected {
|
||||
ctx.Error(http.StatusForbidden, "IsProtectedBranch", fmt.Errorf("branch protected"))
|
||||
return
|
||||
}
|
||||
|
||||
branch, err := repo_module.GetBranch(ctx.Repo.Repository, ctx.Repo.BranchName)
|
||||
if err != nil {
|
||||
if git.IsErrBranchNotExist(err) {
|
||||
ctx.NotFound(err)
|
||||
} else {
|
||||
ctx.Error(http.StatusInternalServerError, "GetBranch", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
c, err := branch.GetCommit()
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "GetCommit", err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := ctx.Repo.GitRepo.DeleteBranch(ctx.Repo.BranchName, git.DeleteBranchOptions{
|
||||
Force: true,
|
||||
}); err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "DeleteBranch", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Don't return error below this
|
||||
if err := repofiles.PushUpdate(
|
||||
ctx.Repo.Repository,
|
||||
ctx.Repo.BranchName,
|
||||
repofiles.PushUpdateOptions{
|
||||
RefFullName: git.BranchPrefix + ctx.Repo.BranchName,
|
||||
OldCommitID: c.ID.String(),
|
||||
NewCommitID: git.EmptySHA,
|
||||
PusherID: ctx.User.ID,
|
||||
PusherName: ctx.User.Name,
|
||||
RepoUserName: ctx.Repo.Owner.Name,
|
||||
RepoName: ctx.Repo.Repository.Name,
|
||||
}); err != nil {
|
||||
log.Error("Update: %v", err)
|
||||
}
|
||||
|
||||
if err := ctx.Repo.Repository.AddDeletedBranch(ctx.Repo.BranchName, c.ID.String(), ctx.User.ID); err != nil {
|
||||
log.Warn("AddDeletedBranch: %v", err)
|
||||
}
|
||||
|
||||
ctx.Status(http.StatusNoContent)
|
||||
}
|
||||
|
||||
// ListBranches list all the branches of a repository
|
||||
func ListBranches(ctx *context.APIContext) {
|
||||
// swagger:operation GET /repos/{owner}/{repo}/branches repository repoListBranches
|
||||
|
|
|
@ -2269,6 +2269,47 @@
|
|||
"$ref": "#/responses/Branch"
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"repository"
|
||||
],
|
||||
"summary": "Delete a specific branch from a repository",
|
||||
"operationId": "repoDeleteBranch",
|
||||
"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": "branch to delete",
|
||||
"name": "branch",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"204": {
|
||||
"$ref": "#/responses/empty"
|
||||
},
|
||||
"403": {
|
||||
"$ref": "#/responses/error"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/repos/{owner}/{repo}/collaborators": {
|
||||
|
|
Reference in a new issue