133 строки
3.8 KiB
Go
133 строки
3.8 KiB
Go
package web
|
|
|
|
import (
|
|
"regexp"
|
|
|
|
"github.com/bradrydzewski/lgtm/cache"
|
|
"github.com/bradrydzewski/lgtm/model"
|
|
"github.com/bradrydzewski/lgtm/remote"
|
|
"github.com/bradrydzewski/lgtm/store"
|
|
|
|
log "github.com/Sirupsen/logrus"
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
func Hook(c *gin.Context) {
|
|
hook, err := remote.GetHook(c, c.Request)
|
|
if err != nil {
|
|
log.Errorf("Error parsing hook. %s", err)
|
|
c.String(500, "Error parsing hook. %s", err)
|
|
return
|
|
}
|
|
if hook == nil {
|
|
c.String(200, "pong")
|
|
return
|
|
}
|
|
|
|
repo, err := store.GetRepoSlug(c, hook.Repo.Slug)
|
|
if err != nil {
|
|
log.Errorf("Error getting repository %s. %s", hook.Repo.Slug, err)
|
|
c.String(404, "Repository not found.")
|
|
return
|
|
}
|
|
user, err := store.GetUser(c, repo.UserID)
|
|
if err != nil {
|
|
log.Errorf("Error getting repository owner %s. %s", repo.Slug, err)
|
|
c.String(404, "Repository owner not found.")
|
|
return
|
|
}
|
|
|
|
// THIS IS COMPLETELY DUPLICATED IN THE API SECTION. NOT IDEAL
|
|
file, err := remote.GetContents(c, user, repo, "MAINTAINERS")
|
|
if err != nil {
|
|
log.Debugf("no MAINTAINERS file for %s. Checking for team members.", repo.Slug)
|
|
members, merr := cache.GetMembers(c, user, repo.Owner)
|
|
if merr != nil {
|
|
log.Errorf("Error getting repository %s. %s", repo.Slug, err)
|
|
log.Errorf("Error getting org members %s. %s", repo.Owner, merr)
|
|
c.String(404, "MAINTAINERS file not found. %s", err)
|
|
return
|
|
} else {
|
|
for _, member := range members {
|
|
file = append(file, member.Login...)
|
|
file = append(file, '\n')
|
|
}
|
|
}
|
|
}
|
|
|
|
maintainer, err := model.ParseMaintainer(file)
|
|
if err != nil {
|
|
log.Errorf("Error parsing MAINTAINERS file for %s. %s", repo.Slug, err)
|
|
c.String(500, "Error parsing MAINTAINERS file. %s.", err)
|
|
return
|
|
}
|
|
|
|
rcfile, _ := remote.GetContents(c, user, repo, ".lgtm")
|
|
config, err := model.ParseConfig(rcfile)
|
|
if err != nil {
|
|
log.Errorf("Error parsing .lgtm file for %s. %s", repo.Slug, err)
|
|
c.String(500, "Error parsing .lgtm file. %s.", err)
|
|
return
|
|
}
|
|
|
|
comments, err := remote.GetComments(c, user, repo, hook.Issue.Number)
|
|
if err != nil {
|
|
log.Errorf("Error retrieving comments for %s pr %d. %s", repo.Slug, hook.Issue.Number, err)
|
|
c.String(500, "Error retrieving comments. %s.", err)
|
|
return
|
|
}
|
|
approvers := getApprovers(config, maintainer, hook.Issue, comments)
|
|
approved := len(approvers) >= config.Approvals
|
|
err = remote.SetStatus(c, user, repo, hook.Issue.Number, approved)
|
|
if err != nil {
|
|
log.Errorf("Error setting status for %s pr %d. %s", repo.Slug, hook.Issue.Number, err)
|
|
c.String(500, "Error setting status. %s.", err)
|
|
return
|
|
}
|
|
|
|
log.Debugf("processed comment for %s. received %d of %d approvals", repo.Slug, len(approvers), config.Approvals)
|
|
|
|
c.IndentedJSON(200, gin.H{
|
|
"approvers": maintainer.People,
|
|
"settings": config,
|
|
"approved": approved,
|
|
"approved_by": approvers,
|
|
})
|
|
}
|
|
|
|
// getApprovers is a helper function that analyzes the list of comments
|
|
// and returns the list of approvers.
|
|
func getApprovers(config *model.Config, maintainer *model.Maintainer, issue *model.Issue, comments []*model.Comment) []*model.Person {
|
|
approverm := map[string]bool{}
|
|
approvers := []*model.Person{}
|
|
|
|
matcher, err := regexp.Compile(config.Pattern)
|
|
if err != nil {
|
|
// this should never happen
|
|
return approvers
|
|
}
|
|
|
|
for _, comment := range comments {
|
|
// cannot lgtm your own pull request
|
|
if config.SelfApprovalOff && comment.Author == issue.Author {
|
|
continue
|
|
}
|
|
// the user must be a valid maintainer of the project
|
|
person, ok := maintainer.People[comment.Author]
|
|
if !ok {
|
|
continue
|
|
}
|
|
// the same author can't approve something twice
|
|
if _, ok := approverm[comment.Author]; ok {
|
|
continue
|
|
}
|
|
// verify the comment matches the approval pattern
|
|
if matcher.MatchString(comment.Body) {
|
|
approverm[comment.Author] = true
|
|
approvers = append(approvers, person)
|
|
}
|
|
}
|
|
|
|
return approvers
|
|
}
|