mirror of
https://github.com/JanDeDobbeleer/oh-my-posh.git
synced 2024-12-31 13:57:26 -08:00
feat(git): better logic
This commit is contained in:
parent
4f921dbb0f
commit
98472abafc
|
@ -87,13 +87,13 @@ func (g *git) deprecatedString(statusColorsEnabled bool) string {
|
||||||
if len(g.BranchStatus) > 0 {
|
if len(g.BranchStatus) > 0 {
|
||||||
buffer.WriteString(g.BranchStatus)
|
buffer.WriteString(g.BranchStatus)
|
||||||
}
|
}
|
||||||
if g.Staging.Changed {
|
if g.Staging.Changed() {
|
||||||
fmt.Fprint(buffer, g.getStatusDetailString(g.Staging, StagingColor, LocalStagingIcon, " \uF046"))
|
fmt.Fprint(buffer, g.getStatusDetailString(g.Staging, StagingColor, LocalStagingIcon, " \uF046"))
|
||||||
}
|
}
|
||||||
if g.Staging.Changed && g.Working.Changed {
|
if g.Staging.Changed() && g.Working.Changed() {
|
||||||
fmt.Fprint(buffer, g.props.getString(StatusSeparatorIcon, " |"))
|
fmt.Fprint(buffer, g.props.getString(StatusSeparatorIcon, " |"))
|
||||||
}
|
}
|
||||||
if g.Working.Changed {
|
if g.Working.Changed() {
|
||||||
fmt.Fprint(buffer, g.getStatusDetailString(g.Working, WorkingColor, LocalWorkingIcon, " \uF044"))
|
fmt.Fprint(buffer, g.getStatusDetailString(g.Working, WorkingColor, LocalWorkingIcon, " \uF044"))
|
||||||
}
|
}
|
||||||
if g.StashCount != 0 {
|
if g.StashCount != 0 {
|
||||||
|
@ -114,7 +114,7 @@ func (g *git) SetStatusColor() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *git) getStatusColor(defaultValue string) string {
|
func (g *git) getStatusColor(defaultValue string) string {
|
||||||
if g.Staging.Changed || g.Working.Changed {
|
if g.Staging.Changed() || g.Working.Changed() {
|
||||||
return g.props.getColor(LocalChangesColor, defaultValue)
|
return g.props.getColor(LocalChangesColor, defaultValue)
|
||||||
} else if g.Ahead > 0 && g.Behind > 0 {
|
} else if g.Ahead > 0 && g.Behind > 0 {
|
||||||
return g.props.getColor(AheadAndBehindColor, defaultValue)
|
return g.props.getColor(AheadAndBehindColor, defaultValue)
|
||||||
|
|
|
@ -13,7 +13,6 @@ import (
|
||||||
func TestGetStatusDetailStringDefault(t *testing.T) {
|
func TestGetStatusDetailStringDefault(t *testing.T) {
|
||||||
expected := "icon +1"
|
expected := "icon +1"
|
||||||
status := &GitStatus{
|
status := &GitStatus{
|
||||||
Changed: true,
|
|
||||||
Added: 1,
|
Added: 1,
|
||||||
}
|
}
|
||||||
g := &git{}
|
g := &git{}
|
||||||
|
@ -23,7 +22,6 @@ func TestGetStatusDetailStringDefault(t *testing.T) {
|
||||||
func TestGetStatusDetailStringDefaultColorOverride(t *testing.T) {
|
func TestGetStatusDetailStringDefaultColorOverride(t *testing.T) {
|
||||||
expected := "<#123456>icon +1</>"
|
expected := "<#123456>icon +1</>"
|
||||||
status := &GitStatus{
|
status := &GitStatus{
|
||||||
Changed: true,
|
|
||||||
Added: 1,
|
Added: 1,
|
||||||
}
|
}
|
||||||
var props properties = map[Property]interface{}{
|
var props properties = map[Property]interface{}{
|
||||||
|
@ -38,7 +36,6 @@ func TestGetStatusDetailStringDefaultColorOverride(t *testing.T) {
|
||||||
func TestGetStatusDetailStringDefaultColorOverrideAndIconColorOverride(t *testing.T) {
|
func TestGetStatusDetailStringDefaultColorOverrideAndIconColorOverride(t *testing.T) {
|
||||||
expected := "<#789123>work</> <#123456>+1</>"
|
expected := "<#789123>work</> <#123456>+1</>"
|
||||||
status := &GitStatus{
|
status := &GitStatus{
|
||||||
Changed: true,
|
|
||||||
Added: 1,
|
Added: 1,
|
||||||
}
|
}
|
||||||
var props properties = map[Property]interface{}{
|
var props properties = map[Property]interface{}{
|
||||||
|
@ -54,7 +51,6 @@ func TestGetStatusDetailStringDefaultColorOverrideAndIconColorOverride(t *testin
|
||||||
func TestGetStatusDetailStringDefaultColorOverrideNoIconColorOverride(t *testing.T) {
|
func TestGetStatusDetailStringDefaultColorOverrideNoIconColorOverride(t *testing.T) {
|
||||||
expected := "<#123456>work +1</>"
|
expected := "<#123456>work +1</>"
|
||||||
status := &GitStatus{
|
status := &GitStatus{
|
||||||
Changed: true,
|
|
||||||
Added: 1,
|
Added: 1,
|
||||||
}
|
}
|
||||||
var props properties = map[Property]interface{}{
|
var props properties = map[Property]interface{}{
|
||||||
|
@ -70,7 +66,6 @@ func TestGetStatusDetailStringDefaultColorOverrideNoIconColorOverride(t *testing
|
||||||
func TestGetStatusDetailStringNoStatus(t *testing.T) {
|
func TestGetStatusDetailStringNoStatus(t *testing.T) {
|
||||||
expected := "icon"
|
expected := "icon"
|
||||||
status := &GitStatus{
|
status := &GitStatus{
|
||||||
Changed: true,
|
|
||||||
Added: 1,
|
Added: 1,
|
||||||
}
|
}
|
||||||
var props properties = map[Property]interface{}{
|
var props properties = map[Property]interface{}{
|
||||||
|
@ -85,7 +80,6 @@ func TestGetStatusDetailStringNoStatus(t *testing.T) {
|
||||||
func TestGetStatusDetailStringNoStatusColorOverride(t *testing.T) {
|
func TestGetStatusDetailStringNoStatusColorOverride(t *testing.T) {
|
||||||
expected := "<#123456>icon</>"
|
expected := "<#123456>icon</>"
|
||||||
status := &GitStatus{
|
status := &GitStatus{
|
||||||
Changed: true,
|
|
||||||
Added: 1,
|
Added: 1,
|
||||||
}
|
}
|
||||||
var props properties = map[Property]interface{}{
|
var props properties = map[Property]interface{}{
|
||||||
|
@ -106,8 +100,9 @@ func TestGetStatusColorLocalChangesStaging(t *testing.T) {
|
||||||
g := &git{
|
g := &git{
|
||||||
props: props,
|
props: props,
|
||||||
Staging: &GitStatus{
|
Staging: &GitStatus{
|
||||||
Changed: true,
|
Modified: 1,
|
||||||
},
|
},
|
||||||
|
Working: &GitStatus{},
|
||||||
}
|
}
|
||||||
assert.Equal(t, expected, g.getStatusColor("#fg1111"))
|
assert.Equal(t, expected, g.getStatusColor("#fg1111"))
|
||||||
}
|
}
|
||||||
|
@ -121,7 +116,7 @@ func TestGetStatusColorLocalChangesWorking(t *testing.T) {
|
||||||
props: props,
|
props: props,
|
||||||
Staging: &GitStatus{},
|
Staging: &GitStatus{},
|
||||||
Working: &GitStatus{
|
Working: &GitStatus{
|
||||||
Changed: true,
|
Modified: 1,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
assert.Equal(t, expected, g.getStatusColor("#fg1111"))
|
assert.Equal(t, expected, g.getStatusColor("#fg1111"))
|
||||||
|
@ -196,8 +191,9 @@ func TestSetStatusColorForeground(t *testing.T) {
|
||||||
g := &git{
|
g := &git{
|
||||||
props: props,
|
props: props,
|
||||||
Staging: &GitStatus{
|
Staging: &GitStatus{
|
||||||
Changed: true,
|
Added: 1,
|
||||||
},
|
},
|
||||||
|
Working: &GitStatus{},
|
||||||
}
|
}
|
||||||
g.SetStatusColor()
|
g.SetStatusColor()
|
||||||
assert.Equal(t, expected, g.props[ForegroundOverride])
|
assert.Equal(t, expected, g.props[ForegroundOverride])
|
||||||
|
@ -211,8 +207,9 @@ func TestSetStatusColorBackground(t *testing.T) {
|
||||||
}
|
}
|
||||||
g := &git{
|
g := &git{
|
||||||
props: props,
|
props: props,
|
||||||
Staging: &GitStatus{
|
Staging: &GitStatus{},
|
||||||
Changed: true,
|
Working: &GitStatus{
|
||||||
|
Modified: 1,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
g.SetStatusColor()
|
g.SetStatusColor()
|
||||||
|
@ -221,16 +218,30 @@ func TestSetStatusColorBackground(t *testing.T) {
|
||||||
|
|
||||||
func TestStatusColorsWithoutDisplayStatus(t *testing.T) {
|
func TestStatusColorsWithoutDisplayStatus(t *testing.T) {
|
||||||
expected := changesColor
|
expected := changesColor
|
||||||
context := &detachedContext{
|
status := "## main...origin/main [ahead 33]\n M myfile"
|
||||||
status: "## main...origin/main [ahead 33]\n M myfile",
|
env := new(MockedEnvironment)
|
||||||
}
|
env.On("isWsl", nil).Return(false)
|
||||||
g := setupHEADContextEnv(context)
|
env.On("getRuntimeGOOS", nil).Return("unix")
|
||||||
var props properties = map[Property]interface{}{
|
env.On("hasFolder", "/rebase-merge").Return(false)
|
||||||
|
env.On("hasFolder", "/rebase-apply").Return(false)
|
||||||
|
env.On("hasFolder", "/sequencer").Return(false)
|
||||||
|
env.On("getFileContent", "/HEAD").Return(status)
|
||||||
|
env.On("hasFilesInDir", "", "CHERRY_PICK_HEAD").Return(false)
|
||||||
|
env.On("hasFilesInDir", "", "REVERT_HEAD").Return(false)
|
||||||
|
env.On("hasFilesInDir", "", "MERGE_MSG").Return(false)
|
||||||
|
env.On("hasFilesInDir", "", "MERGE_HEAD").Return(false)
|
||||||
|
env.On("hasFilesInDir", "", "sequencer/todo").Return(false)
|
||||||
|
env.mockGitCommand("", "describe", "--tags", "--exact-match")
|
||||||
|
env.mockGitCommand(status, "status", "-unormal", "--branch", "--porcelain=2")
|
||||||
|
g := &git{
|
||||||
|
env: env,
|
||||||
|
gitWorkingFolder: "",
|
||||||
|
props: map[Property]interface{}{
|
||||||
DisplayStatus: false,
|
DisplayStatus: false,
|
||||||
StatusColorsEnabled: true,
|
StatusColorsEnabled: true,
|
||||||
LocalChangesColor: expected,
|
LocalChangesColor: expected,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
g.props = props
|
|
||||||
g.string()
|
g.string()
|
||||||
assert.Equal(t, expected, g.props[BackgroundOverride])
|
assert.Equal(t, expected, g.props[BackgroundOverride])
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,29 +14,15 @@ type GitStatus struct {
|
||||||
Deleted int
|
Deleted int
|
||||||
Added int
|
Added int
|
||||||
Modified int
|
Modified int
|
||||||
Changed bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *GitStatus) parse(output []string, working bool) {
|
func (s *GitStatus) add(code string) {
|
||||||
if len(output) <= 1 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for _, line := range output[1:] {
|
|
||||||
if len(line) < 2 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
code := line[0:1]
|
|
||||||
if working {
|
|
||||||
code = line[1:2]
|
|
||||||
}
|
|
||||||
switch code {
|
switch code {
|
||||||
case "?":
|
case ".":
|
||||||
if working {
|
return
|
||||||
s.Added++
|
|
||||||
}
|
|
||||||
case "D":
|
case "D":
|
||||||
s.Deleted++
|
s.Deleted++
|
||||||
case "A":
|
case "A", "?":
|
||||||
s.Added++
|
s.Added++
|
||||||
case "U":
|
case "U":
|
||||||
s.Unmerged++
|
s.Unmerged++
|
||||||
|
@ -44,7 +30,9 @@ func (s *GitStatus) parse(output []string, working bool) {
|
||||||
s.Modified++
|
s.Modified++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s.Changed = s.Added > 0 || s.Deleted > 0 || s.Modified > 0 || s.Unmerged > 0
|
|
||||||
|
func (s *GitStatus) Changed() bool {
|
||||||
|
return s.Added > 0 || s.Deleted > 0 || s.Modified > 0 || s.Unmerged > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *GitStatus) String() string {
|
func (s *GitStatus) String() string {
|
||||||
|
@ -71,6 +59,8 @@ type git struct {
|
||||||
Ahead int
|
Ahead int
|
||||||
Behind int
|
Behind int
|
||||||
HEAD string
|
HEAD string
|
||||||
|
Ref string
|
||||||
|
Hash string
|
||||||
BranchStatus string
|
BranchStatus string
|
||||||
Upstream string
|
Upstream string
|
||||||
UpstreamIcon string
|
UpstreamIcon string
|
||||||
|
@ -133,6 +123,9 @@ const (
|
||||||
GitlabIcon Property = "gitlab_icon"
|
GitlabIcon Property = "gitlab_icon"
|
||||||
// GitIcon shows when the upstream can't be identified
|
// GitIcon shows when the upstream can't be identified
|
||||||
GitIcon Property = "git_icon"
|
GitIcon Property = "git_icon"
|
||||||
|
|
||||||
|
DETACHED = "(detached)"
|
||||||
|
BRANCHPREFIX = "ref: refs/heads/"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (g *git) enabled() bool {
|
func (g *git) enabled() bool {
|
||||||
|
@ -147,12 +140,10 @@ func (g *git) enabled() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
g.Staging = &GitStatus{}
|
|
||||||
g.Working = &GitStatus{}
|
|
||||||
|
|
||||||
if gitdir.isDir {
|
if gitdir.isDir {
|
||||||
g.gitWorkingFolder = gitdir.path
|
g.gitWorkingFolder = gitdir.path
|
||||||
g.gitRootFolder = gitdir.path
|
g.gitRootFolder = gitdir.path
|
||||||
|
g.gitWorktreeFolder = strings.TrimSuffix(gitdir.path, ".git")
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
// handle worktree
|
// handle worktree
|
||||||
|
@ -186,10 +177,12 @@ func (g *git) string() string {
|
||||||
statusColorsEnabled := g.props.getBool(StatusColorsEnabled, false)
|
statusColorsEnabled := g.props.getBool(StatusColorsEnabled, false)
|
||||||
displayStatus := g.props.getOneOfBool(FetchStatus, DisplayStatus, false)
|
displayStatus := g.props.getOneOfBool(FetchStatus, DisplayStatus, false)
|
||||||
if !displayStatus {
|
if !displayStatus {
|
||||||
g.HEAD = g.getPrettyHEADName()
|
g.setPrettyHEADName()
|
||||||
}
|
}
|
||||||
if displayStatus || statusColorsEnabled {
|
if displayStatus || statusColorsEnabled {
|
||||||
g.setGitStatus()
|
g.setGitStatus()
|
||||||
|
g.setGitHEADContext()
|
||||||
|
g.BranchStatus = g.getBranchStatus()
|
||||||
}
|
}
|
||||||
if g.Upstream != "" && g.props.getOneOfBool(FetchUpstreamIcon, DisplayUpstreamIcon, false) {
|
if g.Upstream != "" && g.props.getOneOfBool(FetchUpstreamIcon, DisplayUpstreamIcon, false) {
|
||||||
g.UpstreamIcon = g.getUpstreamIcon()
|
g.UpstreamIcon = g.getUpstreamIcon()
|
||||||
|
@ -266,20 +259,47 @@ func (g *git) getUpstreamIcon() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *git) setGitStatus() {
|
func (g *git) setGitStatus() {
|
||||||
output := g.getGitCommandOutput("status", "-unormal", "--short", "--branch")
|
addToStatus := func(status string) {
|
||||||
splittedOutput := strings.Split(output, "\n")
|
if len(status) <= 4 {
|
||||||
g.Working.parse(splittedOutput, true)
|
return
|
||||||
g.Staging.parse(splittedOutput, false)
|
|
||||||
status := g.parseGitStatusInfo(splittedOutput[0])
|
|
||||||
if status["local"] != "" {
|
|
||||||
g.Ahead, _ = strconv.Atoi(status["ahead"])
|
|
||||||
g.Behind, _ = strconv.Atoi(status["behind"])
|
|
||||||
if status["upstream_status"] != "gone" {
|
|
||||||
g.Upstream = status["upstream"]
|
|
||||||
}
|
}
|
||||||
|
workingCode := status[3:4]
|
||||||
|
stagingCode := status[2:3]
|
||||||
|
g.Working.add(workingCode)
|
||||||
|
g.Staging.add(stagingCode)
|
||||||
|
}
|
||||||
|
const (
|
||||||
|
HASH = "# branch.oid "
|
||||||
|
REF = "# branch.head "
|
||||||
|
UPSTREAM = "# branch.upstream "
|
||||||
|
BRANCHSTATUS = "# branch.ab "
|
||||||
|
)
|
||||||
|
g.Staging = &GitStatus{}
|
||||||
|
g.Working = &GitStatus{}
|
||||||
|
output := g.getGitCommandOutput("status", "-unormal", "--branch", "--porcelain=2")
|
||||||
|
for _, line := range strings.Split(output, "\n") {
|
||||||
|
if strings.HasPrefix(line, HASH) {
|
||||||
|
g.Hash = line[len(HASH) : len(HASH)+7]
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(line, REF) {
|
||||||
|
g.Ref = line[len(REF):]
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(line, UPSTREAM) {
|
||||||
|
g.Upstream = line[len(UPSTREAM):]
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(line, BRANCHSTATUS) {
|
||||||
|
status := line[len(BRANCHSTATUS):]
|
||||||
|
splitted := strings.Split(status, " ")
|
||||||
|
g.Ahead, _ = strconv.Atoi(splitted[0])
|
||||||
|
behind, _ := strconv.Atoi(splitted[1])
|
||||||
|
g.Behind = -behind
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
addToStatus(line)
|
||||||
}
|
}
|
||||||
g.HEAD = g.getGitHEADContext(status["local"])
|
|
||||||
g.BranchStatus = g.getBranchStatus()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *git) getGitCommand() string {
|
func (g *git) getGitCommand() string {
|
||||||
|
@ -309,53 +329,74 @@ func (g *git) getGitCommandOutput(args ...string) string {
|
||||||
return val
|
return val
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *git) getGitHEADContext(ref string) string {
|
func (g *git) setGitHEADContext() {
|
||||||
branchIcon := g.props.getString(BranchIcon, "\uE0A0")
|
branchIcon := g.props.getString(BranchIcon, "\uE0A0")
|
||||||
if ref == "" {
|
if g.Ref == DETACHED {
|
||||||
ref = g.getPrettyHEADName()
|
g.setPrettyHEADName()
|
||||||
} else {
|
} else {
|
||||||
ref = g.truncateBranch(ref)
|
head := g.formatHEAD(g.Ref)
|
||||||
ref = fmt.Sprintf("%s%s", branchIcon, ref)
|
g.HEAD = fmt.Sprintf("%s%s", branchIcon, head)
|
||||||
}
|
}
|
||||||
// rebase
|
|
||||||
|
formatDetached := func() string {
|
||||||
|
if g.Ref == DETACHED {
|
||||||
|
return fmt.Sprintf("%sdetached at %s", branchIcon, g.HEAD)
|
||||||
|
}
|
||||||
|
return g.HEAD
|
||||||
|
}
|
||||||
|
|
||||||
|
getPrettyNameOrigin := func(file string) string {
|
||||||
|
var origin string
|
||||||
|
head := g.getGitFileContents(g.gitWorkingFolder, file)
|
||||||
|
if head == "detached HEAD" {
|
||||||
|
origin = formatDetached()
|
||||||
|
} else {
|
||||||
|
head = strings.Replace(head, "refs/heads/", "", 1)
|
||||||
|
origin = branchIcon + g.formatHEAD(head)
|
||||||
|
}
|
||||||
|
return origin
|
||||||
|
}
|
||||||
|
|
||||||
if g.env.hasFolder(g.gitWorkingFolder + "/rebase-merge") {
|
if g.env.hasFolder(g.gitWorkingFolder + "/rebase-merge") {
|
||||||
head := g.getGitFileContents(g.gitWorkingFolder, "rebase-merge/head-name")
|
origin := getPrettyNameOrigin("rebase-merge/head-name")
|
||||||
origin := strings.Replace(head, "refs/heads/", "", 1)
|
|
||||||
origin = g.truncateBranch(origin)
|
|
||||||
onto := g.getGitRefFileSymbolicName("rebase-merge/onto")
|
onto := g.getGitRefFileSymbolicName("rebase-merge/onto")
|
||||||
onto = g.truncateBranch(onto)
|
onto = g.formatHEAD(onto)
|
||||||
step := g.getGitFileContents(g.gitWorkingFolder, "rebase-merge/msgnum")
|
step := g.getGitFileContents(g.gitWorkingFolder, "rebase-merge/msgnum")
|
||||||
total := g.getGitFileContents(g.gitWorkingFolder, "rebase-merge/end")
|
total := g.getGitFileContents(g.gitWorkingFolder, "rebase-merge/end")
|
||||||
icon := g.props.getString(RebaseIcon, "\uE728 ")
|
icon := g.props.getString(RebaseIcon, "\uE728 ")
|
||||||
return fmt.Sprintf("%s%s%s onto %s%s (%s/%s) at %s", icon, branchIcon, origin, branchIcon, onto, step, total, ref)
|
g.HEAD = fmt.Sprintf("%s%s onto %s%s (%s/%s) at %s", icon, origin, branchIcon, onto, step, total, g.HEAD)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
if g.env.hasFolder(g.gitWorkingFolder + "/rebase-apply") {
|
if g.env.hasFolder(g.gitWorkingFolder + "/rebase-apply") {
|
||||||
head := g.getGitFileContents(g.gitWorkingFolder, "rebase-apply/head-name")
|
origin := getPrettyNameOrigin("rebase-apply/head-name")
|
||||||
origin := strings.Replace(head, "refs/heads/", "", 1)
|
|
||||||
origin = g.truncateBranch(origin)
|
|
||||||
step := g.getGitFileContents(g.gitWorkingFolder, "rebase-apply/next")
|
step := g.getGitFileContents(g.gitWorkingFolder, "rebase-apply/next")
|
||||||
total := g.getGitFileContents(g.gitWorkingFolder, "rebase-apply/last")
|
total := g.getGitFileContents(g.gitWorkingFolder, "rebase-apply/last")
|
||||||
icon := g.props.getString(RebaseIcon, "\uE728 ")
|
icon := g.props.getString(RebaseIcon, "\uE728 ")
|
||||||
return fmt.Sprintf("%s%s%s (%s/%s) at %s", icon, branchIcon, origin, step, total, ref)
|
g.HEAD = fmt.Sprintf("%s%s (%s/%s) at %s", icon, origin, step, total, g.HEAD)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
// merge
|
// merge
|
||||||
if g.hasGitFile("MERGE_MSG") && g.hasGitFile("MERGE_HEAD") {
|
commitIcon := g.props.getString(CommitIcon, "\uF417")
|
||||||
|
if g.hasGitFile("MERGE_MSG") {
|
||||||
icon := g.props.getString(MergeIcon, "\uE727 ")
|
icon := g.props.getString(MergeIcon, "\uE727 ")
|
||||||
mergeContext := g.getGitFileContents(g.gitWorkingFolder, "MERGE_MSG")
|
mergeContext := g.getGitFileContents(g.gitWorkingFolder, "MERGE_MSG")
|
||||||
matches := findNamedRegexMatch(`Merge (?P<type>(remote-tracking )?branch|commit|tag) '(?P<head>.*)' into`, mergeContext)
|
matches := findNamedRegexMatch(`Merge (remote-tracking )?(?P<type>branch|commit|tag) '(?P<theirs>.*)'`, mergeContext)
|
||||||
|
// head := g.getGitRefFileSymbolicName("ORIG_HEAD")
|
||||||
if matches != nil && matches["head"] != "" {
|
if matches != nil && matches["theirs"] != "" {
|
||||||
var headIcon string
|
var headIcon, theirs string
|
||||||
switch matches["type"] {
|
switch matches["type"] {
|
||||||
case "tag":
|
case "tag":
|
||||||
headIcon = g.props.getString(TagIcon, "\uF412")
|
headIcon = g.props.getString(TagIcon, "\uF412")
|
||||||
|
theirs = matches["theirs"]
|
||||||
case "commit":
|
case "commit":
|
||||||
headIcon = g.props.getString(CommitIcon, "\uF417")
|
headIcon = commitIcon
|
||||||
|
theirs = g.formatSHA(matches["theirs"])
|
||||||
default:
|
default:
|
||||||
headIcon = branchIcon
|
headIcon = branchIcon
|
||||||
|
theirs = g.formatHEAD(matches["theirs"])
|
||||||
}
|
}
|
||||||
head := g.truncateBranch(matches["head"])
|
g.HEAD = fmt.Sprintf("%s%s%s into %s", icon, headIcon, theirs, formatDetached())
|
||||||
return fmt.Sprintf("%s%s%s into %s", icon, headIcon, head, ref)
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// sequencer status
|
// sequencer status
|
||||||
|
@ -365,13 +406,17 @@ func (g *git) getGitHEADContext(ref string) string {
|
||||||
// the todo file.
|
// the todo file.
|
||||||
if g.hasGitFile("CHERRY_PICK_HEAD") {
|
if g.hasGitFile("CHERRY_PICK_HEAD") {
|
||||||
sha := g.getGitFileContents(g.gitWorkingFolder, "CHERRY_PICK_HEAD")
|
sha := g.getGitFileContents(g.gitWorkingFolder, "CHERRY_PICK_HEAD")
|
||||||
icon := g.props.getString(CherryPickIcon, "\uE29B ")
|
cherry := g.props.getString(CherryPickIcon, "\uE29B ")
|
||||||
return fmt.Sprintf("%s%s onto %s", icon, sha[0:6], ref)
|
g.HEAD = fmt.Sprintf("%s%s%s onto %s", cherry, commitIcon, g.formatSHA(sha), formatDetached())
|
||||||
} else if g.hasGitFile("REVERT_HEAD") {
|
return
|
||||||
|
}
|
||||||
|
if g.hasGitFile("REVERT_HEAD") {
|
||||||
sha := g.getGitFileContents(g.gitWorkingFolder, "REVERT_HEAD")
|
sha := g.getGitFileContents(g.gitWorkingFolder, "REVERT_HEAD")
|
||||||
icon := g.props.getString(RevertIcon, "\uF0E2 ")
|
revert := g.props.getString(RevertIcon, "\uF0E2 ")
|
||||||
return fmt.Sprintf("%s%s onto %s", icon, sha[0:6], ref)
|
g.HEAD = fmt.Sprintf("%s%s%s onto %s", revert, commitIcon, g.formatSHA(sha), formatDetached())
|
||||||
} else if g.hasGitFile("sequencer/todo") {
|
return
|
||||||
|
}
|
||||||
|
if g.hasGitFile("sequencer/todo") {
|
||||||
todo := g.getGitFileContents(g.gitWorkingFolder, "sequencer/todo")
|
todo := g.getGitFileContents(g.gitWorkingFolder, "sequencer/todo")
|
||||||
matches := findNamedRegexMatch(`^(?P<action>p|pick|revert)\s+(?P<sha>\S+)`, todo)
|
matches := findNamedRegexMatch(`^(?P<action>p|pick|revert)\s+(?P<sha>\S+)`, todo)
|
||||||
if matches != nil && matches["sha"] != "" {
|
if matches != nil && matches["sha"] != "" {
|
||||||
|
@ -379,24 +424,33 @@ func (g *git) getGitHEADContext(ref string) string {
|
||||||
sha := matches["sha"]
|
sha := matches["sha"]
|
||||||
switch action {
|
switch action {
|
||||||
case "p", "pick":
|
case "p", "pick":
|
||||||
icon := g.props.getString(CherryPickIcon, "\uE29B ")
|
cherry := g.props.getString(CherryPickIcon, "\uE29B ")
|
||||||
return fmt.Sprintf("%s%s onto %s", icon, sha[0:6], ref)
|
g.HEAD = fmt.Sprintf("%s%s%s onto %s", cherry, commitIcon, g.formatSHA(sha), formatDetached())
|
||||||
|
return
|
||||||
case "revert":
|
case "revert":
|
||||||
icon := g.props.getString(RevertIcon, "\uF0E2 ")
|
revert := g.props.getString(RevertIcon, "\uF0E2 ")
|
||||||
return fmt.Sprintf("%s%s onto %s", icon, sha[0:6], ref)
|
g.HEAD = fmt.Sprintf("%s%s%s onto %s", revert, commitIcon, g.formatSHA(sha), formatDetached())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ref
|
g.HEAD = formatDetached()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *git) truncateBranch(branch string) string {
|
func (g *git) formatHEAD(head string) string {
|
||||||
maxLength := g.props.getInt(BranchMaxLength, 0)
|
maxLength := g.props.getInt(BranchMaxLength, 0)
|
||||||
if maxLength == 0 || len(branch) < maxLength {
|
if maxLength == 0 || len(head) < maxLength {
|
||||||
return branch
|
return head
|
||||||
}
|
}
|
||||||
symbol := g.props.getString(TruncateSymbol, "")
|
symbol := g.props.getString(TruncateSymbol, "")
|
||||||
return branch[0:maxLength] + symbol
|
return head[0:maxLength] + symbol
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *git) formatSHA(sha string) string {
|
||||||
|
if len(sha) <= 7 {
|
||||||
|
return sha
|
||||||
|
}
|
||||||
|
return sha[0:7]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *git) hasGitFile(file string) bool {
|
func (g *git) hasGitFile(file string) bool {
|
||||||
|
@ -412,28 +466,32 @@ func (g *git) getGitRefFileSymbolicName(refFile string) string {
|
||||||
return g.getGitCommandOutput("name-rev", "--name-only", "--exclude=tags/*", ref)
|
return g.getGitCommandOutput("name-rev", "--name-only", "--exclude=tags/*", ref)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *git) getPrettyHEADName() string {
|
func (g *git) setPrettyHEADName() {
|
||||||
var ref string
|
// we didn't fetch status, fallback to parsing the HEAD file
|
||||||
HEAD := g.getGitFileContents(g.gitWorkingFolder, "HEAD")
|
if len(g.Hash) == 0 {
|
||||||
branchPrefix := "ref: refs/heads/"
|
HEADRef := g.getGitFileContents(g.gitWorkingFolder, "HEAD")
|
||||||
if strings.HasPrefix(HEAD, branchPrefix) {
|
if strings.HasPrefix(HEADRef, BRANCHPREFIX) {
|
||||||
ref = strings.TrimPrefix(HEAD, branchPrefix)
|
branchName := strings.TrimPrefix(HEADRef, BRANCHPREFIX)
|
||||||
|
g.HEAD = fmt.Sprintf("%s%s", g.props.getString(BranchIcon, "\uE0A0"), g.formatHEAD(branchName))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// no branch, points to commit
|
||||||
|
if len(HEADRef) >= 7 {
|
||||||
|
g.Hash = HEADRef[0:7]
|
||||||
}
|
}
|
||||||
if ref != "" {
|
|
||||||
ref = g.truncateBranch(ref)
|
|
||||||
return fmt.Sprintf("%s%s", g.props.getString(BranchIcon, "\uE0A0"), ref)
|
|
||||||
}
|
}
|
||||||
// check for tag
|
// check for tag
|
||||||
ref = g.getGitCommandOutput("describe", "--tags", "--exact-match")
|
tagName := g.getGitCommandOutput("describe", "--tags", "--exact-match")
|
||||||
if ref != "" {
|
if len(tagName) > 0 {
|
||||||
return fmt.Sprintf("%s%s", g.props.getString(TagIcon, "\uF412"), ref)
|
g.HEAD = fmt.Sprintf("%s%s", g.props.getString(TagIcon, "\uF412"), tagName)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
// fallback to commit
|
// fallback to commit
|
||||||
ref = g.getGitCommandOutput("rev-parse", "--short", "HEAD")
|
if len(g.Hash) == 0 {
|
||||||
if ref == "" {
|
g.HEAD = g.props.getString(NoCommitsIcon, "\uF594 ")
|
||||||
return g.props.getString(NoCommitsIcon, "\uF594 ")
|
return
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("%s%s", g.props.getString(CommitIcon, "\uF417"), ref)
|
g.HEAD = fmt.Sprintf("%s%s", g.props.getString(CommitIcon, "\uF417"), g.Hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *git) getStashContext() int {
|
func (g *git) getStashContext() int {
|
||||||
|
@ -453,11 +511,6 @@ func (g *git) getWorktreeContext() int {
|
||||||
return len(worktreeFolders)
|
return len(worktreeFolders)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *git) parseGitStatusInfo(branchInfo string) map[string]string {
|
|
||||||
var branchRegex = `^## (?P<local>\S+?)(\.{3}(?P<upstream>\S+?)( \[(?P<upstream_status>(ahead (?P<ahead>\d+)(, )?)?(behind (?P<behind>\d+))?(gone)?)])?)?$`
|
|
||||||
return findNamedRegexMatch(branchRegex, branchInfo)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g *git) getOriginURL(upstream string) string {
|
func (g *git) getOriginURL(upstream string) string {
|
||||||
cfg, err := ini.Load(g.gitRootFolder + "/config")
|
cfg, err := ini.Load(g.gitRootFolder + "/config")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -2,6 +2,7 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
@ -9,6 +10,7 @@ import (
|
||||||
|
|
||||||
const (
|
const (
|
||||||
changesColor = "#BD8BDE"
|
changesColor = "#BD8BDE"
|
||||||
|
branchName = "main"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestEnabledGitNotFound(t *testing.T) {
|
func TestEnabledGitNotFound(t *testing.T) {
|
||||||
|
@ -76,299 +78,301 @@ func TestGetGitOutputForCommand(t *testing.T) {
|
||||||
assert.Equal(t, want, got)
|
assert.Equal(t, want, got)
|
||||||
}
|
}
|
||||||
|
|
||||||
type detachedContext struct {
|
|
||||||
currentCommit string
|
|
||||||
rebase string
|
|
||||||
rebaseMerge bool
|
|
||||||
rebaseApply bool
|
|
||||||
origin string
|
|
||||||
onto string
|
|
||||||
step string
|
|
||||||
total string
|
|
||||||
branchName string
|
|
||||||
tagName string
|
|
||||||
cherryPick bool
|
|
||||||
cherryPickSHA string
|
|
||||||
revert bool
|
|
||||||
revertSHA string
|
|
||||||
sequencer bool
|
|
||||||
sequencerTodo string
|
|
||||||
merge bool
|
|
||||||
mergeHEAD string
|
|
||||||
mergeMsgStart string
|
|
||||||
status string
|
|
||||||
}
|
|
||||||
|
|
||||||
func setupHEADContextEnv(context *detachedContext) *git {
|
|
||||||
env := new(MockedEnvironment)
|
|
||||||
env.On("isWsl", nil).Return(false)
|
|
||||||
env.On("hasFolder", "/rebase-merge").Return(context.rebaseMerge)
|
|
||||||
env.On("hasFolder", "/rebase-apply").Return(context.rebaseApply)
|
|
||||||
env.On("hasFolder", "/sequencer").Return(context.sequencer)
|
|
||||||
env.On("getFileContent", "/rebase-merge/head-name").Return(context.origin)
|
|
||||||
env.On("getFileContent", "/rebase-merge/onto").Return(context.onto)
|
|
||||||
env.On("getFileContent", "/rebase-merge/msgnum").Return(context.step)
|
|
||||||
env.On("getFileContent", "/rebase-apply/next").Return(context.step)
|
|
||||||
env.On("getFileContent", "/rebase-merge/end").Return(context.total)
|
|
||||||
env.On("getFileContent", "/rebase-apply/last").Return(context.total)
|
|
||||||
env.On("getFileContent", "/rebase-apply/head-name").Return(context.origin)
|
|
||||||
env.On("getFileContent", "/CHERRY_PICK_HEAD").Return(context.cherryPickSHA)
|
|
||||||
env.On("getFileContent", "/REVERT_HEAD").Return(context.revertSHA)
|
|
||||||
env.On("getFileContent", "/MERGE_MSG").Return(fmt.Sprintf("%s '%s' into %s", context.mergeMsgStart, context.mergeHEAD, context.onto))
|
|
||||||
env.On("getFileContent", "/sequencer/todo").Return(context.sequencerTodo)
|
|
||||||
env.On("getFileContent", "/HEAD").Return(context.branchName)
|
|
||||||
env.On("hasFilesInDir", "", "CHERRY_PICK_HEAD").Return(context.cherryPick)
|
|
||||||
env.On("hasFilesInDir", "", "REVERT_HEAD").Return(context.revert)
|
|
||||||
env.On("hasFilesInDir", "", "MERGE_MSG").Return(context.merge)
|
|
||||||
env.On("hasFilesInDir", "", "MERGE_HEAD").Return(context.merge)
|
|
||||||
env.On("hasFilesInDir", "", "sequencer/todo").Return(context.sequencer)
|
|
||||||
env.mockGitCommand(context.currentCommit, "rev-parse", "--short", "HEAD")
|
|
||||||
env.mockGitCommand(context.tagName, "describe", "--tags", "--exact-match")
|
|
||||||
env.mockGitCommand(context.origin, "name-rev", "--name-only", "--exclude=tags/*", context.origin)
|
|
||||||
env.mockGitCommand(context.onto, "name-rev", "--name-only", "--exclude=tags/*", context.onto)
|
|
||||||
env.mockGitCommand(context.branchName, "branch", "--show-current")
|
|
||||||
env.mockGitCommand(context.status, "status", "-unormal", "--short", "--branch")
|
|
||||||
env.On("getRuntimeGOOS", nil).Return("unix")
|
|
||||||
g := &git{
|
|
||||||
env: env,
|
|
||||||
gitWorkingFolder: "",
|
|
||||||
Working: &GitStatus{},
|
|
||||||
Staging: &GitStatus{},
|
|
||||||
}
|
|
||||||
return g
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MockedEnvironment) mockGitCommand(returnValue string, args ...string) {
|
func (m *MockedEnvironment) mockGitCommand(returnValue string, args ...string) {
|
||||||
args = append([]string{"-C", "", "--no-optional-locks", "-c", "core.quotepath=false", "-c", "color.status=false"}, args...)
|
args = append([]string{"-C", "", "--no-optional-locks", "-c", "core.quotepath=false", "-c", "color.status=false"}, args...)
|
||||||
m.On("runCommand", "git", args).Return(returnValue, nil)
|
m.On("runCommand", "git", args).Return(returnValue, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetGitDetachedCommitHash(t *testing.T) {
|
func TestSetGitHEADContextClean(t *testing.T) {
|
||||||
want := "\uf417lalasha1"
|
cases := []struct {
|
||||||
context := &detachedContext{
|
Case string
|
||||||
currentCommit: "lalasha1",
|
Expected string
|
||||||
|
Ref string
|
||||||
|
RebaseMerge bool
|
||||||
|
RebaseApply bool
|
||||||
|
Merge bool
|
||||||
|
CherryPick bool
|
||||||
|
Revert bool
|
||||||
|
Sequencer bool
|
||||||
|
Ours string
|
||||||
|
Theirs string
|
||||||
|
Step string
|
||||||
|
Total string
|
||||||
|
}{
|
||||||
|
{Case: "detached on commit", Ref: DETACHED, Expected: "branch detached at commit 1234567"},
|
||||||
|
{Case: "not detached, clean", Ref: "main", Expected: "branch main"},
|
||||||
|
{
|
||||||
|
Case: "rebase merge",
|
||||||
|
Ref: DETACHED,
|
||||||
|
Expected: "rebase branch origin/main onto branch main (1/2) at commit 1234567",
|
||||||
|
RebaseMerge: true,
|
||||||
|
Ours: "refs/heads/origin/main",
|
||||||
|
Theirs: "main",
|
||||||
|
Step: "1",
|
||||||
|
Total: "2",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Case: "rebase apply",
|
||||||
|
Ref: DETACHED,
|
||||||
|
Expected: "rebase branch origin/main (1/2) at commit 1234567",
|
||||||
|
RebaseApply: true,
|
||||||
|
Ours: "refs/heads/origin/main",
|
||||||
|
Step: "1",
|
||||||
|
Total: "2",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Case: "merge branch",
|
||||||
|
Ref: "main",
|
||||||
|
Expected: "merge branch feat-1 into branch main",
|
||||||
|
Merge: true,
|
||||||
|
Theirs: "branch 'feat-1'",
|
||||||
|
Ours: "main",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Case: "merge commit",
|
||||||
|
Ref: "main",
|
||||||
|
Expected: "merge commit 1234567 into branch main",
|
||||||
|
Merge: true,
|
||||||
|
Theirs: "commit '123456789101112'",
|
||||||
|
Ours: "main",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Case: "merge tag",
|
||||||
|
Ref: "main",
|
||||||
|
Expected: "merge tag 1.2.4 into branch main",
|
||||||
|
Merge: true,
|
||||||
|
Theirs: "tag '1.2.4'",
|
||||||
|
Ours: "main",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Case: "cherry pick",
|
||||||
|
Ref: "main",
|
||||||
|
Expected: "pick commit 1234567 onto branch main",
|
||||||
|
CherryPick: true,
|
||||||
|
Theirs: "123456789101012",
|
||||||
|
Ours: "main",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Case: "revert",
|
||||||
|
Ref: "main",
|
||||||
|
Expected: "revert commit 1234567 onto branch main",
|
||||||
|
Revert: true,
|
||||||
|
Theirs: "123456789101012",
|
||||||
|
Ours: "main",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Case: "sequencer cherry",
|
||||||
|
Ref: "main",
|
||||||
|
Expected: "pick commit 1234567 onto branch main",
|
||||||
|
Sequencer: true,
|
||||||
|
Theirs: "pick 123456789101012",
|
||||||
|
Ours: "main",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Case: "sequencer cherry p",
|
||||||
|
Ref: "main",
|
||||||
|
Expected: "pick commit 1234567 onto branch main",
|
||||||
|
Sequencer: true,
|
||||||
|
Theirs: "p 123456789101012",
|
||||||
|
Ours: "main",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Case: "sequencer revert",
|
||||||
|
Ref: "main",
|
||||||
|
Expected: "revert commit 1234567 onto branch main",
|
||||||
|
Sequencer: true,
|
||||||
|
Theirs: "revert 123456789101012",
|
||||||
|
Ours: "main",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tc := range cases {
|
||||||
|
env := new(MockedEnvironment)
|
||||||
|
env.On("getRuntimeGOOS", nil).Return("unix")
|
||||||
|
env.On("isWsl", nil).Return(false)
|
||||||
|
env.mockGitCommand("", "describe", "--tags", "--exact-match")
|
||||||
|
env.mockGitCommand(tc.Theirs, "name-rev", "--name-only", "--exclude=tags/*", tc.Theirs)
|
||||||
|
env.mockGitCommand(tc.Ours, "name-rev", "--name-only", "--exclude=tags/*", tc.Ours)
|
||||||
|
// rebase merge
|
||||||
|
env.On("hasFolder", "/rebase-merge").Return(tc.RebaseMerge)
|
||||||
|
env.On("getFileContent", "/rebase-merge/head-name").Return(tc.Ours)
|
||||||
|
env.On("getFileContent", "/rebase-merge/onto").Return(tc.Theirs)
|
||||||
|
env.On("getFileContent", "/rebase-merge/msgnum").Return(tc.Step)
|
||||||
|
env.On("getFileContent", "/rebase-merge/end").Return(tc.Total)
|
||||||
|
// rebase apply
|
||||||
|
env.On("hasFolder", "/rebase-apply").Return(tc.RebaseApply)
|
||||||
|
env.On("getFileContent", "/rebase-apply/head-name").Return(tc.Ours)
|
||||||
|
env.On("getFileContent", "/rebase-apply/next").Return(tc.Step)
|
||||||
|
env.On("getFileContent", "/rebase-apply/last").Return(tc.Total)
|
||||||
|
// merge
|
||||||
|
env.On("hasFilesInDir", "", "MERGE_MSG").Return(tc.Merge)
|
||||||
|
env.On("getFileContent", "/MERGE_MSG").Return(fmt.Sprintf("Merge %s into %s", tc.Theirs, tc.Ours))
|
||||||
|
// cherry pick
|
||||||
|
env.On("hasFilesInDir", "", "CHERRY_PICK_HEAD").Return(tc.CherryPick)
|
||||||
|
env.On("getFileContent", "/CHERRY_PICK_HEAD").Return(tc.Theirs)
|
||||||
|
// revert
|
||||||
|
env.On("hasFilesInDir", "", "REVERT_HEAD").Return(tc.Revert)
|
||||||
|
env.On("getFileContent", "/REVERT_HEAD").Return(tc.Theirs)
|
||||||
|
// sequencer
|
||||||
|
env.On("hasFilesInDir", "", "sequencer/todo").Return(tc.Sequencer)
|
||||||
|
env.On("getFileContent", "/sequencer/todo").Return(tc.Theirs)
|
||||||
|
|
||||||
|
g := &git{
|
||||||
|
env: env,
|
||||||
|
props: map[Property]interface{}{
|
||||||
|
BranchIcon: "branch ",
|
||||||
|
CommitIcon: "commit ",
|
||||||
|
RebaseIcon: "rebase ",
|
||||||
|
MergeIcon: "merge ",
|
||||||
|
CherryPickIcon: "pick ",
|
||||||
|
TagIcon: "tag ",
|
||||||
|
RevertIcon: "revert ",
|
||||||
|
},
|
||||||
|
Hash: "1234567",
|
||||||
|
Ref: tc.Ref,
|
||||||
|
}
|
||||||
|
g.setGitHEADContext()
|
||||||
|
assert.Equal(t, tc.Expected, g.HEAD, tc.Case)
|
||||||
}
|
}
|
||||||
g := setupHEADContextEnv(context)
|
|
||||||
got := g.getGitHEADContext("")
|
|
||||||
assert.Equal(t, want, got)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetGitHEADContextTagName(t *testing.T) {
|
func TestSetPrettyHEADName(t *testing.T) {
|
||||||
want := "\uf412lalasha1"
|
cases := []struct {
|
||||||
context := &detachedContext{
|
Case string
|
||||||
currentCommit: "whatever",
|
Expected string
|
||||||
tagName: "lalasha1",
|
Hash string
|
||||||
|
Tag string
|
||||||
|
HEAD string
|
||||||
|
}{
|
||||||
|
{Case: "main", Expected: "branch main", HEAD: BRANCHPREFIX + "main"},
|
||||||
|
{Case: "no hash", Expected: "commit 1234567", HEAD: "12345678910"},
|
||||||
|
{Case: "hash on tag", Hash: "132312322321", Expected: "tag tag-1", HEAD: "12345678910", 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: "no hash on commit", Expected: "commit 1234567", HEAD: "12345678910"},
|
||||||
|
}
|
||||||
|
for _, tc := range cases {
|
||||||
|
env := new(MockedEnvironment)
|
||||||
|
env.On("getFileContent", "/HEAD").Return(tc.HEAD)
|
||||||
|
env.On("getRuntimeGOOS", nil).Return("unix")
|
||||||
|
env.On("isWsl", nil).Return(false)
|
||||||
|
env.mockGitCommand(tc.Tag, "describe", "--tags", "--exact-match")
|
||||||
|
g := &git{
|
||||||
|
env: env,
|
||||||
|
props: map[Property]interface{}{
|
||||||
|
BranchIcon: "branch ",
|
||||||
|
CommitIcon: "commit ",
|
||||||
|
TagIcon: "tag ",
|
||||||
|
},
|
||||||
|
Hash: tc.Hash,
|
||||||
|
}
|
||||||
|
g.setPrettyHEADName()
|
||||||
|
assert.Equal(t, tc.Expected, g.HEAD, tc.Case)
|
||||||
}
|
}
|
||||||
g := setupHEADContextEnv(context)
|
|
||||||
got := g.getGitHEADContext("")
|
|
||||||
assert.Equal(t, want, got)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetGitHEADContextRebaseMerge(t *testing.T) {
|
func TestSetGitStatus(t *testing.T) {
|
||||||
want := "\ue728 \ue0a0cool-feature-bro onto \ue0a0main (2/3) at \uf417whatever"
|
cases := []struct {
|
||||||
context := &detachedContext{
|
Case string
|
||||||
currentCommit: "whatever",
|
Output string
|
||||||
rebase: "true",
|
ExpectedWorking *GitStatus
|
||||||
rebaseMerge: true,
|
ExpectedStaging *GitStatus
|
||||||
origin: "cool-feature-bro",
|
ExpectedHash string
|
||||||
onto: "main",
|
ExpectedRef string
|
||||||
step: "2",
|
ExpectedUpstream string
|
||||||
total: "3",
|
ExpectedAhead int
|
||||||
|
ExpectedBehind int
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
Case: "all different options on working and staging, no remote",
|
||||||
|
Output: `
|
||||||
|
# branch.oid 1234567891011121314
|
||||||
|
# branch.head rework-git-status
|
||||||
|
1 .R N...
|
||||||
|
1 .C N...
|
||||||
|
1 .M N...
|
||||||
|
1 .m N...
|
||||||
|
1 .? N...
|
||||||
|
1 .D N...
|
||||||
|
1 .A N...
|
||||||
|
1 .U N...
|
||||||
|
1 A. N...
|
||||||
|
`,
|
||||||
|
ExpectedWorking: &GitStatus{Modified: 4, Added: 2, Deleted: 1, Unmerged: 1},
|
||||||
|
ExpectedStaging: &GitStatus{Added: 1},
|
||||||
|
ExpectedHash: "1234567",
|
||||||
|
ExpectedRef: "rework-git-status",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Case: "all different options on working and staging, with remote",
|
||||||
|
Output: `
|
||||||
|
# branch.oid 1234567891011121314
|
||||||
|
# branch.head rework-git-status
|
||||||
|
# branch.upstream origin/rework-git-status
|
||||||
|
1 .R N...
|
||||||
|
1 .C N...
|
||||||
|
1 .M N...
|
||||||
|
1 .m N...
|
||||||
|
1 .? N...
|
||||||
|
1 .D N...
|
||||||
|
1 .A N...
|
||||||
|
1 .U N...
|
||||||
|
1 A. N...
|
||||||
|
`,
|
||||||
|
ExpectedWorking: &GitStatus{Modified: 4, Added: 2, Deleted: 1, Unmerged: 1},
|
||||||
|
ExpectedStaging: &GitStatus{Added: 1},
|
||||||
|
ExpectedUpstream: "origin/rework-git-status",
|
||||||
|
ExpectedHash: "1234567",
|
||||||
|
ExpectedRef: "rework-git-status",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Case: "remote with equal branch",
|
||||||
|
Output: `
|
||||||
|
# branch.oid 1234567891011121314
|
||||||
|
# branch.head rework-git-status
|
||||||
|
# branch.upstream origin/rework-git-status
|
||||||
|
`,
|
||||||
|
ExpectedUpstream: "origin/rework-git-status",
|
||||||
|
ExpectedHash: "1234567",
|
||||||
|
ExpectedRef: "rework-git-status",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Case: "remote with branch status",
|
||||||
|
Output: `
|
||||||
|
# branch.oid 1234567891011121314
|
||||||
|
# branch.head rework-git-status
|
||||||
|
# branch.upstream origin/rework-git-status
|
||||||
|
# branch.ab +2 -1
|
||||||
|
`,
|
||||||
|
ExpectedUpstream: "origin/rework-git-status",
|
||||||
|
ExpectedHash: "1234567",
|
||||||
|
ExpectedRef: "rework-git-status",
|
||||||
|
ExpectedAhead: 2,
|
||||||
|
ExpectedBehind: 1,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
g := setupHEADContextEnv(context)
|
for _, tc := range cases {
|
||||||
got := g.getGitHEADContext("")
|
env := new(MockedEnvironment)
|
||||||
assert.Equal(t, want, got)
|
env.On("getRuntimeGOOS", nil).Return("unix")
|
||||||
|
env.On("isWsl", nil).Return(false)
|
||||||
|
env.mockGitCommand(strings.ReplaceAll(tc.Output, "\t", ""), "status", "-unormal", "--branch", "--porcelain=2")
|
||||||
|
g := &git{
|
||||||
|
env: env,
|
||||||
}
|
}
|
||||||
|
if tc.ExpectedWorking == nil {
|
||||||
func TestGetGitHEADContextRebaseApply(t *testing.T) {
|
tc.ExpectedWorking = &GitStatus{}
|
||||||
want := "\ue728 \ue0a0cool-feature-bro (2/3) at \uf417whatever"
|
|
||||||
context := &detachedContext{
|
|
||||||
currentCommit: "whatever",
|
|
||||||
rebase: "true",
|
|
||||||
rebaseApply: true,
|
|
||||||
origin: "cool-feature-bro",
|
|
||||||
step: "2",
|
|
||||||
total: "3",
|
|
||||||
}
|
}
|
||||||
g := setupHEADContextEnv(context)
|
if tc.ExpectedStaging == nil {
|
||||||
got := g.getGitHEADContext("")
|
tc.ExpectedStaging = &GitStatus{}
|
||||||
assert.Equal(t, want, got)
|
|
||||||
}
|
}
|
||||||
|
g.setGitStatus()
|
||||||
func TestGetGitHEADContextRebaseUnknown(t *testing.T) {
|
assert.Equal(t, tc.ExpectedStaging, g.Staging, tc.Case)
|
||||||
want := "\uf417whatever"
|
assert.Equal(t, tc.ExpectedWorking, g.Working, tc.Case)
|
||||||
context := &detachedContext{
|
assert.Equal(t, tc.ExpectedHash, g.Hash, tc.Case)
|
||||||
currentCommit: "whatever",
|
assert.Equal(t, tc.ExpectedRef, g.Ref, tc.Case)
|
||||||
rebase: "true",
|
assert.Equal(t, tc.ExpectedUpstream, g.Upstream, tc.Case)
|
||||||
|
assert.Equal(t, tc.ExpectedAhead, g.Ahead, tc.Case)
|
||||||
|
assert.Equal(t, tc.ExpectedBehind, g.Behind, tc.Case)
|
||||||
}
|
}
|
||||||
g := setupHEADContextEnv(context)
|
|
||||||
got := g.getGitHEADContext("")
|
|
||||||
assert.Equal(t, want, got)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetGitHEADContextCherryPickOnBranch(t *testing.T) {
|
|
||||||
want := "\ue29b pickme onto \ue0a0main"
|
|
||||||
context := &detachedContext{
|
|
||||||
currentCommit: "whatever",
|
|
||||||
branchName: "main",
|
|
||||||
cherryPick: true,
|
|
||||||
cherryPickSHA: "pickme",
|
|
||||||
}
|
|
||||||
g := setupHEADContextEnv(context)
|
|
||||||
got := g.getGitHEADContext("main")
|
|
||||||
assert.Equal(t, want, got)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetGitHEADContextCherryPickOnTag(t *testing.T) {
|
|
||||||
want := "\ue29b pickme onto \uf412v3.4.6"
|
|
||||||
context := &detachedContext{
|
|
||||||
currentCommit: "whatever",
|
|
||||||
tagName: "v3.4.6",
|
|
||||||
cherryPick: true,
|
|
||||||
cherryPickSHA: "pickme",
|
|
||||||
}
|
|
||||||
g := setupHEADContextEnv(context)
|
|
||||||
got := g.getGitHEADContext("")
|
|
||||||
assert.Equal(t, want, got)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetGitHEADContextRevertOnBranch(t *testing.T) {
|
|
||||||
want := "\uf0e2 012345 onto \ue0a0main"
|
|
||||||
context := &detachedContext{
|
|
||||||
currentCommit: "whatever",
|
|
||||||
branchName: "main",
|
|
||||||
revert: true,
|
|
||||||
revertSHA: "01234567",
|
|
||||||
}
|
|
||||||
g := setupHEADContextEnv(context)
|
|
||||||
got := g.getGitHEADContext("main")
|
|
||||||
assert.Equal(t, want, got)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetGitHEADContextRevertOnTag(t *testing.T) {
|
|
||||||
want := "\uf0e2 012345 onto \uf412v3.4.6"
|
|
||||||
context := &detachedContext{
|
|
||||||
currentCommit: "whatever",
|
|
||||||
tagName: "v3.4.6",
|
|
||||||
revert: true,
|
|
||||||
revertSHA: "01234567",
|
|
||||||
}
|
|
||||||
g := setupHEADContextEnv(context)
|
|
||||||
got := g.getGitHEADContext("")
|
|
||||||
assert.Equal(t, want, got)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetGitHEADContextSequencerCherryPickOnBranch(t *testing.T) {
|
|
||||||
want := "\ue29b pickme onto \ue0a0main"
|
|
||||||
context := &detachedContext{
|
|
||||||
currentCommit: "whatever",
|
|
||||||
branchName: "main",
|
|
||||||
sequencer: true,
|
|
||||||
sequencerTodo: "pick pickme message\npick notme message",
|
|
||||||
}
|
|
||||||
g := setupHEADContextEnv(context)
|
|
||||||
got := g.getGitHEADContext("main")
|
|
||||||
assert.Equal(t, want, got)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetGitHEADContextSequencerCherryPickOnTag(t *testing.T) {
|
|
||||||
want := "\ue29b pickme onto \uf412v3.4.6"
|
|
||||||
context := &detachedContext{
|
|
||||||
currentCommit: "whatever",
|
|
||||||
tagName: "v3.4.6",
|
|
||||||
sequencer: true,
|
|
||||||
sequencerTodo: "pick pickme message\npick notme message",
|
|
||||||
}
|
|
||||||
g := setupHEADContextEnv(context)
|
|
||||||
got := g.getGitHEADContext("")
|
|
||||||
assert.Equal(t, want, got)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetGitHEADContextSequencerRevertOnBranch(t *testing.T) {
|
|
||||||
want := "\uf0e2 012345 onto \ue0a0main"
|
|
||||||
context := &detachedContext{
|
|
||||||
currentCommit: "whatever",
|
|
||||||
branchName: "main",
|
|
||||||
sequencer: true,
|
|
||||||
sequencerTodo: "revert 01234567 message\nrevert notme message",
|
|
||||||
}
|
|
||||||
g := setupHEADContextEnv(context)
|
|
||||||
got := g.getGitHEADContext("main")
|
|
||||||
assert.Equal(t, want, got)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetGitHEADContextSequencerRevertOnTag(t *testing.T) {
|
|
||||||
want := "\uf0e2 012345 onto \uf412v3.4.6"
|
|
||||||
context := &detachedContext{
|
|
||||||
currentCommit: "whatever",
|
|
||||||
tagName: "v3.4.6",
|
|
||||||
sequencer: true,
|
|
||||||
sequencerTodo: "revert 01234567 message\nrevert notme message",
|
|
||||||
}
|
|
||||||
g := setupHEADContextEnv(context)
|
|
||||||
got := g.getGitHEADContext("")
|
|
||||||
assert.Equal(t, want, got)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetGitHEADContextMerge(t *testing.T) {
|
|
||||||
want := "\ue727 \ue0a0feat into \ue0a0main"
|
|
||||||
context := &detachedContext{
|
|
||||||
merge: true,
|
|
||||||
mergeHEAD: "feat",
|
|
||||||
mergeMsgStart: "Merge branch",
|
|
||||||
}
|
|
||||||
g := setupHEADContextEnv(context)
|
|
||||||
got := g.getGitHEADContext("main")
|
|
||||||
assert.Equal(t, want, got)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetGitHEADContextMergeRemote(t *testing.T) {
|
|
||||||
want := "\ue727 \ue0a0feat into \ue0a0main"
|
|
||||||
context := &detachedContext{
|
|
||||||
merge: true,
|
|
||||||
mergeHEAD: "feat",
|
|
||||||
mergeMsgStart: "Merge remote-tracking branch",
|
|
||||||
}
|
|
||||||
g := setupHEADContextEnv(context)
|
|
||||||
got := g.getGitHEADContext("main")
|
|
||||||
assert.Equal(t, want, got)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetGitHEADContextMergeTag(t *testing.T) {
|
|
||||||
want := "\ue727 \uf412v7.8.9 into \ue0a0main"
|
|
||||||
context := &detachedContext{
|
|
||||||
merge: true,
|
|
||||||
mergeHEAD: "v7.8.9",
|
|
||||||
mergeMsgStart: "Merge tag",
|
|
||||||
}
|
|
||||||
g := setupHEADContextEnv(context)
|
|
||||||
got := g.getGitHEADContext("main")
|
|
||||||
assert.Equal(t, want, got)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetGitHEADContextMergeCommit(t *testing.T) {
|
|
||||||
want := "\ue727 \uf4178d7e869 into \ue0a0main"
|
|
||||||
context := &detachedContext{
|
|
||||||
merge: true,
|
|
||||||
mergeHEAD: "8d7e869",
|
|
||||||
mergeMsgStart: "Merge commit",
|
|
||||||
}
|
|
||||||
g := setupHEADContextEnv(context)
|
|
||||||
got := g.getGitHEADContext("main")
|
|
||||||
assert.Equal(t, want, got)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetGitHEADContextMergeIntoTag(t *testing.T) {
|
|
||||||
want := "\ue727 \ue0a0feat into \uf412v3.4.6"
|
|
||||||
context := &detachedContext{
|
|
||||||
tagName: "v3.4.6",
|
|
||||||
merge: true,
|
|
||||||
mergeHEAD: "feat",
|
|
||||||
mergeMsgStart: "Merge branch",
|
|
||||||
}
|
|
||||||
g := setupHEADContextEnv(context)
|
|
||||||
got := g.getGitHEADContext("")
|
|
||||||
assert.Equal(t, want, got)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetStashContextZeroEntries(t *testing.T) {
|
func TestGetStashContextZeroEntries(t *testing.T) {
|
||||||
|
@ -392,62 +396,6 @@ func TestGetStashContextZeroEntries(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestParseGitBranchInfoEqual(t *testing.T) {
|
|
||||||
g := git{}
|
|
||||||
branchInfo := "## master...origin/master"
|
|
||||||
got := g.parseGitStatusInfo(branchInfo)
|
|
||||||
assert.Equal(t, "master", got["local"])
|
|
||||||
assert.Equal(t, "origin/master", got["upstream"])
|
|
||||||
assert.Empty(t, got["ahead"])
|
|
||||||
assert.Empty(t, got["behind"])
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestParseGitBranchInfoAhead(t *testing.T) {
|
|
||||||
g := git{}
|
|
||||||
branchInfo := "## master...origin/master [ahead 1]"
|
|
||||||
got := g.parseGitStatusInfo(branchInfo)
|
|
||||||
assert.Equal(t, "master", got["local"])
|
|
||||||
assert.Equal(t, "origin/master", got["upstream"])
|
|
||||||
assert.Equal(t, "1", got["ahead"])
|
|
||||||
assert.Empty(t, got["behind"])
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestParseGitBranchInfoBehind(t *testing.T) {
|
|
||||||
g := git{}
|
|
||||||
branchInfo := "## master...origin/master [behind 1]"
|
|
||||||
got := g.parseGitStatusInfo(branchInfo)
|
|
||||||
assert.Equal(t, "master", got["local"])
|
|
||||||
assert.Equal(t, "origin/master", got["upstream"])
|
|
||||||
assert.Equal(t, "1", got["behind"])
|
|
||||||
assert.Empty(t, got["ahead"])
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestParseGitBranchInfoBehindandAhead(t *testing.T) {
|
|
||||||
g := git{}
|
|
||||||
branchInfo := "## master...origin/master [ahead 1, behind 2]"
|
|
||||||
got := g.parseGitStatusInfo(branchInfo)
|
|
||||||
assert.Equal(t, "master", got["local"])
|
|
||||||
assert.Equal(t, "origin/master", got["upstream"])
|
|
||||||
assert.Equal(t, "2", got["behind"])
|
|
||||||
assert.Equal(t, "1", got["ahead"])
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestParseGitBranchInfoNoRemote(t *testing.T) {
|
|
||||||
g := git{}
|
|
||||||
branchInfo := "## master"
|
|
||||||
got := g.parseGitStatusInfo(branchInfo)
|
|
||||||
assert.Equal(t, "master", got["local"])
|
|
||||||
assert.Empty(t, got["upstream"])
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestParseGitBranchInfoRemoteGone(t *testing.T) {
|
|
||||||
g := git{}
|
|
||||||
branchInfo := "## test-branch...origin/test-branch [gone]"
|
|
||||||
got := g.parseGitStatusInfo(branchInfo)
|
|
||||||
assert.Equal(t, "test-branch", got["local"])
|
|
||||||
assert.Equal(t, "gone", got["upstream_status"])
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGitStatusUnmerged(t *testing.T) {
|
func TestGitStatusUnmerged(t *testing.T) {
|
||||||
expected := "x1"
|
expected := "x1"
|
||||||
status := &GitStatus{
|
status := &GitStatus{
|
||||||
|
@ -471,71 +419,6 @@ func TestGitStatusEmpty(t *testing.T) {
|
||||||
assert.Equal(t, expected, status.String())
|
assert.Equal(t, expected, status.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestParseGitStatsWorking(t *testing.T) {
|
|
||||||
status := &GitStatus{}
|
|
||||||
output := []string{
|
|
||||||
"## amazing-feat",
|
|
||||||
" M change.go",
|
|
||||||
"DD change.go",
|
|
||||||
" ? change.go",
|
|
||||||
" ? change.go",
|
|
||||||
" A change.go",
|
|
||||||
" U change.go",
|
|
||||||
" R change.go",
|
|
||||||
" C change.go",
|
|
||||||
}
|
|
||||||
status.parse(output, true)
|
|
||||||
assert.Equal(t, 3, status.Modified)
|
|
||||||
assert.Equal(t, 1, status.Unmerged)
|
|
||||||
assert.Equal(t, 3, status.Added)
|
|
||||||
assert.Equal(t, 1, status.Deleted)
|
|
||||||
assert.True(t, status.Changed)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestParseGitStatsStaging(t *testing.T) {
|
|
||||||
status := &GitStatus{}
|
|
||||||
output := []string{
|
|
||||||
"## amazing-feat",
|
|
||||||
" M change.go",
|
|
||||||
"DD change.go",
|
|
||||||
" ? change.go",
|
|
||||||
"?? change.go",
|
|
||||||
" A change.go",
|
|
||||||
"DU change.go",
|
|
||||||
"MR change.go",
|
|
||||||
"AC change.go",
|
|
||||||
}
|
|
||||||
status.parse(output, false)
|
|
||||||
assert.Equal(t, 1, status.Modified)
|
|
||||||
assert.Equal(t, 0, status.Unmerged)
|
|
||||||
assert.Equal(t, 1, status.Added)
|
|
||||||
assert.Equal(t, 2, status.Deleted)
|
|
||||||
assert.True(t, status.Changed)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestParseGitStatsNoChanges(t *testing.T) {
|
|
||||||
status := &GitStatus{}
|
|
||||||
expected := &GitStatus{}
|
|
||||||
output := []string{
|
|
||||||
"## amazing-feat",
|
|
||||||
}
|
|
||||||
status.parse(output, false)
|
|
||||||
assert.Equal(t, expected, status)
|
|
||||||
assert.False(t, status.Changed)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestParseGitStatsInvalidLine(t *testing.T) {
|
|
||||||
status := &GitStatus{}
|
|
||||||
expected := &GitStatus{}
|
|
||||||
output := []string{
|
|
||||||
"## amazing-feat",
|
|
||||||
"#",
|
|
||||||
}
|
|
||||||
status.parse(output, false)
|
|
||||||
assert.Equal(t, expected, status)
|
|
||||||
assert.False(t, status.Changed)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGitUpstream(t *testing.T) {
|
func TestGitUpstream(t *testing.T) {
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
Case string
|
Case string
|
||||||
|
@ -580,7 +463,7 @@ func TestGetBranchStatus(t *testing.T) {
|
||||||
Behind int
|
Behind int
|
||||||
Upstream string
|
Upstream string
|
||||||
}{
|
}{
|
||||||
{Case: "Equal with remote", Expected: " equal", Upstream: "main"},
|
{Case: "Equal with remote", Expected: " equal", Upstream: branchName},
|
||||||
{Case: "Ahead", Expected: " up2", Ahead: 2},
|
{Case: "Ahead", Expected: " up2", Ahead: 2},
|
||||||
{Case: "Behind", Expected: " down8", Behind: 8},
|
{Case: "Behind", Expected: " down8", Behind: 8},
|
||||||
{Case: "Behind and ahead", Expected: " up7 down8", Behind: 8, Ahead: 7},
|
{Case: "Behind and ahead", Expected: " up7 down8", Behind: 8, Ahead: 7},
|
||||||
|
@ -657,7 +540,7 @@ func TestTruncateBranch(t *testing.T) {
|
||||||
g := &git{
|
g := &git{
|
||||||
props: props,
|
props: props,
|
||||||
}
|
}
|
||||||
assert.Equal(t, tc.Expected, g.truncateBranch(tc.Branch), tc.Case)
|
assert.Equal(t, tc.Expected, g.formatHEAD(tc.Branch), tc.Case)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -684,7 +567,7 @@ func TestTruncateBranchWithSymbol(t *testing.T) {
|
||||||
g := &git{
|
g := &git{
|
||||||
props: props,
|
props: props,
|
||||||
}
|
}
|
||||||
assert.Equal(t, tc.Expected, g.truncateBranch(tc.Branch), tc.Case)
|
assert.Equal(t, tc.Expected, g.formatHEAD(tc.Branch), tc.Case)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -730,10 +613,10 @@ func TestGitTemplateString(t *testing.T) {
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
Case: "Only HEAD name",
|
Case: "Only HEAD name",
|
||||||
Expected: "main",
|
Expected: branchName,
|
||||||
Template: "{{ .HEAD }}",
|
Template: "{{ .HEAD }}",
|
||||||
Git: &git{
|
Git: &git{
|
||||||
HEAD: "main",
|
HEAD: branchName,
|
||||||
Behind: 2,
|
Behind: 2,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -742,23 +625,20 @@ func TestGitTemplateString(t *testing.T) {
|
||||||
Expected: "main \uF044 +2 ~3",
|
Expected: "main \uF044 +2 ~3",
|
||||||
Template: "{{ .HEAD }}{{ if .Working.Changed }} \uF044 {{ .Working.String }}{{ end }}",
|
Template: "{{ .HEAD }}{{ if .Working.Changed }} \uF044 {{ .Working.String }}{{ end }}",
|
||||||
Git: &git{
|
Git: &git{
|
||||||
HEAD: "main",
|
HEAD: branchName,
|
||||||
Working: &GitStatus{
|
Working: &GitStatus{
|
||||||
Added: 2,
|
Added: 2,
|
||||||
Modified: 3,
|
Modified: 3,
|
||||||
Changed: true,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Case: "No working area changes",
|
Case: "No working area changes",
|
||||||
Expected: "main",
|
Expected: branchName,
|
||||||
Template: "{{ .HEAD }}{{ if .Working.Changed }} \uF044 {{ .Working.String }}{{ end }}",
|
Template: "{{ .HEAD }}{{ if .Working.Changed }} \uF044 {{ .Working.String }}{{ end }}",
|
||||||
Git: &git{
|
Git: &git{
|
||||||
HEAD: "main",
|
HEAD: branchName,
|
||||||
Working: &GitStatus{
|
Working: &GitStatus{},
|
||||||
Changed: false,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -766,16 +646,14 @@ func TestGitTemplateString(t *testing.T) {
|
||||||
Expected: "main \uF046 +5 ~1 \uF044 +2 ~3",
|
Expected: "main \uF046 +5 ~1 \uF044 +2 ~3",
|
||||||
Template: "{{ .HEAD }}{{ if .Staging.Changed }} \uF046 {{ .Staging.String }}{{ end }}{{ if .Working.Changed }} \uF044 {{ .Working.String }}{{ end }}",
|
Template: "{{ .HEAD }}{{ if .Staging.Changed }} \uF046 {{ .Staging.String }}{{ end }}{{ if .Working.Changed }} \uF044 {{ .Working.String }}{{ end }}",
|
||||||
Git: &git{
|
Git: &git{
|
||||||
HEAD: "main",
|
HEAD: branchName,
|
||||||
Working: &GitStatus{
|
Working: &GitStatus{
|
||||||
Added: 2,
|
Added: 2,
|
||||||
Modified: 3,
|
Modified: 3,
|
||||||
Changed: true,
|
|
||||||
},
|
},
|
||||||
Staging: &GitStatus{
|
Staging: &GitStatus{
|
||||||
Added: 5,
|
Added: 5,
|
||||||
Modified: 1,
|
Modified: 1,
|
||||||
Changed: true,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -784,16 +662,14 @@ func TestGitTemplateString(t *testing.T) {
|
||||||
Expected: "main \uF046 +5 ~1 | \uF044 +2 ~3",
|
Expected: "main \uF046 +5 ~1 | \uF044 +2 ~3",
|
||||||
Template: "{{ .HEAD }}{{ if .Staging.Changed }} \uF046 {{ .Staging.String }}{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Working.Changed }} \uF044 {{ .Working.String }}{{ end }}", //nolint:lll
|
Template: "{{ .HEAD }}{{ if .Staging.Changed }} \uF046 {{ .Staging.String }}{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Working.Changed }} \uF044 {{ .Working.String }}{{ end }}", //nolint:lll
|
||||||
Git: &git{
|
Git: &git{
|
||||||
HEAD: "main",
|
HEAD: branchName,
|
||||||
Working: &GitStatus{
|
Working: &GitStatus{
|
||||||
Added: 2,
|
Added: 2,
|
||||||
Modified: 3,
|
Modified: 3,
|
||||||
Changed: true,
|
|
||||||
},
|
},
|
||||||
Staging: &GitStatus{
|
Staging: &GitStatus{
|
||||||
Added: 5,
|
Added: 5,
|
||||||
Modified: 1,
|
Modified: 1,
|
||||||
Changed: true,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -802,26 +678,24 @@ func TestGitTemplateString(t *testing.T) {
|
||||||
Expected: "main \uF046 +5 ~1 | \uF044 +2 ~3 \uf692 3",
|
Expected: "main \uF046 +5 ~1 | \uF044 +2 ~3 \uf692 3",
|
||||||
Template: "{{ .HEAD }}{{ if .Staging.Changed }} \uF046 {{ .Staging.String }}{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Working.Changed }} \uF044 {{ .Working.String }}{{ end }}{{ if gt .StashCount 0 }} \uF692 {{ .StashCount }}{{ end }}", //nolint:lll
|
Template: "{{ .HEAD }}{{ if .Staging.Changed }} \uF046 {{ .Staging.String }}{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Working.Changed }} \uF044 {{ .Working.String }}{{ end }}{{ if gt .StashCount 0 }} \uF692 {{ .StashCount }}{{ end }}", //nolint:lll
|
||||||
Git: &git{
|
Git: &git{
|
||||||
HEAD: "main",
|
HEAD: branchName,
|
||||||
Working: &GitStatus{
|
Working: &GitStatus{
|
||||||
Added: 2,
|
Added: 2,
|
||||||
Modified: 3,
|
Modified: 3,
|
||||||
Changed: true,
|
|
||||||
},
|
},
|
||||||
Staging: &GitStatus{
|
Staging: &GitStatus{
|
||||||
Added: 5,
|
Added: 5,
|
||||||
Modified: 1,
|
Modified: 1,
|
||||||
Changed: true,
|
|
||||||
},
|
},
|
||||||
StashCount: 3,
|
StashCount: 3,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Case: "No local changes",
|
Case: "No local changes",
|
||||||
Expected: "main",
|
Expected: branchName,
|
||||||
Template: "{{ .HEAD }}{{ if .Staging.Changed }} \uF046{{ .Staging.String }}{{ end }}{{ if .Working.Changed }} \uF044{{ .Working.String }}{{ end }}",
|
Template: "{{ .HEAD }}{{ if .Staging.Changed }} \uF046{{ .Staging.String }}{{ end }}{{ if .Working.Changed }} \uF044{{ .Working.String }}{{ end }}",
|
||||||
Git: &git{
|
Git: &git{
|
||||||
HEAD: "main",
|
HEAD: branchName,
|
||||||
Staging: &GitStatus{},
|
Staging: &GitStatus{},
|
||||||
Working: &GitStatus{},
|
Working: &GitStatus{},
|
||||||
},
|
},
|
||||||
|
@ -831,7 +705,7 @@ func TestGitTemplateString(t *testing.T) {
|
||||||
Expected: "from GitHub on main",
|
Expected: "from GitHub on main",
|
||||||
Template: "from {{ .UpstreamIcon }} on {{ .HEAD }}",
|
Template: "from {{ .UpstreamIcon }} on {{ .HEAD }}",
|
||||||
Git: &git{
|
Git: &git{
|
||||||
HEAD: "main",
|
HEAD: branchName,
|
||||||
Staging: &GitStatus{},
|
Staging: &GitStatus{},
|
||||||
Working: &GitStatus{},
|
Working: &GitStatus{},
|
||||||
UpstreamIcon: "GitHub",
|
UpstreamIcon: "GitHub",
|
||||||
|
|
Loading…
Reference in a new issue