Skip to content

Commit

Permalink
Add Windows support
Browse files Browse the repository at this point in the history
  • Loading branch information
arbourd committed Apr 1, 2024
1 parent 71e081d commit 2be737a
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 31 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
os:
- ubuntu-latest
- macOS-latest
# - windows-latest
- windows-latest

steps:
- uses: actions/checkout@v4
Expand All @@ -27,10 +27,10 @@ jobs:
cache: true

- run: go mod download
- run: go test -v ./...
- run: go test -race ./...

- run: go build .
- run: ./git-open .
- run: ./git-open LICENSE

release:
if: startsWith(github.ref, 'refs/tags/v')
Expand Down
37 changes: 23 additions & 14 deletions open/open.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"net/url"
"os"
"os/exec"
"path"
"path/filepath"
"regexp"
"runtime"
Expand Down Expand Up @@ -50,11 +51,11 @@ func GetURL(arg string) (string, error) {
return "", fmt.Errorf("not a git repository")
}
gitdir, _ = filepath.Abs(gitdir)
gitroot := strings.TrimSuffix(gitdir, "/.git")
gitroot := strings.TrimSuffix(gitdir, ".git")

t := parseType(arg)
if t == Path {
arg = parsePath(arg, gitroot)
arg, _ = parsePath(arg, gitroot)
}

remote, ref, err := getRemoteRef(gitdir)
Expand Down Expand Up @@ -91,38 +92,46 @@ func GetURL(arg string) (string, error) {
}

// parsePath returns a cleaned path if the file and folder exist and belong to the root Git repository
func parsePath(path, gitroot string) string {
func parsePath(path, gitroot string) (string, error) {
if path == "" {
return "", nil
}
path = filepath.Clean(path)

_, err := os.Stat(path)
if os.IsNotExist(err) {
return ""
return "", err
}
path, _ = filepath.Abs(path)

// Check if path shares Git root
if !strings.HasPrefix(path, gitroot) {
return ""
return "", fmt.Errorf("path does not contain gitroot: %s; %s", path, gitroot)
}

return strings.TrimPrefix(strings.Replace(path, gitroot, "", 1), "/")
// Remove gitroot from absolute path, making a relative path from the Git root
path = strings.Replace(path, gitroot, "", 1)

// Convert all path seperators to `/` and trim trailing `/`
path = strings.TrimPrefix(filepath.ToSlash(path), "/")
return path, nil
}

// getRemoteRef returns the Git remote and reference (branch, tag, commit), for a provided Git repository
func getRemoteRef(gitroot string) (string, string, error) {
remote, err := gitw.RemoteURL(gitroot)
func getRemoteRef(gitroot string) (remote string, ref string, err error) {
remote, err = gitw.RemoteURL(gitroot)
if err != nil {
return "", "", err
}

ref, err := gitw.CurrentRef(gitroot)
ref, err = gitw.CurrentRef(gitroot)
return remote, ref, err
}

// parseRemote parses the host and repository (username or organization and repository name) from a remote string
func parseRemote(r string) (host, path string) {
u, _ := url.Parse(r)
repo := filepath.Clean(u.Path)
repo = strings.TrimSuffix(repo, ".git")
repo = strings.TrimPrefix(repo, "/")
func parseRemote(remote string) (host, repo string) {
u, _ := url.Parse(remote)
repo = strings.TrimPrefix(strings.TrimSuffix(path.Clean(u.Path), ".git"), "/")
return u.Host, repo
}

Expand Down
29 changes: 20 additions & 9 deletions open/open_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,19 +44,19 @@ func TestGetURL(t *testing.T) {
},
"commit sha with extension": {
arg: "7605d91.txt",
expectedURL: "https://github.com/arbourd/git-open/tree/main",
expectedURL: "https://github.com/arbourd/git-open/tree/%s",
},
"commit sha as a folder": {
arg: "7605d91/example.txt",
expectedURL: "https://github.com/arbourd/git-open/tree/main",
expectedURL: "https://github.com/arbourd/git-open/tree/%s",
},
"out of git dir relative path": {
arg: filepath.FromSlash("../../.."),
expectedURL: "https://github.com/arbourd/git-open/tree/main",
expectedURL: "https://github.com/arbourd/git-open/tree/%s",
},
"out of git dir absolute path": {
arg: filepath.FromSlash(homedir),
expectedURL: "https://github.com/arbourd/git-open/tree/main",
expectedURL: "https://github.com/arbourd/git-open/tree/%s",
},
}

Expand Down Expand Up @@ -175,11 +175,12 @@ func TestParsePath(t *testing.T) {
panic("not a git repository")
}
gitdir, _ = filepath.Abs(gitdir)
gitroot := strings.TrimSuffix(gitdir, "/.git")
gitroot := strings.TrimSuffix(gitdir, ".git")

cases := map[string]struct {
path string
expectedPath string
wantErr bool
}{
"empty argument": {
path: "",
Expand All @@ -201,16 +202,26 @@ func TestParsePath(t *testing.T) {
path: filepath.FromSlash(".././/LICENSE"),
expectedPath: "LICENSE",
},
"out of directory": {
path: filepath.FromSlash("../../.."),
"out of git root": {
path: filepath.FromSlash("../../../.."),
expectedPath: "",
wantErr: true,
},
"file does not exist": {
path: "README.txt",
expectedPath: "",
wantErr: true,
},
}

for name, c := range cases {
t.Run(name, func(t *testing.T) {
path := parsePath(c.path, gitroot)
if path != c.expectedPath {
path, err := parsePath(c.path, gitroot)
if err != nil && !c.wantErr {
t.Fatalf("unexpected error:\n\t(GOT): %s\n\t(WNT): nil", err)
} else if err == nil && c.wantErr {
t.Fatalf("expected error:\n\t(GOT): nil")
} else if path != c.expectedPath {
t.Fatalf("unexpected path:\n\t(GOT): %#v\n\t(WNT): %#v", path, c.expectedPath)
}
})
Expand Down
10 changes: 5 additions & 5 deletions open/provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,33 +42,33 @@ func TestCommitURL(t *testing.T) {
func TestPathURL(t *testing.T) {
cases := map[string]struct {
p Provider
branch string
ref string
path string
expectedURL string
}{
"github": {
p: DefaultProviders[0],
branch: "main",
ref: "main",
path: "LICENSE",
expectedURL: "https://github.com/arbourd/git-open/tree/main/LICENSE",
},
"gitlab": {
p: DefaultProviders[1],
branch: "main",
ref: "main",
path: "LICENSE",
expectedURL: "https://gitlab.com/arbourd/git-open/-/tree/main/LICENSE",
},
"bitbucket": {
p: DefaultProviders[2],
branch: "main",
ref: "main",
path: "LICENSE",
expectedURL: "https://bitbucket.org/arbourd/git-open/src/main/LICENSE",
},
}

for name, c := range cases {
t.Run(name, func(t *testing.T) {
url := c.p.PathURL(repo, c.branch, c.path)
url := c.p.PathURL(repo, c.ref, c.path)
if url != c.expectedURL {
t.Fatalf("unexpected url:\n\t(GOT): %#v\n\t(WNT): %#v", url, c.expectedURL)
}
Expand Down

0 comments on commit 2be737a

Please sign in to comment.