From 18aad5f1b507c2fa6b7dbf4a8c807bad36dd7c39 Mon Sep 17 00:00:00 2001 From: Jeff Carr Date: Thu, 4 Sep 2025 09:15:45 -0500 Subject: [PATCH] common branch handling code --- branches.go | 246 +++++++++++++++++++++++++++++++++++++++++++++++++- humanTable.go | 2 +- 2 files changed, 246 insertions(+), 2 deletions(-) diff --git a/branches.go b/branches.go index 7aa1712..d4849d5 100644 --- a/branches.go +++ b/branches.go @@ -1,6 +1,14 @@ package forgepb -import "go.wit.com/log" +import ( + "os" + "path/filepath" + "time" + + "go.wit.com/lib/gui/shell" + "go.wit.com/lib/protobuf/gitpb" + "go.wit.com/log" +) var ErrorNotAllReposOnMaster error = log.Errorf("not all repos on are on the master branch") var ErrorNotAllReposOnDevel error = log.Errorf("not all repos on are on the devel branch") @@ -26,3 +34,239 @@ func (f *Forge) IsEverythingOnMaster() (int, int, int, error) { } return total, count, nope, nil } + +func (f *Forge) IsEverythingOnDevel() (int, int, int, error) { + var total int + var count int + var nope int + + // first make sure every repo is on the master branch + for repo := range f.Repos.IterAll() { + total += 1 + if repo.GetDevelBranchName() == repo.GetCurrentBranchName() { + count += 1 + } else { + nope += 1 + } + } + if total != count { + return total, count, nope, ErrorNotAllReposOnDevel + } + return total, count, nope, nil +} + +func (f *Forge) IsEverythingOnUser() (int, int, int, error) { + var total int + var count int + var nope int + + // first make sure every repo is on the master branch + for repo := range f.Repos.IterAll() { + total += 1 + if repo.GetCurrentBranchName() == repo.GetUserBranchName() { + count += 1 + } else { + nope += 1 + } + } + if total != count { + return total, count, nope, ErrorNotAllReposOnUser + } + return total, count, nope, nil +} + +// trys to figure out if there is still something to update +func (f *Forge) DoAllCheckoutMaster() error { + now := time.Now() + f.RillFuncError(rillCheckoutMaster) + count := f.RillReload() + if count != 0 { + f.ConfigSave() + } + + total, count, nope, err := f.IsEverythingOnMaster() + log.Printf("Master branch check. %d total repos. (%d ok) (%d not on master branch) (%s)\n", total, count, nope, shell.FormatDuration(time.Since(now))) + if err != nil { + // display all repos not on master + found := new(gitpb.Repos) + all := f.Repos.SortByFullPath() + for all.Scan() { + repo := all.Next() + if repo.GetCurrentBranchName() != repo.GetMasterBranchName() { + found.Append(repo) + } + } + f.PrintHumanTable(found) + log.Printf("There are %d repos that are NOT on the master branch\n", found.Len()) + return err + } + return nil +} + +func rillCheckoutMaster(repo *gitpb.Repo) error { + if repo.IsDirty() { + // never do dirty repos + return nil + } + // 'giterr' means something is very wrong with this repo + if repo.GetMasterVersion() == "giterr" { + repo.CheckoutMaster() + log.Info("master == giterr. BAD REPO", repo.GetFullPath()) + log.Info("master == giterr. BAD REPO", repo.GetFullPath()) + log.Info("master == giterr. BAD REPO", repo.GetFullPath()) + cmd := []string{"git", "checkout", "main"} // todo: figure out main + repo.RunVerbose(cmd) + os.Exit(-1) + return nil + } + if repo.GetCurrentBranchName() == repo.GetMasterBranchName() { + // repo is already on master + return nil + } + repo.CheckoutMaster() + return nil +} + +func rillCheckoutUser(repo *gitpb.Repo) error { + if repo.IsDirty() { + // never do dirty repos + return nil + } + if repo.GetCurrentBranchName() == repo.GetMasterBranchName() { + // repo is already on devel branch. have to move them there first for now + // return repo.CheckoutDevel() + } + if repo.GetCurrentBranchName() == repo.GetUserBranchName() { + // repo is already on user branch + return nil + } + if err := repo.CheckoutUser(); err != nil { + log.Info(repo.GetFullPath(), err) + return err + } + return nil +} + +// trys to figure out if there is still something to update +func (f *Forge) DoAllCheckoutUser(force bool) error { + now := time.Now() + + if force { + log.Info("going to force create user branches") + if err := f.makeUserBranches(); err != nil { + return err + } + } + + f.RillFuncError(rillCheckoutUser) + count := f.RillReload() + if count != 0 { + f.ConfigSave() + } + + total, count, nope, err := f.IsEverythingOnUser() + log.Printf("User branch check. %d total repos. (%d ok) (%d not on user branch) (%s)\n", total, count, nope, shell.FormatDuration(time.Since(now))) + if err != nil { + // display all repos not on user + found := new(gitpb.Repos) + all := f.Repos.SortByFullPath() + for all.Scan() { + repo := all.Next() + if repo.GetCurrentBranchName() != repo.GetUserBranchName() { + found.Append(repo) + } + } + f.PrintHumanTable(found) + log.Printf("There are %d repos that are NOT on the user branch\n", found.Len()) + return err + } + return nil +} + +func (f *Forge) makeUserBranches() error { + all := f.Repos.SortByFullPath() + for all.Scan() { + repo := all.Next() + branch := repo.GetUserBranchName() + if repo.Exists(filepath.Join(".git/refs/heads", branch)) { + continue + } + if repo.Exists(filepath.Join(".git/refs/remotes/origin", branch)) { + cmd := []string{"git", "checkout", branch} + repo.RunVerbose(cmd) + continue + } + cmd := []string{"git", "branch", branch} + repo.RunVerbose(cmd) + cmd = []string{"git", "checkout", branch} + repo.RunVerbose(cmd) + } + return nil +} + +// is every repo on the devel branch? +func (f *Forge) DoAllCheckoutDevel(force bool) error { + now := time.Now() + if force { + log.Info("going to force create devel branches") + f.makeDevelBranches() + } + log.Info("going to rill:") + f.RillFuncError(rillCheckoutDevel) + count := f.RillReload() + if count != 0 { + f.ConfigSave() + } + + total, count, nope, err := f.IsEverythingOnDevel() + log.Printf("Devel branch check. %d total repos. (%d ok) (%d not on devel branch) (%s)\n", total, count, nope, shell.FormatDuration(time.Since(now))) + if err != nil { + // display all repos not on user + found := new(gitpb.Repos) + all := f.Repos.SortByFullPath() + for all.Scan() { + repo := all.Next() + if repo.GetCurrentBranchName() != repo.GetDevelBranchName() { + found.Append(repo) + } + } + f.PrintHumanTable(found) + log.Printf("There are %d repos that are NOT on the devel branch\n", found.Len()) + return err + } + return nil +} + +func (f *Forge) makeDevelBranches() error { + all := f.Repos.SortByFullPath() + for all.Scan() { + repo := all.Next() + branch := repo.GetDevelBranchName() + if repo.Exists(filepath.Join(".git/refs/heads", branch)) { + continue + } + if repo.Exists(filepath.Join(".git/refs/remotes/origin", branch)) { + cmd := []string{"git", "checkout", branch} + repo.RunVerbose(cmd) + continue + } + cmd := []string{"git", "branch", branch} + repo.RunVerbose(cmd) + cmd = []string{"git", "checkout", branch} + repo.RunVerbose(cmd) + } + return nil +} + +func rillCheckoutDevel(repo *gitpb.Repo) error { + if repo.IsDirty() { + // never do dirty repos + return nil + } + if repo.GetCurrentBranchName() == repo.GetDevelBranchName() { + // repo is already on devel branch + return nil + } + repo.CheckoutDevel() + return nil +} diff --git a/humanTable.go b/humanTable.go index 6681a1b..c00ca6a 100644 --- a/humanTable.go +++ b/humanTable.go @@ -235,7 +235,7 @@ func (f *Forge) printRepoToTable(repo *gitpb.Repo, sizes []int, full bool) { } if repo.IsDirty() { - age = "" + age = "#" end += "(dirty) " }