diff options
author | Karthik Nayak <knayak@gitlab.com> | 2023-05-03 10:30:25 +0300 |
---|---|---|
committer | Karthik Nayak <knayak@gitlab.com> | 2023-05-03 10:30:25 +0300 |
commit | 6b6e6257b546748c771768f631cde0b75ae03e72 (patch) | |
tree | 05a252fdcc19960b2b8860dfcf4954e1032a3f98 | |
parent | d96505953555659c8475fe48d1386331f3b37f73 (diff) |
-rw-r--r-- | internal/git/localrepo/merge.go | 39 | ||||
-rw-r--r-- | internal/git/localrepo/merge_test.go | 24 |
2 files changed, 47 insertions, 16 deletions
diff --git a/internal/git/localrepo/merge.go b/internal/git/localrepo/merge.go index f34aa52a6..d0b67cc7b 100644 --- a/internal/git/localrepo/merge.go +++ b/internal/git/localrepo/merge.go @@ -101,9 +101,7 @@ func (repo *Repo) MergeTree( if exitCode > 1 { if text.ChompBytes(stderr.Bytes()) == "fatal: refusing to merge unrelated histories" { - return "", &MergeTreeError{ - InfoMessage: "unrelated histories", - } + return "", &MergeTreeError{} } return "", fmt.Errorf("merge-tree: %w", err) } @@ -141,8 +139,6 @@ func parseMergeTreeError(objectHash git.ObjectHash, cfg mergeTreeConfig, output return "", fmt.Errorf("hex to oid: %w", err) } - mergeTreeError.InfoMessage = strings.TrimSuffix(infoMsg, "\x00") - mergeTreeError.ConflictingFileInfo = make([]ConflictingFileInfo, len(oidAndConflicts[1:])) // From git-merge-tree(1), the information is of the format `<mode> <object> <stage> <filename>` @@ -181,6 +177,31 @@ func parseMergeTreeError(objectHash git.ObjectHash, cfg mergeTreeConfig, output } } + fields := strings.Split(infoMsg, "\x00") + // The git output contains a null characted at the end, which creates a stray empty field. + fields = fields[:len(fields)-1] + + for i := 0; i < len(fields); { + c := ConflictInfoMessage{} + + numOfPaths, err := strconv.Atoi(fields[i]) + if err != nil { + return "", fmt.Errorf("converting stage to int: %w", err) + } + + if i+numOfPaths+2 > len(fields) { + return "", fmt.Errorf("incorrect number of fields: %s", infoMsg) + } + + c.Paths = fields[i+1 : i+numOfPaths+1] + c.Type = fields[i+numOfPaths+1] + c.Message = fields[i+numOfPaths+2] + + mergeTreeError.ConflictInfoMessage = append(mergeTreeError.ConflictInfoMessage, c) + + i = i + numOfPaths + 3 + } + return oid, &mergeTreeError } @@ -191,11 +212,17 @@ type ConflictingFileInfo struct { Stage MergeStage } +type ConflictInfoMessage struct { + Paths []string + Type string + Message string +} + // MergeTreeError encapsulates any conflicting file info and messages that occur // when a merge-tree(1) command fails. type MergeTreeError struct { ConflictingFileInfo []ConflictingFileInfo - InfoMessage string + ConflictInfoMessage []ConflictInfoMessage } // Error returns the error string for a conflict error. diff --git a/internal/git/localrepo/merge_test.go b/internal/git/localrepo/merge_test.go index ede6456b8..3a8e78c42 100644 --- a/internal/git/localrepo/merge_test.go +++ b/internal/git/localrepo/merge_test.go @@ -95,10 +95,8 @@ func TestMergeTree(t *testing.T) { }, }, { - desc: "no shared ancestors", - expectedErr: &MergeTreeError{ - InfoMessage: "unrelated histories", - }, + desc: "no shared ancestors", + expectedErr: &MergeTreeError{}, setupFunc: func(t *testing.T, ctx context.Context, repoPath string) (git.ObjectID, git.ObjectID, []gittest.TreeEntry) { tree1 := gittest.WriteTree(t, cfg, repoPath, []gittest.TreeEntry{ { @@ -138,7 +136,6 @@ func TestMergeTree(t *testing.T) { Stage: 0, }, }, - InfoMessage: "1\x00file2\x00Auto-merging\x00Auto-merging file2\n\x001\x00file2\x00CONFLICT (contents)\x00CONFLICT (add/add): Merge conflict in file2\n", }, setupFunc: func(t *testing.T, ctx context.Context, repoPath string) (git.ObjectID, git.ObjectID, []gittest.TreeEntry) { tree1 := gittest.WriteTree(t, cfg, repoPath, []gittest.TreeEntry{ @@ -321,7 +318,18 @@ func TestParseResult(t *testing.T) { Stage: MergeStageTheirs, }, }, - InfoMessage: "1\x00a\x00Auto-merging\x00Auto-merging a\n\x001\x00a\x00CONFLICT (contents)\x00CONFLICT (content): Merge conflict in a\n", + ConflictInfoMessage: []ConflictInfoMessage{ + { + Paths: []string{"a"}, + Type: "Auto-merging", + Message: "Auto-merging a\n", + }, + { + Paths: []string{"a"}, + Type: "CONFLICT (contents)", + Message: "CONFLICT (content): Merge conflict in a\n", + }, + }, }, }, { @@ -361,7 +369,6 @@ func TestParseResult(t *testing.T) { Stage: MergeStageTheirs, }, }, - InfoMessage: "1\x00a\x00Auto-merging\x00Auto-merging a\n\x001\x00a\x00CONFLICT (contents)\x00CONFLICT (content): Merge conflict in a\n", }, }, { @@ -399,7 +406,6 @@ func TestParseResult(t *testing.T) { Stage: MergeStageTheirs, }, }, - InfoMessage: "3\x00a\x00c\x00d\x00CONFLICT (rename/rename)\x00CONFLICT (rename/rename): a renamed to c in @ and to d in master.\n", }, }, { @@ -459,7 +465,6 @@ func TestParseResult(t *testing.T) { Stage: MergeStageTheirs, }, }, - InfoMessage: "1\x00a\x00Auto-merging\x00Auto-merging a\n\x001\x00a\x00CONFLICT (contents)\x00CONFLICT (content): Merge conflict in a\n\x001\x00b\x00Auto-merging\x00Auto-merging b\n\x001\x00b\x00CONFLICT (contents)\x00CONFLICT (content): Merge conflict in b\n", }, }, { @@ -509,7 +514,6 @@ func TestParseResult(t *testing.T) { Stage: MergeStageTheirs, }, }, - InfoMessage: "1\x00a\x00CONFLICT (modify/delete)\x00CONFLICT (modify/delete): a deleted in @ and modified in master. Version master of a left in tree.\n\x001\x00b\x00Auto-merging\x00Auto-merging b\n\x001\x00b\x00CONFLICT (contents)\x00CONFLICT (content): Merge conflict in b\n", }, }, { |