From 8222a371bbf31cc1540ee22e5069e094c268265f Mon Sep 17 00:00:00 2001 From: sillyguodong Date: Wed, 22 Feb 2023 13:41:29 +0800 Subject: [PATCH 1/4] implement the api for renaming branch --- modules/structs/repo.go | 10 ++++ routers/api/v1/api.go | 1 + routers/api/v1/repo/branch.go | 89 +++++++++++++++++++++++++++++++ routers/api/v1/swagger/options.go | 3 ++ templates/swagger/v1_json.tmpl | 77 +++++++++++++++++++++++++- 5 files changed, 179 insertions(+), 1 deletion(-) diff --git a/modules/structs/repo.go b/modules/structs/repo.go index b5a26a8155956..19eaa048b8656 100644 --- a/modules/structs/repo.go +++ b/modules/structs/repo.go @@ -245,6 +245,16 @@ type CreateBranchRepoOption struct { OldBranchName string `json:"old_branch_name" binding:"GitRefName;MaxSize(100)"` } +// RenameBranchOption options when rename a branch in a repository +// swagger:model +type RenameBranchReopOption struct { + // Name of the branch after modified + // + // required: true + // unique: true + NewName string `json:"new_name" binding:"Required;GitRefName;MaxSize(100)"` +} + // TransferRepoOption options when transfer a repository's ownership // swagger:model type TransferRepoOption struct { diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index 1d2f8b18e0190..0f330f839753b 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -908,6 +908,7 @@ func Routes(ctx gocontext.Context) *web.Route { m.Get("/*", repo.GetBranch) m.Delete("/*", reqToken(auth_model.AccessTokenScopeRepo), reqRepoWriter(unit.TypeCode), repo.DeleteBranch) m.Post("", reqToken(auth_model.AccessTokenScopeRepo), reqRepoWriter(unit.TypeCode), bind(api.CreateBranchRepoOption{}), repo.CreateBranch) + m.Post("/{name}/rename", reqToken(auth_model.AccessTokenScopeRepo), reqRepoWriter(unit.TypeCode), bind(api.RenameBranchReopOption{}), repo.RenameBranch) }, context.ReferencesGitRepo(), reqRepoReader(unit.TypeCode)) 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 8acaeaffb4173..27c49e8e6764e 100644 --- a/routers/api/v1/repo/branch.go +++ b/routers/api/v1/repo/branch.go @@ -20,6 +20,7 @@ import ( "code.gitea.io/gitea/routers/api/v1/utils" "code.gitea.io/gitea/services/convert" pull_service "code.gitea.io/gitea/services/pull" + "code.gitea.io/gitea/services/repository" repo_service "code.gitea.io/gitea/services/repository" ) @@ -300,6 +301,94 @@ func ListBranches(ctx *context.APIContext) { ctx.JSON(http.StatusOK, apiBranches) } +// RenameBranch rename a branch for a user's repository +func RenameBranch(ctx *context.APIContext) { + // swagger:operation POST /repos/{owner}/{repo}/branches/{name}/rename repository repoRenameBranch + // --- + // summary: Rename a branch + // 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: original name of the branch + // type: string + // required: true + // - name: body + // in: body + // schema: + // "$ref": "#/definitions/RenameBranchReopOption" + // responses: + // "201": + // "$ref": "#/responses/Branch" + // "403": + // description: Forbidden + // "400": + // description: Bad request(target exist, branch not exist,) + // "409": + // description: The branch with the same name already exists. + + opt := web.GetForm(ctx).(*api.RenameBranchReopOption) + if ctx.Repo.Repository.IsEmpty { + ctx.Error(http.StatusNotFound, "", "Git Repository is empty.") + return + } + + if !ctx.Repo.CanCreateBranch() { + ctx.Error(http.StatusForbidden, "", "Access Forbidden") + return + } + + if ctx.HasError() { + ctx.Error(http.StatusInternalServerError, "", ctx.GetErrMsg()) + return + } + + msg, err := repository.RenameBranch(ctx.Repo.Repository, ctx.Doer, ctx.Repo.GitRepo, ctx.Params("name"), opt.NewName) + if err != nil { + ctx.Error(http.StatusBadRequest, "", msg) + return + } + + branch, err := ctx.Repo.GitRepo.GetBranch(opt.NewName) + if err != nil { + ctx.Error(http.StatusInternalServerError, "GetBranch", err) + return + } + + commit, err := branch.GetCommit() + if err != nil { + ctx.Error(http.StatusInternalServerError, "GetCommit", err) + return + } + + bp, err := git_model.GetFirstMatchProtectedBranchRule(ctx, ctx.Repo.Repository.ID, branch.Name) + if err != nil { + ctx.Error(http.StatusInternalServerError, "GetFirstMatchProtectedBranchRule", err) + return + } + + br, err := convert.ToBranch(ctx, ctx.Repo.Repository, branch, commit, bp, ctx.Doer, ctx.Repo.IsAdmin()) + if err != nil { + ctx.Error(http.StatusInternalServerError, "convert.ToBranch", err) + return + } + + ctx.JSON(http.StatusCreated, br) +} + // GetBranchProtection gets a branch protection func GetBranchProtection(ctx *context.APIContext) { // swagger:operation GET /repos/{owner}/{repo}/branch_protections/{name} repository repoGetBranchProtection diff --git a/routers/api/v1/swagger/options.go b/routers/api/v1/swagger/options.go index 979b18407590c..005b3562b3fbe 100644 --- a/routers/api/v1/swagger/options.go +++ b/routers/api/v1/swagger/options.go @@ -130,6 +130,9 @@ type swaggerParameterBodies struct { // in:body CreateBranchRepoOption api.CreateBranchRepoOption + // in:body + RenameBranchReopOption api.RenameBranchReopOption + // in:body CreateBranchProtectionOption api.CreateBranchProtectionOption diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index de774deaed13a..84f62545cf8b8 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -3152,6 +3152,65 @@ } } }, + "/repos/{owner}/{repo}/branches/{name}/rename": { + "post": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "repository" + ], + "summary": "Rename a branch", + "operationId": "repoRenameBranch", + "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": "original name of the branch", + "name": "name", + "in": "path", + "required": true + }, + { + "name": "body", + "in": "body", + "schema": { + "$ref": "#/definitions/RenameBranchReopOption" + } + } + ], + "responses": { + "201": { + "$ref": "#/responses/Branch" + }, + "400": { + "description": "Bad request(target exist, branch not exist,)" + }, + "403": { + "description": "Forbidden" + }, + "409": { + "description": "The branch with the same name already exists." + } + } + } + }, "/repos/{owner}/{repo}/collaborators": { "get": { "produces": [ @@ -18937,6 +18996,22 @@ }, "x-go-package": "code.gitea.io/gitea/modules/structs" }, + "RenameBranchReopOption": { + "description": "RenameBranchOption options when rename a branch in a repository", + "type": "object", + "required": [ + "new_name" + ], + "properties": { + "new_name": { + "description": "Name of the branch after modified", + "type": "string", + "uniqueItems": true, + "x-go-name": "NewName" + } + }, + "x-go-package": "code.gitea.io/gitea/modules/structs" + }, "RepoCollaboratorPermission": { "description": "RepoCollaboratorPermission to get repository permission for a collaborator", "type": "object", @@ -21036,4 +21111,4 @@ "TOTPHeader": [] } ] -} +} \ No newline at end of file From 75161c4ee02cd6e872ec0eeef01da2947ce6cd9d Mon Sep 17 00:00:00 2001 From: sillyguodong Date: Wed, 22 Feb 2023 13:57:35 +0800 Subject: [PATCH 2/4] fix package name --- routers/api/v1/repo/branch.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/routers/api/v1/repo/branch.go b/routers/api/v1/repo/branch.go index 27c49e8e6764e..482ef535c9cd4 100644 --- a/routers/api/v1/repo/branch.go +++ b/routers/api/v1/repo/branch.go @@ -20,7 +20,6 @@ import ( "code.gitea.io/gitea/routers/api/v1/utils" "code.gitea.io/gitea/services/convert" pull_service "code.gitea.io/gitea/services/pull" - "code.gitea.io/gitea/services/repository" repo_service "code.gitea.io/gitea/services/repository" ) @@ -356,7 +355,7 @@ func RenameBranch(ctx *context.APIContext) { return } - msg, err := repository.RenameBranch(ctx.Repo.Repository, ctx.Doer, ctx.Repo.GitRepo, ctx.Params("name"), opt.NewName) + msg, err := repo_service.RenameBranch(ctx.Repo.Repository, ctx.Doer, ctx.Repo.GitRepo, ctx.Params("name"), opt.NewName) if err != nil { ctx.Error(http.StatusBadRequest, "", msg) return From c9e241fef2dd006abf6fdd254d4186b270520dd8 Mon Sep 17 00:00:00 2001 From: sillyguodong Date: Wed, 22 Feb 2023 14:05:14 +0800 Subject: [PATCH 3/4] add a new line at the end of swagger json file manually --- templates/swagger/v1_json.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 84f62545cf8b8..9361a551a3ffb 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -21111,4 +21111,4 @@ "TOTPHeader": [] } ] -} \ No newline at end of file +} From f78e4128163386d9cca73179c7217dd20e09ec93 Mon Sep 17 00:00:00 2001 From: sillyguodong Date: Wed, 22 Feb 2023 16:28:07 +0800 Subject: [PATCH 4/4] return error msg if not blank --- routers/api/v1/repo/branch.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/routers/api/v1/repo/branch.go b/routers/api/v1/repo/branch.go index 482ef535c9cd4..2f931525ba8da 100644 --- a/routers/api/v1/repo/branch.go +++ b/routers/api/v1/repo/branch.go @@ -356,10 +356,13 @@ func RenameBranch(ctx *context.APIContext) { } msg, err := repo_service.RenameBranch(ctx.Repo.Repository, ctx.Doer, ctx.Repo.GitRepo, ctx.Params("name"), opt.NewName) - if err != nil { + if msg != "" { ctx.Error(http.StatusBadRequest, "", msg) return } + if err != nil { + ctx.Error(http.StatusInternalServerError, "", err) + } branch, err := ctx.Repo.GitRepo.GetBranch(opt.NewName) if err != nil {