Add a simple way to rename branch like gh (#15870)

- Update default branch if needed
- Update protected branch if needed
- Update all not merged pull request base branch name
- Rename git branch
- Record this rename work and auto redirect for old branch on ui

Signed-off-by: a1012112796 <1012112796@qq.com>
Co-authored-by: delvh <dev.lh@web.de>
This commit is contained in:
a1012112796 2021-10-09 01:03:04 +08:00 committed by GitHub
parent 56d79301b9
commit bb39359668
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 357 additions and 1 deletions

View file

@ -53,6 +53,7 @@ type ProtectedBranch struct {
func init() {
db.RegisterModel(new(ProtectedBranch))
db.RegisterModel(new(DeletedBranch))
db.RegisterModel(new(RenamedBranch))
}
// IsProtected returns if the branch is protected
@ -588,3 +589,83 @@ func RemoveOldDeletedBranches(ctx context.Context, olderThan time.Duration) {
log.Error("DeletedBranchesCleanup: %v", err)
}
}
// RenamedBranch provide renamed branch log
// will check it when a branch can't be found
type RenamedBranch struct {
ID int64 `xorm:"pk autoincr"`
RepoID int64 `xorm:"INDEX NOT NULL"`
From string
To string
CreatedUnix timeutil.TimeStamp `xorm:"created"`
}
// FindRenamedBranch check if a branch was renamed
func FindRenamedBranch(repoID int64, from string) (branch *RenamedBranch, exist bool, err error) {
branch = &RenamedBranch{
RepoID: repoID,
From: from,
}
exist, err = db.GetEngine(db.DefaultContext).Get(branch)
return
}
// RenameBranch rename a branch
func (repo *Repository) RenameBranch(from, to string, gitAction func(isDefault bool) error) (err error) {
sess := db.NewSession(db.DefaultContext)
defer sess.Close()
if err := sess.Begin(); err != nil {
return err
}
// 1. update default branch if needed
isDefault := repo.DefaultBranch == from
if isDefault {
repo.DefaultBranch = to
_, err = sess.ID(repo.ID).Cols("default_branch").Update(repo)
if err != nil {
return err
}
}
// 2. Update protected branch if needed
protectedBranch, err := getProtectedBranchBy(sess, repo.ID, from)
if err != nil {
return err
}
if protectedBranch != nil {
protectedBranch.BranchName = to
_, err = sess.ID(protectedBranch.ID).Cols("branch_name").Update(protectedBranch)
if err != nil {
return err
}
}
// 3. Update all not merged pull request base branch name
_, err = sess.Table(new(PullRequest)).Where("base_repo_id=? AND base_branch=? AND has_merged=?",
repo.ID, from, false).
Update(map[string]interface{}{"base_branch": to})
if err != nil {
return err
}
// 4. do git action
if err = gitAction(isDefault); err != nil {
return err
}
// 5. insert renamed branch record
renamedBranch := &RenamedBranch{
RepoID: repo.ID,
From: from,
To: to,
}
_, err = sess.Insert(renamedBranch)
if err != nil {
return err
}
return sess.Commit()
}

View file

@ -79,3 +79,52 @@ func getDeletedBranch(t *testing.T, branch *DeletedBranch) *DeletedBranch {
return deletedBranch
}
func TestFindRenamedBranch(t *testing.T) {
assert.NoError(t, db.PrepareTestDatabase())
branch, exist, err := FindRenamedBranch(1, "dev")
assert.NoError(t, err)
assert.Equal(t, true, exist)
assert.Equal(t, "master", branch.To)
_, exist, err = FindRenamedBranch(1, "unknow")
assert.NoError(t, err)
assert.Equal(t, false, exist)
}
func TestRenameBranch(t *testing.T) {
assert.NoError(t, db.PrepareTestDatabase())
repo1 := db.AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository)
_isDefault := false
err := UpdateProtectBranch(repo1, &ProtectedBranch{
RepoID: repo1.ID,
BranchName: "master",
}, WhitelistOptions{})
assert.NoError(t, err)
assert.NoError(t, repo1.RenameBranch("master", "main", func(isDefault bool) error {
_isDefault = isDefault
return nil
}))
assert.Equal(t, true, _isDefault)
repo1 = db.AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository)
assert.Equal(t, "main", repo1.DefaultBranch)
pull := db.AssertExistsAndLoadBean(t, &PullRequest{ID: 1}).(*PullRequest) // merged
assert.Equal(t, "master", pull.BaseBranch)
pull = db.AssertExistsAndLoadBean(t, &PullRequest{ID: 2}).(*PullRequest) // open
assert.Equal(t, "main", pull.BaseBranch)
renamedBranch := db.AssertExistsAndLoadBean(t, &RenamedBranch{ID: 2}).(*RenamedBranch)
assert.Equal(t, "master", renamedBranch.From)
assert.Equal(t, "main", renamedBranch.To)
assert.Equal(t, int64(1), renamedBranch.RepoID)
db.AssertExistsAndLoadBean(t, &ProtectedBranch{
RepoID: repo1.ID,
BranchName: "main",
})
}

View file

@ -0,0 +1,5 @@
-
id: 1
repo_id: 1
from: dev
to: master

View file

@ -346,6 +346,8 @@ var migrations = []Migration{
NewMigration("Add table commit_status_index", addTableCommitStatusIndex),
// v196 -> v197
NewMigration("Add Color to ProjectBoard table", addColorColToProjectBoard),
// v197 -> v198
NewMigration("Add renamed_branch table", addRenamedBranchTable),
}
// GetCurrentDBVersion returns the current db version

20
models/migrations/v197.go Normal file
View file

@ -0,0 +1,20 @@
// Copyright 2021 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
import (
"xorm.io/xorm"
)
func addRenamedBranchTable(x *xorm.Engine) error {
type RenamedBranch struct {
ID int64 `xorm:"pk autoincr"`
RepoID int64 `xorm:"INDEX NOT NULL"`
From string
To string
CreatedUnix int64 `xorm:"created"`
}
return x.Sync2(new(RenamedBranch))
}