aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
author6543 <6543@obermui.de>2020-04-19 04:38:09 +0200
committerGitHub <noreply@github.com>2020-04-19 10:38:09 +0800
commit3c5a4d094a572b446435ccf7ebf75836c2d98c57 (patch)
tree9b8e22a014004c4e008024de8b1697565cbac81a
parent0ef11ff2c909d1775642fa03b09f1342fcaaeb69 (diff)
downloadgitea-3c5a4d094a572b446435ccf7ebf75836c2d98c57.tar.gz
gitea-3c5a4d094a572b446435ccf7ebf75836c2d98c57.zip
[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
-rw-r--r--integrations/api_branch_test.go14
-rw-r--r--routers/api/v1/api.go1
-rw-r--r--routers/api/v1/repo/branch.go101
-rw-r--r--templates/swagger/v1_json.tmpl41
4 files changed, 157 insertions, 0 deletions
diff --git a/integrations/api_branch_test.go b/integrations/api_branch_test.go
index b6452a6ab4..8417ab36c5 100644
--- a/integrations/api_branch_test.go
+++ b/integrations/api_branch_test.go
@@ -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)
}
diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go
index bce3bf2452..225f6a5325 100644
--- a/routers/api/v1/api.go
+++ b/routers/api/v1/api.go
@@ -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)
diff --git a/routers/api/v1/repo/branch.go b/routers/api/v1/repo/branch.go
index 07c6159501..57c74d7dab 100644
--- a/routers/api/v1/repo/branch.go
+++ b/routers/api/v1/repo/branch.go
@@ -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
diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl
index e87af4f5c9..24a6330a06 100644
--- a/templates/swagger/v1_json.tmpl
+++ b/templates/swagger/v1_json.tmpl
@@ -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": {