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  }