// getAssigneesAndUnassignees checks to see when someone comments "/assign" or "/unassign"
// returns two sets.String
// 1. github handles to be assigned
// 2. github handles to be unassigned
// Note* Could possibly assign directly in the function call, but easier to test if function returns toAssign, toUnassign
func (h *AssignUnassignHandler) getAssigneesAndUnassignees(obj *github.MungeObject, comments []*githubapi.IssueComment, fileList []*githubapi.CommitFile, potentialOwners weightMap) (toAssign, toUnassign sets.String) {
	toAssign = sets.String{}
	toUnassign = sets.String{}

	assignComments := c.FilterComments(comments, c.CommandName(assignCommand))
	unassignComments := c.FilterComments(comments, c.CommandName(unassignCommand))
	invalidUsers := sets.String{}

	//collect all the people that should be assigned
	for _, cmt := range assignComments {
		if isValidReviewer(potentialOwners, cmt.User) {
			obj.DeleteComment(cmt)
			toAssign.Insert(*cmt.User.Login)
		} else {
			// build the set of people who asked to be assigned but aren't in reviewers
			// use the @ as a prefix so github notifies invalid users
			invalidUsers.Insert("@" + *cmt.User.Login)
		}

	}

	// collect all the people that should be unassigned
	for _, cmt := range unassignComments {
		if isAssignee(obj.Issue.Assignees, cmt.User) {
			obj.DeleteComment(cmt)
			toUnassign.Insert(*cmt.User.Login)
		}
	}

	// Create a notification if someone tried to self assign, but could not because they weren't in the owners files
	if invalidUsers.Len() != 0 {
		previousNotifications := c.FilterComments(comments, c.MungerNotificationName(invalidReviewer))
		if assignComments.Empty() || (!previousNotifications.Empty() && previousNotifications.GetLast().CreatedAt.After(*assignComments.GetLast().CreatedAt)) {
			// if there were no assign comments, no need to notify
			// if the last notification happened after the last assign comment, no need to notify again
			return toAssign, toUnassign
		}
		if !previousNotifications.Empty() {
			for _, c := range previousNotifications {
				obj.DeleteComment(c)
			}
		}
		context := bytes.NewBufferString("The following people cannot be assigned because they are not in the OWNERS files\n")
		for user := range invalidUsers {
			context.WriteString(fmt.Sprintf("- %s\n", user))
		}
		context.WriteString("\n")
		c.Notification{Name: invalidReviewer, Arguments: "", Context: context.String()}.Post(obj)

	}
	return toAssign, toUnassign
}
Example #2
0
func (h *ApprovalHandler) updateNotification(obj *github.MungeObject, ownersMap map[string]sets.String) error {
	notificationMatcher := c.MungerNotificationName(approvalNotificationName)
	comments, err := obj.ListComments()
	if err != nil {
		glog.Error("Could not list the comments for PR%v", obj.Issue.Number)
		return err
	}
	notifications := c.FilterComments(comments, notificationMatcher)
	latestNotification := notifications.GetLast()
	if latestNotification == nil {
		return h.createMessage(obj, ownersMap)
	}
	latestApprove := c.FilterComments(comments, c.CommandName(approveCommand)).GetLast()
	if latestApprove == nil || latestApprove.CreatedAt == nil {
		// there was already a bot notification and nothing has changed since
		// or we wouldn't tell when the latestApproval occurred
		return nil
	}
	if latestApprove.CreatedAt.After(*latestNotification.CreatedAt) {
		// if we can't tell when latestApprove happened, we should make a new one
		obj.DeleteComment(latestNotification)
		return h.createMessage(obj, ownersMap)
	}
	lastModified := obj.LastModifiedTime()
	if latestNotification.CreatedAt.Before(*lastModified) {
		obj.DeleteComment(latestNotification)
		return h.createMessage(obj, ownersMap)
	}
	return nil
}
Example #3
0
// createApproverSet iterates through the list of comments on a PR
// and identifies all of the people that have said /approve and adds
// them to the approverSet.  The function uses the latest approve or cancel comment
// to determine the Users intention
func createApproverSet(comments []*githubapi.IssueComment) sets.String {
	approverSet := sets.NewString()

	approverMatcher := c.CommandName(approveCommand)
	for _, comment := range c.FilterComments(comments, approverMatcher) {
		cmd := c.ParseCommand(comment)
		if cmd.Arguments == "cancel" {
			approverSet.Delete(*comment.User.Login)
		} else {
			approverSet.Insert(*comment.User.Login)
		}
	}
	return approverSet
}