func handle()

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))
}