repo: add functions to read/write git config

Michael Muré created

Change summary

cache/repo_cache.go     |  8 ++++++++
repository/git.go       | 41 +++++++++++++++++++++++++++++++++++------
repository/mock_repo.go | 20 ++++++++++++++++++++
repository/repo.go      |  7 +++++++
4 files changed, 70 insertions(+), 6 deletions(-)

Detailed changes

cache/repo_cache.go 🔗

@@ -75,6 +75,14 @@ func (c *RepoCache) GetUserEmail() (string, error) {
 	return c.repo.GetUserEmail()
 }
 
+func (c *RepoCache) StoreConfig(key string, value string) error {
+	return c.repo.StoreConfig(key, value)
+}
+
+func (c *RepoCache) ReadConfigs(keyPrefix string) (map[string]string, error) {
+	return c.repo.ReadConfigs(keyPrefix)
+}
+
 func (c *RepoCache) lock() error {
 	lockPath := repoLockFilePath(c.repo)
 

repository/git.go 🔗

@@ -6,7 +6,6 @@ import (
 	"errors"
 	"fmt"
 	"io"
-	"os"
 	"os/exec"
 	"path"
 	"strings"
@@ -66,11 +65,6 @@ func (repo *GitRepo) runGitCommand(args ...string) (string, error) {
 	return repo.runGitCommandWithStdin(nil, args...)
 }
 
-// Run the given git command using the same stdin, stdout, and stderr as the review tool.
-func (repo *GitRepo) runGitCommandInline(args ...string) error {
-	return repo.runGitCommandWithIO(os.Stdin, os.Stdout, os.Stderr, args...)
-}
-
 // NewGitRepo determines if the given working directory is inside of a git repository,
 // and returns the corresponding GitRepo instance if it is.
 func NewGitRepo(path string, witnesser func(repo *GitRepo) error) (*GitRepo, error) {
@@ -165,6 +159,41 @@ func (repo *GitRepo) GetCoreEditor() (string, error) {
 	return repo.runGitCommand("var", "GIT_EDITOR")
 }
 
+// StoreConfig store a single key/value pair in the config of the repo
+func (repo *GitRepo) StoreConfig(key string, value string) error {
+	_, err := repo.runGitCommand("config", "--replace-all", key, value)
+
+	return err
+}
+
+// ReadConfigs read all key/value pair matching the key prefix
+func (repo *GitRepo) ReadConfigs(keyPrefix string) (map[string]string, error) {
+	stdout, err := repo.runGitCommand("config", "--get-regexp", keyPrefix)
+
+	if err != nil {
+		return nil, err
+	}
+
+	lines := strings.Split(stdout, "\n")
+
+	result := make(map[string]string, len(lines))
+
+	for _, line := range lines {
+		if strings.TrimSpace(line) == "" {
+			continue
+		}
+
+		parts := strings.Fields(line)
+		if len(parts) != 2 {
+			return nil, fmt.Errorf("bad git config: %s", line)
+		}
+
+		result[parts[0]] = parts[1]
+	}
+
+	return result, nil
+}
+
 // FetchRefs fetch git refs from a remote
 func (repo *GitRepo) FetchRefs(remote, refSpec string) (string, error) {
 	stdout, err := repo.runGitCommand("fetch", remote, refSpec)

repository/mock_repo.go 🔗

@@ -3,6 +3,7 @@ package repository
 import (
 	"crypto/sha1"
 	"fmt"
+	"strings"
 
 	"github.com/MichaelMure/git-bug/util/git"
 	"github.com/MichaelMure/git-bug/util/lamport"
@@ -10,6 +11,7 @@ import (
 
 // mockRepoForTest defines an instance of Repo that can be used for testing.
 type mockRepoForTest struct {
+	config      map[string]string
 	blobs       map[git.Hash][]byte
 	trees       map[git.Hash]string
 	commits     map[git.Hash]commit
@@ -25,6 +27,7 @@ type commit struct {
 
 func NewMockRepoForTest() *mockRepoForTest {
 	return &mockRepoForTest{
+		config:      make(map[string]string),
 		blobs:       make(map[git.Hash][]byte),
 		trees:       make(map[git.Hash]string),
 		commits:     make(map[git.Hash]commit),
@@ -53,6 +56,23 @@ func (r *mockRepoForTest) GetCoreEditor() (string, error) {
 	return "vi", nil
 }
 
+func (r *mockRepoForTest) StoreConfig(key string, value string) error {
+	r.config[key] = value
+	return nil
+}
+
+func (r *mockRepoForTest) ReadConfigs(keyPrefix string) (map[string]string, error) {
+	result := make(map[string]string)
+
+	for key, val := range r.config {
+		if strings.HasPrefix(key, keyPrefix) {
+			result[key] = val
+		}
+	}
+
+	return result, nil
+}
+
 // PushRefs push git refs to a remote
 func (r *mockRepoForTest) PushRefs(remote string, refSpec string) (string, error) {
 	return "", nil

repository/repo.go 🔗

@@ -9,6 +9,7 @@ import (
 	"github.com/MichaelMure/git-bug/util/lamport"
 )
 
+// RepoCommon represent the common function the we want all the repo to implement
 type RepoCommon interface {
 	// GetPath returns the path to the repo.
 	GetPath() string
@@ -21,6 +22,12 @@ type RepoCommon interface {
 
 	// GetCoreEditor returns the name of the editor that the user has used to configure git.
 	GetCoreEditor() (string, error)
+
+	// StoreConfig store a single key/value pair in the config of the repo
+	StoreConfig(key string, value string) error
+
+	// ReadConfigs read all key/value pair matching the key prefix
+	ReadConfigs(keyPrefix string) (map[string]string, error)
 }
 
 // Repo represents a source code repository.