forked from adamm/autogits
613 lines
20 KiB
Go
613 lines
20 KiB
Go
package main
|
|
|
|
//go:generate mockgen -source=pr_processor.go -destination=mock/pr_processor.go -typed
|
|
|
|
import (
|
|
"encoding/json"
|
|
"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
|
|
}
|
|
if pr.PR.State != "open" {
|
|
// remove PRs that are not open from description
|
|
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", "-f", 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")
|
|
}
|
|
|
|
if common.GetLoggingLevel() >= common.LogLevelDebug {
|
|
cjson, _ := json.Marshal(config)
|
|
common.LogDebug("found config:", string(cjson))
|
|
}
|
|
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. %v", 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
|
|
if len(prset.PRs) == 1 {
|
|
git.GitExecOrPanic(common.DefaultGitPrj, "fetch", PrjGitPR.RemoteName, PrjGitPR.PR.Head.Sha)
|
|
common.LogDebug("Only project git in PR. Nothing to update.")
|
|
return nil
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
PrjGitTitle, PrjGitBody := PrjGitDescription(prset)
|
|
if PrjGitPR.PR.Title != PrjGitTitle || PrjGitPR.PR.Body != PrjGitBody {
|
|
common.LogDebug("New title:", PrjGitTitle)
|
|
common.LogDebug(PrjGitBody)
|
|
}
|
|
|
|
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
|
|
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,
|
|
})
|
|
}
|
|
}
|
|
|
|
// remove closed PRs from prset
|
|
prset.RemoveClosedPRs()
|
|
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()
|
|
// TODO: this is broken...
|
|
if pr, err := prset.GetPrjGitPR(); err == nil && false {
|
|
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.GitExecQuietOrPanic(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")
|
|
}
|
|
|
|
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)
|
|
}
|
|
} else {
|
|
prset.AssignReviewers(Gitea, maintainers)
|
|
}
|
|
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)
|
|
}
|