Skip to content

Commit 4df7bd2

Browse files
committed
added project specific configuration file
1 parent 75a2f28 commit 4df7bd2

File tree

4 files changed

+102
-9
lines changed

4 files changed

+102
-9
lines changed

.mob

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
MOB_TIMER_ROOM="mob"

CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# 2.4.0
2-
- As an alternative to the environment variables, you can configure the mob tool with a `.mob` file in your home directory. For an example have a look at `mob-configuration-example` file.
2+
- As an alternative to the environment variables, you can configure the mob tool with a `.mob` file in your home directory. For an example have a look at `mob-configuration-example` file.
3+
- As an alternative to the environment variables, you can configure the mob tool with a `.mob` file in your git project root directory. The configuration options `MOB_VOICE_COMMAND`, `MOB_VOICE_MESSAGE`, `MOB_NOTIFY_COMMAND`, and `MOB_NOTIFY_MESSAGE` are disabled for the project specific configuration to prevent bash injection attacks.
4+
Thanks to @vrpntngr & @hollesse making this release possible as part of the @INNOQ Hands-On Event, February 2022.
35

46
# 2.3.0
57
- With `export MOB_TIMER_ROOM_USE_WIP_BRANCH_QUALIFIER=true` the room name is automatically derived from the value you passed in via the `mob start --branch <branch>` parameter.

mob.go

