// Copyright 2017-2025 WIT.COM Inc. All rights reserved. // Use of this source code is governed by the GPL 3.0 package main import ( "time" "go.wit.com/lib/config" "go.wit.com/lib/gui/shell" "go.wit.com/lib/protobuf/forgepb" "go.wit.com/lib/protobuf/gitpb" "go.wit.com/log" ) func doMerge() (string, error) { if argv.All == true { start := time.Now() repos, err := doMergeDevel() dur := time.Since(start) if err != nil { return "doMergeDevel() failure", err } log.Printf("Merged %d devel branches in %s\n", repos.Len(), shell.FormatDuration(dur)) start = time.Now() repos, err = doMergeMaster() dur = time.Since(start) if err != nil { return "doMergeMaster() failure", err } return log.Sprintf("Merged %d master branches in %s", repos.Len(), shell.FormatDuration(dur)), nil } if argv.Merge.Devel != nil { start := time.Now() repos, err := doMergeDevel() dur := time.Since(start) if err != nil { return "doMergeDevel() failure", err } return log.Sprintf("Merged %d devel branches in %s", repos.Len(), shell.FormatDuration(dur)), nil } if argv.Merge.Master != nil { start := time.Now() repos, err := doMergeMaster() dur := time.Since(start) if err != nil { return "doMergeMaster() failure", err } return log.Sprintf("Merged %d master branches in %s", repos.Len(), shell.FormatDuration(dur)), nil } if argv.Merge.Check != nil { err := safeToPublish() if err == nil { return "probably safe to publish and merge", nil } return "Not safe to Publish.", err } found := findWorkRepos() if found.Len() == 0 { return "There does't seem to be anything to merge. Show your repos with --show", nil } found.SortNamespace() footer := me.forge.PrintDefaultTB(found) return "repos that can't be merged: " + footer, nil } func hashesMatch(repo *gitpb.Repo) error { uhash := repo.ActualGetUserHash() dhash := repo.ActualGetDevelHash() mhashl, mhashr := repo.ActualGetMasterHash() // log.Info(uhash, dhash, mhashl, mhashr) if uhash != dhash { return log.Errorf("user does not match devel") } if dhash != mhashl { return log.Errorf("devel does not match mater") } if mhashl != mhashr { return log.Errorf("local master branch does not match remote branch") } return nil } func safeToPublish() error { // always run dirty first me.forge.CheckDirtyQuiet() // if no option is given to patch, list out the // repos that have patches ready in them found := findReposWithPatches() if found.Len() == 0 { log.Info("you currently have no repos with patches") return log.Errorf("no repos to publish") } footer := me.forge.PrintDefaultTB(found) log.Info("safeToPublish() probably safe footer:", footer) // check if any are dirty for repo := range found.IterAll() { if repo.CheckDirty() { return log.Errorf("%s repo is dirty", repo.FullPath) } } // check the hashes for repo := range found.IterAll() { if err := hashesMatch(repo); err != nil { log.Info("hash mismatch", repo.FullPath, err) return err } } // move them all the the master branch var bad bool for repo := range found.IterAll() { if repo.GetCurrentBranchName() != repo.GetMasterBranchName() { repo.CheckoutMaster() bad = true } } if bad { return log.Errorf("some repos had to be switched to the master branch") } log.Info("it is probably safe to publish(?)") time.Sleep(5 * time.Second) return nil } func doMergeReport() *forgepb.Patches { found := forgepb.NewPatches() for repo := range me.forge.Repos.IterAll() { if repo.GetDevelVersion() == repo.GetMasterVersion() { continue } tmp := log.Sprintf("%s..%s", repo.GetMasterVersion(), repo.GetDevelVersion()) r, err := repo.RunStrict([]string{"git", "log", "--pretty=format:%H", tmp}) _ = err for i, line := range r.Stdout { log.Info(i, line, repo.FullPath) } } return found } func doMergeDevel() (*gitpb.Repos, error) { var err error done := gitpb.NewRepos() found := findMergeToDevel() for repo := range found.IterAll() { if _, err := repo.MergeToDevel(); err != nil { log.Info("merge from user 2 failed", repo.Namespace, err) // err := log.Errorf("merge from user failed") // log.Info(strings.Join(r.Stdout, "\n")) // log.Info(strings.Join(r.Stderr, "\n")) badExit(err) } config.SetChanged("repos", true) // repoMergeToDevel(repo) /* if repo.CheckDirty() { log.Info("repo is dirty", repo.GetFullPath()) continue } log.Infof("%s starting git merge\n", repo.FullPath) if repo.CheckoutDevel() { log.Info("checkout devel failed", repo.Namespace) err = log.Errorf("checkout devel failed") badExit(err) } // hash differences when merging user into devel branch out := repo.GetBranchDifferences(repo.GetDevelBranchName(), repo.GetUserBranchName()) for i, hash := range out { log.Info("MERGE HASHES TO DEVEL:", i, hash) } if _, err := repo.MergeToDevel(); err != nil { log.Info("merge from user 1 failed", repo.Namespace, err) err = log.Errorf("merge from user 1 failed") // log.Info(strings.Join(r.Stdout, "\n")) // log.Info(strings.Join(r.Stderr, "\n")) badExit(err) } done.Append(repo) config.SetChanged("repos", true) */ } return done, err } /* func repoMergeToDevel(repo *gitpb.Repo) error { if _, err := repo.MergeToDevel(); err != nil { log.Info("merge from user 3 failed", repo.Namespace, err) // err := log.Errorf("merge from user failed") // log.Info(strings.Join(r.Stdout, "\n")) // log.Info(strings.Join(r.Stderr, "\n")) badExit(err) } config.SetChanged("repos", true) return nil } */ func doMergeMaster() (*gitpb.Repos, error) { var err error me.forge.SetMode(forgepb.ForgeMode_MASTER) done := gitpb.NewRepos() found := findMergeToMaster() for repo := range found.IterAll() { if _, err := repo.MergeToMaster(); err != nil { log.Info("merge from devel 1 failed", repo.Namespace, err) err = log.Errorf("merge from devel 1 failed") badExit(err) } done.Append(repo) config.SetChanged("repos", true) } return done, err }