in prow/plugins/project/project.go [183:390]
func handle(gc githubClient, log *logrus.Entry, e *github.GenericCommentEvent, projectConfig plugins.ProjectConfig) error {
// Only handle new comments
if e.Action != github.GenericCommentActionCreated {
return nil
}
// Only handle comments that don't come from the bot
botUserChecker, err := gc.BotUserChecker()
if err != nil {
return err
}
if botUserChecker(e.User.Login) {
return nil
}
// Only handle comments that match the regex
matches := projectRegex.FindStringSubmatch(e.Body)
if len(matches) == 0 {
return nil
}
org := e.Repo.Owner.Login
repo := e.Repo.Name
proposedProject, proposedColumnName, shouldClear, msg := processCommand(matches[1])
if proposedProject == "" {
return gc.CreateComment(org, repo, e.Number, plugins.FormatResponseRaw(e.Body, e.HTMLURL, e.User.Login, msg))
}
maintainerTeamID := projectConfig.GetMaintainerTeam(org, repo)
if maintainerTeamID == -1 {
return gc.CreateComment(org, repo, e.Number, plugins.FormatResponseRaw(e.Body, e.HTMLURL, e.User.Login, notTeamConfigMsg))
}
isAMember, err := gc.TeamHasMember(org, maintainerTeamID, e.User.Login)
if err != nil {
return err
}
if !isAMember {
// not in the project maintainers team
msg = fmt.Sprintf(notATeamMemberMsg, org, repo, org, repo)
return gc.CreateComment(org, repo, e.Number, plugins.FormatResponseRaw(e.Body, e.HTMLURL, e.User.Login, msg))
}
var projects []github.Project
// see if the project in the same repo as the issue/pr
repoProjects, err := gc.GetRepoProjects(org, repo)
if err == nil {
projects = append(projects, repoProjects...)
}
updateProjectNameToIDMap(projects)
var ok bool
// Only fetch the other repos in the org if we did not find the project in the same repo as the issue/pr
if _, ok = projectNameToIDMap[proposedProject]; !ok {
repos, err := gc.GetRepos(org, false)
if err != nil {
return err
}
// Get all projects for all repos
for _, repo := range repos {
repoProjects, err := gc.GetRepoProjects(org, repo.Name)
if err != nil {
return err
}
projects = append(projects, repoProjects...)
}
}
// Only fetch org projects if we can't find the proposed project / project to clear in the repo projects
updateProjectNameToIDMap(projects)
var projectID int
if projectID, ok = projectNameToIDMap[proposedProject]; !ok {
// Get all projects for this org
orgProjects, err := gc.GetOrgProjects(org)
if err != nil {
return err
}
projects = append(projects, orgProjects...)
// If still can't find proposed project / project to clear in the list of projects, abort and create a comment
updateProjectNameToIDMap(projects)
if projectID, ok = projectNameToIDMap[proposedProject]; !ok {
slice := make([]string, 0, len(projectNameToIDMap))
for k := range projectNameToIDMap {
slice = append(slice, fmt.Sprintf("`%s`", k))
}
sort.Strings(slice)
msg = fmt.Sprintf(invalidProject, strings.Join(slice, ", "))
return gc.CreateComment(org, repo, e.Number, plugins.FormatResponseRaw(e.Body, e.HTMLURL, e.User.Login, msg))
}
}
// Get all columns for proposedProject
projectColumns, err := gc.GetProjectColumns(org, projectID)
if err != nil {
return err
}
// If proposedColumnName is not found (or not provided), add to one of the default
// columns. If none of the default columns exists, an error will be shown to the user
columnFound := false
proposedColumnID := 0
for _, c := range projectColumns {
if c.Name == proposedColumnName {
columnFound = true
proposedColumnID = c.ID
break
}
}
if !columnFound && !shouldClear {
// If user does not provide a column name, look for the columns
// specified in the project config and see if any of them exists on the
// proposed project
if proposedColumnName == "" {
defaultColumn, exists := projectConfig.GetColumnMap(org, repo)[proposedProject]
if !exists {
// Try to find the proposedProject in the org config in case the
// project is on the org level
defaultColumn, exists = projectConfig.GetOrgColumnMap(org)[proposedProject]
}
if exists {
// See if the default column exists in the actual list of project columns
for _, pc := range projectColumns {
if pc.Name == defaultColumn {
proposedColumnID = pc.ID
proposedColumnName = pc.Name
columnFound = true
break
}
}
}
}
// In this case, user does not provide the column name in the command,
// or the provided column name cannot be found, and none of the default
// columns are available in the proposed project. An error will be
// shown to the user
if !columnFound {
projectColumnNames := []string{}
for _, c := range projectColumns {
projectColumnNames = append(projectColumnNames, c.Name)
}
msg = fmt.Sprintf(invalidColumn, proposedProject, projectColumnNames)
return gc.CreateComment(org, repo, e.Number, plugins.FormatResponseRaw(e.Body, e.HTMLURL, e.User.Login, msg))
}
}
// Move this issue/PR to the new column if there's already a project card for
// this issue/PR in this project
var existingProjectCard *github.ProjectCard
var foundColumnID int
for _, colID := range projectColumns {
// make issue URL in the form of card content URL
issueURL := fmt.Sprintf("https://api.github.com/repos/%s/%s/issues/%v", org, repo, e.Number)
existingProjectCard, err = gc.GetColumnProjectCard(org, colID.ID, issueURL)
if err != nil {
return err
}
if existingProjectCard != nil {
foundColumnID = colID.ID
break
}
}
// no need to move the card if it is in the same column
if (existingProjectCard != nil) && (proposedColumnID == foundColumnID) {
return nil
}
// Clear issue/PR from project if command is to clear
if shouldClear {
if existingProjectCard != nil {
if err := gc.DeleteProjectCard(org, existingProjectCard.ID); err != nil {
return err
}
msg = fmt.Sprintf(successClearingProjectMsg, proposedProject)
return gc.CreateComment(org, repo, e.Number, plugins.FormatResponseRaw(e.Body, e.HTMLURL, e.User.Login, msg))
}
msg = fmt.Sprintf(failedClearingProjectMsg, proposedProject, e.Number)
return gc.CreateComment(org, repo, e.Number, plugins.FormatResponseRaw(e.Body, e.HTMLURL, e.User.Login, msg))
}
// Move this issue/PR to the new column if there's already a project card for this issue/PR in this project
if existingProjectCard != nil {
log.Infof("Move card to column proposedColumnID: %v with issue: %v ", proposedColumnID, e.Number)
if err := gc.MoveProjectCard(org, existingProjectCard.ID, proposedColumnID); err != nil {
return err
}
msg = fmt.Sprintf(successMovingCardMsg, proposedColumnName, proposedColumnID)
return gc.CreateComment(org, repo, e.Number, plugins.FormatResponseRaw(e.Body, e.HTMLURL, e.User.Login, msg))
}
projectCard := github.ProjectCard{}
projectCard.ContentID = e.ID
if e.IsPR {
projectCard.ContentType = "PullRequest"
} else {
projectCard.ContentType = "Issue"
}
if _, err := gc.CreateProjectCard(org, proposedColumnID, projectCard); err != nil {
return err
}
msg = fmt.Sprintf(successCreatingCardMsg, proposedProject, proposedColumnName, proposedColumnID)
return gc.CreateComment(org, repo, e.Number, plugins.FormatResponseRaw(e.Body, e.HTMLURL, e.User.Login, msg))
}