feat(git): add link to GitKraken

This commit is contained in:
Jan De Dobbeleer 2022-09-01 19:49:17 +02:00 committed by Jan De Dobbeleer
parent 5df8d89902
commit 56a59a1b32
3 changed files with 49 additions and 37 deletions

View file

@ -2,6 +2,7 @@ package segments
import ( import (
"fmt" "fmt"
url2 "net/url"
"oh-my-posh/environment" "oh-my-posh/environment"
"oh-my-posh/properties" "oh-my-posh/properties"
"oh-my-posh/regex" "oh-my-posh/regex"
@ -34,27 +35,6 @@ func (s *GitStatus) add(code string) {
} }
} }
type Git struct {
scm
Working *GitStatus
Staging *GitStatus
Ahead int
Behind int
HEAD string
Ref string
Hash string
BranchStatus string
Upstream string
UpstreamIcon string
UpstreamURL string
UpstreamGone bool
StashCount int
WorktreeCount int
IsWorkTree bool
RepoName string
}
const ( const (
// FetchStatus fetches the status of the repository // FetchStatus fetches the status of the repository
FetchStatus properties.Property = "fetch_status" FetchStatus properties.Property = "fetch_status"
@ -109,6 +89,28 @@ const (
GITCOMMAND = "git" GITCOMMAND = "git"
) )
type Git struct {
scm
Working *GitStatus
Staging *GitStatus
Ahead int
Behind int
HEAD string
Ref string
Hash string
ShortHash string
BranchStatus string
Upstream string
UpstreamIcon string
UpstreamURL string
UpstreamGone bool
StashCount int
WorktreeCount int
IsWorkTree bool
RepoName string
}
func (g *Git) Template() string { func (g *Git) Template() string {
return " {{ .HEAD }} {{ .BranchStatus }}{{ if .Working.Changed }} \uF044 {{ .Working.String }}{{ end }}{{ if and (.Staging.Changed) (.Working.Changed) }} |{{ end }}{{ if .Staging.Changed }} \uF046 {{ .Staging.String }}{{ end }}{{ if gt .StashCount 0}} \uF692 {{ .StashCount }}{{ end }}{{ if gt .WorktreeCount 0}} \uf1bb {{ .WorktreeCount }}{{ end }} " //nolint: lll return " {{ .HEAD }} {{ .BranchStatus }}{{ if .Working.Changed }} \uF044 {{ .Working.String }}{{ end }}{{ if and (.Staging.Changed) (.Working.Changed) }} |{{ end }}{{ if .Staging.Changed }} \uF046 {{ .Staging.String }}{{ end }}{{ if gt .StashCount 0}} \uF692 {{ .StashCount }}{{ end }}{{ if gt .WorktreeCount 0}} \uf1bb {{ .WorktreeCount }}{{ end }} " //nolint: lll
} }
@ -140,6 +142,12 @@ func (g *Git) Enabled() bool {
return true return true
} }
func (g *Git) Kraken() string {
root := g.getGitCommandOutput("rev-list", "--max-parents=0", "HEAD")
remote := g.getGitCommandOutput("remote", "get-url", "origin")
return fmt.Sprintf("gitkraken://repolink/%s/commit/%s?url=%s", root, g.Hash, url2.QueryEscape(remote))
}
func (g *Git) shouldDisplay() bool { func (g *Git) shouldDisplay() bool {
// when in a WSL shared folder, we must use git.exe and convert paths accordingly // when in a WSL shared folder, we must use git.exe and convert paths accordingly
// for worktrees, stashes, and path to work // for worktrees, stashes, and path to work
@ -307,7 +315,8 @@ func (g *Git) setGitStatus() {
output := g.getGitCommandOutput(args...) output := g.getGitCommandOutput(args...)
for _, line := range strings.Split(output, "\n") { for _, line := range strings.Split(output, "\n") {
if strings.HasPrefix(line, HASH) && len(line) >= len(HASH)+7 { if strings.HasPrefix(line, HASH) && len(line) >= len(HASH)+7 {
g.Hash = line[len(HASH) : len(HASH)+7] g.ShortHash = line[len(HASH) : len(HASH)+7]
g.Hash = line[len(HASH):]
continue continue
} }
if strings.HasPrefix(line, REF) && len(line) > len(REF) { if strings.HasPrefix(line, REF) && len(line) > len(REF) {
@ -480,7 +489,7 @@ func (g *Git) getGitRefFileSymbolicName(refFile string) string {
func (g *Git) setPrettyHEADName() { func (g *Git) setPrettyHEADName() {
// we didn't fetch status, fallback to parsing the HEAD file // we didn't fetch status, fallback to parsing the HEAD file
if len(g.Hash) == 0 { if len(g.ShortHash) == 0 {
HEADRef := g.FileContents(g.workingDir, "HEAD") HEADRef := g.FileContents(g.workingDir, "HEAD")
if strings.HasPrefix(HEADRef, BRANCHPREFIX) { if strings.HasPrefix(HEADRef, BRANCHPREFIX) {
branchName := strings.TrimPrefix(HEADRef, BRANCHPREFIX) branchName := strings.TrimPrefix(HEADRef, BRANCHPREFIX)
@ -489,7 +498,8 @@ func (g *Git) setPrettyHEADName() {
} }
// no branch, points to commit // no branch, points to commit
if len(HEADRef) >= 7 { if len(HEADRef) >= 7 {
g.Hash = HEADRef[0:7] g.ShortHash = HEADRef[0:7]
g.Hash = HEADRef[0:]
} }
} }
// check for tag // check for tag
@ -499,11 +509,11 @@ func (g *Git) setPrettyHEADName() {
return return
} }
// fallback to commit // fallback to commit
if len(g.Hash) == 0 { if len(g.ShortHash) == 0 {
g.HEAD = g.props.GetString(NoCommitsIcon, "\uF594 ") g.HEAD = g.props.GetString(NoCommitsIcon, "\uF594 ")
return return
} }
g.HEAD = fmt.Sprintf("%s%s", g.props.GetString(CommitIcon, "\uF417"), g.Hash) g.HEAD = fmt.Sprintf("%s%s", g.props.GetString(CommitIcon, "\uF417"), g.ShortHash)
} }
func (g *Git) getStashContext() int { func (g *Git) getStashContext() int {

View file

@ -308,7 +308,7 @@ func TestSetGitHEADContextClean(t *testing.T) {
RevertIcon: "revert ", RevertIcon: "revert ",
}, },
}, },
Hash: "1234567", ShortHash: "1234567",
Ref: tc.Ref, Ref: tc.Ref,
} }
g.setGitHEADContext() g.setGitHEADContext()
@ -320,15 +320,15 @@ func TestSetPrettyHEADName(t *testing.T) {
cases := []struct { cases := []struct {
Case string Case string
Expected string Expected string
Hash string ShortHash string
Tag string Tag string
HEAD string HEAD string
}{ }{
{Case: "main", Expected: "branch main", HEAD: BRANCHPREFIX + "main"}, {Case: "main", Expected: "branch main", HEAD: BRANCHPREFIX + "main"},
{Case: "no hash", Expected: "commit 1234567", HEAD: "12345678910"}, {Case: "no hash", Expected: "commit 1234567", HEAD: "12345678910"},
{Case: "hash on tag", Hash: "132312322321", Expected: "tag tag-1", HEAD: "12345678910", Tag: "tag-1"}, {Case: "hash on tag", ShortHash: "132312322321", Expected: "tag tag-1", HEAD: "12345678910", Tag: "tag-1"},
{Case: "no hash on tag", Expected: "tag tag-1", Tag: "tag-1"}, {Case: "no hash on tag", Expected: "tag tag-1", Tag: "tag-1"},
{Case: "hash on commit", Hash: "1234567", Expected: "commit 1234567"}, {Case: "hash on commit", ShortHash: "1234567", Expected: "commit 1234567"},
{Case: "no hash on commit", Expected: "commit 1234567", HEAD: "12345678910"}, {Case: "no hash on commit", Expected: "commit 1234567", HEAD: "12345678910"},
} }
for _, tc := range cases { for _, tc := range cases {
@ -346,7 +346,7 @@ func TestSetPrettyHEADName(t *testing.T) {
TagIcon: "tag ", TagIcon: "tag ",
}, },
}, },
Hash: tc.Hash, ShortHash: tc.ShortHash,
} }
g.setPrettyHEADName() g.setPrettyHEADName()
assert.Equal(t, tc.Expected, g.HEAD, tc.Case) assert.Equal(t, tc.Expected, g.HEAD, tc.Case)
@ -485,7 +485,7 @@ func TestSetGitStatus(t *testing.T) {
g.setGitStatus() g.setGitStatus()
assert.Equal(t, tc.ExpectedStaging, g.Staging, tc.Case) assert.Equal(t, tc.ExpectedStaging, g.Staging, tc.Case)
assert.Equal(t, tc.ExpectedWorking, g.Working, tc.Case) assert.Equal(t, tc.ExpectedWorking, g.Working, tc.Case)
assert.Equal(t, tc.ExpectedHash, g.Hash, tc.Case) assert.Equal(t, tc.ExpectedHash, g.ShortHash, tc.Case)
assert.Equal(t, tc.ExpectedRef, g.Ref, tc.Case) assert.Equal(t, tc.ExpectedRef, g.Ref, tc.Case)
assert.Equal(t, tc.ExpectedUpstream, g.Upstream, tc.Case) assert.Equal(t, tc.ExpectedUpstream, g.Upstream, tc.Case)
assert.Equal(t, tc.ExpectedUpstreamGone, g.UpstreamGone, tc.Case) assert.Equal(t, tc.ExpectedUpstreamGone, g.UpstreamGone, tc.Case)

View file

@ -131,6 +131,7 @@ instead of the repo path.
- `.WorktreeCount`: `int` - the worktree count - `.WorktreeCount`: `int` - the worktree count
- `.IsWorkTree`: `boolean` - if in a worktree repo or not - `.IsWorkTree`: `boolean` - if in a worktree repo or not
- `.Dir`: `string` - the repository's root directory - `.Dir`: `string` - the repository's root directory
- `.Kraken`: `string` - a link to the current HEAD in [GitKraken][kraken-ref] for use in [hyperlinks][hyperlinks] in templates `{{ url .HEAD .Kraken }}`
### GitStatus ### GitStatus
@ -146,3 +147,4 @@ instead of the repo path.
[hyperlinks]: /docs/configuration/templates#helper-functions [hyperlinks]: /docs/configuration/templates#helper-functions
[untracked]: https://git-scm.com/docs/git-status#Documentation/git-status.txt---untracked-filesltmodegt [untracked]: https://git-scm.com/docs/git-status#Documentation/git-status.txt---untracked-filesltmodegt
[submodules]: https://git-scm.com/docs/git-status#Documentation/git-status.txt---ignore-submodulesltwhengt [submodules]: https://git-scm.com/docs/git-status#Documentation/git-status.txt---ignore-submodulesltwhengt
[kraken-ref]: https://www.gitkraken.com/invite/nQmDPR9D