// MungePullRequest is the workhorse the will actually make updates to the PR func (b *BlunderbussMunger) MungePullRequest(config *github_util.Config, pr *github.PullRequest, issue *github.Issue, commits []github.RepositoryCommit, events []github.IssueEvent) { if !b.blunderbussReassign && issue.Assignee != nil { glog.V(6).Infof("skipping %v: reassign: %v assignee: %v", *pr.Number, b.blunderbussReassign, describeUser(issue.Assignee)) return } potentialOwners := weightMap{} weightSum := int64(0) for _, commit := range commits { if commit.Author == nil || commit.Author.Login == nil || commit.SHA == nil { glog.Warningf("Skipping invalid commit for %d: %#v", *pr.Number, commit) continue } for _, file := range commit.Files { fileWeight := int64(1) if file.Changes != nil && *file.Changes != 0 { fileWeight = int64(*file.Changes) } // Judge file size on a log scale-- effectively this // makes three buckets, we shouldn't have many 10k+ // line changes. fileWeight = int64(math.Log10(float64(fileWeight))) + 1 fileOwners := b.config.findOwners(*file.Filename) if len(fileOwners) == 0 { glog.Warningf("Couldn't find an owner for: %s", *file.Filename) } for owner, ownerWeight := range fileOwners { if owner == *pr.User.Login { continue } potentialOwners[owner] = potentialOwners[owner] + fileWeight*ownerWeight weightSum += fileWeight * ownerWeight } } } if len(potentialOwners) == 0 { glog.Errorf("No owners found for PR %d", *pr.Number) return } glog.V(4).Infof("Weights: %#v\nSum: %v", potentialOwners, weightSum) if issue.Assignee != nil { cur := *issue.Assignee.Login glog.Infof("Current assignee %v has a %02.2f%% chance of having been chosen", cur, 100.0*float64(potentialOwners[cur])/float64(weightSum)) } selection := rand.Int63n(weightSum) owner := "" for o, w := range potentialOwners { owner = o selection -= w if selection <= 0 { break } } glog.Infof("Assigning %v to %v (previously assigned to %v)", *pr.Number, owner, describeUser(issue.Assignee)) config.AssignPR(*pr.Number, owner) }