6
0
mirror of https://github.com/grdl/git-get.git synced 2026-02-11 10:04:15 +00:00

Add a list flag and basic rendering of repos status

This commit is contained in:
Grzegorz Dlugoszewski
2020-06-03 15:59:51 +02:00
parent b7bd30c960
commit 64dfea5a7f
5 changed files with 108 additions and 41 deletions

View File

@@ -18,15 +18,30 @@ var cmd = &cobra.Command{
Use: "git-get <repo>", Use: "git-get <repo>",
Short: "git get", Short: "git get",
Run: Run, Run: Run,
Args: cobra.ExactArgs(1), Args: cobra.MaximumNArgs(1),
Version: fmt.Sprintf("%s - %s, build at %s", version, commit, date), Version: fmt.Sprintf("%s - %s, build at %s", version, commit, date),
} }
var list bool
func init() { func init() {
pkg.LoadConf() pkg.LoadConf()
cmd.PersistentFlags().BoolVarP(&list, "list", "l", false, "Lists all repositories inside git-get root")
} }
func Run(cmd *cobra.Command, args []string) { func Run(cmd *cobra.Command, args []string) {
if list {
paths, err := pkg.FindRepos()
exitIfError(err)
repos, err := pkg.OpenAll(paths)
exitIfError(err)
pkg.PrintRepos(repos)
os.Exit(0)
}
url, err := pkg.ParseURL(args[0]) url, err := pkg.ParseURL(args[0])
exitIfError(err) exitIfError(err)

View File

@@ -119,8 +119,6 @@ func PrintRepos(repos []*Repo) {
seg[i] = make([]string, len(subpaths)) seg[i] = make([]string, len(subpaths))
//t.AddBranch(fmt.Sprintf("\033[1;31m%s\033[0m", path))
branch := t branch := t
for j, sub := range subpaths { for j, sub := range subpaths {
seg[i][j] = sub seg[i][j] = sub
@@ -134,7 +132,7 @@ func PrintRepos(repos []*Repo) {
// if this is the last segment, it means that's the name of the repository and we need to print its status // if this is the last segment, it means that's the name of the repository and we need to print its status
if j == len(seg[i])-1 { if j == len(seg[i])-1 {
value = value + PrintRepoStatus(repo) value = value + " " + renderWorktreeStatus(repo)
} }
branch = branch.AddBranch(value) branch = branch.AddBranch(value)
@@ -146,21 +144,88 @@ func PrintRepos(repos []*Repo) {
const ( const (
ColorRed = "\033[1;31m%s\033[0m" ColorRed = "\033[1;31m%s\033[0m"
ColorGreen = "\033[0;32m%s\033[0m" ColorGreen = "\033[1;32m%s\033[0m"
ColorBlue = "\033[1;34m%s\033[0m" ColorBlue = "\033[1;34m%s\033[0m"
ColorYellow = "\033[1;33m%s\033[0m" ColorYellow = "\033[1;33m%s\033[0m"
) )
func PrintRepoStatus(repo *Repo) string { func renderWorktreeStatus(repo *Repo) string {
status := fmt.Sprintf(ColorGreen, StatusOk) clean := true
var status []string
// if current branch status can't be found it's probably a detached head
// TODO: what if current HEAD points to a tag?
if current := repo.findCurrentBranchStatus(); current == nil {
status = append(status, fmt.Sprintf(ColorYellow, repo.Status.CurrentBranch))
} else {
status = append(status, renderBranchStatus(current))
}
// TODO: this is ugly
// unset clean flag to use it to render braces around worktree status and remove "ok" from branch status if it's there
if repo.Status.HasUncommittedChanges || repo.Status.HasUntrackedFiles {
clean = false
}
if !clean {
status[len(status)-1] = strings.TrimSuffix(status[len(status)-1], StatusOk)
status = append(status, "[")
}
if repo.Status.HasUntrackedFiles { if repo.Status.HasUntrackedFiles {
status = fmt.Sprintf(ColorRed, StatusUntracked) status = append(status, fmt.Sprintf(ColorRed, StatusUntracked))
} }
if repo.Status.HasUncommittedChanges { if repo.Status.HasUncommittedChanges {
status = fmt.Sprintf(ColorRed, StatusUncommitted) status = append(status, fmt.Sprintf(ColorRed, StatusUncommitted))
} }
return " " + status if !clean {
status = append(status, "]")
}
return strings.Join(status, " ")
}
func renderBranchStatus(branch *BranchStatus) string {
// ok indicates that the branch has upstream and is not ahead or behind it
ok := true
var status []string
status = append(status, fmt.Sprintf(ColorBlue, branch.Name))
if branch.Upstream == "" {
ok = false
status = append(status, fmt.Sprintf(ColorYellow, StatusNoUpstream))
}
if branch.NeedsPull {
ok = false
status = append(status, fmt.Sprintf(ColorYellow, StatusBehind))
}
if branch.NeedsPush {
ok = false
status = append(status, fmt.Sprintf(ColorYellow, StatusAhead))
}
if ok {
status = append(status, fmt.Sprintf(ColorGreen, StatusOk))
}
return strings.Join(status, " ")
}
func (r *Repo) findCurrentBranchStatus() *BranchStatus {
if r.Status.CurrentBranch == StatusDetached || r.Status.CurrentBranch == StatusUnknown {
return nil
}
for _, b := range r.Status.Branches {
if b.Name == r.Status.CurrentBranch {
return b
}
}
return nil
} }

View File

@@ -1,17 +0,0 @@
package pkg
import (
"os"
"testing"
)
func TestList(t *testing.T) {
_ = os.Setenv(EnvReposRoot, "/home/gru/workspace")
paths, err := FindRepos()
checkFatal(t, err)
repos, _ := OpenAll(paths)
PrintRepos(repos)
}

View File

@@ -16,6 +16,9 @@ import (
const ( const (
StatusUnknown = "unknown" StatusUnknown = "unknown"
StatusDetached = "detached HEAD" StatusDetached = "detached HEAD"
StatusNoUpstream = "no upstream"
StatusAhead = "ahead"
StatusBehind = "behind"
StatusOk = "ok" StatusOk = "ok"
StatusUncommitted = "uncommitted" StatusUncommitted = "uncommitted"
StatusUntracked = "untracked" StatusUntracked = "untracked"
@@ -24,7 +27,7 @@ const (
type RepoStatus struct { type RepoStatus struct {
HasUntrackedFiles bool HasUntrackedFiles bool
HasUncommittedChanges bool HasUncommittedChanges bool
Current string CurrentBranch string
Branches []*BranchStatus Branches []*BranchStatus
} }
@@ -63,7 +66,7 @@ func (r *Repo) LoadStatus() error {
r.Status.HasUncommittedChanges = hasUncommitted(status) r.Status.HasUncommittedChanges = hasUncommitted(status)
r.Status.HasUntrackedFiles = hasUntracked(status) r.Status.HasUntrackedFiles = hasUntracked(status)
r.Status.Current = currentBranch(r) r.Status.CurrentBranch = currentBranch(r)
err = r.loadBranchesStatus() err = r.loadBranchesStatus()
if err != nil { if err != nil {

View File

@@ -13,25 +13,25 @@ func TestStatus(t *testing.T) {
{newRepoEmpty, &RepoStatus{ {newRepoEmpty, &RepoStatus{
HasUntrackedFiles: false, HasUntrackedFiles: false,
HasUncommittedChanges: false, HasUncommittedChanges: false,
Current: StatusUnknown, CurrentBranch: StatusUnknown,
Branches: nil, Branches: nil,
}}, }},
{newRepoWithUntracked, &RepoStatus{ {newRepoWithUntracked, &RepoStatus{
HasUntrackedFiles: true, HasUntrackedFiles: true,
HasUncommittedChanges: false, HasUncommittedChanges: false,
Current: StatusUnknown, CurrentBranch: StatusUnknown,
Branches: nil, Branches: nil,
}}, }},
{newRepoWithStaged, &RepoStatus{ {newRepoWithStaged, &RepoStatus{
HasUntrackedFiles: false, HasUntrackedFiles: false,
HasUncommittedChanges: true, HasUncommittedChanges: true,
Current: StatusUnknown, CurrentBranch: StatusUnknown,
Branches: nil, Branches: nil,
}}, }},
{newRepoWithCommit, &RepoStatus{ {newRepoWithCommit, &RepoStatus{
HasUntrackedFiles: false, HasUntrackedFiles: false,
HasUncommittedChanges: false, HasUncommittedChanges: false,
Current: "master", CurrentBranch: "master",
Branches: []*BranchStatus{ Branches: []*BranchStatus{
{ {
Name: "master", Name: "master",
@@ -44,7 +44,7 @@ func TestStatus(t *testing.T) {
{newRepoWithModified, &RepoStatus{ {newRepoWithModified, &RepoStatus{
HasUntrackedFiles: false, HasUntrackedFiles: false,
HasUncommittedChanges: true, HasUncommittedChanges: true,
Current: "master", CurrentBranch: "master",
Branches: []*BranchStatus{ Branches: []*BranchStatus{
{ {
Name: "master", Name: "master",
@@ -57,7 +57,7 @@ func TestStatus(t *testing.T) {
{newRepoWithIgnored, &RepoStatus{ {newRepoWithIgnored, &RepoStatus{
HasUntrackedFiles: false, HasUntrackedFiles: false,
HasUncommittedChanges: false, HasUncommittedChanges: false,
Current: "master", CurrentBranch: "master",
Branches: []*BranchStatus{ Branches: []*BranchStatus{
{ {
Name: "master", Name: "master",
@@ -70,7 +70,7 @@ func TestStatus(t *testing.T) {
{newRepoWithLocalBranch, &RepoStatus{ {newRepoWithLocalBranch, &RepoStatus{
HasUntrackedFiles: false, HasUntrackedFiles: false,
HasUncommittedChanges: false, HasUncommittedChanges: false,
Current: "master", CurrentBranch: "master",
Branches: []*BranchStatus{ Branches: []*BranchStatus{
{ {
Name: "local", Name: "local",
@@ -88,7 +88,7 @@ func TestStatus(t *testing.T) {
{newRepoWithClonedBranch, &RepoStatus{ {newRepoWithClonedBranch, &RepoStatus{
HasUntrackedFiles: false, HasUntrackedFiles: false,
HasUncommittedChanges: false, HasUncommittedChanges: false,
Current: "local", CurrentBranch: "local",
Branches: []*BranchStatus{ Branches: []*BranchStatus{
{ {
Name: "local", Name: "local",
@@ -106,7 +106,7 @@ func TestStatus(t *testing.T) {
{newRepoWithDetachedHead, &RepoStatus{ {newRepoWithDetachedHead, &RepoStatus{
HasUntrackedFiles: false, HasUntrackedFiles: false,
HasUncommittedChanges: false, HasUncommittedChanges: false,
Current: StatusDetached, CurrentBranch: StatusDetached,
Branches: []*BranchStatus{ Branches: []*BranchStatus{
{ {
Name: "master", Name: "master",
@@ -119,7 +119,7 @@ func TestStatus(t *testing.T) {
{newRepoWithBranchAhead, &RepoStatus{ {newRepoWithBranchAhead, &RepoStatus{
HasUntrackedFiles: false, HasUntrackedFiles: false,
HasUncommittedChanges: false, HasUncommittedChanges: false,
Current: "master", CurrentBranch: "master",
Branches: []*BranchStatus{ Branches: []*BranchStatus{
{ {
Name: "master", Name: "master",
@@ -132,7 +132,7 @@ func TestStatus(t *testing.T) {
{newRepoWithBranchBehind, &RepoStatus{ {newRepoWithBranchBehind, &RepoStatus{
HasUntrackedFiles: false, HasUntrackedFiles: false,
HasUncommittedChanges: false, HasUncommittedChanges: false,
Current: "master", CurrentBranch: "master",
Branches: []*BranchStatus{ Branches: []*BranchStatus{
{ {
Name: "master", Name: "master",
@@ -145,7 +145,7 @@ func TestStatus(t *testing.T) {
{newRepoWithBranchAheadAndBehind, &RepoStatus{ {newRepoWithBranchAheadAndBehind, &RepoStatus{
HasUntrackedFiles: false, HasUntrackedFiles: false,
HasUncommittedChanges: false, HasUncommittedChanges: false,
Current: "master", CurrentBranch: "master",
Branches: []*BranchStatus{ Branches: []*BranchStatus{
{ {
Name: "master", Name: "master",
@@ -170,5 +170,6 @@ func TestStatus(t *testing.T) {
} }
// TODO: test branch status when tracking a local branch // TODO: test branch status when tracking a local branch
// TODO: test head pointing to a tag
// TODO: newRepoWithGlobalGitignore // TODO: newRepoWithGlobalGitignore
// TODO: newRepoWithGlobalGitignoreSymlink // TODO: newRepoWithGlobalGitignoreSymlink