Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Chunk mode, recursive mode, and Octopus with recursive fallback mode #31

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@ package config
import (
"errors"
"flag"
"github.com/lesfurets/git-octopus/git"
"strconv"
"strings"

"github.com/lesfurets/git-octopus/git"
)

type OctopusConfig struct {
PrintVersion bool
DoCommit bool
RecursiveMode bool
ChunkSize int
ExcludedPatterns []string
Patterns []string
Expand All @@ -29,14 +31,15 @@ func (e *excluded_patterns) Set(value string) error {

func GetOctopusConfig(repo *git.Repository, args []string) (*OctopusConfig, error) {

var printVersion, noCommitArg, commitArg bool
var printVersion, noCommitArg, commitArg, recursiveArg bool
var chunkSizeArg int
var excludedPatternsArg excluded_patterns

var commandLine = flag.NewFlagSet("git-octopus", flag.ExitOnError)
commandLine.BoolVar(&printVersion, "v", false, "prints the version of git-octopus.")
commandLine.BoolVar(&noCommitArg, "n", false, "leaves the repository back to HEAD.")
commandLine.BoolVar(&commitArg, "c", false, "Commit the resulting merge in the current branch.")
commandLine.BoolVar(&recursiveArg, "r", false, "merge using a traditional recursive merge (implies -s 1)")
commandLine.IntVar(&chunkSizeArg, "s", 0, "do the octopus by chunk of n branches.")
commandLine.Var(&excludedPatternsArg, "e", "exclude branches matching the pattern.")

Expand Down Expand Up @@ -90,6 +93,7 @@ func GetOctopusConfig(repo *git.Repository, args []string) (*OctopusConfig, erro
return &OctopusConfig{
PrintVersion: printVersion,
DoCommit: configCommit,
RecursiveMode: recursiveArg,
ChunkSize: chunkSizeArg,
ExcludedPatterns: excludedPatterns,
Patterns: patterns,
Expand Down
24 changes: 23 additions & 1 deletion config/config_test.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package config

import (
"testing"

"github.com/lesfurets/git-octopus/git"
"github.com/lesfurets/git-octopus/test"
"github.com/stretchr/testify/assert"
"testing"
)

func createTestRepo() *git.Repository {
Expand Down Expand Up @@ -146,3 +147,24 @@ func TestPatterns(t *testing.T) {
assert.Equal(t, []string{"arg1", "arg2"}, octopusConfig.Patterns)
assert.Nil(t, err)
}

func TestRecurisveMode(t *testing.T) {
repo := createTestRepo()
defer test.Cleanup(repo)

// GIVEN No option
// WHEN
octopusConfig, err := GetOctopusConfig(repo, nil)

// THEN RecursiveMode should be false
assert.False(t, octopusConfig.RecursiveMode)
assert.Nil(t, err)

// GIVEN option -r
// WHEN
octopusConfig, err = GetOctopusConfig(repo, []string{"-r"})

// THEN RecursiveMode should be true
assert.True(t, octopusConfig.RecursiveMode)
assert.Nil(t, err)
}
74 changes: 74 additions & 0 deletions run/basic_chunked_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package run

import (
"os"
"path/filepath"
"testing"

"github.com/lesfurets/git-octopus/test"
"github.com/stretchr/testify/assert"
)

// Basic merge of 3 branches with chunk of 2. Asserts the resulting tree and the merge commit
func TestOctopus3BranchesChunked(t *testing.T) {
context, _ := CreateTestContext()
repo := context.Repo
defer test.Cleanup(repo)

// Create and commit file foo1 in branch1
repo.Git("checkout", "-b", "branch1")
writeFile(repo, "foo1", "First line")
repo.Git("add", "foo1")
repo.Git("commit", "-m\"\"")

// Create and commit file foo2 in branch2
repo.Git("checkout", "-b", "branch2", "master")
writeFile(repo, "foo2", "First line")
repo.Git("add", "foo2")
repo.Git("commit", "-m\"\"")

// Create and commit file foo3 in branch3
repo.Git("checkout", "-b", "branch3", "master")
writeFile(repo, "foo3", "First line")
repo.Git("add", "foo3")
repo.Git("commit", "-m\"\"")

// Merge the 3 branches in a new octopus branch
repo.Git("checkout", "-b", "octopus", "master")

err := Run(context, "-s=2", "branch*")
assert.Nil(t, err)

// The working tree should have the 3 files and status should be clean
_, err = os.Open(filepath.Join(repo.Path, "foo1"))
assert.Nil(t, err)
_, err = os.Open(filepath.Join(repo.Path, "foo2"))
assert.Nil(t, err)
_, err = os.Open(filepath.Join(repo.Path, "foo3"))
assert.Nil(t, err)

status, _ := repo.Git("status", "--porcelain")
assert.Empty(t, status)

// octopus branch should contain the 3 branches
_, err = repo.Git("merge-base", "--is-ancestor", "branch1", "octopus")
assert.Nil(t, err)
_, err = repo.Git("merge-base", "--is-ancestor", "branch2", "octopus")
assert.Nil(t, err)
_, err = repo.Git("merge-base", "--is-ancestor", "branch3", "octopus")
assert.Nil(t, err)

// // Assert the commit message
commitMessage1, _ := repo.Git("show", "--pretty=format:%B") // gets the commit body only
assert.Contains(t, commitMessage1,
"Merged branches:\n"+
"refs/heads/branch3\n"+
"\nCommit created by git-octopus "+VERSION+".")

commitMessage2, _ := repo.Git("show", "--pretty=format:%B", "HEAD^") // gets the commit body only
assert.Contains(t, commitMessage2,
"Merged branches:\n"+
"refs/heads/branch1\n"+
"refs/heads/branch2\n"+
"\nCommit created by git-octopus "+VERSION+".")
}
148 changes: 148 additions & 0 deletions run/recursive_mode_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
package run

import (
"os"
"path/filepath"
"testing"

"github.com/lesfurets/git-octopus/test"
"github.com/stretchr/testify/assert"
)

// Basic merge of 3 branches. Asserts the resulting tree and the merge commit
func TestOctopus3BranchesRecursive(t *testing.T) {
context, _ := CreateTestContext()
repo := context.Repo
defer test.Cleanup(repo)

// Create and commit file foo1 in branch1
repo.Git("checkout", "-b", "branch1")
writeFile(repo, "foo1", "First line")
repo.Git("add", "foo1")
repo.Git("commit", "-m\"\"")

// Create and commit file foo2 in branch2
repo.Git("checkout", "-b", "branch2", "master")
writeFile(repo, "foo2", "First line")
repo.Git("add", "foo2")
repo.Git("commit", "-m\"\"")

// Create and commit file foo3 in branch3
repo.Git("checkout", "-b", "branch3", "master")
writeFile(repo, "foo3", "First line")
repo.Git("add", "foo3")
repo.Git("commit", "-m\"\"")

// Merge the 3 branches in a new octopus branch
repo.Git("checkout", "-b", "octopus", "master")

err := Run(context, "-r", "branch*")
assert.Nil(t, err)

// The working tree should have the 3 files and status should be clean
_, err = os.Open(filepath.Join(repo.Path, "foo1"))
assert.Nil(t, err)
_, err = os.Open(filepath.Join(repo.Path, "foo2"))
assert.Nil(t, err)
_, err = os.Open(filepath.Join(repo.Path, "foo3"))
assert.Nil(t, err)

status, _ := repo.Git("status", "--porcelain")
assert.Empty(t, status)

// octopus branch should contain the 3 branches
_, err = repo.Git("merge-base", "--is-ancestor", "branch1", "octopus")
assert.Nil(t, err)
_, err = repo.Git("merge-base", "--is-ancestor", "branch2", "octopus")
assert.Nil(t, err)
_, err = repo.Git("merge-base", "--is-ancestor", "branch3", "octopus")
assert.Nil(t, err)
}

func TestOctopus2BranchesRecursiveUnresolvedConflict(t *testing.T) {
context, _ := CreateTestContext()
repo := context.Repo
defer test.Cleanup(repo)

// Create and commit file foo1 in branch1
repo.Git("checkout", "-b", "branch1")
writeFile(repo, "foo1", "First line from b1")
repo.Git("add", "foo1")
repo.Git("commit", "-m\"\"")

// Create and commit file foo2 in branch2
repo.Git("checkout", "-b", "branch2", "master")
writeFile(repo, "foo1", "First line from b2")
repo.Git("add", "foo1")
repo.Git("commit", "-m\"\"")

// Merge the 3 branches in a new octopus branch
repo.Git("checkout", "-b", "octopus", "master")

err := Run(context, "-r", "branch*")
assert.EqualError(t, err, "Unresolved merge conflict:\nAA foo1", "There should be a conflict")
}

func TestOctopus2BranchesRecursivePreRecordedConflict(t *testing.T) {
context, _ := CreateTestContext()
repo := context.Repo
defer test.Cleanup(repo)

// Create and commit file foo1 in branch1
repo.Git("checkout", "-b", "branch1")
writeFile(repo, "foo1", "First line from b1")
repo.Git("add", "foo1")
repo.Git("commit", "-m\"\"")

// Create and commit file foo2 in branch2
repo.Git("checkout", "-b", "branch2", "master")
writeFile(repo, "foo1", "First line from b2")
repo.Git("add", "foo1")
repo.Git("commit", "-m\"\"")

repo.Git("checkout", "-b", "rereretrain", "master")
repo.Git("config", "--local", "rerere.enabled", "true")
repo.Git("merge", "branch1")
repo.Git("merge", "branch2")
writeFile(repo, "foo1", "First line from b1\nFirst line from b2")
repo.Git("add", "foo1")
repo.Git("commit", "--no-edit")

// Merge the 3 branches in a new octopus branch
repo.Git("checkout", "-b", "octopus", "master")

err := Run(context, "-r", "branch*")
assert.Nil(t, err)
}

func TestOctopus2BranchesRecursiveFallbackPreRecordedConflict(t *testing.T) {
context, _ := CreateTestContext()
repo := context.Repo
defer test.Cleanup(repo)

// Create and commit file foo1 in branch1
repo.Git("checkout", "-b", "branch1")
writeFile(repo, "foo1", "First line from b1")
repo.Git("add", "foo1")
repo.Git("commit", "-m\"\"")

// Create and commit file foo2 in branch2
repo.Git("checkout", "-b", "branch2", "master")
writeFile(repo, "foo1", "First line from b2")
repo.Git("add", "foo1")
repo.Git("commit", "-m\"\"")

repo.Git("checkout", "-b", "rereretrain", "master")
repo.Git("config", "--local", "rerere.enabled", "true")
repo.Git("merge", "branch1")
repo.Git("merge", "branch2")
writeFile(repo, "foo1", "First line from b1\nFirst line from b2")
repo.Git("add", "foo1")
repo.Git("commit", "--no-edit")

// Merge the 3 branches in a new octopus branch
repo.Git("checkout", "-b", "octopus", "master")

err := Run(context, "-r", "-s=2", "branch*")
assert.Nil(t, err)
}
Loading