mirror of https://github.com/harness/drone.git
107 lines
3.2 KiB
Go
107 lines
3.2 KiB
Go
// Copyright 2023 Harness, Inc.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package merge
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/harness/gitness/errors"
|
|
"github.com/harness/gitness/git/command"
|
|
"github.com/harness/gitness/git/sharedrepo"
|
|
|
|
"github.com/rs/zerolog/log"
|
|
)
|
|
|
|
// FindConflicts checks if two git revisions are mergeable and returns list of conflict files if they are not.
|
|
func FindConflicts(
|
|
ctx context.Context,
|
|
repoPath,
|
|
base, head string,
|
|
) (mergeable bool, treeSHA string, conflicts []string, err error) {
|
|
cmd := command.New("merge-tree",
|
|
command.WithFlag("--write-tree"),
|
|
command.WithFlag("--name-only"),
|
|
command.WithFlag("--no-messages"),
|
|
command.WithFlag("--stdin"))
|
|
|
|
stdin := base + " " + head
|
|
stdout := bytes.NewBuffer(nil)
|
|
|
|
err = cmd.Run(ctx,
|
|
command.WithDir(repoPath),
|
|
command.WithStdin(strings.NewReader(stdin)),
|
|
command.WithStdout(stdout))
|
|
|
|
if err != nil {
|
|
return false, "", nil, errors.Internal(err, "Failed to find conflicts between %s and %s", base, head)
|
|
}
|
|
|
|
output := strings.TrimSpace(stdout.String())
|
|
output = strings.TrimSuffix(output, "\000")
|
|
|
|
lines := strings.Split(output, "\000")
|
|
if len(lines) < 2 {
|
|
log.Ctx(ctx).Error().Str("output", output).Msg("Unexpected merge-tree output")
|
|
return false, "", nil, errors.Internal(nil,
|
|
"Failed to find conflicts between %s and %s: Unexpected git output", base, head)
|
|
}
|
|
|
|
status, err := strconv.Atoi(lines[0])
|
|
if err != nil {
|
|
log.Ctx(ctx).Err(err).Str("output", output).Msg("Unexpected merge status")
|
|
return false, "", nil, errors.Internal(nil,
|
|
"Failed to find conflicts between %s and %s: Unexpected merge status", base, head)
|
|
}
|
|
|
|
if status < 0 {
|
|
return false, "", nil, errors.Internal(nil,
|
|
"Failed to find conflicts between %s and %s: Operation blocked. Status=%d", base, head, status)
|
|
}
|
|
|
|
treeSHA = lines[1]
|
|
if status == 1 {
|
|
return true, treeSHA, nil, nil // all good, merge possible, no conflicts found
|
|
}
|
|
|
|
conflicts = sharedrepo.CleanupMergeConflicts(lines[2:])
|
|
|
|
return false, treeSHA, conflicts, nil // conflict found, list of conflicted files returned
|
|
}
|
|
|
|
// CommitCount returns number of commits between the two git revisions.
|
|
func CommitCount(
|
|
ctx context.Context,
|
|
repoPath string,
|
|
start, end string,
|
|
) (int, error) {
|
|
cmd := command.New("rev-list", command.WithFlag("--count"), command.WithArg(start+".."+end))
|
|
|
|
stdout := bytes.NewBuffer(nil)
|
|
|
|
if err := cmd.Run(ctx, command.WithDir(repoPath), command.WithStdout(stdout)); err != nil {
|
|
return 0, errors.Internal(err, "failed to rev-list in shared repo")
|
|
}
|
|
|
|
commitCount, err := strconv.Atoi(strings.TrimSpace(stdout.String()))
|
|
if err != nil {
|
|
return 0, errors.Internal(err, "failed to parse commit count from rev-list output in shared repo")
|
|
}
|
|
|
|
return commitCount, nil
|
|
}
|