Skip to content

Commit

Permalink
Improve tests by using temporary Git config
Browse files Browse the repository at this point in the history
Adds a test fixture that generates a .gitconfig file within a temporary
folder for each test. This ensures that the user running the test
doesn't have their global Git config changed under them.

Also removes `go-homedir` in favour of stdlib.
  • Loading branch information
arbourd committed Apr 3, 2024
1 parent 237d80b commit 55eea1c
Show file tree
Hide file tree
Showing 6 changed files with 119 additions and 112 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:

steps:
- uses: actions/checkout@v4
- run: git config --global url.https://github.com/.insteadOf ssh://[email protected]/
- run: git config url.https://github.com/.insteadOf ssh://[email protected]/

- uses: actions/setup-go@v5
with:
Expand Down
26 changes: 13 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,7 @@

## Usage

Set a `GETPATH` with `git config` or use the default of `~/src`

```console
$ git config --global get.path "~/src"
```

The environmental variable `$GETPATH` may also be set:

```shell
export GETPATH=~/src
```

Get a repository.
Get a repository to `~/src`

```console
$ git get github.com/arbourd/git-get
Expand All @@ -29,6 +17,18 @@ $ git get [email protected]:arbourd/git-get.git
~/src/github.com/arbourd/git-get
```

Set a custom `GETPATH` with `git config`.

```console
$ git config --global get.path "~/dev"
```

Set a custom `GETPATH` with the environmental variable `$GETPATH`.

```shell
export GETPATH=~/dev
```

### Using SSH as the default

By default, when getting a repository without specifying a protocol (eg: github.com/arbourd/git-get) HTTPS will be used.
Expand Down
53 changes: 28 additions & 25 deletions get/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,59 +12,62 @@ import (
"github.com/ldez/go-git-cmd-wrapper/v2/config"
"github.com/ldez/go-git-cmd-wrapper/v2/git"
"github.com/ldez/go-git-cmd-wrapper/v2/types"
"github.com/mitchellh/go-homedir"
)

// DefaultGetPath is the default path where repositories will be cloned if not configured
const defaultGetPath = "~/src"
const (
// defaultGetpath is the default path where repositories will be cloned if not configured
defaultGetpath = "~/src"

// DefaultScheme is the scheme used when a URL is provided without one
const defaultScheme = "https"
// defaultScheme is the scheme used when a URL is provided without one
defaultScheme = "https"

// GitConfigKey is the key that is used to store GETPATH information in the global Git config
GitConfigKey = "get.path"

// EnvKey is the name of the environmental variable that is used to store GETPATH information
EnvKey = "GETPATH"
)

