github.com/justinjmoses/evergreen@v0.0.0-20170530173719-1d50e381ff0d/repotracker/runner.go (about) 1 package repotracker 2 3 import ( 4 "sync" 5 "time" 6 7 "github.com/evergreen-ci/evergreen" 8 "github.com/evergreen-ci/evergreen/db" 9 "github.com/evergreen-ci/evergreen/model" 10 "github.com/evergreen-ci/evergreen/thirdparty" 11 "github.com/mongodb/grip" 12 "github.com/pkg/errors" 13 ) 14 15 type Runner struct{} 16 17 const ( 18 RunnerName = "repotracker" 19 Description = "poll version control for new commits" 20 // githubAPILimitCeiling is arbitrary but corresponds to when we start logging errors in 21 // thirdparty/github.go/getGithubRateLimit 22 githubAPILimitCeiling = 20 23 githubCredentialsKey = "github" 24 ) 25 26 func (r *Runner) Name() string { 27 return RunnerName 28 } 29 30 func (r *Runner) Description() string { 31 return Description 32 } 33 34 func (r *Runner) Run(config *evergreen.Settings) error { 35 status, err := thirdparty.GetGithubAPIStatus() 36 if err != nil { 37 errM := errors.Wrap(err, "contacting github") 38 grip.Error(errM) 39 return errM 40 } 41 if status != thirdparty.GithubAPIStatusGood { 42 errM := errors.Errorf("bad github api status: %v", status) 43 grip.Error(errM) 44 return errM 45 } 46 47 token, ok := config.Credentials[githubCredentialsKey] 48 if !ok { 49 err = errors.New("Github credentials not specified in Evergreen credentials file") 50 grip.Error(err) 51 return err 52 } 53 remaining, err := thirdparty.CheckGithubAPILimit(token) 54 if err != nil { 55 err = errors.Wrap(err, "Error checking Github API limit") 56 grip.Error(err) 57 return err 58 } 59 if remaining < githubAPILimitCeiling { 60 err = errors.Errorf("Too few Github API requests remaining: %d < %d", remaining, githubAPILimitCeiling) 61 grip.Alert(err) 62 return err 63 } 64 grip.Debugf("%d Github API requests remaining", remaining) 65 66 lockAcquired, err := db.WaitTillAcquireGlobalLock(RunnerName, db.LockTimeout) 67 if err != nil { 68 err = errors.Wrap(err, "Error acquiring global lock") 69 grip.Error(err) 70 return err 71 } 72 73 if !lockAcquired { 74 err = errors.New("Timed out acquiring global lock") 75 grip.Error(err) 76 return err 77 } 78 79 defer func() { 80 if err = db.ReleaseGlobalLock(RunnerName); err != nil { 81 grip.Errorln("Error releasing global lock:", err) 82 } 83 }() 84 85 startTime := time.Now() 86 grip.Infoln("Running repository tracker with db:", config.Database.DB) 87 88 allProjects, err := model.FindAllTrackedProjectRefs() 89 if err != nil { 90 err = errors.Wrap(err, "Error finding tracked projects") 91 grip.Error(err) 92 return err 93 } 94 95 numNewRepoRevisionsToFetch := config.RepoTracker.NumNewRepoRevisionsToFetch 96 if numNewRepoRevisionsToFetch <= 0 { 97 numNewRepoRevisionsToFetch = DefaultNumNewRepoRevisionsToFetch 98 } 99 100 var wg sync.WaitGroup 101 wg.Add(len(allProjects)) 102 for _, projectRef := range allProjects { 103 go func(projectRef model.ProjectRef) { 104 defer wg.Done() 105 106 tracker := &RepoTracker{ 107 config, 108 &projectRef, 109 NewGithubRepositoryPoller(&projectRef, config.Credentials["github"]), 110 } 111 112 err = tracker.FetchRevisions(numNewRepoRevisionsToFetch) 113 if err != nil { 114 grip.Errorln("Error fetching revisions:", err) 115 } 116 }(projectRef) 117 } 118 wg.Wait() 119 120 runtime := time.Since(startTime) 121 if err = model.SetProcessRuntimeCompleted(RunnerName, runtime); err != nil { 122 err = errors.Wrap(err, "Error updating process status") 123 grip.Error(err) 124 return err 125 } 126 grip.Infof("Repository tracker took %s to run", runtime) 127 return nil 128 }