Skip to content

Commit c2a1106

Browse files
committed
show pr status in view
1 parent d77d2fe commit c2a1106

2 files changed

Lines changed: 56 additions & 4 deletions

File tree

cmd/view.go

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,18 +90,66 @@ func runView(cfg *config.Config, opts *viewOptions) error {
9090
}
9191

9292
func viewShort(cfg *config.Config, s *stack.Stack, currentBranch string) error {
93+
var repoOwner, repoName string
94+
if repo, err := cfg.Repo(); err == nil {
95+
repoOwner = repo.Owner
96+
repoName = repo.Name
97+
}
98+
9399
for i := len(s.Branches) - 1; i >= 0; i-- {
94100
b := s.Branches[i]
101+
merged := b.PullRequest != nil && b.PullRequest.Merged
102+
indicator := branchStatusIndicator(cfg, s, b)
103+
prSuffix := shortPRSuffix(cfg, b, repoOwner, repoName)
95104
if b.Branch == currentBranch {
96-
cfg.Outf("● %s %s\n", cfg.ColorBold(b.Branch), cfg.ColorCyan("(current)"))
105+
cfg.Outf("» %s%s%s %s\n", cfg.ColorBold(b.Branch), indicator, prSuffix, cfg.ColorCyan("(current)"))
106+
} else if merged {
107+
cfg.Outf("│ %s%s%s\n", cfg.ColorGray(b.Branch), indicator, prSuffix)
97108
} else {
98-
cfg.Outf(" %s\n", b.Branch)
109+
cfg.Outf(" %s%s%s\n", b.Branch, indicator, prSuffix)
99110
}
100111
}
101112
cfg.Outf("└ %s\n", s.Trunk.Branch)
102113
return nil
103114
}
104115

116+
// branchStatusIndicator returns a colored status icon for a branch:
117+
// - ✓ (purple) if the PR has been merged
118+
// - ⚠ (yellow) if the branch needs rebasing (non-linear history)
119+
// - ○ (green) if there is an open PR
120+
func branchStatusIndicator(cfg *config.Config, s *stack.Stack, b stack.BranchRef) string {
121+
if b.PullRequest != nil && b.PullRequest.Merged {
122+
return " " + cfg.ColorMagenta("✓")
123+
}
124+
125+
baseBranch := s.BaseBranch(b.Branch)
126+
if needsRebase, err := git.IsAncestor(baseBranch, b.Branch); err == nil && !needsRebase {
127+
return " " + cfg.ColorWarning("⚠")
128+
}
129+
130+
if b.PullRequest != nil && b.PullRequest.Number != 0 {
131+
return " " + cfg.ColorSuccess("○")
132+
}
133+
134+
return ""
135+
}
136+
137+
func shortPRSuffix(cfg *config.Config, b stack.BranchRef, owner, repo string) string {
138+
if b.PullRequest == nil || b.PullRequest.Number == 0 {
139+
return ""
140+
}
141+
prNum := fmt.Sprintf("#%d", b.PullRequest.Number)
142+
if owner != "" && repo != "" {
143+
url := fmt.Sprintf("https://github.com/%s/%s/pull/%d", owner, repo, b.PullRequest.Number)
144+
prNum = fmt.Sprintf("\033]8;;%s\033\\%s\033]8;;\033\\", url, prNum)
145+
}
146+
colorFn := cfg.ColorSuccess // green for open
147+
if b.PullRequest.Merged {
148+
colorFn = cfg.ColorMagenta // purple for merged
149+
}
150+
return fmt.Sprintf(" %s", colorFn(prNum))
151+
}
152+
105153
func viewFull(cfg *config.Config, s *stack.Stack, currentBranch string) error {
106154
client, clientErr := cfg.GitHubClient()
107155

@@ -123,6 +171,8 @@ func viewFull(cfg *config.Config, s *stack.Stack, currentBranch string) error {
123171
bullet = "●"
124172
}
125173

174+
indicator := branchStatusIndicator(cfg, s, b)
175+
126176
prInfo := ""
127177
if clientErr == nil && repoErr == nil {
128178
pr, err := client.FindPRForBranch(b.Branch)
@@ -136,7 +186,7 @@ func viewFull(cfg *config.Config, s *stack.Stack, currentBranch string) error {
136186
branchName = cfg.ColorCyan(b.Branch + " (current)")
137187
}
138188

139-
fmt.Fprintf(&buf, "%s %s%s\n", bullet, branchName, prInfo)
189+
fmt.Fprintf(&buf, "%s %s %s%s\n", bullet, branchName, indicator, prInfo)
140190

141191
commits, err := git.Log(b.Branch, 1)
142192
if err == nil && len(commits) > 0 {

internal/git/git.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package git
22

33
import (
44
"context"
5+
"errors"
56
"os"
67
"os/exec"
78
"path/filepath"
@@ -277,7 +278,8 @@ func IsAncestor(ancestor, descendant string) (bool, error) {
277278
return true, nil
278279
}
279280
// Exit code 1 means "not an ancestor", which is not an error condition.
280-
if exitErr, ok := err.(*exec.ExitError); ok && exitErr.ExitCode() == 1 {
281+
var exitErr *exec.ExitError
282+
if errors.As(err, &exitErr) && exitErr.ExitCode() == 1 {
281283
return false, nil
282284
}
283285
return false, err

0 commit comments

Comments
 (0)