diff --git a/cmd/clone.go b/cmd/clone.go index 3af9d1ff33..e595512935 100644 --- a/cmd/clone.go +++ b/cmd/clone.go @@ -633,7 +633,7 @@ func CloneAllRepos(git git.Gitter, cloneTargets []scm.Repo) { limit := limiter.NewConcurrencyLimiter(l) - var cloneCount, pulledCount, updateRemoteCount int + var cloneCount, pulledCount, updateRemoteCount, newCommits int // maps in go are not safe for concurrent use var mutex = &sync.RWMutex{} @@ -713,7 +713,8 @@ func CloneAllRepos(git git.Gitter, cloneTargets []scm.Repo) { } action := "cloning" - if repoExistsLocally(repo) { + repoWillBePulled := repoExistsLocally(repo) + if repoWillBePulled { // prevents git from asking for user for credentials, needs to be unset so creds aren't stored err := git.SetOriginWithCredentials(repo) if err != nil { @@ -779,6 +780,14 @@ func CloneAllRepos(git git.Gitter, cloneTargets []scm.Repo) { } } + count, _ := git.RepoCommitCount(repo) + if err != nil { + e := fmt.Sprintf("Problem trying to get pre pull commit count for on repo: %s", repo.URL) + cloneInfos = append(cloneInfos, e) + } + + repo.Commits.CountPrePull = count + err = git.Clean(repo) if err != nil { @@ -803,6 +812,15 @@ func CloneAllRepos(git git.Gitter, cloneTargets []scm.Repo) { return } + count, _ = git.RepoCommitCount(repo) + if err != nil { + e := fmt.Sprintf("Problem trying to get post pull commit count for on repo: %s", repo.URL) + cloneInfos = append(cloneInfos, e) + } + + repo.Commits.CountPostPull = count + repo.Commits.CountDiff = (repo.Commits.CountPostPull - repo.Commits.CountPrePull) + newCommits = (newCommits + repo.Commits.CountDiff) action = "pulling" pulledCount++ } @@ -864,7 +882,11 @@ func CloneAllRepos(git git.Gitter, cloneTargets []scm.Repo) { } } - colorlog.PrintSuccess("Success " + action + " " + repo.URL + " -> branch: " + repo.CloneBranch) + if repoWillBePulled && repo.Commits.CountDiff > 0 { + colorlog.PrintSuccess(fmt.Sprintf("Success %s %s, branch: %s, new commits: %d", action, repo.URL, repo.CloneBranch, repo.Commits.CountDiff)) + } else { + colorlog.PrintSuccess(fmt.Sprintf("Success %s %s, branch: %s", action, repo.URL, repo.CloneBranch)) + } }) } @@ -872,7 +894,7 @@ func CloneAllRepos(git git.Gitter, cloneTargets []scm.Repo) { limit.WaitAndClose() printRemainingMessages() - printCloneStatsMessage(cloneCount, pulledCount, updateRemoteCount) + printCloneStatsMessage(cloneCount, pulledCount, updateRemoteCount, newCommits) if hasCollisions { fmt.Println("") @@ -1025,9 +1047,14 @@ func pruneRepos(cloneTargets []scm.Repo) { } } -func printCloneStatsMessage(cloneCount, pulledCount, updateRemoteCount int) { +func printCloneStatsMessage(cloneCount, pulledCount, updateRemoteCount, newCommits int) { if updateRemoteCount > 0 { - colorlog.PrintSuccess(fmt.Sprintf("New clones: %v, existing resources pulled: %v, remotes updated: %v", cloneCount, pulledCount, updateRemoteCount)) + colorlog.PrintSuccess(fmt.Sprintf("New clones: %v, existing resources pulled: %v, total new commits: %v, remotes updated: %v", cloneCount, pulledCount, newCommits, updateRemoteCount)) + return + } + + if newCommits > 0 { + colorlog.PrintSuccess(fmt.Sprintf("New clones: %v, existing resources pulled: %v, total new commits: %v", cloneCount, pulledCount, newCommits)) return } diff --git a/cmd/clone_test.go b/cmd/clone_test.go index 929c3f8bdc..95161e5c67 100644 --- a/cmd/clone_test.go +++ b/cmd/clone_test.go @@ -101,6 +101,10 @@ func (g MockGitClient) FetchCloneBranch(repo scm.Repo) error { return nil } +func (g MockGitClient) RepoCommitCount(repo scm.Repo) (int, error) { + return 0, nil +} + func TestInitialClone(t *testing.T) { defer UnsetEnv("GHORG_")() dir, err := os.MkdirTemp("", "ghorg_test_initial") diff --git a/git/git.go b/git/git.go index d40bd9c57d..496274cf0d 100644 --- a/git/git.go +++ b/git/git.go @@ -4,6 +4,8 @@ import ( "fmt" "os" "os/exec" + "strconv" + "strings" "github.com/davecgh/go-spew/spew" "github.com/gabrie30/ghorg/scm" @@ -20,6 +22,7 @@ type Gitter interface { UpdateRemote(scm.Repo) error FetchAll(scm.Repo) error FetchCloneBranch(scm.Repo) error + RepoCommitCount(scm.Repo) (int, error) } type GitClient struct{} @@ -192,3 +195,28 @@ func (g GitClient) FetchCloneBranch(repo scm.Repo) error { } return cmd.Run() } + +func (g GitClient) RepoCommitCount(repo scm.Repo) (int, error) { + args := []string{"rev-list", "--count", repo.CloneBranch} + cmd := exec.Command("git", args...) + cmd.Dir = repo.HostPath + + if os.Getenv("GHORG_DEBUG") != "" { + err := printDebugCmd(cmd, repo) + if err != nil { + return 0, err + } + } + + output, err := cmd.Output() + if err != nil { + return 0, err + } + + count, err := strconv.Atoi(strings.TrimSpace(string(output))) + if err != nil { + return 0, err + } + + return count, nil +} diff --git a/scm/structs.go b/scm/structs.go index 8aa32dec7a..31519012e9 100644 --- a/scm/structs.go +++ b/scm/structs.go @@ -24,6 +24,13 @@ type Repo struct { IsGitLabRootLevelSnippet bool // GitLabSnippetInfo provides additional information when the thing we are cloning is a gitlab snippet GitLabSnippetInfo GitLabSnippet + Commits RepoCommits +} + +type RepoCommits struct { + CountPrePull int + CountPostPull int + CountDiff int } type GitLabSnippet struct {