Repository: remotemobprogramming/mob
Pull request #180 (2021-06-17 22:19:18)

Multiple wip branches
This is going in the suggested direction.
What do you think?


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a3a1c8e..247730f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,6 @@
+# 1.8.0
+- Allows creating parallel mob-sessions on the same repository more easily.
+
 # 1.7.0
 - `mob branch` shows all remote mob branches currently available.
 
diff --git a/mob.go b/mob.go
index 3cdb5e0..9adc054 100644
--- a/mob.go
+++ b/mob.go
@@ -543,15 +543,6 @@ func start(configuration Configuration) error {
 	git("fetch", configuration.RemoteName, "--prune")
 	currentBaseBranch, currentWipBranch := determineBranches(gitCurrentBranch(), gitBranches(), configuration)
 
-	hasWipBranchesWithQualifier := hasQualifiedBranches(currentBaseBranch, gitRemoteBranches(), configuration)
-
-	if !isMobProgramming(configuration) && hasWipBranchesWithQualifier && !configuration.WipBranchQualifierSet {
-		sayInfo("qualified mob branches detected")
-		sayTodo("To start mob programming, use", "mob start --branch <branch>")
-		sayIndented("(use \"\" for the default mob branch)")
-		return errors.New("qualified mob branches detected")
-	}
-
 	if !hasRemoteBranch(currentBaseBranch, configuration) {
 		sayError("Remote branch " + configuration.RemoteName + "/" + currentBaseBranch + " is missing")
 		sayTodo("To set the upstream branch, use", "git push "+configuration.RemoteName+" "+currentBaseBranch+" --set-upstream")
@@ -563,6 +554,14 @@ func start(configuration Configuration) error {
 		return errors.New("cannot start; unpushed changes on base branch must be pushed upstream")
 	}
 
+	wipBranchesWithQualifier := getQualifiedWipBranches(currentBaseBranch, configuration)
+	if !isMobProgramming(configuration) && !hasRemoteBranch(currentWipBranch, configuration) && len(wipBranchesWithQualifier) > 0 && !configuration.WipBranchQualifierSet {
+		sayWarning("Creating a new mob branch even though preexisting mob branches have been detected.")
+		for _, wipBranch := range wipBranchesWithQualifier {
+			sayWithPrefix(wipBranch, "   - ")
+		}
+	}
+
 	if !isMobProgramming(configuration) {
 		git("merge", "FETCH_HEAD", "--ff-only")
 	}
@@ -603,11 +602,19 @@ func sayUnstagedChangesInfo() {
 	}
 }
 
-func hasQualifiedBranches(currentBaseBranch string, remoteBranches []string, configuration Configuration) bool {
+func getQualifiedWipBranches(currentBaseBranch string, configuration Configuration) []string {
+	remoteBranches := gitRemoteBranches()
 	debugInfo("check on current base branch " + currentBaseBranch + " with remote branches " + strings.Join(remoteBranches, ","))
-	remoteBranchWithQualifier := configuration.RemoteName + "/" + configuration.WipBranchPrefix + currentBaseBranch + configuration.WipBranchQualifierSeparator
-	hasWipBranchesWithQualifier := strings.Contains(strings.Join(remoteBranches, "\n"), remoteBranchWithQualifier)
-	return hasWipBranchesWithQualifier
+	remoteBranchWithQualifier := configuration.RemoteName + "/" + addWipQualifier(configuration.addWipPrefix(currentBaseBranch), configuration)
+
+	var branchesWithQualifier []string
+	for _, remoteBranch := range remoteBranches {
+		if strings.Contains(remoteBranch, remoteBranchWithQualifier) {
+			branchesWithQualifier = append(branchesWithQualifier, remoteBranch)
+		}
+	}
+
+	return branchesWithQualifier
 }
 
 func startJoinMobSession(configuration Configuration) {
@@ -1056,6 +1063,10 @@ func sayInfo(text string) {
 	sayWithPrefix(text, " > ")
 }
 
+func sayWarning(text string) {
+	sayWithPrefix(text, " ⚠ ")
+}
+
 func sayWithPrefix(s string, prefix string) {
 	lines := strings.Split(strings.TrimSpace(s), "\n")
 	for i := 0; i < len(lines); i++ {


Test patch:
diff --git a/mob_test.go b/mob_test.go
index 753642d..5d11519 100644
--- a/mob_test.go
+++ b/mob_test.go
@@ -343,8 +343,9 @@ func TestStartWithMultipleExistingBranches(t *testing.T) {
 
 	configuration.WipBranchQualifier = ""
 	start(configuration)
-	assertOnBranch(t, "master")
-	assertOutputContains(t, output, "qualified mob branches detected")
+	assertOnBranch(t, "mob-session")
+	assertOutputContains(t, output, "preexisting mob branches have been detected")
+	assertOutputContains(t, output, "mob/master-green")
 }
 
 func TestStartWithMultipleExistingBranchesAndEmptyWipBranchQualifier(t *testing.T) {
@@ -412,6 +413,37 @@ func TestStartNextStartWithBranch(t *testing.T) {
 	assertOnBranch(t, "mob/master-green")
 }
 
+func TestStartFromDivergingBranches(t *testing.T) {
+	output, configuration := setup(t)
+	checkoutBranch("feature-something")
+	checkoutBranch("feature-something-2")
+
+	assertOnBranch(t, "feature-something-2")
+	start(configuration)
+	assertOnBranch(t, "mob/feature-something-2")
+	next(configuration)
+
+	git("checkout", "feature-something")
+	start(configuration)
+	assertOnBranch(t, "mob/feature-something")
+	assertOutputContains(t, output, "preexisting mob branches have been detected")
+	assertOutputContains(t, output, "mob/feature-something-2")
+}
+
+func TestStartFromDivergingBranches_noWarning(t *testing.T) {
+	output, configuration := setup(t)
+	checkoutBranch("mob/feature-something")
+	checkoutBranch("feature-something")
+	checkoutBranch("mob/feature-something-2")
+	checkoutBranch("feature-something-2")
+
+	assertOnBranch(t, "feature-something-2")
+	start(configuration)
+	assertOnBranch(t, "mob/feature-something-2")
+
+	assertOutputNotContains(t, output, "qualified mob branches detected")
+}
+
 func TestStartNextOnFeatureWithBranch(t *testing.T) {
 	_, configuration := setup(t)
 	configuration.WipBranchQualifier = "green"
@@ -1056,3 +1088,8 @@ func failWithFailure(t *testing.T, exp interface{}, act interface{}) {
 	fmt.Printf("\033[31m%s:%d:\n\n\texp: %#v\n\n\tgot: %#v\033[39m\n\n", filepath.Base(file), line, exp, act)
 	t.FailNow()
 }
+
+func checkoutBranch(datBranch string) {
+	git("checkout", "-b", datBranch)
+	git("push", "origin", datBranch, "--set-upstream")
+}