mirror of
https://github.com/harness/drone.git
synced 2025-05-06 11:51:10 +08:00
feat: [CODE-2385]: add fast-forward merge (#2718)
* add fast-forward merge
This commit is contained in:
parent
8bcd4aa0a6
commit
7c83c5520e
@ -71,8 +71,10 @@ func (in *MergeInput) sanitize() error {
|
|||||||
in.Title = strings.TrimSpace(in.Title)
|
in.Title = strings.TrimSpace(in.Title)
|
||||||
in.Message = strings.TrimSpace(in.Message)
|
in.Message = strings.TrimSpace(in.Message)
|
||||||
|
|
||||||
if in.Method == enum.MergeMethodRebase && (in.Title != "" || in.Message != "") {
|
if (in.Method == enum.MergeMethodRebase || in.Method == enum.MergeMethodFastForward) &&
|
||||||
return usererror.BadRequest("rebase doesn't support customizing commit title and message")
|
(in.Title != "" || in.Message != "") {
|
||||||
|
return usererror.BadRequestf(
|
||||||
|
"merge method %q doesn't support customizing commit title and message", in.Method)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -338,8 +340,8 @@ func (c *Controller) Merge(
|
|||||||
author = identityFromPrincipalInfo(*session.Principal.ToPrincipalInfo())
|
author = identityFromPrincipalInfo(*session.Principal.ToPrincipalInfo())
|
||||||
case enum.MergeMethodSquash:
|
case enum.MergeMethodSquash:
|
||||||
author = identityFromPrincipalInfo(pr.Author)
|
author = identityFromPrincipalInfo(pr.Author)
|
||||||
case enum.MergeMethodRebase:
|
case enum.MergeMethodRebase, enum.MergeMethodFastForward:
|
||||||
author = nil // Not important for the rebase merge: the author info in the commits will be preserved.
|
author = nil // Not important for these merge methods: the author info in the commits will be preserved.
|
||||||
}
|
}
|
||||||
|
|
||||||
var committer *git.Identity
|
var committer *git.Identity
|
||||||
@ -349,6 +351,8 @@ func (c *Controller) Merge(
|
|||||||
committer = identityFromPrincipalInfo(*bootstrap.NewSystemServiceSession().Principal.ToPrincipalInfo())
|
committer = identityFromPrincipalInfo(*bootstrap.NewSystemServiceSession().Principal.ToPrincipalInfo())
|
||||||
case enum.MergeMethodRebase:
|
case enum.MergeMethodRebase:
|
||||||
committer = identityFromPrincipalInfo(*session.Principal.ToPrincipalInfo())
|
committer = identityFromPrincipalInfo(*session.Principal.ToPrincipalInfo())
|
||||||
|
case enum.MergeMethodFastForward:
|
||||||
|
committer = nil // Not important for fast-forward merge
|
||||||
}
|
}
|
||||||
|
|
||||||
// backfill commit title if none provided
|
// backfill commit title if none provided
|
||||||
@ -358,7 +362,7 @@ func (c *Controller) Merge(
|
|||||||
in.Title = fmt.Sprintf("Merge branch '%s' of %s (#%d)", pr.SourceBranch, sourceRepo.Path, pr.Number)
|
in.Title = fmt.Sprintf("Merge branch '%s' of %s (#%d)", pr.SourceBranch, sourceRepo.Path, pr.Number)
|
||||||
case enum.MergeMethodSquash:
|
case enum.MergeMethodSquash:
|
||||||
in.Title = fmt.Sprintf("%s (#%d)", pr.Title, pr.Number)
|
in.Title = fmt.Sprintf("%s (#%d)", pr.Title, pr.Number)
|
||||||
case enum.MergeMethodRebase:
|
case enum.MergeMethodRebase, enum.MergeMethodFastForward:
|
||||||
// Not used.
|
// Not used.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -228,6 +228,7 @@ func TestBranch_MergeVerify(t *testing.T) {
|
|||||||
},
|
},
|
||||||
expOut: MergeVerifyOutput{
|
expOut: MergeVerifyOutput{
|
||||||
AllowedMethods: []enum.MergeMethod{
|
AllowedMethods: []enum.MergeMethod{
|
||||||
|
enum.MergeMethodFastForward,
|
||||||
enum.MergeMethodMerge,
|
enum.MergeMethodMerge,
|
||||||
enum.MergeMethodRebase,
|
enum.MergeMethodRebase,
|
||||||
enum.MergeMethodSquash,
|
enum.MergeMethodSquash,
|
||||||
|
@ -24,17 +24,20 @@ const (
|
|||||||
MergeMethodSquash MergeMethod = "squash"
|
MergeMethodSquash MergeMethod = "squash"
|
||||||
// MergeMethodRebase rebase before merging.
|
// MergeMethodRebase rebase before merging.
|
||||||
MergeMethodRebase MergeMethod = "rebase"
|
MergeMethodRebase MergeMethod = "rebase"
|
||||||
|
// MergeMethodFastForward fast-forward merging.
|
||||||
|
MergeMethodFastForward MergeMethod = "fast-forward"
|
||||||
)
|
)
|
||||||
|
|
||||||
var MergeMethods = []MergeMethod{
|
var MergeMethods = []MergeMethod{
|
||||||
MergeMethodMerge,
|
MergeMethodMerge,
|
||||||
MergeMethodSquash,
|
MergeMethodSquash,
|
||||||
MergeMethodRebase,
|
MergeMethodRebase,
|
||||||
|
MergeMethodFastForward,
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m MergeMethod) Sanitize() (MergeMethod, bool) {
|
func (m MergeMethod) Sanitize() (MergeMethod, bool) {
|
||||||
switch m {
|
switch m {
|
||||||
case MergeMethodMerge, MergeMethodSquash, MergeMethodRebase:
|
case MergeMethodMerge, MergeMethodSquash, MergeMethodRebase, MergeMethodFastForward:
|
||||||
return m, true
|
return m, true
|
||||||
default:
|
default:
|
||||||
return MergeMethodMerge, false
|
return MergeMethodMerge, false
|
||||||
|
@ -144,6 +144,8 @@ func (s *Service) Merge(ctx context.Context, params *MergeParams) (MergeOutput,
|
|||||||
mergeFunc = merge.Squash
|
mergeFunc = merge.Squash
|
||||||
case enum.MergeMethodRebase:
|
case enum.MergeMethodRebase:
|
||||||
mergeFunc = merge.Rebase
|
mergeFunc = merge.Rebase
|
||||||
|
case enum.MergeMethodFastForward:
|
||||||
|
mergeFunc = merge.FastForward
|
||||||
default:
|
default:
|
||||||
// should not happen, the call to Sanitize above should handle this case.
|
// should not happen, the call to Sanitize above should handle this case.
|
||||||
panic("unsupported merge method")
|
panic("unsupported merge method")
|
||||||
@ -295,6 +297,10 @@ func (s *Service) Merge(ctx context.Context, params *MergeParams) (MergeOutput,
|
|||||||
&author, &committer,
|
&author, &committer,
|
||||||
mergeMsg,
|
mergeMsg,
|
||||||
mergeBaseCommitSHA, baseCommitSHA, headCommitSHA)
|
mergeBaseCommitSHA, baseCommitSHA, headCommitSHA)
|
||||||
|
if errors.IsConflict(err) {
|
||||||
|
return MergeOutput{}, fmt.Errorf("failed to merge %q to %q in %q using the %q merge method: %w",
|
||||||
|
params.HeadBranch, params.BaseBranch, params.RepoUID, mergeMethod, err)
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return MergeOutput{}, errors.Internal(err, "failed to merge %q to %q in %q using the %q merge method",
|
return MergeOutput{}, errors.Internal(err, "failed to merge %q to %q in %q using the %q merge method",
|
||||||
params.HeadBranch, params.BaseBranch, params.RepoUID, mergeMethod)
|
params.HeadBranch, params.BaseBranch, params.RepoUID, mergeMethod)
|
||||||
|
@ -16,9 +16,9 @@ package merge
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/harness/gitness/errors"
|
||||||
"github.com/harness/gitness/git/api"
|
"github.com/harness/gitness/git/api"
|
||||||
"github.com/harness/gitness/git/hook"
|
"github.com/harness/gitness/git/hook"
|
||||||
"github.com/harness/gitness/git/sha"
|
"github.com/harness/gitness/git/sha"
|
||||||
@ -215,3 +215,27 @@ func Rebase(
|
|||||||
|
|
||||||
return mergeSHA, conflicts, nil
|
return mergeSHA, conflicts, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FastForward points the is internal implementation of merge used for Merge and Squash methods.
|
||||||
|
func FastForward(
|
||||||
|
ctx context.Context,
|
||||||
|
refUpdater *hook.RefUpdater,
|
||||||
|
repoPath, tmpDir string,
|
||||||
|
_, _ *api.Signature, // commit author and committer aren't used here
|
||||||
|
_ string, // commit message isn't used here
|
||||||
|
mergeBaseSHA, targetSHA, sourceSHA sha.SHA,
|
||||||
|
) (mergeSHA sha.SHA, conflicts []string, err error) {
|
||||||
|
if targetSHA != mergeBaseSHA {
|
||||||
|
return sha.None, nil,
|
||||||
|
errors.Conflict("Target branch has diverged from the source branch. Fast-forward not possible.")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = sharedrepo.Run(ctx, refUpdater, tmpDir, repoPath, func(*sharedrepo.SharedRepo) error {
|
||||||
|
return refUpdater.InitNew(ctx, sourceSHA)
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return sha.None, nil, fmt.Errorf("merge method=fast-forward: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return sourceSHA, nil, nil
|
||||||
|
}
|
||||||
|
@ -219,15 +219,17 @@ type MergeMethod gitenum.MergeMethod
|
|||||||
|
|
||||||
// MergeMethod enumeration.
|
// MergeMethod enumeration.
|
||||||
const (
|
const (
|
||||||
MergeMethodMerge = MergeMethod(gitenum.MergeMethodMerge)
|
MergeMethodMerge = MergeMethod(gitenum.MergeMethodMerge)
|
||||||
MergeMethodSquash = MergeMethod(gitenum.MergeMethodSquash)
|
MergeMethodSquash = MergeMethod(gitenum.MergeMethodSquash)
|
||||||
MergeMethodRebase = MergeMethod(gitenum.MergeMethodRebase)
|
MergeMethodRebase = MergeMethod(gitenum.MergeMethodRebase)
|
||||||
|
MergeMethodFastForward = MergeMethod(gitenum.MergeMethodFastForward)
|
||||||
)
|
)
|
||||||
|
|
||||||
var MergeMethods = sortEnum([]MergeMethod{
|
var MergeMethods = sortEnum([]MergeMethod{
|
||||||
MergeMethodMerge,
|
MergeMethodMerge,
|
||||||
MergeMethodSquash,
|
MergeMethodSquash,
|
||||||
MergeMethodRebase,
|
MergeMethodRebase,
|
||||||
|
MergeMethodFastForward,
|
||||||
})
|
})
|
||||||
|
|
||||||
func (MergeMethod) Enum() []interface{} { return toInterfaceSlice(MergeMethods) }
|
func (MergeMethod) Enum() []interface{} { return toInterfaceSlice(MergeMethods) }
|
||||||
|
Loading…
Reference in New Issue
Block a user