Repository: remotemobprogramming/mob
Pull request #430 (2024-06-28 07:43:39)

Goals


Patch:
diff --git a/README.md b/README.md
index 9f7a30f..e10bce7 100644
--- a/README.md
+++ b/README.md
@@ -196,6 +196,9 @@ Timer Commands:
     [--room <room-name>]    Set room name for timer.mob.sh once
   start <minutes>           Start mob session in wip branch and a <minutes> timer
   break <minutes>           Start a <minutes> break timer
+  goal                      Gives you the current goal of your timer.mob.sh room
+    [<your-goal>]           Sets the goal of your timer.mob.sh room
+    [--delete]              Deletes the goal of your timer.mob.sh room
 
 Short Commands (Options and descriptions as above):
   s                  alias for 'start'
@@ -203,6 +206,7 @@ Short Commands (Options and descriptions as above):
   d                  alias for 'done'
   b                  alias for 'branch'
   t                  alias for 'timer'
+  g                  Alias for 'goal'
 
 Get more information:
   status             show the status of the current session
@@ -473,7 +477,6 @@ go test -coverprofile=cover.out && go tool cover -html=cover.out
 - [BLUME2000](https://twitter.com/slashBene/status/1337329356637687811?s=20)
 - [REWE Digital](https://www.rewe-digital.com/)
 - [Amadeus IT Group](https://amadeus.com/)
-- [DB Systel GmbH](https://www.dbsystel.de/)
 - [FlixMobility TECH (FlixBus)](https://www.flixbus.com/)
 - And probably many others who shall not be named.
 
diff --git a/goal/goal.go b/goal/goal.go
new file mode 100644
index 0000000..aa20449
--- /dev/null
+++ b/goal/goal.go
@@ -0,0 +1,132 @@
+package goal
+
+import (
+	"encoding/json"
+	"errors"
+	"fmt"
+	config "github.com/remotemobprogramming/mob/v4/configuration"
+	"github.com/remotemobprogramming/mob/v4/httpclient"
+	"github.com/remotemobprogramming/mob/v4/say"
+	"io"
+	"os"
+	"strings"
+)
+
+type GoalResponse struct {
+	Goal string `json:"goal"`
+}
+
+type DeleteGoalRequest struct {
+	User string `json:"user"`
+}
+
+type PutGoalRequest struct {
+	Goal string `json:"goal"`
+	User string `json:"user"`
+}
+
+func Goal(configuration config.Configuration, parameter []string) {
+	if err := goal(configuration, parameter); err != nil {
+		say.Error(err.Error())
+		exit(1)
+	}
+}
+
+func goal(configuration config.Configuration, parameter []string) error {
+	if configuration.TimerRoom == "" {
+		return errors.New("No room sepcified. Set MOB_TIMER_ROOM to your timer.mob.sh room in .mob file.")
+	}
+	var err error
+	if len(parameter) <= 0 {
+		err = showGoal(configuration)
+	} else if parameter[0] == "--delete" {
+		err = deleteCurrentGoal(configuration)
+	} else {
+		err = setNewGoal(configuration, strings.Join(parameter, " "))
+	}
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+func setNewGoal(configuration config.Configuration, goal string) error {
+	if err := putGoalHttp(goal, configuration); err != nil {
+		say.Debug(err.Error())
+		return errors.New("Could not set new goal. An error occurred while sending the request.")
+	}
+	say.Info(fmt.Sprintf("Set new goal to \"%s\"", goal))
+	return nil
+}
+
+func putGoalHttp(goal string, configuration config.Configuration) error {
+	requestBody, err := json.Marshal(PutGoalRequest{Goal: goal, User: configuration.TimerUser})
+	if err != nil {
+		return err
+	}
+	_, err = httpclient.SendRequest(requestBody, "PUT", getGoalUrl(configuration), configuration.TimerInsecure)
+	return err
+}
+
+func getGoalUrl(configuration config.Configuration) string {
+	return configuration.TimerUrl + configuration.TimerRoom + "/goal"
+}
+
+func deleteCurrentGoal(configuration config.Configuration) error {
+	err := deleteGoalHttp(configuration.TimerRoom, configuration.TimerUser, configuration.TimerUrl, configuration.TimerInsecure)
+	if err != nil {
+		say.Debug(err.Error())
+		return errors.New("Could not delete goal. An error occurred while sending the request.")
+	}
+	say.Info("Current goal has been deleted!")
+	return nil
+}
+
+func deleteGoalHttp(room string, user string, timerService string, disableSslVerification bool) error {
+	requestBody, err := json.Marshal(DeleteGoalRequest{User: user})
+	if err != nil {
+		return err
+	}
+	_, err = httpclient.SendRequest(requestBody, "DELETE", timerService+room+"/goal", disableSslVerification)
+	return err
+}
+
+func showGoal(configuration config.Configuration) error {
+	goal, err := getGoalHttp(configuration.TimerRoom, configuration.TimerUrl, configuration.TimerInsecure)
+	if err != nil {
+		say.Debug(err.Error())
+		return errors.New("Could not get goal. An error occurred while sending the request.")
+	}
+	if goal == "" {
+		say.Fix("No goal set. To set a goal, use", configuration.Mob("goal <your awesome goal>"))
+		return nil
+	}
+	say.Info(goal)
+	return nil
+}
+func getGoalHttp(room string, timerService string, disableSslVerification bool) (string, error) {
+	url := timerService + room + "/goal"
+	response, err := httpclient.GetHttpClient(disableSslVerification).Get(url)
+	if err != nil {
+		say.Debug(err.Error())
+		return "", err
+	}
+	if response.StatusCode >= 300 {
+		return "", errors.New("got an error while requesting it: " + url + " " + response.Status)
+	}
+	body, err := io.ReadAll(response.Body)
+	if err != nil {
+		say.Debug(err.Error())
+		return "", err
+	}
+	var goalResponse GoalResponse
+	if err := json.Unmarshal(body, &goalResponse); err != nil {
+		say.Debug(err.Error())
+		return "", err
+	}
+	return goalResponse.Goal, nil
+}
+
+var exit = func(code int) {
+	os.Exit(code)
+}
diff --git a/help/help.go b/help/help.go
index 501e2d7..c65eed6 100644
--- a/help/help.go
+++ b/help/help.go
@@ -39,6 +39,9 @@ Timer Commands:
     [--room <room-name>]    Set room name for timer.mob.sh once
   start <minutes>           Start mob session in wip branch and a <minutes> timer
   break <minutes>           Start a <minutes> break timer
+  goal                      Gives you the current goal of your timer.mob.sh room
+    [<your-goal>]           Sets the goal of your timer.mob.sh room
+    [--delete]              Deletes the goal of your timer.mob.sh room
 
 Short Commands (Options and descriptions as above):
   s                  Alias for 'start'
@@ -46,6 +49,7 @@ Short Commands (Options and descriptions as above):
   d                  Alias for 'done'
   b                  Alias for 'branch'
   t                  Alias for 'timer'
+  g                  Alias for 'goal'
 
 Get more information:
   status             Show status of the current session
diff --git a/httpclient/httpclient.go b/httpclient/httpclient.go
new file mode 100644
index 0000000..314ccb0
--- /dev/null
+++ b/httpclient/httpclient.go
@@ -0,0 +1,85 @@
+package httpclient
+
+import (
+	"bytes"
+	"crypto/tls"
+	"crypto/x509"
+	"errors"
+	"fmt"
+	"github.com/remotemobprogramming/mob/v4/say"
+	"io/ioutil"
+	"net/http"
+	"net/url"
+)
+
+func GetHttpClient(disableSSLVerification bool) *http.Client {
+	if disableSSLVerification {
+		transCfg := &http.Transport{
+			TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
+		}
+		return &http.Client{Transport: transCfg}
+	}
+	return http.DefaultClient
+}
+
+func SendRequest(requestBody []byte, requestMethod string, requestUrl string, disableSSLVerification bool) (string, error) {
+	say.Info(requestMethod + " " + requestUrl + " " + string(requestBody))
+
+	responseBody := bytes.NewBuffer(requestBody)
+	request, requestCreationError := http.NewRequest(requestMethod, requestUrl, responseBody)
+
+	httpClient := http.DefaultClient
+	if disableSSLVerification {
+		transCfg := &http.Transport{
+			TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
+		}
+		httpClient = &http.Client{Transport: transCfg}
+	}
+
+	if requestCreationError != nil {
+		return "", fmt.Errorf("failed to create the http request object: %w", requestCreationError)
+	}
+
+	request.Header.Set("Content-Type", "application/json")
+	response, responseErr := httpClient.Do(request)
+	if e, ok := responseErr.(*url.Error); ok {
+		switch e.Err.(type) {
+		case x509.UnknownAuthorityError:
+			say.Error("The timer.mob.sh SSL certificate is signed by an unknown authority!")
+			say.Fix("HINT: You can ignore that by adding MOB_TIMER_INSECURE=true to your configuration or environment.",
+				"echo MOB_TIMER_INSECURE=true >> ~/.mob")
+			return "", fmt.Errorf("failed, to make the http request: %w", responseErr)
+
+		default:
+			return "", fmt.Errorf("failed to make the http request: %w", responseErr)
+
+		}
+	}
+
+	if responseErr != nil {
+		return "", fmt.Errorf("failed to make the http request: %w", responseErr)
+	}
+	if response.StatusCode >= 300 {
+		return "", errors.New("got an error from the server: " + requestUrl + " " + response.Status)
+	}
+	defer response.Body.Close()
+	bodyBytes, responseReadingErr := ioutil.ReadAll(response.Body)
+	body := string(bodyBytes)
+	if responseReadingErr != nil {
+		return "", fmt.Errorf("failed to read the http response: %w", responseReadingErr)
+	}
+	if string(body) != "" {
+		say.Info(body)
+	}
+	return body, nil
+}
+
+func getHttpClient(disableSSLVerification bool) *http.Client {
+	if disableSSLVerification {
+		transCfg := &http.Transport{
+			TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
+		}
+		return &http.Client{Transport: transCfg}
+	}
+	return http.DefaultClient
+}
diff --git a/mob.go b/mob.go
index b197fae..2a65d46 100644
--- a/mob.go
+++ b/mob.go
@@ -5,6 +5,7 @@ import (
 	"errors"
 	"fmt"
 	config "github.com/remotemobprogramming/mob/v4/configuration"
+	"github.com/remotemobprogramming/mob/v4/goal"
 	"github.com/remotemobprogramming/mob/v4/help"
 	"github.com/remotemobprogramming/mob/v4/open"
 	"github.com/remotemobprogramming/mob/v4/say"
@@ -240,14 +241,14 @@ func run(osArgs []string) {
 	if versionString == "" {
 		say.Error("'git' command was not found in PATH. It may be not installed. " +
 			"To learn how to install 'git' refer to https://git-scm.com/book/en/v2/Getting-Started-Installing-Git.")
-		Exit(1)
+		exit(1)
 	}
 
 	currentVersion := parseGitVersion(versionString)
 	if currentVersion.Less(parseGitVersion(minimumGitVersion)) {
 		say.Error(fmt.Sprintf("'git' command version '%s' is lower than the required minimum version (%s). "+
 			"Please update your 'git' installation!", versionString, minimumGitVersion))
-		Exit(1)
+		exit(1)
 	}
 
 	projectRootDir := ""
@@ -255,7 +256,7 @@ func run(osArgs []string) {
 		projectRootDir = gitRootDir()
 		if !hasCommits() {
 			say.Error("Git repository does not have any commits yet. Please create an initial commit.")
-			Exit(1)
+			exit(1)
 		}
 	}
 
@@ -300,7 +301,7 @@ func execute(command string, parameter []string, configuration config.Configurat
 	case "s", "start":
 		err := start(configuration)
 		if !isMobProgramming(configuration) || err != nil {
-			Exit(1)
+			return
 		}
 		if len(parameter) > 0 {
 			timer := parameter[0]
@@ -355,6 +356,8 @@ func execute(command string, parameter []string, configuration config.Configurat
 		} else if len(parameter) > 1 && parameter[0] == "--git-sequence-editor" {
 			squashWipGitSequenceEditor(parameter[1], configuration)
 		}
+	case "g", "goal":
+		goal.Goal(configuration, parameter)
 	case "version", "--version", "-v":
 		version()
 	case "help", "--help", "-h":
@@ -455,7 +458,7 @@ func injectCommandWithMessage(command string, message string) string {
 	placeHolders := strings.Count(command, "%s")
 	if placeHolders > 1 {
 		say.Error(fmt.Sprintf("Too many placeholders (%d) in format command string: %s", placeHolders, command))
-		Exit(1)
+		exit(1)
 	}
 	if placeHolders == 0 {
 		return fmt.Sprintf("%s %s", command, message)
@@ -528,7 +531,7 @@ func start(configuration config.Configuration) error {
 		say.Info("cannot start; clean working tree required")
 		sayUnstagedChangesInfo()
 		sayUntrackedFilesInfo()
-		sayFixUncommittedChanges(configuration)
+		sayFixUncommitedChanges(configuration)
 		return errors.New("cannot start; clean working tree required")
 	}
 
@@ -586,31 +589,19 @@ func start(configuration config.Configuration) error {
 	return nil // no error
 }
 
-func sayFixUncommittedChanges(configuration config.Configuration) {
-	var instruction string
+func sayFixUncommitedChanges(configuration config.Configuration) {
+	fixCommand := configuration.CliName + " start"
+	instruction := "To start, including uncommitted changes, use"
 	if configuration.StartCreate {
 		instruction = "To start, including uncommitted changes and create the remote branch, use"
-	} else {
-		instruction = "To start, including uncommitted changes, use"
+		fixCommand += " --create"
 	}
-
-	fixCommand := configuration.CliName + " start" + createFix(configuration) + branchFix(configuration) + " --include-uncommitted-changes"
-
-	say.Fix(instruction, fixCommand)
-}
-
-func createFix(configuration config.Configuration) string {
-	if configuration.StartCreate {
-		return " --create"
+	if containsAny(args, "-b", "--branch") && configuration.WipBranchQualifier != "" {
+		fixCommand += " --branch " + configuration.WipBranchQualifier
 	}
-	return ""
-}
+	fixCommand += " --include-uncommitted-changes"
 
-func branchFix(configuration config.Configuration) string {
-	if branchParameter(configuration) {
-		return " --branch " + configuration.WipBranchQualifier
-	}
-	return ""
+	say.Fix(instruction, fixCommand)
 }
 
 func branchParameter(configuration config.Configuration) bool {
@@ -1108,7 +1099,7 @@ func silentgit(args ...string) string {
 			say.Error(output)
 			say.Error(err.Error())
 		}
-		Exit(1)
+		exit(1)
 	}
 	return strings.TrimSpace(output)
 }
@@ -1138,7 +1129,6 @@ func gitWithoutEmptyStrings(args ...string) {
 }
 
 func git(args ...string) {
-	say.Indented("git " + strings.Join(args, " "))
 	commandString, output, err := "", "", error(nil)
 	if GitPassthroughStderrStdout {
 		commandString, output, err = runCommand("git", args...)
@@ -1154,7 +1144,9 @@ func git(args ...string) {
 			say.Error(output)
 			say.Error(err.Error())
 		}
-		Exit(1)
+		exit(1)
+	} else {
+		say.Indented(commandString)
 	}
 }
 
@@ -1169,7 +1161,7 @@ func gitIgnoreFailure(args ...string) error {
 	if err != nil {
 		if !isGit() {
 			say.Error("expecting the current working directory to be a git repository.")
-			Exit(1)
+			exit(1)
 		} else {
 			say.Warning(commandString)
 			say.Warning(output)
@@ -1268,6 +1260,6 @@ func startCommand(name string, args ...string) (string, error) {
 	return commandString, err
 }
 
-var Exit = func(code int) {
+var exit = func(code int) {
 	os.Exit(code)
 }
diff --git a/open/open_unix.go b/open/open_linux.go
similarity index 100%
rename from open/open_unix.go
rename to open/open_linux.go
diff --git a/timer.go b/timer.go
index c7e1e78..8367a4c 100644
--- a/timer.go
+++ b/timer.go
@@ -1,17 +1,12 @@
 package main
 
 import (
-	"bytes"
-	"crypto/tls"
-	"crypto/x509"
 	"encoding/json"
 	"errors"
 	"fmt"
 	config "github.com/remotemobprogramming/mob/v4/configuration"
+	"github.com/remotemobprogramming/mob/v4/httpclient"
 	"github.com/remotemobprogramming/mob/v4/say"
-	"io"
-	"net/http"
-	"net/url"
 	"runtime"
 	"strconv"
 	"time"
@@ -19,7 +14,7 @@ import (
 
 func StartTimer(timerInMinutes string, configuration config.Configuration) {
 	if err := startTimer(configuration.Timer, configuration); err != nil {
-		Exit(1)
+		exit(1)
 	}
 }
 
@@ -39,7 +34,7 @@ func startTimer(timerInMinutes string, configuration config.Configuration) error
 
 	if !startRemoteTimer && !startLocalTimer {
 		say.Error("No timer configured, not starting timer")
-		Exit(1)
+		exit(1)
 	}
 
 	if startRemoteTimer {
@@ -48,7 +43,7 @@ func startTimer(timerInMinutes string, configuration config.Configuration) error
 		if err != nil {
 			say.Error("remote timer couldn't be started")
 			say.Error(err.Error())
-			Exit(1)
+			exit(1)
 		}
 	}
 
@@ -58,7 +53,7 @@ func startTimer(timerInMinutes string, configuration config.Configuration) error
 		if err != nil {
 			say.Error(fmt.Sprintf("timer couldn't be started on your system (%s)", runtime.GOOS))
 			say.Error(err.Error())
-			Exit(1)
+			exit(1)
 		}
 	}
 
@@ -93,7 +88,7 @@ func getMobTimerRoom(configuration config.Configuration) string {
 
 func StartBreakTimer(timerInMinutes string, configuration config.Configuration) {
 	if err := startBreakTimer(configuration.Timer, configuration); err != nil {
-		Exit(1)
+		exit(1)
 	}
 }
 
@@ -113,7 +108,7 @@ func startBreakTimer(timerInMinutes string, configuration config.Configuration)
 
 	if !startRemoteTimer && !startLocalTimer {
 		say.Error("No break timer configured, not starting break timer")
-		Exit(1)
+		exit(1)
 	}
 
 	if startRemoteTimer {
@@ -123,7 +118,7 @@ func startBreakTimer(timerInMinutes string, configuration config.Configuration)
 		if err != nil {
 			say.Error("remote break timer couldn't be started")
 			say.Error(err.Error())
-			Exit(1)
+			exit(1)
 		}
 	}
 
@@ -133,7 +128,7 @@ func startBreakTimer(timerInMinutes string, configuration config.Configuration)
 		if err != nil {
 			say.Error(fmt.Sprintf("break timer couldn't be started on your system (%s)", runtime.GOOS))
 			say.Error(err.Error())
-			Exit(1)
+			exit(1)
 		}
 	}
 
@@ -162,7 +157,8 @@ func httpPutTimer(timeoutInMinutes int, room string, user string, timerService s
 		"timer": timeoutInMinutes,
 		"user":  user,
 	})
-	return sendRequest(putBody, "PUT", timerService+room, disableSSLVerification)
+	_, err := httpclient.SendRequest(putBody, "PUT", timerService+room, disableSSLVerification)
+	return err
 }
 
 func httpPutBreakTimer(timeoutInMinutes int, room string, user string, timerService string, disableSSLVerification bool) error {
@@ -170,55 +166,8 @@ func httpPutBreakTimer(timeoutInMinutes int, room string, user string, timerServ
 		"breaktimer": timeoutInMinutes,
 		"user":       user,
 	})
-	return sendRequest(putBody, "PUT", timerService+room, disableSSLVerification)
-}
-
-func sendRequest(requestBody []byte, requestMethod string, requestUrl string, disableSSLVerification bool) error {
-	say.Info(requestMethod + " " + requestUrl + " " + string(requestBody))
-
-	responseBody := bytes.NewBuffer(requestBody)
-	request, requestCreationError := http.NewRequest(requestMethod, requestUrl, responseBody)
-
-	httpClient := http.DefaultClient
-	if disableSSLVerification {
-		transCfg := &http.Transport{
-			TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
-		}
-		httpClient = &http.Client{Transport: transCfg}
-	}
-
-	if requestCreationError != nil {
-		return fmt.Errorf("failed to create the http request object: %w", requestCreationError)
-	}
-
-	request.Header.Set("Content-Type", "application/json")
-	response, responseErr := httpClient.Do(request)
-	if e, ok := responseErr.(*url.Error); ok {
-		switch e.Err.(type) {
-		case x509.UnknownAuthorityError:
-			say.Error("The timer.mob.sh SSL certificate is signed by an unknown authority!")
-			say.Fix("HINT: You can ignore that by adding MOB_TIMER_INSECURE=true to your configuration or environment.",
-				"echo MOB_TIMER_INSECURE=true >> ~/.mob")
-			return fmt.Errorf("failed, to amke the http request: %w", responseErr)
-
-		default:
-			return fmt.Errorf("failed to make the http request: %w", responseErr)
-
-		}
-	}
-
-	if responseErr != nil {
-		return fmt.Errorf("failed to make the http request: %w", responseErr)
-	}
-	defer response.Body.Close()
-	body, responseReadingErr := io.ReadAll(response.Body)
-	if responseReadingErr != nil {
-		return fmt.Errorf("failed to read the http response: %w", responseReadingErr)
-	}
-	if string(body) != "" {
-		say.Info(string(body))
-	}
-	return nil
+	_, err := httpclient.SendRequest(putBody, "PUT", timerService+room, disableSSLVerification)
+	return err
 }
 
 func getSleepCommand(timeoutInSeconds int) string {


Test patch:
diff --git a/mob_test.go b/mob_test.go
index 9505755..fb4a74a 100644
--- a/mob_test.go
+++ b/mob_test.go
@@ -16,8 +16,7 @@ import (
 )
 
 var (
-	tempDir              string
-	originalExitFunction func(int)
+	tempDir string
 )
 
 type GitStatus = map[string]string
@@ -1489,7 +1488,6 @@ func TestStartNextPushManualCommits(t *testing.T) {
 
 func TestStartBranchWithUncommitedChangesFixWithBranch(t *testing.T) {
 	output, _ := setup(t)
-	mockExit()
 
 	setWorkingDir(tempDir + "/local")
 
@@ -1497,12 +1495,10 @@ func TestStartBranchWithUncommitedChangesFixWithBranch(t *testing.T) {
 	runMob(t, tempDir+"/local", "start", "-b", "green")
 
 	assertOutputContains(t, output, "mob start --branch green --include-uncommitted-changes")
-	resetExit()
 }
 
 func TestStartBranchEnvWithUncommitedChangesFixWithoutBranch(t *testing.T) {
 	output, _ := setup(t)
-	mockExit()
 
 	setWorkingDir(tempDir + "/local")
 	t.Setenv("MOB_WIP_BRANCH_QUALIFIER", "red")
@@ -1510,12 +1506,10 @@ func TestStartBranchEnvWithUncommitedChangesFixWithoutBranch(t *testing.T) {
 	runMob(t, tempDir+"/local", "start")
 
 	assertOutputContains(t, output, "mob start --include-uncommitted-changes")
-	resetExit()
 }
 
 func TestStartCreateBranchWithUncommitedChangesFixWithBranch(t *testing.T) {
 	output, _ := setup(t)
-	mockExit()
 
 	setWorkingDir(tempDir + "/local")
 
@@ -1524,12 +1518,10 @@ func TestStartCreateBranchWithUncommitedChangesFixWithBranch(t *testing.T) {
 	runMob(t, tempDir+"/local", "start", "--create", "-b", "green")
 
 	assertOutputContains(t, output, "mob start --create --branch green --include-uncommitted-changes")
-	resetExit()
 }
 
 func TestStartCreateBranchEnvWithUncommitedChangesFixWithoutBranch(t *testing.T) {
 	output, _ := setup(t)
-	mockExit()
 
 	setWorkingDir(tempDir + "/local")
 	os.Setenv("MOB_WIP_BRANCH_QUALIFIER", "red")
@@ -1539,7 +1531,6 @@ func TestStartCreateBranchEnvWithUncommitedChangesFixWithoutBranch(t *testing.T)
 
 	os.Unsetenv("MOB_WIP_BRANCH_QUALIFIER")
 	assertOutputContains(t, output, "mob start --create --include-uncommitted-changes")
-	resetExit()
 }
 
 func TestStartNextPushManualCommitsFeatureBranch(t *testing.T) {
@@ -1927,23 +1918,6 @@ func mockOpenInBrowser() {
 	}
 }
 
-func mockExit() {
-	originalExitFunction = Exit
-	Exit = func(code int) {
-		defer func() {
-			if r := recover(); r != nil {
-				fmt.Printf("exit(%d)\n", code)
-			}
-		}()
-
-		panic(code)
-	}
-}
-
-func resetExit() {
-	Exit = originalExitFunction
-}
-
 func createTestbed(t *testing.T, configuration config.Configuration) {
 	workingDir = ""