forked from adamm/autogits
Compare commits
8 Commits
Author | SHA256 | Date | |
---|---|---|---|
3d8671a7fe | |||
c5db1c83a7 | |||
9f0909621b | |||
b3914b04bd | |||
b43a19189e | |||
01b665230e | |||
1a07d4c541 | |||
22e44dff47 |
@@ -769,6 +769,8 @@ func (e *GitHandlerImpl) GitSubmoduleList(gitPath, commitId string) (submoduleLi
|
|||||||
done.Lock()
|
done.Lock()
|
||||||
data_in, data_out := ChanIO{make(chan byte)}, ChanIO{make(chan byte)}
|
data_in, data_out := ChanIO{make(chan byte)}, ChanIO{make(chan byte)}
|
||||||
|
|
||||||
|
LogDebug("Getting submodules for:", commitId)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
defer done.Unlock()
|
defer done.Unlock()
|
||||||
defer close(data_out.ch)
|
defer close(data_out.ch)
|
||||||
@@ -916,6 +918,16 @@ type GitStatusData struct {
|
|||||||
Path string
|
Path string
|
||||||
Status int
|
Status int
|
||||||
States [3]string
|
States [3]string
|
||||||
|
|
||||||
|
/*
|
||||||
|
<sub> A 4 character field describing the submodule state.
|
||||||
|
"N..." when the entry is not a submodule.
|
||||||
|
"S<c><m><u>" when the entry is a submodule.
|
||||||
|
<c> is "C" if the commit changed; otherwise ".".
|
||||||
|
<m> is "M" if it has tracked changes; otherwise ".".
|
||||||
|
<u> is "U" if there are untracked changes; otherwise ".".
|
||||||
|
*/
|
||||||
|
SubmoduleChanges string
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseGitStatusHexString(data io.ByteReader) (string, error) {
|
func parseGitStatusHexString(data io.ByteReader) (string, error) {
|
||||||
@@ -938,6 +950,20 @@ func parseGitStatusHexString(data io.ByteReader) (string, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
func parseGitStatusString(data io.ByteReader) (string, error) {
|
func parseGitStatusString(data io.ByteReader) (string, error) {
|
||||||
|
str := make([]byte, 0, 100)
|
||||||
|
for {
|
||||||
|
c, err := data.ReadByte()
|
||||||
|
if err != nil {
|
||||||
|
return "", errors.New("Unexpected EOF. Expected NUL string term")
|
||||||
|
}
|
||||||
|
if c == 0 || c == ' ' {
|
||||||
|
return string(str), nil
|
||||||
|
}
|
||||||
|
str = append(str, c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseGitStatusStringWithSpace(data io.ByteReader) (string, error) {
|
||||||
str := make([]byte, 0, 100)
|
str := make([]byte, 0, 100)
|
||||||
for {
|
for {
|
||||||
c, err := data.ReadByte()
|
c, err := data.ReadByte()
|
||||||
@@ -978,7 +1004,7 @@ func parseSingleStatusEntry(data io.ByteReader) (*GitStatusData, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
ret.Status = GitStatus_Modified
|
ret.Status = GitStatus_Modified
|
||||||
ret.Path, err = parseGitStatusString(data)
|
ret.Path, err = parseGitStatusStringWithSpace(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -988,11 +1014,11 @@ func parseSingleStatusEntry(data io.ByteReader) (*GitStatusData, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
ret.Status = GitStatus_Renamed
|
ret.Status = GitStatus_Renamed
|
||||||
ret.Path, err = parseGitStatusString(data)
|
ret.Path, err = parseGitStatusStringWithSpace(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
ret.States[0], err = parseGitStatusString(data)
|
ret.States[0], err = parseGitStatusStringWithSpace(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -1002,7 +1028,7 @@ func parseSingleStatusEntry(data io.ByteReader) (*GitStatusData, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
ret.Status = GitStatus_Untracked
|
ret.Status = GitStatus_Untracked
|
||||||
ret.Path, err = parseGitStatusString(data)
|
ret.Path, err = parseGitStatusStringWithSpace(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -1012,15 +1038,22 @@ func parseSingleStatusEntry(data io.ByteReader) (*GitStatusData, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
ret.Status = GitStatus_Ignored
|
ret.Status = GitStatus_Ignored
|
||||||
ret.Path, err = parseGitStatusString(data)
|
ret.Path, err = parseGitStatusStringWithSpace(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
case 'u':
|
case 'u':
|
||||||
var err error
|
var err error
|
||||||
if err = skipGitStatusEntry(data, 7); err != nil {
|
if err = skipGitStatusEntry(data, 2); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if ret.SubmoduleChanges, err = parseGitStatusString(data); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err = skipGitStatusEntry(data, 4); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
if ret.States[0], err = parseGitStatusHexString(data); err != nil {
|
if ret.States[0], err = parseGitStatusHexString(data); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -1031,7 +1064,7 @@ func parseSingleStatusEntry(data io.ByteReader) (*GitStatusData, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
ret.Status = GitStatus_Unmerged
|
ret.Status = GitStatus_Unmerged
|
||||||
ret.Path, err = parseGitStatusString(data)
|
ret.Path, err = parseGitStatusStringWithSpace(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@@ -555,6 +555,8 @@ func TestGitStatusParse(t *testing.T) {
|
|||||||
Path: ".gitmodules",
|
Path: ".gitmodules",
|
||||||
Status: GitStatus_Unmerged,
|
Status: GitStatus_Unmerged,
|
||||||
States: [3]string{"587ec403f01113f2629da538f6e14b84781f70ac59c41aeedd978ea8b1253a76", "d23eb05d9ca92883ab9f4d28f3ec90c05f667f3a5c8c8e291bd65e03bac9ae3c", "087b1d5f22dbf0aa4a879fff27fff03568b334c90daa5f2653f4a7961e24ea33"},
|
States: [3]string{"587ec403f01113f2629da538f6e14b84781f70ac59c41aeedd978ea8b1253a76", "d23eb05d9ca92883ab9f4d28f3ec90c05f667f3a5c8c8e291bd65e03bac9ae3c", "087b1d5f22dbf0aa4a879fff27fff03568b334c90daa5f2653f4a7961e24ea33"},
|
||||||
|
|
||||||
|
SubmoduleChanges: "N...",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@@ -603,14 +603,14 @@ func (gitea *GiteaTransport) CreateRepositoryIfNotExist(git Git, org, repoName s
|
|||||||
|
|
||||||
func (gitea *GiteaTransport) CreatePullRequestIfNotExist(repo *models.Repository, srcId, targetId, title, body string) (*models.PullRequest, error) {
|
func (gitea *GiteaTransport) CreatePullRequestIfNotExist(repo *models.Repository, srcId, targetId, title, body string) (*models.PullRequest, error) {
|
||||||
prOptions := models.CreatePullRequestOption{
|
prOptions := models.CreatePullRequestOption{
|
||||||
Base: repo.DefaultBranch,
|
Base: targetId,
|
||||||
Head: srcId,
|
Head: srcId,
|
||||||
Title: title,
|
Title: title,
|
||||||
Body: body,
|
Body: body,
|
||||||
}
|
}
|
||||||
|
|
||||||
if pr, err := gitea.client.Repository.RepoGetPullRequestByBaseHead(
|
if pr, err := gitea.client.Repository.RepoGetPullRequestByBaseHead(
|
||||||
repository.NewRepoGetPullRequestByBaseHeadParams().WithOwner(repo.Owner.UserName).WithRepo(repo.Name).WithBase(repo.DefaultBranch).WithHead(srcId),
|
repository.NewRepoGetPullRequestByBaseHeadParams().WithOwner(repo.Owner.UserName).WithRepo(repo.Name).WithBase(targetId).WithHead(srcId),
|
||||||
gitea.transport.DefaultAuthentication,
|
gitea.transport.DefaultAuthentication,
|
||||||
); err == nil {
|
); err == nil {
|
||||||
return pr.Payload, nil
|
return pr.Payload, nil
|
||||||
@@ -718,20 +718,18 @@ func (gitea *GiteaTransport) AddComment(pr *models.PullRequest, comment string)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (gitea *GiteaTransport) GetTimeline(org, repo string, idx int64) ([]*models.TimelineComment, error) {
|
func (gitea *GiteaTransport) GetTimeline(org, repo string, idx int64) ([]*models.TimelineComment, error) {
|
||||||
limit := int64(20)
|
|
||||||
page := int64(1)
|
page := int64(1)
|
||||||
resCount := limit
|
resCount := 1
|
||||||
|
|
||||||
retData := []*models.TimelineComment{}
|
retData := []*models.TimelineComment{}
|
||||||
|
|
||||||
for resCount == limit {
|
for resCount > 0 {
|
||||||
res, err := gitea.client.Issue.IssueGetCommentsAndTimeline(
|
res, err := gitea.client.Issue.IssueGetCommentsAndTimeline(
|
||||||
issue.NewIssueGetCommentsAndTimelineParams().
|
issue.NewIssueGetCommentsAndTimelineParams().
|
||||||
WithOwner(org).
|
WithOwner(org).
|
||||||
WithRepo(repo).
|
WithRepo(repo).
|
||||||
WithIndex(idx).
|
WithIndex(idx).
|
||||||
WithPage(&page).
|
WithPage(&page),
|
||||||
WithLimit(&limit),
|
|
||||||
gitea.transport.DefaultAuthentication,
|
gitea.transport.DefaultAuthentication,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -739,11 +737,13 @@ func (gitea *GiteaTransport) GetTimeline(org, repo string, idx int64) ([]*models
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
resCount = int64(len(res.Payload))
|
resCount = len(res.Payload)
|
||||||
|
LogDebug("page:", page, "len:", resCount)
|
||||||
page++
|
page++
|
||||||
|
|
||||||
retData = append(retData, res.Payload...)
|
retData = append(retData, res.Payload...)
|
||||||
}
|
}
|
||||||
|
LogDebug("total results:", len(retData))
|
||||||
|
|
||||||
slices.SortFunc(retData, func(a, b *models.TimelineComment) int {
|
slices.SortFunc(retData, func(a, b *models.TimelineComment) int {
|
||||||
return time.Time(b.Created).Compare(time.Time(a.Created))
|
return time.Time(b.Created).Compare(time.Time(a.Created))
|
||||||
|
30
common/pr.go
30
common/pr.go
@@ -121,27 +121,28 @@ func FetchPRSet(user string, gitea GiteaPRTimelineFetcher, org, repo string, num
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rs *PRSet) Contains(pr *models.PullRequest) bool {
|
func (rs *PRSet) Find(pr *models.PullRequest) (*PRInfo, bool) {
|
||||||
for _, p := range rs.PRs {
|
for _, p := range rs.PRs {
|
||||||
if p.PR.Base.RepoID == pr.Base.RepoID &&
|
if p.PR.Base.RepoID == pr.Base.RepoID &&
|
||||||
p.PR.Head.Sha == pr.Head.Sha &&
|
p.PR.Head.Sha == pr.Head.Sha &&
|
||||||
p.PR.Base.Name == pr.Base.Name {
|
p.PR.Base.Name == pr.Base.Name {
|
||||||
return true
|
return p, true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rs *PRSet) AddPR(pr *models.PullRequest) error {
|
func (rs *PRSet) AddPR(pr *models.PullRequest) *PRInfo {
|
||||||
if rs.Contains(pr) {
|
if pr, found := rs.Find(pr); found {
|
||||||
return nil
|
return pr
|
||||||
}
|
}
|
||||||
|
|
||||||
rs.PRs = append(rs.PRs, &PRInfo{
|
prinfo := &PRInfo{
|
||||||
PR: pr,
|
PR: pr,
|
||||||
})
|
}
|
||||||
return nil
|
rs.PRs = append(rs.PRs, prinfo)
|
||||||
|
return prinfo
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rs *PRSet) IsPrjGitPR(pr *models.PullRequest) bool {
|
func (rs *PRSet) IsPrjGitPR(pr *models.PullRequest) bool {
|
||||||
@@ -172,6 +173,15 @@ func (rs *PRSet) GetPrjGitPR() (*PRInfo, error) {
|
|||||||
return nil, PRSet_PrjGitMissing
|
return nil, PRSet_PrjGitMissing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (rs *PRSet) NeedRecreatingPrjGit(currentBranchHash string) bool {
|
||||||
|
pr, err := rs.GetPrjGitPR()
|
||||||
|
if err != nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return pr.PR.Base.Sha == currentBranchHash
|
||||||
|
}
|
||||||
|
|
||||||
func (rs *PRSet) IsConsistent() bool {
|
func (rs *PRSet) IsConsistent() bool {
|
||||||
prjpr_info, err := rs.GetPrjGitPR()
|
prjpr_info, err := rs.GetPrjGitPR()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -302,7 +312,7 @@ func (rs *PRSet) IsApproved(gitea GiteaPRChecker, maintainers MaintainershipData
|
|||||||
}
|
}
|
||||||
pr.Reviews = r
|
pr.Reviews = r
|
||||||
if !pr.Reviews.IsManualMergeOK() {
|
if !pr.Reviews.IsManualMergeOK() {
|
||||||
LogInfo("Not approved manual merge")
|
LogInfo("Not approved manual merge. PR:", pr.PR.URL)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
48
common/pr_conflict_resolution.go
Normal file
48
common/pr_conflict_resolution.go
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
package common
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var UnknownParser error = errors.New("Cannot parse path")
|
||||||
|
|
||||||
|
type PRConflictResolver interface {
|
||||||
|
/*
|
||||||
|
stage_content -> { merge_base (stage1), head (stage2), merge_head (stage3) }
|
||||||
|
*/
|
||||||
|
Resolve(path string, stage_contents [3]string) error
|
||||||
|
}
|
||||||
|
|
||||||
|
var resolvers []PRConflictResolver = []PRConflictResolver{
|
||||||
|
&submodule_conflict_resolver{},
|
||||||
|
}
|
||||||
|
|
||||||
|
func ResolveMergeConflict(path string, file_contents [3]string) error {
|
||||||
|
for _, r := range resolvers {
|
||||||
|
if err := r.Resolve(path, file_contents); err != UnknownParser {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return UnknownParser
|
||||||
|
}
|
||||||
|
|
||||||
|
type submodule_conflict_resolver struct{}
|
||||||
|
|
||||||
|
func (*submodule_conflict_resolver) Resolve(path string, stage [3]string) error {
|
||||||
|
if path != ".gitmodules" {
|
||||||
|
return UnknownParser
|
||||||
|
}
|
||||||
|
return UnknownParser
|
||||||
|
}
|
||||||
|
|
||||||
|
type changes_file_resolver struct{}
|
||||||
|
|
||||||
|
func (*changes_file_resolver) Resolve(path string, stage [3]string) error {
|
||||||
|
if !strings.HasSuffix(path, ".changes") {
|
||||||
|
return UnknownParser
|
||||||
|
}
|
||||||
|
|
||||||
|
return UnknownParser
|
||||||
|
}
|
10
common/pr_conflict_resolution_test.go
Normal file
10
common/pr_conflict_resolution_test.go
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
package common_test
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func ResolveSubmoduleConflicts(t *testing.T) {
|
||||||
|
}
|
||||||
|
|
||||||
|
func ResolveChangesFileConflict(t *testing.T) {
|
||||||
|
}
|
||||||
|
|
@@ -15,7 +15,23 @@ import (
|
|||||||
"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"
|
||||||
)
|
)
|
||||||
|
/*
|
||||||
|
func TestCockpit(t *testing.T) {
|
||||||
|
common.SetLoggingLevel(common.LogLevelDebug)
|
||||||
|
gitea := common.AllocateGiteaTransport("https://src.opensuse.org")
|
||||||
|
tl, err := gitea.GetTimeline("cockpit", "cockpit", 29)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("Fail to timeline", err)
|
||||||
|
}
|
||||||
|
t.Log(tl)
|
||||||
|
r, err := common.FetchGiteaReviews(gitea, []string{}, "cockpit", "cockpit", 29)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("Error:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Error(r)
|
||||||
|
}
|
||||||
|
*/
|
||||||
func reviewsToTimeline(reviews []*models.PullReview) []*models.TimelineComment {
|
func reviewsToTimeline(reviews []*models.PullReview) []*models.TimelineComment {
|
||||||
timeline := make([]*models.TimelineComment, len(reviews))
|
timeline := make([]*models.TimelineComment, len(reviews))
|
||||||
for idx, review := range reviews {
|
for idx, review := range reviews {
|
||||||
|
@@ -25,26 +25,39 @@ func FetchGiteaReviews(rf GiteaReviewTimelineFetcher, reviewers []string, org, r
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
reviews := make([]*models.PullReview, 0, 10)
|
reviews := make([]*models.PullReview, 0, len(reviewers))
|
||||||
var comments []*models.TimelineComment
|
var comments []*models.TimelineComment
|
||||||
|
|
||||||
|
alreadyHaveUserReview := func(user string) bool {
|
||||||
|
for _, r := range reviews {
|
||||||
|
if r.User != nil && r.User.UserName == user {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
for idx, item := range timeline {
|
for idx, item := range timeline {
|
||||||
if item.Type == TimelineCommentType_Review {
|
if item.Type == TimelineCommentType_Review {
|
||||||
for _, r := range rawReviews {
|
for _, r := range rawReviews {
|
||||||
if r.ID == item.ReviewID {
|
if r.ID == item.ReviewID {
|
||||||
reviews = append(reviews, r)
|
if !alreadyHaveUserReview(r.User.UserName) {
|
||||||
|
reviews = append(reviews, r)
|
||||||
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if item.Type == TimelineCommentType_Comment {
|
} else if item.Type == TimelineCommentType_Comment {
|
||||||
comments = append(comments, item)
|
comments = append(comments, item)
|
||||||
} else if item.Type == TimelineCommentType_PushPull {
|
} else if item.Type == TimelineCommentType_PushPull {
|
||||||
|
LogDebug("cut-off", item.Created)
|
||||||
timeline = timeline[0:idx]
|
timeline = timeline[0:idx]
|
||||||
break
|
break
|
||||||
} else {
|
} else {
|
||||||
LogDebug("Unhandled timeline type:", item.Type)
|
LogDebug("Unhandled timeline type:", item.Type)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
LogDebug("num comments:", len(comments), "reviews:", len(reviews), len(timeline))
|
||||||
|
|
||||||
return &PRReviews{
|
return &PRReviews{
|
||||||
reviews: reviews,
|
reviews: reviews,
|
||||||
@@ -72,6 +85,7 @@ func (r *PRReviews) IsManualMergeOK() bool {
|
|||||||
if c.Updated != c.Created {
|
if c.Updated != c.Created {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
LogDebug("comment:", c.User.UserName, c.Body)
|
||||||
if slices.Contains(r.reviewers, c.User.UserName) {
|
if slices.Contains(r.reviewers, c.User.UserName) {
|
||||||
if bodyCommandManualMergeOK(c.Body) {
|
if bodyCommandManualMergeOK(c.Body) {
|
||||||
return true
|
return true
|
||||||
|
@@ -315,7 +315,9 @@ func GenerateObsPrjMeta(git common.Git, gitea common.Gitea, pr *models.PullReque
|
|||||||
}
|
}
|
||||||
meta.ScmSync = pr.Head.Repo.CloneURL + "?" + strings.Join(urlPkg, "&") + "#" + pr.Head.Sha
|
meta.ScmSync = pr.Head.Repo.CloneURL + "?" + strings.Join(urlPkg, "&") + "#" + pr.Head.Sha
|
||||||
meta.Title = fmt.Sprintf("PR#%d to %s", pr.Index, pr.Base.Name)
|
meta.Title = fmt.Sprintf("PR#%d to %s", pr.Index, pr.Base.Name)
|
||||||
meta.PublicFlags = common.Flags{Contents: "<disable/>"}
|
// QE wants it published ... also we should not hardcode it here, since
|
||||||
|
// it is configurable via the :PullRequest project
|
||||||
|
// meta.PublicFlags = common.Flags{Contents: "<disable/>"}
|
||||||
|
|
||||||
meta.Groups = nil
|
meta.Groups = nil
|
||||||
meta.Persons = nil
|
meta.Persons = nil
|
||||||
@@ -459,7 +461,7 @@ func FetchOurLatestActionableReview(gitea common.Gitea, org, repo string, id int
|
|||||||
|
|
||||||
for idx := len(reviews) - 1; idx >= 0; idx-- {
|
for idx := len(reviews) - 1; idx >= 0; idx-- {
|
||||||
review := reviews[idx]
|
review := reviews[idx]
|
||||||
if review.User != nil || review.User.UserName == Username {
|
if review.User == nil || review.User.UserName == Username {
|
||||||
if IsDryRun {
|
if IsDryRun {
|
||||||
// for purposes of moving forward a no-op check
|
// for purposes of moving forward a no-op check
|
||||||
return review, nil
|
return review, nil
|
||||||
@@ -547,7 +549,7 @@ func CleanupPullNotification(gitea common.Gitea, thread *models.NotificationThre
|
|||||||
}
|
}
|
||||||
|
|
||||||
if pr.State != "closed" {
|
if pr.State != "closed" {
|
||||||
common.LogInfo(" ignoring peding PR", thread.Subject.HTMLURL, " state:", pr.State)
|
common.LogInfo(" ignoring pending PR", thread.Subject.HTMLURL, " state:", pr.State)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -6,6 +6,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"path"
|
"path"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/opentracing/opentracing-go/log"
|
"github.com/opentracing/opentracing-go/log"
|
||||||
@@ -80,6 +81,9 @@ func AllocatePRProcessor(req *common.PullRequestWebhookEvent, configs common.Aut
|
|||||||
}
|
}
|
||||||
common.LogDebug("git path:", git.GetPath())
|
common.LogDebug("git path:", git.GetPath())
|
||||||
|
|
||||||
|
// git.GitExecOrPanic("", "config", "set", "--global", "advice.submoduleMergeConflict", "false")
|
||||||
|
// git.GitExecOrPanic("", "config", "set", "--global", "advice.mergeConflict", "false")
|
||||||
|
|
||||||
return &PRProcessor{
|
return &PRProcessor{
|
||||||
config: config,
|
config: config,
|
||||||
git: git,
|
git: git,
|
||||||
@@ -87,11 +91,6 @@ func AllocatePRProcessor(req *common.PullRequestWebhookEvent, configs common.Aut
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (pr *PRProcessor) SetSubmodulesToMatchPRSet(prset *common.PRSet) ([]string, []string, error) {
|
func (pr *PRProcessor) SetSubmodulesToMatchPRSet(prset *common.PRSet) ([]string, []string, error) {
|
||||||
prjGitPR, err := prset.GetPrjGitPR()
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
git := pr.git
|
git := pr.git
|
||||||
subList, err := git.GitSubmoduleList(common.DefaultGitPrj, "HEAD")
|
subList, err := git.GitSubmoduleList(common.DefaultGitPrj, "HEAD")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -113,13 +112,15 @@ func (pr *PRProcessor) SetSubmodulesToMatchPRSet(prset *common.PRSet) ([]string,
|
|||||||
revert := false
|
revert := false
|
||||||
|
|
||||||
if pr.PR.State != "open" {
|
if pr.PR.State != "open" {
|
||||||
// remove PR from PrjGit
|
prjGitPR, err := prset.GetPrjGitPR()
|
||||||
var valid bool
|
if prjGitPR != nil {
|
||||||
if prHead, valid = git.GitSubmoduleCommitId(common.DefaultGitPrj, repo, prjGitPR.PR.MergeBase); !valid {
|
// remove PR from PrjGit
|
||||||
common.LogError("Failed fetching original submodule commit id for repo")
|
var valid bool
|
||||||
return nil, nil, err
|
if prHead, valid = git.GitSubmoduleCommitId(common.DefaultGitPrj, repo, prjGitPR.PR.MergeBase); !valid {
|
||||||
|
common.LogError("Failed fetching original submodule commit id for repo")
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
revert = true
|
revert = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -166,9 +167,9 @@ func (pr *PRProcessor) CreatePRjGitPR(prjGitPRbranch string, prset *common.PRSet
|
|||||||
common.LogError("Failed to fetch PrjGit repository data.", PrjGitOrg, PrjGitRepo, err)
|
common.LogError("Failed to fetch PrjGit repository data.", PrjGitOrg, PrjGitRepo, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
remoteName, err := git.GitClone(common.DefaultGitPrj, PrjGitBranch, PrjGit.SSHURL)
|
RemoteName, err := git.GitClone(common.DefaultGitPrj, PrjGitBranch, PrjGit.SSHURL)
|
||||||
common.PanicOnError(err)
|
common.PanicOnError(err)
|
||||||
git.GitExecOrPanic(common.DefaultGitPrj, "checkout", "-B", prjGitPRbranch, remoteName+"/"+PrjGitBranch)
|
git.GitExecOrPanic(common.DefaultGitPrj, "checkout", "-B", prjGitPRbranch, RemoteName+"/"+PrjGitBranch)
|
||||||
|
|
||||||
headCommit, err := git.GitBranchHead(common.DefaultGitPrj, prjGitPRbranch)
|
headCommit, err := git.GitBranchHead(common.DefaultGitPrj, prjGitPRbranch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -186,7 +187,7 @@ func (pr *PRProcessor) CreatePRjGitPR(prjGitPRbranch string, prset *common.PRSet
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !common.IsDryRun && headCommit != newHeadCommit {
|
if !common.IsDryRun && headCommit != newHeadCommit {
|
||||||
common.PanicOnError(git.GitExec(common.DefaultGitPrj, "push", remoteName, "+HEAD:"+prjGitPRbranch))
|
common.PanicOnError(git.GitExec(common.DefaultGitPrj, "push", RemoteName, "+HEAD:"+prjGitPRbranch))
|
||||||
pr, err := Gitea.CreatePullRequestIfNotExist(PrjGit, prjGitPRbranch, PrjGitBranch,
|
pr, err := Gitea.CreatePullRequestIfNotExist(PrjGit, prjGitPRbranch, PrjGitBranch,
|
||||||
"Forwarded PRs: "+strings.Join(title_refs, ", "),
|
"Forwarded PRs: "+strings.Join(title_refs, ", "),
|
||||||
fmt.Sprintf("This is a forwarded pull request by %s\nreferencing the following pull request(s):\n\n", GitAuthor)+strings.Join(refs, ", "),
|
fmt.Sprintf("This is a forwarded pull request by %s\nreferencing the following pull request(s):\n\n", GitAuthor)+strings.Join(refs, ", "),
|
||||||
@@ -199,12 +200,40 @@ func (pr *PRProcessor) CreatePRjGitPR(prjGitPRbranch string, prset *common.PRSet
|
|||||||
RemoveDeadline: true,
|
RemoveDeadline: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
prset.AddPR(pr)
|
prinfo := prset.AddPR(pr)
|
||||||
|
prinfo.RemoteName = RemoteName
|
||||||
}
|
}
|
||||||
return nil
|
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 {
|
func (pr *PRProcessor) UpdatePrjGitPR(prset *common.PRSet) error {
|
||||||
|
_, _, PrjGitBranch := prset.Config.GetPrjGit()
|
||||||
PrjGitPR, err := prset.GetPrjGitPR()
|
PrjGitPR, err := prset.GetPrjGitPR()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
common.LogError("Updating PrjGitPR but not found?", err)
|
common.LogError("Updating PrjGitPR but not found?", err)
|
||||||
@@ -215,8 +244,16 @@ func (pr *PRProcessor) UpdatePrjGitPR(prset *common.PRSet) error {
|
|||||||
PrjGit := PrjGitPR.PR.Base.Repo
|
PrjGit := PrjGitPR.PR.Base.Repo
|
||||||
prjGitPRbranch := PrjGitPR.PR.Head.Name
|
prjGitPRbranch := PrjGitPR.PR.Head.Name
|
||||||
|
|
||||||
remoteName, err := git.GitClone(common.DefaultGitPrj, prjGitPRbranch, PrjGit.SSHURL)
|
PrjGitPR.RemoteName, err = git.GitClone(common.DefaultGitPrj, prjGitPRbranch, PrjGit.SSHURL)
|
||||||
common.PanicOnError(err)
|
common.PanicOnError(err)
|
||||||
|
git.GitExecOrPanic(common.DefaultGitPrj, "fetch", PrjGitPR.RemoteName, PrjGitBranch)
|
||||||
|
ExpectedMergeCommit, err := git.GitRemoteHead(common.DefaultGitPrj, PrjGitPR.RemoteName, PrjGitBranch)
|
||||||
|
|
||||||
|
forcePush := false
|
||||||
|
if ExpectedMergeCommit != PrjGitPR.PR.MergeBase {
|
||||||
|
common.PanicOnError(pr.RebaseAndSkipSubmoduleCommits(prset, PrjGitBranch))
|
||||||
|
forcePush = true
|
||||||
|
}
|
||||||
|
|
||||||
headCommit, err := git.GitBranchHead(common.DefaultGitPrj, prjGitPRbranch)
|
headCommit, err := git.GitBranchHead(common.DefaultGitPrj, prjGitPRbranch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -234,7 +271,11 @@ func (pr *PRProcessor) UpdatePrjGitPR(prset *common.PRSet) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !common.IsDryRun && headCommit != newHeadCommit {
|
if !common.IsDryRun && headCommit != newHeadCommit {
|
||||||
common.PanicOnError(git.GitExec(common.DefaultGitPrj, "push", remoteName, "+HEAD:"+prjGitPRbranch))
|
params := []string{"push", PrjGitPR.RemoteName, "+HEAD:" + prjGitPRbranch}
|
||||||
|
if forcePush {
|
||||||
|
params = slices.Insert(params, 1, "-f")
|
||||||
|
}
|
||||||
|
common.PanicOnError(git.GitExec(common.DefaultGitPrj, params...))
|
||||||
|
|
||||||
// update PR
|
// update PR
|
||||||
PrjGitTitle := "Forwarded PRs: " + strings.Join(title_refs, ", ")
|
PrjGitTitle := "Forwarded PRs: " + strings.Join(title_refs, ", ")
|
||||||
@@ -314,13 +355,10 @@ func (pr *PRProcessor) Process(req *common.PullRequestWebhookEvent) error {
|
|||||||
// make sure that prjgit is consistent and only submodules that are to be *updated*
|
// 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
|
// reset anything that changed that is not part of the prset
|
||||||
// package removals/additions are *not* counted here
|
// package removals/additions are *not* counted here
|
||||||
|
org, repo, branch := config.GetPrjGit()
|
||||||
if pr, err := prset.GetPrjGitPR(); err == nil {
|
if pr, err := prset.GetPrjGitPR(); err == nil {
|
||||||
remote, err := git.GitClone(common.DefaultGitPrj, prjGitPRbranch, pr.PR.Base.Repo.CloneURL)
|
common.LogDebug("Submodule parse begin")
|
||||||
common.PanicOnError(err)
|
orig_subs, err := git.GitSubmoduleList(common.DefaultGitPrj, pr.RemoteName+"/"+branch) // merge base must remote branch, checked in prjgit udate
|
||||||
git.GitExecOrPanic(common.DefaultGitPrj, "fetch", remote, pr.PR.MergeBase, pr.PR.Head.Ref)
|
|
||||||
|
|
||||||
common.LogDebug("Fetch done")
|
|
||||||
orig_subs, err := git.GitSubmoduleList(common.DefaultGitPrj, pr.PR.MergeBase)
|
|
||||||
common.PanicOnError(err)
|
common.PanicOnError(err)
|
||||||
new_subs, err := git.GitSubmoduleList(common.DefaultGitPrj, pr.PR.Head.Sha)
|
new_subs, err := git.GitSubmoduleList(common.DefaultGitPrj, pr.PR.Head.Sha)
|
||||||
common.PanicOnError(err)
|
common.PanicOnError(err)
|
||||||
@@ -357,7 +395,6 @@ func (pr *PRProcessor) Process(req *common.PullRequestWebhookEvent) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
common.LogDebug(" num of reviewers:", len(prjGitPR.PR.RequestedReviewers))
|
common.LogDebug(" num of reviewers:", len(prjGitPR.PR.RequestedReviewers))
|
||||||
org, repo, branch := config.GetPrjGit()
|
|
||||||
maintainers, err := common.FetchProjectMaintainershipData(Gitea, org, repo, branch)
|
maintainers, err := common.FetchProjectMaintainershipData(Gitea, org, repo, branch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
Reference in New Issue
Block a user