mirror of
https://github.com/go-gitea/gitea.git
synced 2026-05-14 19:38:04 +02:00
Delete non-exist branch should return 404 (#36694)
Fix #36682 --------- Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
parent
716a800f50
commit
0e0daa8afe
@ -247,7 +247,7 @@ func DeleteBranches(ctx context.Context, repoID, doerID int64, branchIDs []int64
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, branch := range branches {
|
for _, branch := range branches {
|
||||||
if err := AddDeletedBranch(ctx, repoID, branch.Name, doerID); err != nil {
|
if err := MarkBranchAsDeleted(ctx, repoID, branch.Name, doerID); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -268,8 +268,8 @@ func UpdateBranch(ctx context.Context, repoID, pusherID int64, branchName string
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddDeletedBranch adds a deleted branch to the database
|
// MarkBranchAsDeleted marks branch as deleted
|
||||||
func AddDeletedBranch(ctx context.Context, repoID int64, branchName string, deletedByID int64) error {
|
func MarkBranchAsDeleted(ctx context.Context, repoID int64, branchName string, deletedByID int64) error {
|
||||||
branch, err := GetBranch(ctx, repoID, branchName)
|
branch, err := GetBranch(ctx, repoID, branchName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@ -28,8 +28,8 @@ func TestAddDeletedBranch(t *testing.T) {
|
|||||||
firstBranch := unittest.AssertExistsAndLoadBean(t, &git_model.Branch{ID: 1})
|
firstBranch := unittest.AssertExistsAndLoadBean(t, &git_model.Branch{ID: 1})
|
||||||
|
|
||||||
assert.True(t, firstBranch.IsDeleted)
|
assert.True(t, firstBranch.IsDeleted)
|
||||||
assert.NoError(t, git_model.AddDeletedBranch(t.Context(), repo.ID, firstBranch.Name, firstBranch.DeletedByID))
|
assert.NoError(t, git_model.MarkBranchAsDeleted(t.Context(), repo.ID, firstBranch.Name, firstBranch.DeletedByID))
|
||||||
assert.NoError(t, git_model.AddDeletedBranch(t.Context(), repo.ID, "branch2", int64(1)))
|
assert.NoError(t, git_model.MarkBranchAsDeleted(t.Context(), repo.ID, "branch2", int64(1)))
|
||||||
|
|
||||||
secondBranch := unittest.AssertExistsAndLoadBean(t, &git_model.Branch{RepoID: repo.ID, Name: "branch2"})
|
secondBranch := unittest.AssertExistsAndLoadBean(t, &git_model.Branch{RepoID: repo.ID, Name: "branch2"})
|
||||||
assert.True(t, secondBranch.IsDeleted)
|
assert.True(t, secondBranch.IsDeleted)
|
||||||
|
|||||||
@ -150,7 +150,7 @@ func DeleteBranch(ctx *context.APIContext) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := repo_service.DeleteBranch(ctx, ctx.Doer, ctx.Repo.Repository, ctx.Repo.GitRepo, branchName, nil); err != nil {
|
if err := repo_service.DeleteBranch(ctx, ctx.Doer, ctx.Repo.Repository, ctx.Repo.GitRepo, branchName); err != nil {
|
||||||
switch {
|
switch {
|
||||||
case git.IsErrBranchNotExist(err):
|
case git.IsErrBranchNotExist(err):
|
||||||
ctx.APIErrorNotFound(err)
|
ctx.APIErrorNotFound(err)
|
||||||
|
|||||||
@ -106,10 +106,10 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if update.IsDelRef() {
|
if update.IsDelRef() {
|
||||||
if err := git_model.AddDeletedBranch(ctx, repo.ID, update.RefFullName.BranchName(), update.PusherID); err != nil {
|
if err := git_model.MarkBranchAsDeleted(ctx, repo.ID, update.RefFullName.BranchName(), update.PusherID); err != nil {
|
||||||
log.Error("Failed to add deleted branch: %s/%s Error: %v", ownerName, repoName, err)
|
log.Error("Failed to mark branch as deleted: %s/%s Error: %v", ownerName, repoName, err)
|
||||||
ctx.JSON(http.StatusInternalServerError, private.HookPostReceiveResult{
|
ctx.JSON(http.StatusInternalServerError, private.HookPostReceiveResult{
|
||||||
Err: fmt.Sprintf("Failed to add deleted branch: %s/%s Error: %v", ownerName, repoName, err),
|
Err: fmt.Sprintf("Failed to mark branch as deleted: %s/%s Error: %v", ownerName, repoName, err),
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@ -95,7 +95,7 @@ func DeleteBranchPost(ctx *context.Context) {
|
|||||||
defer jsonRedirectBranches(ctx)
|
defer jsonRedirectBranches(ctx)
|
||||||
branchName := ctx.FormString("name")
|
branchName := ctx.FormString("name")
|
||||||
|
|
||||||
if err := repo_service.DeleteBranch(ctx, ctx.Doer, ctx.Repo.Repository, ctx.Repo.GitRepo, branchName, nil); err != nil {
|
if err := repo_service.DeleteBranch(ctx, ctx.Doer, ctx.Repo.Repository, ctx.Repo.GitRepo, branchName); err != nil {
|
||||||
switch {
|
switch {
|
||||||
case git.IsErrBranchNotExist(err):
|
case git.IsErrBranchNotExist(err):
|
||||||
log.Debug("DeleteBranch: Can't delete non existing branch '%s'", branchName)
|
log.Debug("DeleteBranch: Can't delete non existing branch '%s'", branchName)
|
||||||
|
|||||||
@ -573,8 +573,38 @@ func CanDeleteBranch(ctx context.Context, repo *repo_model.Repository, branchNam
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func deleteBranchInternal(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, branchName string, branchCommit *git.Commit) (branchExisted bool, err error) {
|
||||||
|
activeInDB, err := git_model.IsBranchExist(ctx, repo.ID, branchName)
|
||||||
|
if err != nil {
|
||||||
|
return false, fmt.Errorf("IsBranchExist: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// process the branch in db
|
||||||
|
if activeInDB {
|
||||||
|
if err := git_model.MarkBranchAsDeleted(ctx, repo.ID, branchName, doer.ID); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// process the branch in git
|
||||||
|
if branchCommit != nil {
|
||||||
|
err := gitrepo.DeleteBranch(ctx, repo, branchName, true)
|
||||||
|
if err != nil {
|
||||||
|
return false, fmt.Errorf("DeleteBranch: %w", err)
|
||||||
|
}
|
||||||
|
// since the branch existed in git, return branchExisted=true
|
||||||
|
branchExisted = true
|
||||||
|
} else {
|
||||||
|
// the branch didn't exist in git, return activeInDB to indicate whether the branch was active in DB,
|
||||||
|
// for consistency with that the user had seen on the web ui or in the branch list API response.
|
||||||
|
branchExisted = activeInDB
|
||||||
|
}
|
||||||
|
|
||||||
|
return branchExisted, nil
|
||||||
|
}
|
||||||
|
|
||||||
// DeleteBranch delete branch
|
// DeleteBranch delete branch
|
||||||
func DeleteBranch(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, gitRepo *git.Repository, branchName string, pr *issues_model.PullRequest) error {
|
func DeleteBranch(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, gitRepo *git.Repository, branchName string) error {
|
||||||
err := repo.MustNotBeArchived()
|
err := repo.MustNotBeArchived()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -584,46 +614,31 @@ func DeleteBranch(ctx context.Context, doer *user_model.User, repo *repo_model.R
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
rawBranch, err := git_model.GetBranch(ctx, repo.ID, branchName)
|
|
||||||
if err != nil && !git_model.IsErrBranchNotExist(err) {
|
|
||||||
return fmt.Errorf("GetBranch: %vc", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// database branch record not exist or it's a deleted branch
|
|
||||||
notExist := git_model.IsErrBranchNotExist(err) || rawBranch.IsDeleted
|
|
||||||
|
|
||||||
branchCommit, err := gitRepo.GetBranchCommit(branchName)
|
branchCommit, err := gitRepo.GetBranchCommit(branchName)
|
||||||
|
// branchCommit can be nil if the branch doesn't exist in git
|
||||||
if err != nil && !errors.Is(err, util.ErrNotExist) {
|
if err != nil && !errors.Is(err, util.ErrNotExist) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := db.WithTx(ctx, func(ctx context.Context) error {
|
branchExisted, err := db.WithTx2(ctx, func(ctx context.Context) (bool, error) {
|
||||||
if !notExist {
|
return deleteBranchInternal(ctx, doer, repo, branchName, branchCommit)
|
||||||
if err := git_model.AddDeletedBranch(ctx, repo.ID, branchName, doer.ID); err != nil {
|
})
|
||||||
return err
|
if err != nil {
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if pr != nil {
|
|
||||||
if err := issues_model.AddDeletePRBranchComment(ctx, doer, pr.BaseRepo, pr.Issue.ID, pr.HeadBranch); err != nil {
|
|
||||||
return fmt.Errorf("DeleteBranch: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if branchCommit == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return gitrepo.DeleteBranch(ctx, repo, branchName, true)
|
|
||||||
}); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if branchCommit == nil {
|
if !branchExisted {
|
||||||
return nil
|
return git.ErrBranchNotExist{Name: branchName}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't return error below this
|
// Don't return error below this since the deletion has succeeded
|
||||||
|
if branchCommit != nil {
|
||||||
|
deleteBranchSuccessPostProcess(doer, repo, branchName, branchCommit)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteBranchSuccessPostProcess(doer *user_model.User, repo *repo_model.Repository, branchName string, branchCommit *git.Commit) {
|
||||||
objectFormat := git.ObjectFormatFromName(repo.ObjectFormatName)
|
objectFormat := git.ObjectFormatFromName(repo.ObjectFormatName)
|
||||||
if err := PushUpdate(
|
if err := PushUpdate(
|
||||||
&repo_module.PushUpdateOptions{
|
&repo_module.PushUpdateOptions{
|
||||||
@ -637,8 +652,6 @@ func DeleteBranch(ctx context.Context, doer *user_model.User, repo *repo_model.R
|
|||||||
}); err != nil {
|
}); err != nil {
|
||||||
log.Error("PushUpdateOptions: %v", err)
|
log.Error("PushUpdateOptions: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type BranchSyncOptions struct {
|
type BranchSyncOptions struct {
|
||||||
@ -886,9 +899,17 @@ func DeleteBranchAfterMerge(ctx context.Context, doer *user_model.User, prID int
|
|||||||
return util.ErrorWrapTranslatable(util.ErrUnprocessableContent, "repo.branch.delete_branch_has_new_commits", fullBranchName)
|
return util.ErrorWrapTranslatable(util.ErrUnprocessableContent, "repo.branch.delete_branch_has_new_commits", fullBranchName)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = DeleteBranch(ctx, doer, pr.HeadRepo, gitHeadRepo, pr.HeadBranch, pr)
|
err = DeleteBranch(ctx, doer, pr.HeadRepo, gitHeadRepo, pr.HeadBranch)
|
||||||
if errors.Is(err, util.ErrPermissionDenied) || errors.Is(err, util.ErrNotExist) {
|
if errors.Is(err, util.ErrPermissionDenied) || errors.Is(err, util.ErrNotExist) {
|
||||||
return errFailedToDelete(err)
|
return errFailedToDelete(err)
|
||||||
}
|
}
|
||||||
return err
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// intentionally ignore the following error, since the branch has already been deleted successfully
|
||||||
|
if err := issues_model.AddDeletePRBranchComment(ctx, doer, pr.BaseRepo, pr.Issue.ID, pr.HeadBranch); err != nil {
|
||||||
|
log.Error("AddDeletePRBranchComment: %v", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@ -438,7 +438,7 @@ jobs:
|
|||||||
assert.NotNil(t, run)
|
assert.NotNil(t, run)
|
||||||
|
|
||||||
// delete the branch
|
// delete the branch
|
||||||
err = repo_service.DeleteBranch(t.Context(), user2, repo, gitRepo, "test-create-branch", nil)
|
err = repo_service.DeleteBranch(t.Context(), user2, repo, gitRepo, "test-create-branch")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
run = unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{
|
run = unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{
|
||||||
Title: "add workflow",
|
Title: "add workflow",
|
||||||
|
|||||||
@ -402,6 +402,8 @@ func TestAPIBranchProtection(t *testing.T) {
|
|||||||
// Test branch deletion
|
// Test branch deletion
|
||||||
testAPIDeleteBranch(t, "master", http.StatusForbidden)
|
testAPIDeleteBranch(t, "master", http.StatusForbidden)
|
||||||
testAPIDeleteBranch(t, "branch2", http.StatusNoContent)
|
testAPIDeleteBranch(t, "branch2", http.StatusNoContent)
|
||||||
|
testAPIDeleteBranch(t, "branch2", http.StatusNotFound) // deleted branch, there is a record in DB with IsDelete=true
|
||||||
|
testAPIDeleteBranch(t, "no-such-branch", http.StatusNotFound) // non-existing branch, not exist in git or DB
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAPICreateBranchWithSyncBranches(t *testing.T) {
|
func TestAPICreateBranchWithSyncBranches(t *testing.T) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user