|
|
@ -5,32 +5,192 @@ |
|
|
|
package repo |
|
|
|
|
|
|
|
import ( |
|
|
|
"strings" |
|
|
|
|
|
|
|
"code.gitea.io/git" |
|
|
|
"code.gitea.io/gitea/models" |
|
|
|
"code.gitea.io/gitea/modules/auth" |
|
|
|
"code.gitea.io/gitea/modules/base" |
|
|
|
"code.gitea.io/gitea/modules/context" |
|
|
|
"code.gitea.io/gitea/modules/log" |
|
|
|
) |
|
|
|
|
|
|
|
const ( |
|
|
|
tplBranch base.TplName = "repo/branch" |
|
|
|
tplBranch base.TplName = "repo/branch/list" |
|
|
|
) |
|
|
|
|
|
|
|
// Branch contains the branch information
|
|
|
|
type Branch struct { |
|
|
|
Name string |
|
|
|
Commit *git.Commit |
|
|
|
IsProtected bool |
|
|
|
IsDeleted bool |
|
|
|
DeletedBranch *models.DeletedBranch |
|
|
|
} |
|
|
|
|
|
|
|
// Branches render repository branch page
|
|
|
|
func Branches(ctx *context.Context) { |
|
|
|
ctx.Data["Title"] = "Branches" |
|
|
|
ctx.Data["IsRepoToolbarBranches"] = true |
|
|
|
ctx.Data["DefaultBranch"] = ctx.Repo.Repository.DefaultBranch |
|
|
|
ctx.Data["IsWriter"] = ctx.Repo.IsWriter() |
|
|
|
ctx.Data["IsMirror"] = ctx.Repo.Repository.IsMirror |
|
|
|
ctx.Data["PageIsViewCode"] = true |
|
|
|
ctx.Data["PageIsBranches"] = true |
|
|
|
|
|
|
|
brs, err := ctx.Repo.GitRepo.GetBranches() |
|
|
|
ctx.Data["Branches"] = loadBranches(ctx) |
|
|
|
ctx.HTML(200, tplBranch) |
|
|
|
} |
|
|
|
|
|
|
|
// DeleteBranchPost responses for delete merged branch
|
|
|
|
func DeleteBranchPost(ctx *context.Context) { |
|
|
|
defer redirect(ctx) |
|
|
|
|
|
|
|
branchName := ctx.Query("name") |
|
|
|
isProtected, err := ctx.Repo.Repository.IsProtectedBranch(branchName, ctx.User) |
|
|
|
if err != nil { |
|
|
|
ctx.Handle(500, "repo.Branches(GetBranches)", err) |
|
|
|
log.Error(4, "DeleteBranch: %v", err) |
|
|
|
ctx.Flash.Error(ctx.Tr("repo.branch.deletion_failed", branchName)) |
|
|
|
return |
|
|
|
} else if len(brs) == 0 { |
|
|
|
ctx.Handle(404, "repo.Branches(GetBranches)", nil) |
|
|
|
} |
|
|
|
|
|
|
|
if isProtected { |
|
|
|
ctx.Flash.Error(ctx.Tr("repo.branch.protected_deletion_failed", branchName)) |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
ctx.Data["Branches"] = brs |
|
|
|
ctx.HTML(200, tplBranch) |
|
|
|
if !ctx.Repo.GitRepo.IsBranchExist(branchName) || branchName == ctx.Repo.Repository.DefaultBranch { |
|
|
|
ctx.Flash.Error(ctx.Tr("repo.branch.deletion_failed", branchName)) |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
if err := deleteBranch(ctx, branchName); err != nil { |
|
|
|
ctx.Flash.Error(ctx.Tr("repo.branch.deletion_failed", branchName)) |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
ctx.Flash.Success(ctx.Tr("repo.branch.deletion_success", branchName)) |
|
|
|
} |
|
|
|
|
|
|
|
// RestoreBranchPost responses for delete merged branch
|
|
|
|
func RestoreBranchPost(ctx *context.Context) { |
|
|
|
defer redirect(ctx) |
|
|
|
|
|
|
|
branchID := ctx.QueryInt64("branch_id") |
|
|
|
branchName := ctx.Query("name") |
|
|
|
|
|
|
|
deletedBranch, err := ctx.Repo.Repository.GetDeletedBranchByID(branchID) |
|
|
|
if err != nil { |
|
|
|
log.Error(4, "GetDeletedBranchByID: %v", err) |
|
|
|
ctx.Flash.Error(ctx.Tr("repo.branch.restore_failed", branchName)) |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
if err := ctx.Repo.GitRepo.CreateBranch(deletedBranch.Name, deletedBranch.Commit); err != nil { |
|
|
|
if strings.Contains(err.Error(), "already exists") { |
|
|
|
ctx.Flash.Error(ctx.Tr("repo.branch.already_exists", deletedBranch.Name)) |
|
|
|
return |
|
|
|
} |
|
|
|
log.Error(4, "CreateBranch: %v", err) |
|
|
|
ctx.Flash.Error(ctx.Tr("repo.branch.restore_failed", deletedBranch.Name)) |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
if err := ctx.Repo.Repository.RemoveDeletedBranch(deletedBranch.ID); err != nil { |
|
|
|
log.Error(4, "RemoveDeletedBranch: %v", err) |
|
|
|
ctx.Flash.Error(ctx.Tr("repo.branch.restore_failed", deletedBranch.Name)) |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
ctx.Flash.Success(ctx.Tr("repo.branch.restore_success", deletedBranch.Name)) |
|
|
|
} |
|
|
|
|
|
|
|
func redirect(ctx *context.Context) { |
|
|
|
ctx.JSON(200, map[string]interface{}{ |
|
|
|
"redirect": ctx.Repo.RepoLink + "/branches", |
|
|
|
}) |
|
|
|
} |
|
|
|
|
|
|
|
func deleteBranch(ctx *context.Context, branchName string) error { |
|
|
|
commit, err := ctx.Repo.GitRepo.GetBranchCommit(branchName) |
|
|
|
if err != nil { |
|
|
|
log.Error(4, "GetBranchCommit: %v", err) |
|
|
|
return err |
|
|
|
} |
|
|
|
|
|
|
|
if err := ctx.Repo.GitRepo.DeleteBranch(branchName, git.DeleteBranchOptions{ |
|
|
|
Force: true, |
|
|
|
}); err != nil { |
|
|
|
log.Error(4, "DeleteBranch: %v", err) |
|
|
|
return err |
|
|
|
} |
|
|
|
|
|
|
|
// Don't return error here
|
|
|
|
if err := ctx.Repo.Repository.AddDeletedBranch(branchName, commit.ID.String(), ctx.User.ID); err != nil { |
|
|
|
log.Warn("AddDeletedBranch: %v", err) |
|
|
|
} |
|
|
|
|
|
|
|
return nil |
|
|
|
} |
|
|
|
|
|
|
|
func loadBranches(ctx *context.Context) []*Branch { |
|
|
|
rawBranches, err := ctx.Repo.Repository.GetBranches() |
|
|
|
if err != nil { |
|
|
|
ctx.Handle(500, "GetBranches", err) |
|
|
|
return nil |
|
|
|
} |
|
|
|
|
|
|
|
branches := make([]*Branch, len(rawBranches)) |
|
|
|
for i := range rawBranches { |
|
|
|
commit, err := rawBranches[i].GetCommit() |
|
|
|
if err != nil { |
|
|
|
ctx.Handle(500, "GetCommit", err) |
|
|
|
return nil |
|
|
|
} |
|
|
|
|
|
|
|
isProtected, err := ctx.Repo.Repository.IsProtectedBranch(rawBranches[i].Name, ctx.User) |
|
|
|
if err != nil { |
|
|
|
ctx.Handle(500, "IsProtectedBranch", err) |
|
|
|
return nil |
|
|
|
} |
|
|
|
|
|
|
|
branches[i] = &Branch{ |
|
|
|
Name: rawBranches[i].Name, |
|
|
|
Commit: commit, |
|
|
|
IsProtected: isProtected, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if ctx.Repo.IsWriter() { |
|
|
|
deletedBranches, err := getDeletedBranches(ctx) |
|
|
|
if err != nil { |
|
|
|
ctx.Handle(500, "getDeletedBranches", err) |
|
|
|
return nil |
|
|
|
} |
|
|
|
branches = append(branches, deletedBranches...) |
|
|
|
} |
|
|
|
|
|
|
|
return branches |
|
|
|
} |
|
|
|
|
|
|
|
func getDeletedBranches(ctx *context.Context) ([]*Branch, error) { |
|
|
|
branches := []*Branch{} |
|
|
|
|
|
|
|
deletedBranches, err := ctx.Repo.Repository.GetDeletedBranches() |
|
|
|
if err != nil { |
|
|
|
return branches, err |
|
|
|
} |
|
|
|
|
|
|
|
for i := range deletedBranches { |
|
|
|
deletedBranches[i].LoadUser() |
|
|
|
branches = append(branches, &Branch{ |
|
|
|
Name: deletedBranches[i].Name, |
|
|
|
IsDeleted: true, |
|
|
|
DeletedBranch: deletedBranches[i], |
|
|
|
}) |
|
|
|
} |
|
|
|
|
|
|
|
return branches, nil |
|
|
|
} |
|
|
|
|
|
|
|
// CreateBranch creates new branch in repository
|
|
|
|