PRset is used elsewhere and if the pending, unpushed commits are not part of it, we have an old state
590 lines
19 KiB
Go
590 lines
19 KiB
Go
package main
|
|
|
|
//go:generate mockgen -source=pr_processor.go -destination=mock/pr_processor.go -typed
|
|
|
|
import (
|
|
"fmt"
|
|
"path"
|
|
"runtime/debug"
|
|
"slices"
|
|
"strings"
|
|
|
|
"github.com/opentracing/opentracing-go/log"
|
|
"src.opensuse.org/autogits/common"
|
|
"src.opensuse.org/autogits/common/gitea-generated/client/repository"
|
|
"src.opensuse.org/autogits/common/gitea-generated/models"
|
|
)
|
|
|
|
func prGitBranchNameForPR(repo string, prNo int64) string {
|
|
return fmt.Sprintf("PR_%s#%d", repo, prNo)
|
|
}
|
|
|
|
func PrjGitDescription(prset *common.PRSet) (title string, desc string) {
|
|
title_refs := make([]string, 0, len(prset.PRs)-1)
|
|
refs := make([]string, 0, len(prset.PRs)-1)
|
|
|
|
for _, pr := range prset.PRs {
|
|
if prset.IsPrjGitPR(pr.PR) {
|
|
continue
|
|
}
|
|
org, repo, idx := pr.PRComponents()
|
|
|
|
title_refs = append(title_refs, repo)
|
|
ref := fmt.Sprintf(common.PrPattern, org, repo, idx)
|
|
refs = append(refs, ref)
|
|
}
|
|
|
|
title = "Forwarded PRs: " + strings.Join(title_refs, ", ")
|
|
desc = fmt.Sprintf("This is a forwarded pull request by %s\nreferencing the following pull request(s):\n\n", GitAuthor) + strings.Join(refs, "\n") + "\n"
|
|
|
|
if prset.Config.ManualMergeOnly {
|
|
desc = desc + "\n### ManualMergeOnly enabled. To merge, 'merge ok' is required in either the project PR or every package PR."
|
|
}
|
|
if prset.Config.ManualMergeProject {
|
|
desc = desc + "\n### ManualMergeProject enabled. To merge, 'merge ok' is required by project maintainer in the project PR."
|
|
}
|
|
if !prset.Config.ManualMergeOnly && !prset.Config.ManualMergeProject {
|
|
desc = desc + "\n### Automatic merge enabled. This will merge when all review requirements are satisfied."
|
|
}
|
|
return
|
|
}
|
|
|
|
func verifyRepositoryConfiguration(repo *models.Repository) error {
|
|
if repo.AutodetectManualMerge && repo.AllowManualMerge {
|
|
return nil
|
|
}
|
|
|
|
// modify repo to allow above
|
|
common.LogDebug("Adjusting repo to accept manual merges:", repo.Owner.UserName+"/"+repo.Name)
|
|
_, err := Gitea.SetRepoOptions(repo.Owner.UserName, repo.Name, true)
|
|
if err != nil {
|
|
common.LogError("Failed to set repo to manual merges:", err)
|
|
}
|
|
return err
|
|
}
|
|
|
|
func updateSubmoduleInPR(submodule, headSha string, git common.Git) {
|
|
common.LogDebug("updating submodule", submodule, "to HEAD", headSha)
|
|
// NOTE: this can fail if current PrjGit is pointing to outdated, GC'ed commit
|
|
// as long as we can update to newer one later, we are still OK
|
|
git.GitExec(common.DefaultGitPrj, "submodule", "update", "--init", "--checkout", "--depth", "1", submodule)
|
|
common.PanicOnError(git.GitExec(path.Join(common.DefaultGitPrj, submodule), "fetch", "--depth", "1", "origin", headSha))
|
|
common.PanicOnError(git.GitExec(path.Join(common.DefaultGitPrj, submodule), "checkout", headSha))
|
|
}
|
|
|
|
type PRProcessor struct {
|
|
config *common.AutogitConfig
|
|
git common.Git
|
|
}
|
|
|
|
func AllocatePRProcessor(req *models.PullRequest, configs common.AutogitConfigs) (*PRProcessor, error) {
|
|
org := req.Base.Repo.Owner.UserName
|
|
repo := req.Base.Repo.Name
|
|
id := req.Index
|
|
|
|
branch := req.Base.Ref
|
|
|
|
PRstr := fmt.Sprintf("%s/%s!%d", org, repo, id)
|
|
common.LogInfo("*** Starting processing PR:", PRstr, "branch:", branch)
|
|
|
|
config := configs.GetPrjGitConfig(org, repo, branch)
|
|
if config == nil {
|
|
if req.Base.Repo.DefaultBranch == branch {
|
|
common.LogDebug("Default branch submission...", org, repo)
|
|
config = configs.GetPrjGitConfig(org, repo, "")
|
|
}
|
|
}
|
|
if config == nil {
|
|
common.LogError("Cannot find config for PR.")
|
|
return nil, fmt.Errorf("Cannot find config for PR")
|
|
}
|
|
|
|
common.LogDebug("found config", config)
|
|
if config == nil {
|
|
common.LogError("Cannot find config for branch '%s'", req.Base.Ref)
|
|
return nil, fmt.Errorf("Cannot find config for branch '%s'", req.Base.Ref)
|
|
}
|
|
|
|
git, err := GitHandler.CreateGitHandler(config.Organization)
|
|
if err != nil {
|
|
common.LogError("Cannot allocate GitHandler:", err)
|
|
return nil, fmt.Errorf("Error allocating GitHandler. Err: %w", err)
|
|
}
|
|
common.LogDebug("git path:", git.GetPath())
|
|
|
|
// git.GitExecOrPanic("", "config", "set", "--global", "advice.submoduleMergeConflict", "false")
|
|
// git.GitExecOrPanic("", "config", "set", "--global", "advice.mergeConflict", "false")
|
|
|
|
return &PRProcessor{
|
|
config: config,
|
|
git: git,
|
|
}, nil
|
|
}
|
|
|
|
func (pr *PRProcessor) SetSubmodulesToMatchPRSet(prset *common.PRSet) error {
|
|
git := pr.git
|
|
subList, err := git.GitSubmoduleList(common.DefaultGitPrj, "HEAD")
|
|
if err != nil {
|
|
common.LogError("Error fetching submodule list for PrjGit", err)
|
|
return err
|
|
}
|
|
|
|
for _, pr := range prset.PRs {
|
|
if prset.IsPrjGitPR(pr.PR) {
|
|
continue
|
|
}
|
|
|
|
org, repo, idx := pr.PRComponents()
|
|
prHead := pr.PR.Head.Sha
|
|
revert := false
|
|
|
|
if pr.PR.State != "open" {
|
|
prjGitPR, err := prset.GetPrjGitPR()
|
|
if prjGitPR != nil {
|
|
// remove PR from PrjGit
|
|
var valid bool
|
|
if prHead, valid = git.GitSubmoduleCommitId(common.DefaultGitPrj, repo, prjGitPR.PR.MergeBase); !valid {
|
|
common.LogError("Failed fetching original submodule commit id for repo")
|
|
return err
|
|
}
|
|
}
|
|
revert = true
|
|
}
|
|
|
|
// find 'repo' in the submodule list
|
|
submodule_found := false
|
|
for submodulePath, id := range subList {
|
|
if path.Base(submodulePath) == repo {
|
|
submodule_found = true
|
|
if id != prHead {
|
|
ref := fmt.Sprintf(common.PrPattern, org, repo, idx)
|
|
commitMsg := fmt.Sprintln("auto-created for", repo, "\n\nThis commit was autocreated by", GitAuthor, "\n\nreferencing PRs:\n", ref)
|
|
|
|
if revert {
|
|
commitMsg = fmt.Sprintln("auto-created for", repo, "\n\nThis commit was autocreated by", GitAuthor, "\n\nremoving PRs:\n", ref)
|
|
}
|
|
|
|
updateSubmoduleInPR(submodulePath, prHead, git)
|
|
status, err := git.GitStatus(common.DefaultGitPrj)
|
|
common.LogDebug("status:", status)
|
|
common.LogDebug("submodule", repo, " hash:", id, " -> ", prHead)
|
|
common.PanicOnError(err)
|
|
common.PanicOnError(git.GitExec(common.DefaultGitPrj, "commit", "-a", "-m", commitMsg))
|
|
|
|
pr.PR.Head.Sha = id // update the prset
|
|
}
|
|
submodule_found = true
|
|
break
|
|
}
|
|
}
|
|
|
|
if !submodule_found {
|
|
common.LogError("Failed to find expected repo:", repo)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (pr *PRProcessor) CreatePRjGitPR(prjGitPRbranch string, prset *common.PRSet) error {
|
|
git := pr.git
|
|
PrjGitOrg, PrjGitRepo, PrjGitBranch := prset.Config.GetPrjGit()
|
|
PrjGit, err := Gitea.GetRepository(PrjGitOrg, PrjGitRepo)
|
|
if err != nil {
|
|
common.LogError("Failed to fetch PrjGit repository data.", PrjGitOrg, PrjGitRepo, err)
|
|
return err
|
|
}
|
|
RemoteName, err := git.GitClone(common.DefaultGitPrj, PrjGitBranch, PrjGit.SSHURL)
|
|
common.PanicOnError(err)
|
|
git.GitExecOrPanic(common.DefaultGitPrj, "checkout", "-B", prjGitPRbranch, RemoteName+"/"+PrjGitBranch)
|
|
|
|
headCommit, err := git.GitBranchHead(common.DefaultGitPrj, prjGitPRbranch)
|
|
if err != nil {
|
|
common.LogError("Failed to fetch PrjGit branch", prjGitPRbranch, err)
|
|
return err
|
|
}
|
|
if err := pr.SetSubmodulesToMatchPRSet(prset); err != nil {
|
|
return err
|
|
}
|
|
newHeadCommit, err := git.GitBranchHead(common.DefaultGitPrj, prjGitPRbranch)
|
|
if err != nil {
|
|
common.LogError("Failed to fetch updated PrjGit branch", prjGitPRbranch, err)
|
|
return err
|
|
}
|
|
|
|
if !common.IsDryRun && !pr.config.NoProjectGitPR {
|
|
if headCommit != newHeadCommit {
|
|
common.PanicOnError(git.GitExec(common.DefaultGitPrj, "push", RemoteName, "+HEAD:"+prjGitPRbranch))
|
|
}
|
|
|
|
title, desc := PrjGitDescription(prset)
|
|
pr, err := Gitea.CreatePullRequestIfNotExist(PrjGit, prjGitPRbranch, PrjGitBranch, title, desc)
|
|
if err != nil {
|
|
common.LogError("Error creating PrjGit PR:", err)
|
|
return err
|
|
}
|
|
Gitea.UpdatePullRequest(PrjGit.Owner.UserName, PrjGit.Name, pr.Index, &models.EditPullRequestOption{
|
|
RemoveDeadline: true,
|
|
})
|
|
|
|
prinfo := prset.AddPR(pr)
|
|
prinfo.RemoteName = RemoteName
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (pr *PRProcessor) RebaseAndSkipSubmoduleCommits(prset *common.PRSet, branch string) error {
|
|
git := pr.git
|
|
PrjGitPR, err := prset.GetPrjGitPR()
|
|
common.PanicOnError(err)
|
|
|
|
remoteBranch := PrjGitPR.RemoteName + "/" + branch
|
|
|
|
common.LogDebug("Rebasing on top of", remoteBranch)
|
|
for conflict := git.GitExec(common.DefaultGitPrj, "rebase", remoteBranch); conflict != nil; {
|
|
statuses, err := git.GitStatus(common.DefaultGitPrj)
|
|
if err != nil {
|
|
git.GitExecOrPanic(common.DefaultGitPrj, "rebase", "--abort")
|
|
common.PanicOnError(err)
|
|
}
|
|
for _, s := range statuses {
|
|
if s.SubmoduleChanges != "S..." {
|
|
git.GitExecOrPanic(common.DefaultGitPrj, "rebase", "--abort")
|
|
return fmt.Errorf("Unexpected conflict in rebase. %s", s)
|
|
}
|
|
}
|
|
conflict = git.GitExec(common.DefaultGitPrj, "rebase", "--skip")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (pr *PRProcessor) UpdatePrjGitPR(prset *common.PRSet) error {
|
|
_, _, PrjGitBranch := prset.Config.GetPrjGit()
|
|
PrjGitPR, err := prset.GetPrjGitPR()
|
|
if err != nil {
|
|
common.LogError("Updating PrjGitPR but not found?", err)
|
|
return err
|
|
}
|
|
|
|
git := pr.git
|
|
PrjGit := PrjGitPR.PR.Base.Repo
|
|
prjGitPRbranch := PrjGitPR.PR.Head.Name
|
|
if strings.Contains(prjGitPRbranch, "/") {
|
|
PrjGitPR.RemoteName, err = git.GitClone(common.DefaultGitPrj, "", PrjGit.SSHURL)
|
|
git.GitExecOrPanic(common.DefaultGitPrj, "fetch", PrjGitPR.RemoteName, PrjGitPR.PR.Head.Sha)
|
|
git.GitExecOrPanic(common.DefaultGitPrj, "checkout", PrjGitPR.PR.Head.Sha)
|
|
common.LogInfo("Cannot update this PR as it's on another remote, not branch:", prjGitPRbranch, "Assuming this is by-design. (eg. project git PR only)")
|
|
return nil
|
|
}
|
|
|
|
PrjGitPR.RemoteName, err = git.GitClone(common.DefaultGitPrj, prjGitPRbranch, PrjGit.SSHURL)
|
|
common.PanicOnError(err)
|
|
git.GitExecOrPanic(common.DefaultGitPrj, "fetch", PrjGitPR.RemoteName, PrjGitBranch)
|
|
|
|
forcePush := false
|
|
// trust Gitea here on mergeability
|
|
if !PrjGitPR.PR.Mergeable {
|
|
common.PanicOnError(pr.RebaseAndSkipSubmoduleCommits(prset, PrjGitBranch))
|
|
forcePush = true
|
|
}
|
|
|
|
headCommit, err := git.GitBranchHead(common.DefaultGitPrj, prjGitPRbranch)
|
|
if err != nil {
|
|
common.LogError("Failed to fetch PrjGit branch", prjGitPRbranch, err)
|
|
return err
|
|
}
|
|
if err := pr.SetSubmodulesToMatchPRSet(prset); err != nil {
|
|
return err
|
|
}
|
|
newHeadCommit, err := git.GitBranchHead(common.DefaultGitPrj, prjGitPRbranch)
|
|
if err != nil {
|
|
common.LogError("Failed to fetch updated PrjGit branch", prjGitPRbranch, err)
|
|
return err
|
|
}
|
|
|
|
if !common.IsDryRun {
|
|
if headCommit != newHeadCommit {
|
|
params := []string{"push", PrjGitPR.RemoteName, "+HEAD:" + prjGitPRbranch}
|
|
if forcePush {
|
|
params = slices.Insert(params, 1, "-f")
|
|
}
|
|
common.PanicOnError(git.GitExec(common.DefaultGitPrj, params...))
|
|
}
|
|
|
|
// update PR
|
|
PrjGitTitle, PrjGitBody := PrjGitDescription(prset)
|
|
if PrjGitPR.PR.Body != PrjGitBody || PrjGitPR.PR.Title != PrjGitTitle {
|
|
Gitea.UpdatePullRequest(PrjGit.Owner.UserName, PrjGit.Name, PrjGitPR.PR.Index, &models.EditPullRequestOption{
|
|
RemoveDeadline: true,
|
|
Title: PrjGitTitle,
|
|
Body: PrjGitBody,
|
|
})
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (pr *PRProcessor) Process(req *models.PullRequest) error {
|
|
config := pr.config
|
|
git := pr.git
|
|
|
|
// requests against project are not handled here
|
|
common.LogInfo("processing opened PR:", req.URL)
|
|
prOrg := req.Base.Repo.Owner.UserName
|
|
prRepo := req.Base.Repo.Name
|
|
prNo := req.Index
|
|
|
|
common.LogError(req)
|
|
|
|
prset, err := common.FetchPRSet(CurrentUser.UserName, Gitea, prOrg, prRepo, prNo, config)
|
|
if err != nil {
|
|
common.LogError("Cannot fetch PRSet:", err)
|
|
return err
|
|
}
|
|
common.LogInfo("fetched PRSet of size:", len(prset.PRs))
|
|
|
|
prjGitPRbranch := prGitBranchNameForPR(prRepo, prNo)
|
|
prjGitPR, err := prset.GetPrjGitPR()
|
|
if err == common.PRSet_PrjGitMissing {
|
|
common.LogDebug("Missing PrjGit. Need to create one under branch", prjGitPRbranch)
|
|
|
|
if err = pr.CreatePRjGitPR(prjGitPRbranch, prset); err != nil {
|
|
return err
|
|
}
|
|
} else if err == nil {
|
|
common.LogDebug("Found PrjGit PR:", common.PRtoString(prjGitPR.PR))
|
|
prjGitPRbranch = prjGitPR.PR.Head.Name
|
|
|
|
if prjGitPR.PR.State != "open" {
|
|
if prjGitPR.PR.HasMerged {
|
|
// update branches in project
|
|
prjGitPR.RemoteName, err = git.GitClone(common.DefaultGitPrj, prjGitPRbranch, prjGitPR.PR.Base.Repo.SSHURL)
|
|
common.PanicOnError(err)
|
|
|
|
old_pkgs, err := git.GitSubmoduleList(common.DefaultGitPrj, prjGitPR.PR.MergeBase)
|
|
common.PanicOnError(err)
|
|
new_pkgs, err := git.GitSubmoduleList(common.DefaultGitPrj, prjGitPRbranch)
|
|
common.PanicOnError(err)
|
|
|
|
pkgs := make(map[string]string)
|
|
for pkg, old_commit := range old_pkgs {
|
|
if new_commit, found := new_pkgs[pkg]; found {
|
|
// pkg modified
|
|
if new_commit != old_commit {
|
|
pkgs[pkg] = new_commit
|
|
}
|
|
} else { // not found, pkg removed
|
|
pkgs[pkg] = ""
|
|
}
|
|
}
|
|
for pkg, commit := range new_pkgs {
|
|
if _, found := old_pkgs[pkg]; !found {
|
|
// pkg added
|
|
pkgs[pkg] = commit
|
|
}
|
|
}
|
|
|
|
PrjGitSubmoduleCheck(config, git, common.DefaultGitPrj, pkgs)
|
|
}
|
|
|
|
// manually merge or close entire prset that is still open
|
|
for _, pr := range prset.PRs {
|
|
if pr.PR.State == "open" {
|
|
org, repo, idx := pr.PRComponents()
|
|
if prjGitPR.PR.HasMerged {
|
|
Gitea.AddComment(pr.PR, "This PR is merged via the associated Project PR.")
|
|
err = Gitea.ManualMergePR(org, repo, idx, pr.PR.Head.Sha, false)
|
|
if _, ok := err.(*repository.RepoMergePullRequestConflict); !ok {
|
|
common.PanicOnError(err)
|
|
}
|
|
} else {
|
|
Gitea.AddComment(pr.PR, "Closing here because the associated Project PR has been closed.")
|
|
Gitea.UpdatePullRequest(org, repo, idx, &models.EditPullRequestOption{
|
|
State: "closed",
|
|
})
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
if len(prset.PRs) > 1 {
|
|
for _, pr := range prset.PRs {
|
|
if prset.IsPrjGitPR(pr.PR) {
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
|
|
if err = pr.UpdatePrjGitPR(prset); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
if prjGitPR == nil {
|
|
prjGitPR, err = prset.GetPrjGitPR()
|
|
if err == common.PRSet_PrjGitMissing && config.NoProjectGitPR {
|
|
// we could be waiting for other tooling to create the
|
|
// project git PR. In meantime, we can assign some
|
|
// reviewers here.
|
|
} else if err != nil {
|
|
common.LogError("Error fetching PrjGitPR:", err)
|
|
return nil
|
|
}
|
|
}
|
|
|
|
common.LogDebug("Updated PR")
|
|
|
|
// make sure that prjgit is consistent and only submodules that are to be *updated*
|
|
// reset anything that changed that is not part of the prset
|
|
// package removals/additions are *not* counted here
|
|
org, repo, branch := config.GetPrjGit()
|
|
if pr, err := prset.GetPrjGitPR(); err == nil {
|
|
common.LogDebug("Submodule parse begin")
|
|
orig_subs, err := git.GitSubmoduleList(common.DefaultGitPrj, pr.PR.MergeBase)
|
|
common.PanicOnError(err)
|
|
new_subs, err := git.GitSubmoduleList(common.DefaultGitPrj, "HEAD")
|
|
common.PanicOnError(err)
|
|
common.LogDebug("Submodule parse done")
|
|
|
|
reset_submodule := func(submodule, sha string) {
|
|
updateSubmoduleInPR(submodule, sha, git)
|
|
}
|
|
|
|
common.LogDebug("Checking we only change linked commits")
|
|
for path, commit := range new_subs {
|
|
if old, ok := orig_subs[path]; ok && old != commit {
|
|
found := false
|
|
for _, pr := range prset.PRs {
|
|
if pr.PR.Base.Repo.Name == path && commit == pr.PR.Head.Sha {
|
|
found = true
|
|
break
|
|
} else if pr.PR.Base.Repo.Name == path {
|
|
common.LogError(path, "-- commits not match", commit, pr.PR.Head.Sha)
|
|
}
|
|
}
|
|
if !found {
|
|
reset_submodule(path, old)
|
|
}
|
|
}
|
|
}
|
|
|
|
stats, err := git.GitStatus(common.DefaultGitPrj)
|
|
common.LogDebug("Check Done", len(stats), "changes")
|
|
common.PanicOnError(err)
|
|
if len(stats) > 0 {
|
|
git.GitExecOrPanic(common.DefaultGitPrj, "commit", "-a", "-m", "Sync submodule updates with PR-set")
|
|
git.GitExecOrPanic(common.DefaultGitPrj, "submodule", "deinit", "--all", "--force")
|
|
if !common.IsDryRun {
|
|
git.GitExecOrPanic(common.DefaultGitPrj, "push")
|
|
}
|
|
}
|
|
}
|
|
|
|
if prjGitPR != nil {
|
|
common.LogDebug(" num of reviewers:", len(prjGitPR.PR.RequestedReviewers))
|
|
} else {
|
|
common.LogInfo("* No prjgit")
|
|
}
|
|
maintainers, err := common.FetchProjectMaintainershipData(Gitea, org, repo, branch)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// handle case where PrjGit PR is only one left and there are no changes, then we can just close the PR
|
|
if len(prset.PRs) == 1 && prjGitPR != nil && prset.PRs[0] == prjGitPR && prjGitPR.PR.User.UserName == prset.BotUser {
|
|
common.LogDebug(" --> checking if superflous PR")
|
|
diff, err := git.GitDiff(common.DefaultGitPrj, prjGitPR.PR.MergeBase, prjGitPR.PR.Head.Sha)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if len(diff) == 0 {
|
|
common.LogInfo("PR is no-op and can be closed. Closing.")
|
|
if !common.IsDryRun {
|
|
Gitea.AddComment(prjGitPR.PR, "Pull request no longer contains any changes. Closing.")
|
|
_, err = Gitea.UpdatePullRequest(prjGitPR.PR.Base.Repo.Owner.UserName, prjGitPR.PR.Base.Repo.Name, prjGitPR.PR.Index, &models.EditPullRequestOption{
|
|
State: "closed",
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
common.LogDebug(" --> NOT superflous PR")
|
|
}
|
|
|
|
prset.AssignReviewers(Gitea, maintainers)
|
|
for _, pr := range prset.PRs {
|
|
if err := verifyRepositoryConfiguration(pr.PR.Base.Repo); err != nil {
|
|
common.LogError("Cannot set manual merge... aborting processing")
|
|
return err
|
|
}
|
|
}
|
|
|
|
common.LogInfo("Consistent PRSet:", prset.IsConsistent())
|
|
common.LogInfo("Reviewed?", prset.IsApproved(Gitea, maintainers))
|
|
if prset.IsConsistent() && prset.IsApproved(Gitea, maintainers) {
|
|
common.LogInfo("Merging...")
|
|
if err = prset.Merge(Gitea, git); err != nil {
|
|
common.LogError("merge error:", err)
|
|
}
|
|
}
|
|
|
|
return err
|
|
}
|
|
|
|
type RequestProcessor struct {
|
|
configuredRepos map[string][]*common.AutogitConfig
|
|
}
|
|
|
|
func ProcesPullRequest(pr *models.PullRequest, configs []*common.AutogitConfig) error {
|
|
if len(configs) < 1 {
|
|
// ignoring pull request against unconfigured project (could be just regular sources?)
|
|
return nil
|
|
}
|
|
|
|
PRProcessor, err := AllocatePRProcessor(pr, configs)
|
|
if err != nil {
|
|
log.Error(err)
|
|
return err
|
|
}
|
|
defer PRProcessor.git.Close()
|
|
|
|
return PRProcessor.Process(pr)
|
|
}
|
|
|
|
func (w *RequestProcessor) ProcessFunc(request *common.Request) error {
|
|
defer func() {
|
|
if r := recover(); r != nil {
|
|
common.LogInfo("panic cought --- recovered")
|
|
common.LogError(string(debug.Stack()))
|
|
}
|
|
}()
|
|
|
|
var pr *models.PullRequest
|
|
var err error
|
|
if req, ok := request.Data.(*common.PullRequestWebhookEvent); ok {
|
|
pr, err = Gitea.GetPullRequest(req.Pull_Request.Base.Repo.Owner.Username, req.Pull_Request.Base.Repo.Name, req.Pull_Request.Number)
|
|
if err != nil {
|
|
common.LogError("Cannot find PR for issue:", req.Pull_Request.Base.Repo.Owner.Username, req.Pull_Request.Base.Repo.Name, req.Pull_Request.Number)
|
|
return err
|
|
}
|
|
} else if req, ok := request.Data.(*common.IssueWebhookEvent); ok {
|
|
pr, err = Gitea.GetPullRequest(req.Repository.Owner.Username, req.Repository.Name, int64(req.Issue.Number))
|
|
if err != nil {
|
|
common.LogError("Cannot find PR for issue:", req.Repository.Owner.Username, req.Repository.Name, int64(req.Issue.Number))
|
|
return err
|
|
}
|
|
} else {
|
|
common.LogError("*** Invalid data format for PR processing.")
|
|
return fmt.Errorf("*** Invalid data format for PR processing.")
|
|
}
|
|
|
|
configs, ok := w.configuredRepos[pr.Base.Repo.Owner.UserName]
|
|
if !ok {
|
|
common.LogError("*** Cannot find config for org:", pr.Base.Repo.Owner.UserName)
|
|
}
|
|
return ProcesPullRequest(pr, configs)
|
|
}
|