mirror of
https://github.com/grdl/git-get.git
synced 2026-02-11 18:09:01 +00:00
Add a list flag and basic rendering of repos status
This commit is contained in:
@@ -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)
|
||||||
|
|
||||||
|
|||||||
83
pkg/list.go
83
pkg/list.go
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
|
||||||
}
|
|
||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user