This commit is contained in:
2025-02-14 17:13:51 +01:00
parent 072d7b4825
commit 1c38c2105b
10 changed files with 243 additions and 49 deletions

View File

@@ -25,6 +25,7 @@ import (
"path" "path"
"path/filepath" "path/filepath"
"slices" "slices"
"strings"
"time" "time"
transport "github.com/go-openapi/runtime/client" transport "github.com/go-openapi/runtime/client"
@@ -79,7 +80,7 @@ type GiteaPRChecker interface {
} }
type GiteaReviewRequester interface { type GiteaReviewRequester interface {
RequestReviews(pr *models.PullRequest, reviewer string) ([]*models.PullReview, error) RequestReviews(pr *models.PullRequest, reviewer ...string) ([]*models.PullReview, error)
} }
type GiteaReviewer interface { type GiteaReviewer interface {
@@ -96,8 +97,9 @@ type Gitea interface {
SetNotificationRead(notificationId int64) error SetNotificationRead(notificationId int64) error
GetOrganization(orgName string) (*models.Organization, error) GetOrganization(orgName string) (*models.Organization, error)
GetOrganizationRepositories(orgName string) ([]*models.Repository, error) GetOrganizationRepositories(orgName string) ([]*models.Repository, error)
CreateRepositoryIfNotExist(git Git, org Organization, repoName string) (*models.Repository, error) CreateRepositoryIfNotExist(git Git, org, repoName string) (*models.Repository, error)
CreatePullRequestIfNotExist(repo *models.Repository, srcId, targetId, title, body string) (*models.PullRequest, error) CreatePullRequestIfNotExist(repo *models.Repository, srcId, targetId, title, body string) (*models.PullRequest, error)
GetAssociatedPrjGitPR(prjGitOrg, prjGitRepo, refOrg, refRepo string, Index int) (*models.PullRequest, error)
GetRepositoryFileContent(org, repo, hash, path string) ([]byte, error) GetRepositoryFileContent(org, repo, hash, path string) ([]byte, error)
GetPullRequestFileContent(pr *models.PullRequest, path string) ([]byte, error) GetPullRequestFileContent(pr *models.PullRequest, path string) ([]byte, error)
GetRecentPullRequests(org, repo string) ([]*models.PullRequest, error) GetRecentPullRequests(org, repo string) ([]*models.PullRequest, error)
@@ -248,9 +250,9 @@ func (gitea *GiteaTransport) GetOrganizationRepositories(orgName string) ([]*mod
return repos, nil return repos, nil
} }
func (gitea *GiteaTransport) CreateRepositoryIfNotExist(git Git, org Organization, repoName string) (*models.Repository, error) { func (gitea *GiteaTransport) CreateRepositoryIfNotExist(git Git, org, repoName string) (*models.Repository, error) {
repo, err := gitea.client.Repository.RepoGet( repo, err := gitea.client.Repository.RepoGet(
repository.NewRepoGetParams().WithDefaults().WithOwner(org.Username).WithRepo(repoName), repository.NewRepoGetParams().WithDefaults().WithOwner(org).WithRepo(repoName),
gitea.transport.DefaultAuthentication) gitea.transport.DefaultAuthentication)
if err != nil { if err != nil {
@@ -263,7 +265,7 @@ func (gitea *GiteaTransport) CreateRepositoryIfNotExist(git Git, org Organizatio
Name: &repoName, Name: &repoName,
ObjectFormatName: models.CreateRepoOptionObjectFormatNameSha256, ObjectFormatName: models.CreateRepoOptionObjectFormatNameSha256,
}, },
).WithOrg(org.Username), ).WithOrg(org),
nil, nil,
) )
@@ -272,7 +274,7 @@ func (gitea *GiteaTransport) CreateRepositoryIfNotExist(git Git, org Organizatio
case *organization.CreateOrgRepoCreated: case *organization.CreateOrgRepoCreated:
// weird, but ok, repo created // weird, but ok, repo created
default: default:
return nil, fmt.Errorf("error creating repo '%s' under '%s'. Err: %w", repoName, org.Username, err) return nil, fmt.Errorf("error creating repo '%s' under '%s'. Err: %w", repoName, org, err)
} }
} }
@@ -305,7 +307,7 @@ func (gitea *GiteaTransport) CreateRepositoryIfNotExist(git Git, org Organizatio
return repo.Payload, nil return repo.Payload, nil
default: default:
return nil, fmt.Errorf("cannot fetch repo data for '%s' / '%s' : %w", org.Username, repoName, err) return nil, fmt.Errorf("cannot fetch repo data for %s/%s: %w", org, repoName, err)
} }
} }
@@ -344,9 +346,49 @@ func (gitea *GiteaTransport) CreatePullRequestIfNotExist(repo *models.Repository
return pr.GetPayload(), nil return pr.GetPayload(), nil
} }
func (gitea *GiteaTransport) RequestReviews(pr *models.PullRequest, reviewer string) ([]*models.PullReview, error) { func (gitea *GiteaTransport) GetAssociatedPrjGitPR(prjGitOrg, prjGitRepo, refOrg, refRepo string, Index int) (*models.PullRequest, error) {
var page int64
state := "open"
for {
page++
prs, err := gitea.client.Repository.RepoListPullRequests(
repository.
NewRepoListPullRequestsParams().
WithDefaults().
WithOwner(prjGitOrg).
WithRepo(prjGitRepo).
WithState(&state).
WithPage(&page),
gitea.transport.DefaultAuthentication)
if err != nil {
return nil, fmt.Errorf("cannot fetch PR list for %s / %s : %w", prjGitOrg, prjGitRepo, err)
}
prLine := fmt.Sprintf(PrPattern, refOrg, refRepo, Index)
// payload_processing:
for _, pr := range prs.Payload {
lines := strings.Split(pr.Body, "\n")
for _, line := range lines {
if strings.TrimSpace(line) == prLine {
return pr, nil
}
}
}
if len(prs.Payload) < 10 {
break
}
}
return nil, nil
}
func (gitea *GiteaTransport) RequestReviews(pr *models.PullRequest, reviewers ...string) ([]*models.PullReview, error) {
reviewOptions := models.PullReviewRequestOptions{ reviewOptions := models.PullReviewRequestOptions{
Reviewers: []string{reviewer}, Reviewers: reviewers,
} }
review, err := gitea.client.Repository.RepoCreatePullReviewRequests( review, err := gitea.client.Repository.RepoCreatePullReviewRequests(
@@ -360,7 +402,7 @@ func (gitea *GiteaTransport) RequestReviews(pr *models.PullRequest, reviewer str
) )
if err != nil { if err != nil {
return nil, fmt.Errorf("Cannot create pull request: %w", err) return nil, fmt.Errorf("Cannot create pull request reviews: %w", err)
} }
return review.GetPayload(), nil return review.GetPayload(), nil
@@ -482,8 +524,7 @@ func (gitea *GiteaTransport) GetRecentPullRequests(org, repo string) ([]*models.
func (gitea *GiteaTransport) GetRecentCommits(org, repo, branch string, commitNo int64) ([]*models.Commit, error) { func (gitea *GiteaTransport) GetRecentCommits(org, repo, branch string, commitNo int64) ([]*models.Commit, error) {
not := false not := false
var page int64 var page int64 = 1
page = 1
commits, err := gitea.client.Repository.RepoGetAllCommits( commits, err := gitea.client.Repository.RepoGetAllCommits(
repository.NewRepoGetAllCommitsParams(). repository.NewRepoGetAllCommitsParams().
WithOwner(org). WithOwner(org).

View File

@@ -27,6 +27,7 @@ import (
"path" "path"
"path/filepath" "path/filepath"
"slices" "slices"
"strings"
"time" "time"
"src.opensuse.org/autogits/common" "src.opensuse.org/autogits/common"
@@ -97,7 +98,7 @@ func processConfiguredRepositoryAction(action *common.RepositoryWebhookEvent, co
config.Branch = action.Repository.Default_Branch config.Branch = action.Repository.Default_Branch
} }
prjGitRepo, err := gitea.CreateRepositoryIfNotExist(git, *action.Organization, prjgit) prjGitRepo, err := gitea.CreateRepositoryIfNotExist(git, action.Organization.Username, prjgit)
if err != nil { if err != nil {
return fmt.Errorf("Error accessing/creating prjgit: %s err: %w", prjgit, err) return fmt.Errorf("Error accessing/creating prjgit: %s err: %w", prjgit, err)
} }
@@ -110,12 +111,13 @@ func processConfiguredRepositoryAction(action *common.RepositoryWebhookEvent, co
return fmt.Errorf(" - '%s' repo is not sha256. Ignoring.", action.Repository.Name) return fmt.Errorf(" - '%s' repo is not sha256. Ignoring.", action.Repository.Name)
} }
common.PanicOnError(git.GitExec(prjgit, "submodule", "--quiet", "add", "--depth", "1", action.Repository.Clone_Url, action.Repository.Name)) common.PanicOnError(git.GitExec(prjgit, "submodule", "--quiet", "add", "--depth", "1", action.Repository.Clone_Url, action.Repository.Name))
if _, err := git.GitBranchHead(path.Join(prjgit, action.Repository.Name), config.Branch); err != nil { branch := strings.TrimSpace(git.GitExecWithOutputOrPanic(path.Join(prjgit, action.Repository.Name), "branch", "--show-current"))
if branch != config.Branch {
if err := git.GitExec(path.Join(prjgit, action.Repository.Name), "fetch", "--depth", "1", "origin", config.Branch+":"+config.Branch); err != nil { if err := git.GitExec(path.Join(prjgit, action.Repository.Name), "fetch", "--depth", "1", "origin", config.Branch+":"+config.Branch); err != nil {
return fmt.Errorf("error fetching branch %s. ignoring as non-existent. err: %w", config.Branch, err) // no branch? so ignore repo here return fmt.Errorf("error fetching branch %s. ignoring as non-existent. err: %w", config.Branch, err) // no branch? so ignore repo here
} }
}
common.PanicOnError(git.GitExec(path.Join(prjgit, action.Repository.Name), "checkout", config.Branch)) common.PanicOnError(git.GitExec(path.Join(prjgit, action.Repository.Name), "checkout", config.Branch))
}
common.PanicOnError(git.GitExec(prjgit, "commit", "-m", "Automatic package inclusion via Direct Workflow")) common.PanicOnError(git.GitExec(prjgit, "commit", "-m", "Automatic package inclusion via Direct Workflow"))
common.PanicOnError(git.GitExec(prjgit, "push")) common.PanicOnError(git.GitExec(prjgit, "push"))
@@ -177,7 +179,7 @@ func processConfiguredPushAction(action *common.PushWebhookEvent, config *common
log.Println(" + default branch", action.Repository.Default_Branch) log.Println(" + default branch", action.Repository.Default_Branch)
} }
prjGitRepo, err := gitea.CreateRepositoryIfNotExist(git, *action.Repository.Owner, prjgit) prjGitRepo, err := gitea.CreateRepositoryIfNotExist(git, action.Repository.Owner.Username, prjgit)
if err != nil { if err != nil {
return fmt.Errorf("Error accessing/creating prjgit: %s err: %w", prjgit, err) return fmt.Errorf("Error accessing/creating prjgit: %s err: %w", prjgit, err)
} }
@@ -209,7 +211,7 @@ func processConfiguredPushAction(action *common.PushWebhookEvent, config *common
return nil return nil
} }
func verifyProjectState(git common.Git, orgName string, config *common.AutogitConfig, configs []*common.AutogitConfig) (err error) { func verifyProjectState(git common.Git, org string, config *common.AutogitConfig, configs []*common.AutogitConfig) (err error) {
defer func() { defer func() {
e := recover() e := recover()
if e != nil { if e != nil {
@@ -220,12 +222,9 @@ func verifyProjectState(git common.Git, orgName string, config *common.AutogitCo
} }
}() }()
org := common.Organization{
Username: orgName,
}
repo, err := gitea.CreateRepositoryIfNotExist(git, org, config.GitProjectName) repo, err := gitea.CreateRepositoryIfNotExist(git, org, config.GitProjectName)
if err != nil { if err != nil {
return fmt.Errorf("Error fetching or creating '%s/%s' -- aborting verifyProjectState(). Err: %w", orgName, config.GitProjectName, err) return fmt.Errorf("Error fetching or creating '%s/%s' -- aborting verifyProjectState(). Err: %w", org, config.GitProjectName, err)
} }
common.PanicOnError(git.GitExec("", "clone", "--depth", "1", repo.SSHURL, config.GitProjectName)) common.PanicOnError(git.GitExec("", "clone", "--depth", "1", repo.SSHURL, config.GitProjectName))
@@ -245,7 +244,7 @@ next_package:
} }
log.Println(" verifying package:", filename, commitId, config.Branch) log.Println(" verifying package:", filename, commitId, config.Branch)
commits, err := gitea.GetRecentCommits(orgName, filename, config.Branch, 10) commits, err := gitea.GetRecentCommits(org, filename, config.Branch, 10)
if err != nil { if err != nil {
// assumption that package does not exist, remove from project // assumption that package does not exist, remove from project
// https://github.com/go-gitea/gitea/issues/31976 // https://github.com/go-gitea/gitea/issues/31976
@@ -285,7 +284,7 @@ next_package:
if DebugMode { if DebugMode {
log.Println("checking for missing repositories...") log.Println("checking for missing repositories...")
} }
repos, err := gitea.GetOrganizationRepositories(orgName) repos, err := gitea.GetOrganizationRepositories(org)
if err != nil { if err != nil {
return err return err
} }
@@ -308,7 +307,7 @@ next_repo:
} }
for _, c := range configs { for _, c := range configs {
if c.Organization == orgName && c.GitProjectName == r.Name { if c.Organization == org && c.GitProjectName == r.Name {
// ignore project gits // ignore project gits
continue next_repo continue next_repo
} }
@@ -325,7 +324,7 @@ next_repo:
log.Println(" -- checking repository:", r.Name) log.Println(" -- checking repository:", r.Name)
} }
if _, err := gitea.GetRecentCommits(orgName, r.Name, config.Branch, 1); err != nil { if _, err := gitea.GetRecentCommits(org, r.Name, config.Branch, 1); err != nil {
// assumption that package does not exist, so not part of project // assumption that package does not exist, so not part of project
// https://github.com/go-gitea/gitea/issues/31976 // https://github.com/go-gitea/gitea/issues/31976
continue continue
@@ -335,11 +334,14 @@ next_repo:
common.PanicOnError(git.GitExec(config.GitProjectName, "submodule", "--quiet", "add", "--depth", "1", r.CloneURL, r.Name)) common.PanicOnError(git.GitExec(config.GitProjectName, "submodule", "--quiet", "add", "--depth", "1", r.CloneURL, r.Name))
if len(config.Branch) > 0 { if len(config.Branch) > 0 {
branch := strings.TrimSpace(git.GitExecWithOutputOrPanic(path.Join(config.GitProjectName, r.Name), "branch", "--show-current"))
if branch != config.Branch {
if err := git.GitExec(path.Join(config.GitProjectName, r.Name), "fetch", "--depth", "1", "origin", config.Branch+":"+config.Branch); err != nil { if err := git.GitExec(path.Join(config.GitProjectName, r.Name), "fetch", "--depth", "1", "origin", config.Branch+":"+config.Branch); err != nil {
return fmt.Errorf("Fetching branch %s for %s/%s failed. Ignoring.", config.Branch, repo.Owner.UserName, r.Name) return fmt.Errorf("Fetching branch %s for %s/%s failed. Ignoring.", config.Branch, repo.Owner.UserName, r.Name)
} }
common.PanicOnError(git.GitExec(path.Join(config.GitProjectName, r.Name), "checkout", config.Branch)) common.PanicOnError(git.GitExec(path.Join(config.GitProjectName, r.Name), "checkout", config.Branch))
} }
}
isGitUpdated = true isGitUpdated = true
} }
@@ -350,7 +352,7 @@ next_repo:
} }
if DebugMode { if DebugMode {
log.Println("Verification finished for ", orgName, ", config", config.GitProjectName) log.Println("Verification finished for ", org, ", config", config.GitProjectName)
} }
return nil return nil

View File

@@ -50,6 +50,8 @@ func fetchPrGit(h *common.RequestHandler, pr *models.PullRequest) error {
}*/ }*/
var DebugMode bool var DebugMode bool
var ListPROnly bool
var PRID int64
func main() { func main() {
if err := common.RequireGiteaSecretToken(); err != nil { if err := common.RequireGiteaSecretToken(); err != nil {
@@ -65,6 +67,9 @@ func main() {
flag.BoolVar(&DebugMode, "debug", false, "Extra debugging information") flag.BoolVar(&DebugMode, "debug", false, "Extra debugging information")
checkOnStart := flag.Bool("check-on-start", false, "Check all repositories for consistency on start, without delays") checkOnStart := flag.Bool("check-on-start", false, "Check all repositories for consistency on start, without delays")
checkIntervalHours := flag.Float64("check-interval", 5, "Check interval (+-random delay) for repositories for consitency, in hours") checkIntervalHours := flag.Float64("check-interval", 5, "Check interval (+-random delay) for repositories for consitency, in hours")
flag.BoolVar(&ListPROnly, "list-prs-only", false, "Only lists PRs without acting on them")
flag.Int64Var(&PRID, "id", -1, "Process only the specific ID and ignore the rest. Use for debugging")
flag.Parse() flag.Parse()
if len(*workflowConfig) == 0 { if len(*workflowConfig) == 0 {
@@ -109,6 +114,7 @@ func main() {
gitea: gitea, gitea: gitea,
} }
req.Review = &PullRequestReviewed{ req.Review = &PullRequestReviewed{
gitea: gitea,
} }
checker := CreateDefaultStateChecker(*checkOnStart, req, gitea, time.Duration(*checkIntervalHours)*time.Hour) checker := CreateDefaultStateChecker(*checkOnStart, req, gitea, time.Duration(*checkIntervalHours)*time.Hour)

View File

@@ -4,6 +4,7 @@ import (
"encoding/json" "encoding/json"
"src.opensuse.org/autogits/common" "src.opensuse.org/autogits/common"
"src.opensuse.org/autogits/common/gitea-generated/client/repository"
) )
//go:generate mockgen -source=maintainership.go -destination=mock/maintainership.go -typed //go:generate mockgen -source=maintainership.go -destination=mock/maintainership.go -typed
@@ -38,10 +39,18 @@ func FetchProjectMaintainershipData(gitea common.GiteaMaintainershipReader, org,
dir := true dir := true
if err != nil || data == nil { if err != nil || data == nil {
dir = false dir = false
if _, notFound := err.(*repository.RepoGetRawFileNotFound); !notFound {
return nil, err
}
data, err = gitea.FetchMaintainershipFile(org, prjGit, branch) data, err = gitea.FetchMaintainershipFile(org, prjGit, branch)
if err != nil || data == nil { if err != nil || data == nil {
if _, notFound := err.(*repository.RepoGetRawFileNotFound); !notFound {
return nil, err return nil, err
} }
// no mainatiners
data = []byte("{}")
}
} }
m, err := parseMaintainershipData(data) m, err := parseMaintainershipData(data)

View File

@@ -7,6 +7,7 @@ import (
"go.uber.org/mock/gomock" "go.uber.org/mock/gomock"
"src.opensuse.org/autogits/common" "src.opensuse.org/autogits/common"
"src.opensuse.org/autogits/common/gitea-generated/client/repository"
mock_common "src.opensuse.org/autogits/common/mock" mock_common "src.opensuse.org/autogits/common/mock"
) )
@@ -36,7 +37,7 @@ func TestMaintainership(t *testing.T) {
}, },
{ {
name: "Error in MaintainerListForPackage when remote has an error", name: "Error in MaintainerListForPackage when remote has an error",
maintainersFileErr: errors.New("some error here"), maintainersFileErr: errors.New("Some error"), // repository.NewRepoGetRawFileNotFound(),
packageName: "foo", packageName: "foo",
}, },
{ {
@@ -82,7 +83,7 @@ func TestMaintainership(t *testing.T) {
}, },
{ {
name: "Error in MaintainerListForProject when remote has an error", name: "Error in MaintainerListForProject when remote has an error",
maintainersFileErr: errors.New("some error here"), maintainersFileErr: errors.New("some error"), //repository.NewRepoGetRawFileNotFound(),
}, },
{ {
name: "Multiple project maintainers", name: "Multiple project maintainers",
@@ -118,7 +119,7 @@ func TestMaintainership(t *testing.T) {
}, },
} }
notFoundError := errors.New("not found") notFoundError := repository.NewRepoGetRawFileNotFound()
for _, test := range packageTests { for _, test := range packageTests {
runTests := func(t *testing.T, mi common.GiteaMaintainershipReader) { runTests := func(t *testing.T, mi common.GiteaMaintainershipReader) {
maintainers, err := FetchProjectMaintainershipData(mi, config.Organization, config.GitProjectName, config.Branch) maintainers, err := FetchProjectMaintainershipData(mi, config.Organization, config.GitProjectName, config.Branch)

View File

@@ -4,6 +4,7 @@ import (
"bufio" "bufio"
"errors" "errors"
"fmt" "fmt"
"log"
"os" "os"
"path" "path"
"slices" "slices"
@@ -103,6 +104,33 @@ func (rs *PRSet) IsConsistent() bool {
return true return true
} }
func (rs *PRSet) AssignReviewers(gitea common.GiteaReviewRequester, maintainers MaintainershipData) error {
configReviewers := ParseReviewers(rs.config.Reviewers)
for _, pr := range rs.prs {
reviewers := []string{}
if rs.IsPrjGitPR(pr.pr) {
reviewers = configReviewers.Prj
} else {
reviewers = configReviewers.Pkg
}
// submitters do not need to review their own work
if idx := slices.Index(reviewers, pr.pr.User.UserName); idx != -1 {
reviewers = slices.Delete(reviewers, idx, idx+1)
}
// get maintainers associated with the PR too
log.Printf("revieweres to be added to %s/%s#%d - [%s]\n", pr.pr.Base.Repo.Owner.UserName, pr.pr.Base.Repo.Name, pr.pr.Index, strings.Join(reviewers, ", "))
if len(reviewers) > 0 {
if _, err := gitea.RequestReviews(pr.pr, reviewers...); err != nil {
return fmt.Errorf("Cannot create reviews on %s/%s#%d for [%s]: %w", pr.pr.Base.Repo.Owner.UserName, pr.pr.Base.Repo.Name, pr.pr.Index, strings.Join(reviewers, ", "), err)
}
}
}
return nil
}
func (rs *PRSet) IsReviewed(gitea common.GiteaPRChecker) bool { func (rs *PRSet) IsReviewed(gitea common.GiteaPRChecker) bool {
configReviewers := ParseReviewers(rs.config.Reviewers) configReviewers := ParseReviewers(rs.config.Reviewers)

View File

@@ -2,6 +2,7 @@ package main
import ( import (
"fmt" "fmt"
"log"
"src.opensuse.org/autogits/common" "src.opensuse.org/autogits/common"
) )
@@ -31,7 +32,8 @@ referencing
req.Pull_Request.Number, req.Pull_Request.Number,
) )
prjGit, err := o.gitea.CreateRepositoryIfNotExist(git, *req.Repository.Owner, config.GitProjectName) // TODO: fix this for config.Organization
prjGit, err := o.gitea.CreateRepositoryIfNotExist(git, config.Organization, config.GitProjectName)
if err != nil { if err != nil {
return err return err
} }
@@ -65,13 +67,17 @@ referencing the following pull request:
return err return err
} }
// request build review prset, err := FetchPRSet(o.gitea, req.Repository.Owner.Username, req.Repository.Name, req.Number, config)
for _, reviewer := range config.Reviewers {
_, err := o.gitea.RequestReviews(PR, reviewer)
if err != nil { if err != nil {
return fmt.Errorf("Failed to create reviewer '%s' for request: %s/%s/%d Err: %w", reviewer, PR.Base.Repo.Owner.UserName, PR.Base.Repo.Name, PR.Index, err) return err
}
} }
// request build review
log.Println("num of current reviewers:", len(PR.RequestedReviewers))
maintainers, err := FetchProjectMaintainershipData(o.gitea, config.Organization, config.GitProjectName, config.Branch)
if err != nil {
return err
}
prset.AssignReviewers(o.gitea, maintainers)
return nil return nil
} }

View File

@@ -86,8 +86,8 @@ func TestOpenPR(t *testing.T) {
giteaPR := &models.PullRequest{} giteaPR := &models.PullRequest{}
gitea.EXPECT().CreateRepositoryIfNotExist(git, *event.Repository.Owner, "prjcopy").Return(prjgit, nil) gitea.EXPECT().CreateRepositoryIfNotExist(git, *event.Repository.Owner, "prjcopy").Return(prjgit, nil)
gitea.EXPECT().CreatePullRequestIfNotExist(prjgit, gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(giteaPR, nil) gitea.EXPECT().CreatePullRequestIfNotExist(prjgit, gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(giteaPR, nil)
gitea.EXPECT().RequestReviews(giteaPR, "reviewer1").Return(nil, nil) gitea.EXPECT().RequestReviews(giteaPR, "reviewer1", "reviewer2").Return(nil, nil)
gitea.EXPECT().RequestReviews(giteaPR, "reviewer2").Return(nil, nil) // gitea.EXPECT().RequestReviews(giteaPR, "reviewer2").Return(nil, nil)
err := pr.Process(event, git, config) err := pr.Process(event, git, config)
if err != nil { if err != nil {

View File

@@ -2,6 +2,7 @@ package main
import ( import (
"errors" "errors"
"fmt"
"os" "os"
"os/exec" "os/exec"
"path" "path"
@@ -12,6 +13,7 @@ import (
"src.opensuse.org/autogits/common" "src.opensuse.org/autogits/common"
"src.opensuse.org/autogits/common/gitea-generated/models" "src.opensuse.org/autogits/common/gitea-generated/models"
mock_common "src.opensuse.org/autogits/common/mock" mock_common "src.opensuse.org/autogits/common/mock"
mock_main "src.opensuse.org/workflow-pr/mock"
) )
func TestPR(t *testing.T) { func TestPR(t *testing.T) {
@@ -144,6 +146,7 @@ func TestPR(t *testing.T) {
ctl := gomock.NewController(t) ctl := gomock.NewController(t)
pr_mock := mock_common.NewMockGiteaPRFetcher(ctl) pr_mock := mock_common.NewMockGiteaPRFetcher(ctl)
review_mock := mock_common.NewMockGiteaPRChecker(ctl) review_mock := mock_common.NewMockGiteaPRChecker(ctl)
// reviewer_mock := mock_common.NewMockGiteaReviewRequester(ctl)
var test_err error var test_err error
for _, data := range test.data { for _, data := range test.data {
@@ -212,7 +215,11 @@ func TestPR(t *testing.T) {
if res.IsConsistent() != test.consistentSet { if res.IsConsistent() != test.consistentSet {
t.Error("IsConsistent() returned unexpected:", test.consistentSet) t.Error("IsConsistent() returned unexpected:", test.consistentSet)
} }
/*
if err := res.AssignReviewers(reviewer_mock); err != nil {
t.Error("expected no errors assigning reviewers:", err)
}
*/
if isReviewed := res.IsReviewed(review_mock); isReviewed != test.reviewed { if isReviewed := res.IsReviewed(review_mock); isReviewed != test.reviewed {
t.Error("expected reviewed to be NOT", isReviewed) t.Error("expected reviewed to be NOT", isReviewed)
} }
@@ -221,6 +228,104 @@ func TestPR(t *testing.T) {
}) })
} }
func TestPRAssignReviewers(t *testing.T) {
tests := []struct {
name string
config common.AutogitConfig
reviews []*models.PullReview
reviewers []struct {
org, repo string
num int64
reviewer string
}
expectedReviewerCall [2][]string
}{
{
name: "No reviewers",
config: common.AutogitConfig{
GitProjectName: "repo",
Organization: "org",
Branch: "main",
Reviewers: []string{},
},
expectedReviewerCall: [2][]string{{"autogits_obs_staging_bot"}},
},
{
name: "One project reviewer only",
config: common.AutogitConfig{
GitProjectName: "repo",
Organization: "org",
Branch: "main",
Reviewers: []string{"-user1"},
},
expectedReviewerCall: [2][]string{{"user1", "autogits_obs_staging_bot"}},
},
{
name: "One project reviewer and one pkg reviewer only",
config: common.AutogitConfig{
GitProjectName: "repo",
Organization: "org",
Branch: "main",
Reviewers: []string{"-user1", "user2"},
},
expectedReviewerCall: [2][]string{{"user1", "autogits_obs_staging_bot"}, {"user2"}},
},
{
name: "No need to get reviews of submitter",
config: common.AutogitConfig{
GitProjectName: "repo",
Organization: "org",
Branch: "main",
Reviewers: []string{"-user1", "submitter"},
},
expectedReviewerCall: [2][]string{{"user1", "autogits_obs_staging_bot"}, {}},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
ctl := gomock.NewController(t)
pr_mock := mock_common.NewMockGiteaPRFetcher(ctl)
review_mock := mock_common.NewMockGiteaReviewRequester(ctl)
maintainership_mock := mock_main.NewMockMaintainershipData(ctl)
pr_mock.EXPECT().GetPullRequest("org", "repo", int64(42)).Return(&models.PullRequest{
Body: fmt.Sprintf(common.PrPattern, "other", "pkgrepo", 1),
User: &models.User{UserName: "bot1"},
RequestedReviewers: []*models.User{},
Base: &models.PRBranchInfo{Repo: &models.Repository{Name: "repo", Owner: &models.User{UserName: "org"}}},
Head: &models.PRBranchInfo{},
Index: 42,
}, nil)
pr_mock.EXPECT().GetPullRequest("other", "pkgrepo", int64(1)).Return(&models.PullRequest{
Body: fmt.Sprintf(common.PrPattern, "org", "repo", 42),
User: &models.User{UserName: "submitter"},
RequestedReviewers: []*models.User{},
Base: &models.PRBranchInfo{Repo: &models.Repository{Name: "pkgrepo", Owner: &models.User{UserName: "other"}}},
Head: &models.PRBranchInfo{},
Index: 1,
}, nil)
prs, _ := FetchPRSet(pr_mock, "org", "repo", 42, &test.config)
if len(prs.prs) != 2 {
t.Fatal("PRs not fetched")
}
for _, pr := range prs.prs {
r := test.expectedReviewerCall[0]
if !prs.IsPrjGitPR(pr.pr) {
r = test.expectedReviewerCall[1]
}
if len(r) > 0 {
review_mock.EXPECT().RequestReviews(pr.pr, r).Return(nil, nil)
}
}
// review_mock.EXPECT().RequestReviews(prs.prs[0].pr, "user1").Return(nil, nil)
prs.AssignReviewers(review_mock, maintainership_mock)
})
}
}
func TestPRMerge(t *testing.T) { func TestPRMerge(t *testing.T) {
cwd, _ := os.Getwd() cwd, _ := os.Getwd()
cmd := exec.Command("/usr/bin/bash", path.Join(cwd, "test_repo_setup.sh")) cmd := exec.Command("/usr/bin/bash", path.Join(cwd, "test_repo_setup.sh"))

View File

@@ -43,11 +43,7 @@ func CreateDefaultStateChecker(checkOnStart bool, processor *RequestProcessor, g
return s return s
} }
func (s *DefaultStateChecker) VerifyProjectState(orgName string, configs []*common.AutogitConfig, idx int) error { func (s *DefaultStateChecker) VerifyProjectState(org string, configs []*common.AutogitConfig, idx int) error {
org := common.Organization{
Username: orgName,
}
git, err := s.git.CreateGitHandler(GitAuthor, GitEmail, AppName) git, err := s.git.CreateGitHandler(GitAuthor, GitEmail, AppName)
if err != nil { if err != nil {
return fmt.Errorf("Cannot create git handler: %w", err) return fmt.Errorf("Cannot create git handler: %w", err)
@@ -56,7 +52,7 @@ func (s *DefaultStateChecker) VerifyProjectState(orgName string, configs []*comm
config := configs[idx] config := configs[idx]
repo, err := s.gitea.CreateRepositoryIfNotExist(git, org, config.GitProjectName) repo, err := s.gitea.CreateRepositoryIfNotExist(git, org, config.GitProjectName)
if err != nil { if err != nil {
return fmt.Errorf("Error fetching or creating '%s/%s' -- aborting verifyProjectState(). Err: %w", orgName, config.GitProjectName, err) return fmt.Errorf("Error fetching or creating '%s/%s' -- aborting verifyProjectState(). Err: %w", org, config.GitProjectName, err)
} }
common.PanicOnError(git.GitExec("", "clone", "--depth", "1", repo.SSHURL, config.GitProjectName)) common.PanicOnError(git.GitExec("", "clone", "--depth", "1", repo.SSHURL, config.GitProjectName))