Lines changed: 88 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"net/http"
1111
"os"
1212
"os/exec"
13+
"os/user"
1314
"reflect"
1415
"runtime"
1516
"strconv"
@@ -211,7 +212,13 @@ func main() {
211212

212213
configuration := getDefaultConfiguration()
213214
configuration = parseEnvironmentVariables(configuration)
214-
configuration = parseSettings(configuration, userConfigurationPath)
215+
216+
currentUser, _ := user.Current()
217+
userConfigurationPath = currentUser.HomeDir + "/.mob"
218+
configuration = parseConfiguration(configuration, userConfigurationPath)
219+
if isGit() {
220+
configuration = parseProjectConfiguration(configuration, gitRootDir()+"/.mob")
221+
}
215222
debugInfo("Args '" + strings.Join(os.Args, " ") + "'")
216223
currentCliName := currentCliName(os.Args[0])
217224
if currentCliName != configuration.CliName {
@@ -287,12 +294,14 @@ func (c Configuration) mob(command string) string {
287294
return c.CliName + " " + command
288295
}
289296

290-
func parseSettings(configuration Configuration, path string) Configuration {
297+
func parseConfiguration(configuration Configuration, path string) Configuration {
291298
file, err := os.Open(path)
292299

293300
if err != nil {
294-
debugInfo(`No configuration file found.`)
301+
debugInfo("No configuration file found. (" + path + ") Error: " + err.Error())
295302
return configuration
303+
} else {
304+
debugInfo("Found configuration file at " + path)
296305
}
297306

298307
fileScanner := bufio.NewScanner(file)
@@ -362,6 +371,77 @@ func parseSettings(configuration Configuration, path string) Configuration {
362371
return configuration
363372
}
364373

374+
func parseProjectConfiguration(configuration Configuration, path string) Configuration {
375+
file, err := os.Open(path)
376+
377+
if err != nil {
378+
debugInfo("No configuration file found. (" + path + ") Error: " + err.Error())
379+
return configuration
380+
} else {
381+
debugInfo("Found configuration file at " + path)
382+
}
383+
384+
fileScanner := bufio.NewScanner(file)
385+
386+
for fileScanner.Scan() {
387+
line := strings.TrimSpace(fileScanner.Text())
388+
debugInfo(line)
389+
if !strings.Contains(line, "=") {
390+
debugInfo("Skip line because line contains no =. Line=" + line)
391+
continue
392+
}
393+
key := line[0:strings.Index(line, "=")]
394+
value := strings.TrimPrefix(line, key+"=")
395+
debugInfo("Key is " + key)
396+
debugInfo("Value is " + value)
397+
switch key {
398+
case "MOB_VOICE_COMMAND", "MOB_VOICE_MESSAGE", "MOB_NOTIFY_COMMAND", "MOB_NOTIFY_MESSAGE":
399+
sayWarning("Skipped overwriting key " + key + " from project/.mob file out of security reasons!")
400+
case "MOB_CLI_NAME":
401+
setUnquotedString(&configuration.CliName, key, value)
402+
case "MOB_REMOTE_NAME":
403+
setUnquotedString(&configuration.RemoteName, key, value)
404+
case "MOB_WIP_COMMIT_MESSAGE":
405+
setUnquotedString(&configuration.WipCommitMessage, key, value)
406+
case "MOB_REQUIRE_COMMIT_MESSAGE":
407+
setBoolean(&configuration.RequireCommitMessage, key, value)
408+
case "MOB_NEXT_STAY":
409+
setBoolean(&configuration.NextStay, key, value)
410+
case "MOB_START_INCLUDE_UNCOMMITTED_CHANGES":
411+
setBoolean(&configuration.StartIncludeUncommittedChanges, key, value)
412+
case "MOB_WIP_BRANCH_QUALIFIER":
413+
setUnquotedString(&configuration.WipBranchQualifier, key, value)
414+
case "MOB_WIP_BRANCH_QUALIFIER_SEPARATOR":
415+
setUnquotedString(&configuration.WipBranchQualifierSeparator, key, value)
416+
case "MOB_DONE_SQUASH":
417+
setBoolean(&configuration.DoneSquash, key, value)
418+
case "MOB_TIMER":
419+
setUnquotedString(&configuration.Timer, key, value)
420+
case "MOB_TIMER_ROOM":
421+
setUnquotedString(&configuration.TimerRoom, key, value)
422+
case "MOB_TIMER_ROOM_USE_WIP_BRANCH_QUALIFIER":
423+
setBoolean(&configuration.TimerRoomUseWipBranchQualifier, key, value)
424+
case "MOB_TIMER_LOCAL":
425+
setBoolean(&configuration.TimerLocal, key, value)
426+
case "MOB_TIMER_USER":
427+
setUnquotedString(&configuration.TimerUser, key, value)
428+
case "MOB_TIMER_URL":
429+
setUnquotedString(&configuration.TimerUrl, key, value)
430+
case "MOB_STASH_NAME":
431+
setUnquotedString(&configuration.StashName, key, value)
432+
433+
default:
434+
continue
435+
}
436+
}
437+
438+
if err := fileScanner.Err(); err != nil {
439+
sayWarning("Configuration file exists, but could not be read. (" + path + ")")
440+
}
441+
442+
return configuration
443+
}
444+
365445
func setUnquotedString(s *string, key string, value string) {
366446
unquotedValue, err := strconv.Unquote(value)
367447
if err != nil {
@@ -493,7 +573,7 @@ func config(c Configuration) {
493573
say("MOB_WIP_BRANCH_QUALIFIER" + "=" + quote(c.WipBranchQualifier))
494574
say("MOB_WIP_BRANCH_QUALIFIER_SEPARATOR" + "=" + quote(c.WipBranchQualifierSeparator))
495575
say("MOB_DONE_SQUASH" + "=" + strconv.FormatBool(c.DoneSquash))
496-
say("MOB_TIMER" + "=" + c.Timer)
576+
say("MOB_TIMER" + "=" + quote(c.Timer))
497577
say("MOB_TIMER_ROOM" + "=" + quote(c.TimerRoom))
498578
say("MOB_TIMER_ROOM_USE_WIP_BRANCH_QUALIFIER" + "=" + strconv.FormatBool(c.TimerRoomUseWipBranchQualifier))
499579
say("MOB_TIMER_LOCAL" + "=" + strconv.FormatBool(c.TimerLocal))
@@ -1133,6 +1213,10 @@ func gitDir() string {
11331213
return silentgit("rev-parse", "--absolute-git-dir")
11341214
}
11351215

1216+
func gitRootDir() string {
1217+
return strings.TrimSuffix(gitDir(), "/.git")
1218+
}
1219+
11361220
func squashOrNoCommit(configuration Configuration) string {
11371221
if configuration.DoneSquash {
11381222
return "--squash"

mob_test.go

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,7 @@ func TestReadConfigurationFromFileOverrideEverything(t *testing.T) {
339339
MOB_TIMER_URL="https://timer.innoq.io/"
340340
MOB_STASH_NAME="team-stash-name"
341341
`)
342-
actualConfiguration := parseSettings(getDefaultConfiguration(), tempDir+"/.mob")
342+
actualConfiguration := parseConfiguration(getDefaultConfiguration(), tempDir+"/.mob")
343343
equals(t, "team", actualConfiguration.CliName)
344344
equals(t, "gitlab", actualConfiguration.RemoteName)
345345
equals(t, "team next", actualConfiguration.WipCommitMessage)
@@ -362,7 +362,7 @@ func TestReadConfigurationFromFileOverrideEverything(t *testing.T) {
362362
equals(t, "team-stash-name", actualConfiguration.StashName)
363363

364364
createFile(t, ".mob", "\nMOB_TIMER_ROOM=\"Room\\\"\\\"_42\"\n")
365-
actualConfiguration1 := parseSettings(getDefaultConfiguration(), tempDir+"/.mob")
365+
actualConfiguration1 := parseConfiguration(getDefaultConfiguration(), tempDir+"/.mob")
366366
equals(t, "Room\"\"_42", actualConfiguration1.TimerRoom)
367367
}
368368

@@ -372,7 +372,7 @@ func TestReadConfigurationFromFileAndSkipBrokenLines(t *testing.T) {
372372
setWorkingDir(tempDir)
373373

374374
createFile(t, ".mob", "\nMOB_TIMER_ROOM=\"Broken\" \"String\"")
375-
actualConfiguration := parseSettings(getDefaultConfiguration(), tempDir+"/.mob")
375+
actualConfiguration := parseConfiguration(getDefaultConfiguration(), tempDir+"/.mob")
376376
equals(t, getDefaultConfiguration().TimerRoom, actualConfiguration.TimerRoom)
377377
}
378378

@@ -381,7 +381,7 @@ func TestSkipIfConfigurationDoesNotExist(t *testing.T) {
381381
tempDir = t.TempDir()
382382
setWorkingDir(tempDir)
383383

384-
actualConfiguration := parseSettings(getDefaultConfiguration(), tempDir+"/.mob")
384+
actualConfiguration := parseConfiguration(getDefaultConfiguration(), tempDir+"/.mob")
385385
equals(t, getDefaultConfiguration(), actualConfiguration)
386386
}
387387

@@ -847,6 +847,12 @@ func TestStartDoneLocalFeatureBranch(t *testing.T) {
847847
assertOutputContains(t, output, "git push origin feature1 --set-upstream")
848848
}
849849

850+
func TestGitRootDir(t *testing.T) {
851+
setup(t)
852+
expectedPath, _ := filepath.EvalSymlinks(tempDir + "/local")
853+
equals(t, expectedPath, gitRootDir());
854+
}
855+
850856
func TestBothCreateNonemptyCommitWithNext(t *testing.T) {
851857
_, configuration := setup(t)
852858

0 commit comments

Comments
 (0)