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)
|
||||||
@@ -802,7 +804,6 @@ func (e *GitHandlerImpl) GitSubmoduleList(gitPath, commitId string) (submoduleLi
|
|||||||
for _, te := range tree.items {
|
for _, te := range tree.items {
|
||||||
if te.isTree() {
|
if te.isTree() {
|
||||||
trees[p+te.name+"/"] = te.hash
|
trees[p+te.name+"/"] = te.hash
|
||||||
submoduleList[p+te.name] = te.hash
|
|
||||||
} else if te.isSubmodule() {
|
} else if te.isSubmodule() {
|
||||||
submoduleList[p+te.name] = te.hash
|
submoduleList[p+te.name] = te.hash
|
||||||
}
|
}
|
||||||
@@ -917,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) {
|
||||||
@@ -939,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()
|
||||||
@@ -979,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
|
||||||
}
|
}
|
||||||
@@ -989,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
|
||||||
}
|
}
|
||||||
@@ -1003,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
|
||||||
}
|
}
|
||||||
@@ -1013,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
|
||||||
}
|
}
|
||||||
@@ -1032,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...",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@@ -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))
|
||||||
|
@@ -551,6 +551,7 @@ func (c *ObsClient) DeleteProject(project string) error {
|
|||||||
query.Add("force", "1")
|
query.Add("force", "1")
|
||||||
url.RawQuery = query.Encode()
|
url.RawQuery = query.Encode()
|
||||||
res, err := c.ObsRequestRaw("DELETE", url.String(), nil)
|
res, err := c.ObsRequestRaw("DELETE", url.String(), nil)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
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
|
||||||
|
@@ -263,7 +263,7 @@ func ProcessRepoBuildStatus(results, ref []common.PackageBuildStatus) (status Bu
|
|||||||
return BuildStatusSummarySuccess, SomeSuccess
|
return BuildStatusSummarySuccess, SomeSuccess
|
||||||
}
|
}
|
||||||
|
|
||||||
func GenerateObsPrjMeta(git common.Git, gitea common.Gitea, pr *models.PullRequest, stagingPrj, buildPrj string, stagingMasterPrj string) (*common.ProjectMeta, error) {
|
func GenerateObsPrjMeta(git common.Git, gitea common.Gitea, pr *models.PullRequest, stagingPrj, buildPrj string) (*common.ProjectMeta, error) {
|
||||||
common.LogDebug("repo content fetching ...")
|
common.LogDebug("repo content fetching ...")
|
||||||
err := FetchPrGit(git, pr)
|
err := FetchPrGit(git, pr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -289,15 +289,7 @@ func GenerateObsPrjMeta(git common.Git, gitea common.Gitea, pr *models.PullReque
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
common.LogDebug("Trying first staging master project: ", stagingMasterPrj)
|
meta, err := ObsClient.GetProjectMeta(buildPrj)
|
||||||
meta, err := ObsClient.GetProjectMeta(stagingMasterPrj)
|
|
||||||
if err == nil {
|
|
||||||
// success, so we use that staging master project as our build project
|
|
||||||
buildPrj = stagingMasterPrj
|
|
||||||
} else {
|
|
||||||
common.LogInfo("error fetching project meta for ", stagingMasterPrj, ". Fall Back to ", buildPrj)
|
|
||||||
meta, err = ObsClient.GetProjectMeta(buildPrj)
|
|
||||||
}
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
common.LogError("error fetching project meta for", buildPrj, ". Err:", err)
|
common.LogError("error fetching project meta for", buildPrj, ". Err:", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -422,8 +414,7 @@ func StartOrUpdateBuild(config *common.StagingConfig, git common.Git, gitea comm
|
|||||||
var state RequestModification = RequestModificationSourceChanged
|
var state RequestModification = RequestModificationSourceChanged
|
||||||
if meta == nil {
|
if meta == nil {
|
||||||
// new build
|
// new build
|
||||||
common.LogDebug(" Staging master:", config.StagingProject)
|
meta, err = GenerateObsPrjMeta(git, gitea, pr, obsPrProject, config.ObsProject)
|
||||||
meta, err = GenerateObsPrjMeta(git, gitea, pr, obsPrProject, config.ObsProject, config.StagingProject)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return RequestModificationNoChange, err
|
return RequestModificationNoChange, err
|
||||||
}
|
}
|
||||||
@@ -437,8 +428,6 @@ func StartOrUpdateBuild(config *common.StagingConfig, git common.Git, gitea comm
|
|||||||
} else {
|
} else {
|
||||||
err = ObsClient.SetProjectMeta(meta)
|
err = ObsClient.SetProjectMeta(meta)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
x, _ := xml.MarshalIndent(meta, "", " ")
|
|
||||||
common.LogDebug(" meta:", string(x))
|
|
||||||
common.LogError("cannot create meta project:", err)
|
common.LogError("cannot create meta project:", err)
|
||||||
return RequestModificationNoChange, err
|
return RequestModificationNoChange, err
|
||||||
}
|
}
|
||||||
@@ -654,6 +643,7 @@ func ProcessPullRequest(gitea common.Gitea, org, repo string, id int64) (bool, e
|
|||||||
common.LogError("No PR associated with review:", org, "/", repo, "#", id, "Error:", err)
|
common.LogError("No PR associated with review:", org, "/", repo, "#", id, "Error:", err)
|
||||||
return true, err
|
return true, err
|
||||||
}
|
}
|
||||||
|
|
||||||
common.LogDebug("PR state:", pr.State)
|
common.LogDebug("PR state:", pr.State)
|
||||||
if pr.State == "closed" {
|
if pr.State == "closed" {
|
||||||
// dismiss the review
|
// dismiss the review
|
||||||
@@ -670,68 +660,40 @@ func ProcessPullRequest(gitea common.Gitea, org, repo string, id int64) (bool, e
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetching data
|
if review, err := FetchOurLatestActionableReview(gitea, org, repo, id); err == nil {
|
||||||
review, review_error := FetchOurLatestActionableReview(gitea, org, repo, id)
|
common.LogInfo("processing review", review.HTMLURL, "state", review.State)
|
||||||
if pr.State != "closed" && review_error != nil {
|
|
||||||
// Nothing to do
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
err = FetchPrGit(git, pr)
|
err = FetchPrGit(git, pr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
common.LogError("Cannot fetch PR git:", pr.URL)
|
common.LogError("Cannot fetch PR git:", pr.URL)
|
||||||
return false, err
|
return false, err
|
||||||
}
|
|
||||||
|
|
||||||
// we want the possibly pending modification here, in case stagings are added, etc.
|
|
||||||
// jobs of review team to deal with issues
|
|
||||||
common.LogDebug("QA configuration fetching ...", common.StagingConfigFile)
|
|
||||||
data, err := git.GitCatFile(pr.Head.Sha, pr.Head.Sha, common.StagingConfigFile)
|
|
||||||
if err != nil {
|
|
||||||
common.LogError("Staging config", common.StagingConfigFile, "not found in PR to the project. Aborting.")
|
|
||||||
if !IsDryRun {
|
|
||||||
_, err = gitea.AddReviewComment(pr, common.ReviewStateRequestChanges, "Cannot find project config in PR: "+common.ProjectConfigFile)
|
|
||||||
}
|
}
|
||||||
return true, err
|
|
||||||
}
|
|
||||||
|
|
||||||
stagingConfig, err := common.ParseStagingConfig(data)
|
// we want the possibly pending modification here, in case stagings are added, etc.
|
||||||
if err != nil {
|
// jobs of review team to deal with issues
|
||||||
common.LogError("Error parsing config file", common.StagingConfigFile, err)
|
common.LogDebug("QA configuration fetching ...", common.StagingConfigFile)
|
||||||
}
|
data, err := git.GitCatFile(pr.Head.Sha, pr.Head.Sha, common.StagingConfigFile)
|
||||||
|
if err != nil {
|
||||||
if stagingConfig.ObsProject == "" {
|
common.LogError("Staging config", common.StagingConfigFile, "not found in PR to the project. Aborting.")
|
||||||
common.LogError("Cannot find reference project for PR#", pr.Index)
|
if !IsDryRun {
|
||||||
if !IsDryRun && review_error == nil {
|
_, err = gitea.AddReviewComment(pr, common.ReviewStateRequestChanges, "Cannot find project config in PR: "+common.ProjectConfigFile)
|
||||||
_, err := gitea.AddReviewComment(pr, common.ReviewStateRequestChanges, "Cannot find reference project")
|
}
|
||||||
return true, err
|
return true, err
|
||||||
}
|
}
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
common.LogDebug("ObsProject:", stagingConfig.ObsProject)
|
stagingConfig, err := common.ParseStagingConfig(data)
|
||||||
stagingProject := GetObsProjectAssociatedWithPr(stagingConfig, ObsClient.HomeProject, pr)
|
if err != nil {
|
||||||
|
common.LogError("Error parsing config file", common.StagingConfigFile, err)
|
||||||
// Cleanup projects
|
|
||||||
if pr.State == "closed" {
|
|
||||||
// review is done, cleanup
|
|
||||||
common.LogInfo(" -- closed request, cleanup staging projects")
|
|
||||||
for _, setup := range stagingConfig.QA {
|
|
||||||
if !IsDryRun {
|
|
||||||
ObsClient.DeleteProject(stagingProject + ":" + setup.Name)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if stagingProject != "" {
|
|
||||||
if !IsDryRun {
|
|
||||||
ObsClient.DeleteProject(stagingProject)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process review aka setup projects
|
if stagingConfig.ObsProject == "" {
|
||||||
if review_error == nil {
|
common.LogError("Cannot find reference project for PR#", pr.Index)
|
||||||
common.LogInfo("processing review", review.HTMLURL, "state", review.State)
|
if !IsDryRun {
|
||||||
|
_, err := gitea.AddReviewComment(pr, common.ReviewStateRequestChanges, "Cannot find reference project")
|
||||||
|
return true, err
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
meta, err := ObsClient.GetProjectMeta(stagingConfig.ObsProject)
|
meta, err := ObsClient.GetProjectMeta(stagingConfig.ObsProject)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -765,6 +727,16 @@ func ProcessPullRequest(gitea common.Gitea, org, repo string, id int64) (bool, e
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if stagingConfig.StagingProject != "" {
|
||||||
|
// staging project must either be nothing or be *under* the target project.
|
||||||
|
// other setups are currently not supported
|
||||||
|
// NOTE: this is user input, so we need some limits here
|
||||||
|
l := len(stagingConfig.ObsProject)
|
||||||
|
if l >= len(stagingConfig.StagingProject) || stagingConfig.ObsProject != stagingConfig.StagingProject[0:l] {
|
||||||
|
common.LogError("StagingProject (", stagingConfig.StagingProject, ") is not child of target project", stagingConfig.ObsProject)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if meta.Name != stagingConfig.ObsProject {
|
if meta.Name != stagingConfig.ObsProject {
|
||||||
common.LogError("staging.config . ObsProject:", stagingConfig.ObsProject, " is not target project name", meta.Name)
|
common.LogError("staging.config . ObsProject:", stagingConfig.ObsProject, " is not target project name", meta.Name)
|
||||||
if !IsDryRun {
|
if !IsDryRun {
|
||||||
@@ -785,22 +757,17 @@ func ProcessPullRequest(gitea common.Gitea, org, repo string, id int64) (bool, e
|
|||||||
common.LogDebug(" # head submodules:", len(headSubmodules))
|
common.LogDebug(" # head submodules:", len(headSubmodules))
|
||||||
common.LogDebug(" # base submodules:", len(baseSubmodules))
|
common.LogDebug(" # base submodules:", len(baseSubmodules))
|
||||||
|
|
||||||
modifiedPackages := make([]string, 0, 16)
|
modifiedOrNew := make([]string, 0, 16)
|
||||||
newPackages := make([]string, 0, 16)
|
|
||||||
if !stagingConfig.RebuildAll {
|
if !stagingConfig.RebuildAll {
|
||||||
for pkg, headOid := range headSubmodules {
|
for pkg, headOid := range headSubmodules {
|
||||||
if baseOid, exists := baseSubmodules[pkg]; !exists || baseOid != headOid {
|
if baseOid, exists := baseSubmodules[pkg]; !exists || baseOid != headOid {
|
||||||
if len(baseOid) > 0 {
|
modifiedOrNew = append(modifiedOrNew, pkg)
|
||||||
modifiedPackages = append(modifiedPackages, pkg)
|
|
||||||
} else {
|
|
||||||
newPackages = append(newPackages, pkg)
|
|
||||||
}
|
|
||||||
common.LogDebug(pkg, ":", baseOid, "->", headOid)
|
common.LogDebug(pkg, ":", baseOid, "->", headOid)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(modifiedPackages) == 0 && len(newPackages) == 0 {
|
if len(modifiedOrNew) == 0 {
|
||||||
rebuild_all := false || stagingConfig.RebuildAll
|
rebuild_all := false || stagingConfig.RebuildAll
|
||||||
|
|
||||||
reviews, err := gitea.GetPullRequestReviews(pr.Base.Repo.Owner.UserName, pr.Base.Repo.Name, pr.Index)
|
reviews, err := gitea.GetPullRequestReviews(pr.Base.Repo.Owner.UserName, pr.Base.Repo.Name, pr.Index)
|
||||||
@@ -877,13 +844,13 @@ func ProcessPullRequest(gitea common.Gitea, org, repo string, id int64) (bool, e
|
|||||||
gitea.AddComment(pr, msg)
|
gitea.AddComment(pr, msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
baseResult, err := ObsClient.LastBuildResults(stagingConfig.ObsProject, modifiedPackages...)
|
baseResult, err := ObsClient.LastBuildResults(stagingConfig.ObsProject, modifiedOrNew...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
common.LogError("failed fetching ref project status for", stagingConfig.ObsProject, ":", err)
|
common.LogError("failed fetching ref project status for", stagingConfig.ObsProject, ":", err)
|
||||||
}
|
}
|
||||||
stagingResult, err := ObsClient.BuildStatus(stagingProject)
|
stagingResult, err := ObsClient.BuildStatus(stagingProject)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
common.LogError("failed fetching stage project status for", stagingProject, ":", err)
|
common.LogError("failed fetching ref project status for", stagingProject, ":", err)
|
||||||
}
|
}
|
||||||
buildStatus := ProcessBuildStatus(stagingResult, baseResult)
|
buildStatus := ProcessBuildStatus(stagingResult, baseResult)
|
||||||
|
|
||||||
|
@@ -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,
|
||||||
@@ -108,7 +112,7 @@ func (pr *PRProcessor) SetSubmodulesToMatchPRSet(prset *common.PRSet) ([]string,
|
|||||||
revert := false
|
revert := false
|
||||||
|
|
||||||
if pr.PR.State != "open" {
|
if pr.PR.State != "open" {
|
||||||
prjGitPR, err := prset.GetPrjGitPR()
|
prjGitPR, err := prset.GetPrjGitPR()
|
||||||
if prjGitPR != nil {
|
if prjGitPR != nil {
|
||||||
// remove PR from PrjGit
|
// remove PR from PrjGit
|
||||||
var valid bool
|
var valid bool
|
||||||
@@ -163,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 {
|
||||||
@@ -183,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, ", "),
|
||||||
@@ -196,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)
|
||||||
@@ -212,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 {
|
||||||
@@ -231,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, ", ")
|
||||||
@@ -311,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)
|
||||||
@@ -354,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