Skip to content

Commit

Permalink
added project specific configuration file
Browse files Browse the repository at this point in the history
  • Loading branch information
hollesse committed Feb 11, 2022
1 parent 75a2f28 commit 4df7bd2
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 9 deletions.
1 change: 1 addition & 0 deletions .mob
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
MOB_TIMER_ROOM="mob"
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# 2.4.0
- 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.
- 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.
- 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.
Thanks to @vrpntngr & @hollesse making this release possible as part of the @INNOQ Hands-On Event, February 2022.

# 2.3.0
- 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.
Expand Down
92 changes: 88 additions & 4 deletions mob.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"net/http"
"os"
"os/exec"
"os/user"
"reflect"
"runtime"
"strconv"
Expand Down Expand Up @@ -211,7 +212,13 @@ func main() {

configuration := getDefaultConfiguration()
configuration = parseEnvironmentVariables(configuration)
configuration = parseSettings(configuration, userConfigurationPath)

currentUser, _ := user.Current()
userConfigurationPath = currentUser.HomeDir + "/.mob"
configuration = parseConfiguration(configuration, userConfigurationPath)
if isGit() {
configuration = parseProjectConfiguration(configuration, gitRootDir()+"/.mob")
}
debugInfo("Args '" + strings.Join(os.Args, " ") + "'")
currentCliName := currentCliName(os.Args[0])
if currentCliName != configuration.CliName {
Expand Down Expand Up @@ -287,12 +294,14 @@ func (c Configuration) mob(command string) string {
return c.CliName + " " + command
}

func parseSettings(configuration Configuration, path string) Configuration {
func parseConfiguration(configuration Configuration, path string) Configuration {
file, err := os.Open(path)

if err != nil {
debugInfo(`No configuration file found.`)
debugInfo("No configuration file found. (" + path + ") Error: " + err.Error())
return configuration
} else {
debugInfo("Found configuration file at " + path)
}

fileScanner := bufio.NewScanner(file)
Expand Down Expand Up @@ -362,6 +371,77 @@ func parseSettings(configuration Configuration, path string) Configuration {
return configuration
}

func parseProjectConfiguration(configuration Configuration, path string) Configuration {
file, err := os.Open(path)

if err != nil {
debugInfo("No configuration file found. (" + path + ") Error: " + err.Error())
return configuration
} else {
debugInfo("Found configuration file at " + path)
}

fileScanner := bufio.NewScanner(file)

for fileScanner.Scan() {
line := strings.TrimSpace(fileScanner.Text())
debugInfo(line)
if !strings.Contains(line, "=") {
debugInfo("Skip line because line contains no =. Line=" + line)
continue
}
key := line[0:strings.Index(line, "=")]
value := strings.TrimPrefix(line, key+"=")
debugInfo("Key is " + key)
debugInfo("Value is " + value)
switch key {
case "MOB_VOICE_COMMAND", "MOB_VOICE_MESSAGE", "MOB_NOTIFY_COMMAND", "MOB_NOTIFY_MESSAGE":
sayWarning("Skipped overwriting key " + key + " from project/.mob file out of security reasons!")
case "MOB_CLI_NAME":
setUnquotedString(&configuration.CliName, key, value)
case "MOB_REMOTE_NAME":
setUnquotedString(&configuration.RemoteName, key, value)
case "MOB_WIP_COMMIT_MESSAGE":
setUnquotedString(&configuration.WipCommitMessage, key, value)
case "MOB_REQUIRE_COMMIT_MESSAGE":
setBoolean(&configuration.RequireCommitMessage, key, value)
case "MOB_NEXT_STAY":
setBoolean(&configuration.NextStay, key, value)
case "MOB_START_INCLUDE_UNCOMMITTED_CHANGES":
setBoolean(&configuration.StartIncludeUncommittedChanges, key, value)
case "MOB_WIP_BRANCH_QUALIFIER":
setUnquotedString(&configuration.WipBranchQualifier, key, value)
case "MOB_WIP_BRANCH_QUALIFIER_SEPARATOR":
setUnquotedString(&configuration.WipBranchQualifierSeparator, key, value)
case "MOB_DONE_SQUASH":
setBoolean(&configuration.DoneSquash, key, value)
case "MOB_TIMER":
setUnquotedString(&configuration.Timer, key, value)
case "MOB_TIMER_ROOM":
setUnquotedString(&configuration.TimerRoom, key, value)
case "MOB_TIMER_ROOM_USE_WIP_BRANCH_QUALIFIER":
setBoolean(&configuration.TimerRoomUseWipBranchQualifier, key, value)
case "MOB_TIMER_LOCAL":
setBoolean(&configuration.TimerLocal, key, value)
case "MOB_TIMER_USER":
setUnquotedString(&configuration.TimerUser, key, value)
case "MOB_TIMER_URL":
setUnquotedString(&configuration.TimerUrl, key, value)
case "MOB_STASH_NAME":
setUnquotedString(&configuration.StashName, key, value)

default:
continue
}
}

if err := fileScanner.Err(); err != nil {
sayWarning("Configuration file exists, but could not be read. (" + path + ")")
}

return configuration
}

func setUnquotedString(s *string, key string, value string) {
unquotedValue, err := strconv.Unquote(value)
if err != nil {
Expand Down Expand Up @@ -493,7 +573,7 @@ func config(c Configuration) {
say("MOB_WIP_BRANCH_QUALIFIER" + "=" + quote(c.WipBranchQualifier))
say("MOB_WIP_BRANCH_QUALIFIER_SEPARATOR" + "=" + quote(c.WipBranchQualifierSeparator))
say("MOB_DONE_SQUASH" + "=" + strconv.FormatBool(c.DoneSquash))
say("MOB_TIMER" + "=" + c.Timer)
say("MOB_TIMER" + "=" + quote(c.Timer))
say("MOB_TIMER_ROOM" + "=" + quote(c.TimerRoom))
say("MOB_TIMER_ROOM_USE_WIP_BRANCH_QUALIFIER" + "=" + strconv.FormatBool(c.TimerRoomUseWipBranchQualifier))
say("MOB_TIMER_LOCAL" + "=" + strconv.FormatBool(c.TimerLocal))
Expand Down Expand Up @@ -1133,6 +1213,10 @@ func gitDir() string {
return silentgit("rev-parse", "--absolute-git-dir")
}

func gitRootDir() string {
return strings.TrimSuffix(gitDir(), "/.git")
}

func squashOrNoCommit(configuration Configuration) string {
if configuration.DoneSquash {
return "--squash"
Expand Down
14 changes: 10 additions & 4 deletions mob_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ func TestReadConfigurationFromFileOverrideEverything(t *testing.T) {
MOB_TIMER_URL="https://timer.innoq.io/"
MOB_STASH_NAME="team-stash-name"
`)
actualConfiguration := parseSettings(getDefaultConfiguration(), tempDir+"/.mob")
actualConfiguration := parseConfiguration(getDefaultConfiguration(), tempDir+"/.mob")
equals(t, "team", actualConfiguration.CliName)
equals(t, "gitlab", actualConfiguration.RemoteName)
equals(t, "team next", actualConfiguration.WipCommitMessage)
Expand All @@ -362,7 +362,7 @@ func TestReadConfigurationFromFileOverrideEverything(t *testing.T) {
equals(t, "team-stash-name", actualConfiguration.StashName)

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

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

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

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

actualConfiguration := parseSettings(getDefaultConfiguration(), tempDir+"/.mob")
actualConfiguration := parseConfiguration(getDefaultConfiguration(), tempDir+"/.mob")
equals(t, getDefaultConfiguration(), actualConfiguration)
}

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

func TestGitRootDir(t *testing.T) {
setup(t)
expectedPath, _ := filepath.EvalSymlinks(tempDir + "/local")
equals(t, expectedPath, gitRootDir());
}

func TestBothCreateNonemptyCommitWithNext(t *testing.T) {
_, configuration := setup(t)

Expand Down

0 comments on commit 4df7bd2

Please sign in to comment.