// Path returns the absolute GETPATH
func Path() (string, error) {
path := configPath()
p := configPath()

path, err := homedir.Expand(path)
if err != nil {
return "", err
if strings.HasPrefix(p, "~") {
dir, err := os.UserHomeDir()
if err != nil {
return "", err
}

p = filepath.Join(dir, p[1:])
}

if !filepath.IsAbs(path) {
return "", fmt.Errorf("GETPATH entry is relative; must be an absolute path: \"%s\"", path)
if !filepath.IsAbs(p) {
return "", fmt.Errorf("GETPATH is not an absolute path: \"%s\"", p)
}

// Make GETPATH directory if it does not exist
if _, err := os.Stat(path); os.IsNotExist(err) {
err := os.MkdirAll(path, os.ModePerm)
if _, err := os.Stat(p); os.IsNotExist(err) {
err := os.MkdirAll(p, os.ModePerm)
if err != nil {
return "", err
}
}

return path, nil
return p, nil
}

const (
// GitConfigKey is the key that is used to store GETPATH information in the global Git config
GitConfigKey = "get.path"

// EnvVar is the name of the environmental variable that is used to store GETPATH information
EnvVar = "GETPATH"
)

// configPath returns the GETPATH from the config, environment or default
func configPath() string {
out, _ := git.Config(config.Global, config.Get(GitConfigKey, ""))
if getpath := strings.TrimSpace(out); getpath != "" {
return getpath
}

if getpath := os.Getenv(EnvVar); getpath != "" {
if getpath := os.Getenv(EnvKey); getpath != "" {
return getpath
}

return defaultGetPath
return defaultGetpath
}

var scpSyntaxRe = regexp.MustCompile(`^(\w+)@([\w.-]+):(.*)$`)
Expand Down Expand Up @@ -128,7 +131,7 @@ func Clone(u *url.URL, dir string) (string, error) {

_, err = git.Clone(clone.Repository(u.String()), clone.Directory(dir))
if err != nil {
return "", err
return "", fmt.Errorf("git clone: %s", err)
}
}

Expand Down
143 changes: 76 additions & 67 deletions get/get_test.go
Original file line number Diff line number Diff line change
@@ -1,74 +1,69 @@
package get

import (
"fmt"
"net/url"
"os"
"path/filepath"
"strings"
"runtime"
"testing"

"github.com/ldez/go-git-cmd-wrapper/v2/config"
"github.com/ldez/go-git-cmd-wrapper/v2/git"
"github.com/mitchellh/go-homedir"
)

func TestPath(t *testing.T) {
home, _ := homedir.Dir()

configDir, _ := os.MkdirTemp("", "git-get-gitconfig-")
envDir, _ := os.MkdirTemp("", "git-get-envvar-")
defer os.RemoveAll(configDir)
defer os.RemoveAll(envDir)

out, _ := git.Config(config.Global, config.Get(GitConfigKey, ""))
if before := strings.TrimSpace(out); before != "" {
// Set git-get global gitconfig at the end of tests if previously set
defer git.Config(config.Global, config.Entry(GitConfigKey, before))
} else {
// Unset git-get global gitconfig at the end of tests if previously unset
defer git.Config(config.Global, config.Unset(GitConfigKey, ""))
home, err := os.UserHomeDir()
if err != nil {
t.Fatalf("unable to detect homedir: %s", err)
}

defaultGetpath := filepath.Join(home, "src")
configGetpath := t.TempDir()
envGetpath := t.TempDir()

cases := map[string]struct {
gitConfigGetPath string
envVarGetPath string
gitConfigGetpath string
envGetpath string
expectedPath string
wantErr bool
}{
"default": {
expectedPath: filepath.Join(home, "src"),
expectedPath: defaultGetpath,
},
"git config getpath": {
envVarGetPath: filepath.Join(configDir),
expectedPath: filepath.Join(configDir),
gitConfigGetpath: configGetpath,
expectedPath: configGetpath,
},
"env var getpath": {
envVarGetPath: filepath.Join(envDir),
expectedPath: filepath.Join(envDir),
envGetpath: envGetpath,
expectedPath: envGetpath,
},
"git config getpath over env var getpath": {
gitConfigGetPath: filepath.Join(configDir),
envVarGetPath: filepath.Join(envDir),
expectedPath: filepath.Join(configDir),
"git config getpath overrides env var getpath": {
gitConfigGetpath: configGetpath,
envGetpath: envGetpath,
expectedPath: configGetpath,
},
"relative GETPATH": {
envVarGetPath: "../test",
wantErr: true,
envGetpath: "../test",
wantErr: true,
},
}

for name, c := range cases {
t.Run(name, func(t *testing.T) {
// Empty GETPATH for tests
git.Config(config.Global, config.Unset(GitConfigKey, ""))
os.Setenv("GETPATH", "")
err := gitConfigGlobalFixture(t)
if err != nil {
t.Fatalf("unable to setup test fixture: %s", err)
}

if c.gitConfigGetPath != "" {
git.Config(config.Global, config.Entry(GitConfigKey, c.gitConfigGetPath))
if c.gitConfigGetpath != "" {
git.Config(config.Global, config.Entry(GitConfigKey, c.gitConfigGetpath))
}

if c.envVarGetPath != "" {
os.Setenv("GETPATH", c.envVarGetPath)
os.Setenv("GETPATH", "")
if c.envGetpath != "" {
os.Setenv("GETPATH", c.envGetpath)
}

path, err := Path()
Expand All @@ -84,55 +79,46 @@ func TestPath(t *testing.T) {
}

func TestConfigPath(t *testing.T) {
configDir, _ := os.MkdirTemp("", "git-get-gitconfig-")
envDir, _ := os.MkdirTemp("", "git-get-envvar-")
defer os.RemoveAll(configDir)
defer os.RemoveAll(envDir)

out, _ := git.Config(config.Global, config.Get(GitConfigKey, ""))
if before := strings.TrimSpace(out); before != "" {
// Set git-get global gitconfig at the end of tests if previously set
defer git.Config(config.Global, config.Entry(GitConfigKey, before))
} else {
// Unset git-get global gitconfig at the end of tests if previously unset
defer git.Config(config.Global, config.Unset(GitConfigKey, ""))
}
configGetpath := t.TempDir()
envGetpath := t.TempDir()

cases := map[string]struct {
gitConfigGetPath string
envVarGetPath string
gitConfigGetpath string
envGetpath string
expectedPath string
}{
"default": {
expectedPath: "~/src",
},
"git config getpath": {
envVarGetPath: filepath.Join(configDir),
expectedPath: filepath.Join(configDir),
envGetpath: configGetpath,
expectedPath: configGetpath,
},
"env var getpath": {
envVarGetPath: filepath.Join(envDir),
expectedPath: filepath.Join(envDir),
envGetpath: envGetpath,
expectedPath: envGetpath,
},
"git config getpath over env var getpath": {
gitConfigGetPath: filepath.Join(configDir),
envVarGetPath: filepath.Join(envDir),
expectedPath: filepath.Join(configDir),
gitConfigGetpath: configGetpath,
envGetpath: envGetpath,
expectedPath: configGetpath,
},
}

for name, c := range cases {
t.Run(name, func(t *testing.T) {
// Empty GETPATH for tests
git.Config(config.Global, config.Unset(GitConfigKey, ""))
os.Setenv("GETPATH", "")
err := gitConfigGlobalFixture(t)
if err != nil {
t.Fatalf("unable to setup test fixture: %s", err)
}

if c.gitConfigGetPath != "" {
git.Config(config.Global, config.Entry(GitConfigKey, c.gitConfigGetPath))
if c.gitConfigGetpath != "" {
git.Config(config.Global, config.Entry(GitConfigKey, c.gitConfigGetpath))
}

if c.envVarGetPath != "" {
os.Setenv("GETPATH", c.envVarGetPath)
os.Setenv("GETPATH", "")
if c.envGetpath != "" {
os.Setenv("GETPATH", c.envGetpath)
}

path := configPath()
Expand Down Expand Up @@ -237,8 +223,7 @@ func TestDirectory(t *testing.T) {
}

func TestClone(t *testing.T) {
dir, _ := os.MkdirTemp("", "git-get-")
defer os.RemoveAll(dir)
dir := t.TempDir()

cases := map[string]struct {
url *url.URL
Expand Down Expand Up @@ -302,3 +287,27 @@ func TestClone(t *testing.T) {
})
}
}

// gitConfigGlobalFixture creates a temporary folder and .gitconfig to be used as the global
// Git config for tests.
func gitConfigGlobalFixture(t *testing.T) error {
// Skip fixture on Windows in CI
if os.Getenv("CI") == "true" && runtime.GOOS == "windows" {
git.Config(config.Global, config.Entry(GitConfigKey, ""))
return nil
}

gitconfig := filepath.Join(t.TempDir(), ".gitconfig")

_, err := os.Create(gitconfig)
if err != nil {
return fmt.Errorf("unable create .gitconfig: %s", err)
}

err = os.Setenv("GIT_CONFIG_GLOBAL", gitconfig)
if err != nil {
return fmt.Errorf("unable to set GIT_CONFIG_GLOBAL: %s", err)
}

return nil
}
5 changes: 1 addition & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,4 @@ module github.com/arbourd/git-get

go 1.22

require (
github.com/ldez/go-git-cmd-wrapper/v2 v2.6.0
github.com/mitchellh/go-homedir v1.1.0
)
require github.com/ldez/go-git-cmd-wrapper/v2 v2.6.0
2 changes: 0 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,4 +1,2 @@
github.com/ldez/go-git-cmd-wrapper/v2 v2.6.0 h1:o5QIusOiH9phm1gY2UGO6JQjYSPFYbgFCcntOigBvMg=
github.com/ldez/go-git-cmd-wrapper/v2 v2.6.0/go.mod h1:whnaSah+AmezZS8vwp8FyFzEBHZCLKywWILUj5D8Jq0=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=

0 comments on commit 55eea1c

Please sign in to comment.