package main import ( "bufio" "fmt" "slices" "strings" "src.opensuse.org/autogits/common" "src.opensuse.org/autogits/common/gitea-generated/models" ) type PRReviewInfo struct { pr *models.PullRequest reviews []*models.PullReview } func fetchPRandReviews(gitea GiteaPRInterface, org, repo string, prNum int64) (PRReviewInfo, error) { pr, reviews, err := gitea.GetPullRequestAndReviews(org, repo, prNum) if err != nil { return PRReviewInfo{}, err } return PRReviewInfo{ pr: pr, reviews: reviews, }, nil } func isMaintainerApprovedPR(pr PRReviewInfo, maintainers MaintainershipData) bool { m := slices.Concat(maintainers.ListPackageMaintainers(pr.pr.Base.Name), maintainers.ListProjectMaintainers()) for _, review := range pr.reviews { if review.Stale { continue } if slices.Contains(m, review.User.UserName) { if review.State == common.ReviewStateApproved { return true } return false } } return true } func IsPrjGitPRApproved(gitea common.GiteaMaintainershipInterface, giteapr GiteaPRInterface, config common.AutogitConfig, prjGitPRNumber int64) (bool, error) { prjPR, _ := fetchPRandReviews(giteapr, config.Organization, config.GitProjectName, prjGitPRNumber) maintainers, _ := FetchProjectMaintainershipData(gitea, config.Organization, config.GitProjectName, config.Branch) _, prjAssociatedPRs := common.ExtractDescriptionAndPRs(bufio.NewScanner(strings.NewReader(prjPR.pr.Body))) for _, PR := range prjAssociatedPRs { prInfo, _ := fetchPRandReviews(giteapr, PR.Org, PR.Repo, PR.Num) _, associatedPRs := common.ExtractDescriptionAndPRs(bufio.NewScanner(strings.NewReader(prInfo.pr.Body))) if len(associatedPRs) != 1 { return false, fmt.Errorf("Associated PR doesn't link only to the prjgit PR: %s/%s#%d", associatedPRs[0].Org, associatedPRs[0].Repo, associatedPRs[0].Num) } if associatedPRs[0].Org != config.Organization || associatedPRs[0].Repo != config.GitProjectName || associatedPRs[0].Num != prjGitPRNumber { return false, fmt.Errorf("Associated PR (%s/%s#%d) not linking back to prj PR (%s/%s#%d)", associatedPRs[0].Org, associatedPRs[0].Repo, associatedPRs[0].Num, config.Organization, config.GitProjectName, prjGitPRNumber) } if !isMaintainerApprovedPR(prInfo, maintainers) { return false, nil } } requiredReviews := slices.Clone(config.Reviewers) for _, r := range prjPR.reviews { if !r.Stale && r.State == common.ReviewStateApproved && slices.Contains(requiredReviews, r.User.UserName) { idx := slices.Index(requiredReviews, r.User.UserName) requiredReviews = slices.Delete(requiredReviews, idx, idx+1) } } return len(requiredReviews) == 0, nil }