Compare commits
1 Commits
| Author | SHA256 | Date | |
|---|---|---|---|
| aeb3917591 |
@@ -23,6 +23,7 @@ jobs:
|
||||
- run: git checkout FETCH_HEAD
|
||||
- run: go generate -C common
|
||||
- run: go generate -C workflow-pr
|
||||
- run: go generate -C workflow-pr/interfaces
|
||||
- run: git add -N .; git diff
|
||||
- run: |
|
||||
status=$(git status --short)
|
||||
|
||||
@@ -12,6 +12,7 @@ jobs:
|
||||
- run: git checkout FETCH_HEAD
|
||||
- run: go generate -C common
|
||||
- run: go generate -C workflow-pr
|
||||
- run: go generate -C workflow-pr/interfaces
|
||||
- run: |
|
||||
host=${{ gitea.server_url }}
|
||||
host=${host#https://}
|
||||
|
||||
@@ -129,9 +129,6 @@ go build \
|
||||
go build \
|
||||
-C utils/hujson \
|
||||
-buildmode=pie
|
||||
go build \
|
||||
-C utils/maintainer-update \
|
||||
-buildmode=pie
|
||||
go build \
|
||||
-C gitea-events-rabbitmq-publisher \
|
||||
-buildmode=pie
|
||||
@@ -163,7 +160,6 @@ go test -C group-review -v
|
||||
go test -C obs-staging-bot -v
|
||||
go test -C obs-status-service -v
|
||||
go test -C workflow-direct -v
|
||||
go test -C utils/maintainer-update
|
||||
# TODO build fails
|
||||
#go test -C workflow-pr -v
|
||||
|
||||
@@ -183,7 +179,6 @@ install -D -m0755 workflow-direct/workflow-direct
|
||||
install -D -m0644 systemd/workflow-direct@.service %{buildroot}%{_unitdir}/workflow-direct@.service
|
||||
install -D -m0755 workflow-pr/workflow-pr %{buildroot}%{_bindir}/workflow-pr
|
||||
install -D -m0755 utils/hujson/hujson %{buildroot}%{_bindir}/hujson
|
||||
install -D -m0755 utils/maintainer-update/maintainer-update %{buildroot}${_bindir}/maintainer-update
|
||||
|
||||
%pre gitea-events-rabbitmq-publisher
|
||||
%service_add_pre gitea-events-rabbitmq-publisher.service
|
||||
@@ -290,7 +285,6 @@ install -D -m0755 utils/maintainer-update/maintainer-update
|
||||
%files utils
|
||||
%license COPYING
|
||||
%{_bindir}/hujson
|
||||
%{_bindir}/maintainer-update
|
||||
|
||||
%files workflow-direct
|
||||
%license COPYING
|
||||
|
||||
@@ -54,7 +54,6 @@ type ReviewGroup struct {
|
||||
type QAConfig struct {
|
||||
Name string
|
||||
Origin string
|
||||
BuildDisableRepos []string // which repos to build disable in the new project
|
||||
}
|
||||
|
||||
type Permissions struct {
|
||||
@@ -92,7 +91,6 @@ type AutogitConfig struct {
|
||||
NoProjectGitPR bool // do not automatically create project git PRs, just assign reviewers and assume somethign else creates the ProjectGit PR
|
||||
ManualMergeOnly bool // only merge with "Merge OK" comment by Project Maintainers and/or Package Maintainers and/or reviewers
|
||||
ManualMergeProject bool // require merge of ProjectGit PRs with "Merge OK" by ProjectMaintainers and/or reviewers
|
||||
ReviewRequired bool // always require a maintainer review, even if maintainer submits it. Only ignored if no other package or project reviewers
|
||||
}
|
||||
|
||||
type AutogitConfigs []*AutogitConfig
|
||||
@@ -294,9 +292,9 @@ func (config *AutogitConfig) GetRemoteBranch() string {
|
||||
}
|
||||
|
||||
func (config *AutogitConfig) Label(label string) string {
|
||||
if t, found := config.Labels[LabelKey(label)]; found {
|
||||
return t
|
||||
}
|
||||
if t, found := config.Labels[LabelKey(label)]; found {
|
||||
return t
|
||||
}
|
||||
|
||||
return label
|
||||
}
|
||||
|
||||
@@ -76,7 +76,6 @@ type GiteaLabelSettter interface {
|
||||
}
|
||||
|
||||
type GiteaTimelineFetcher interface {
|
||||
ResetTimelineCache(org, repo string, idx int64)
|
||||
GetTimeline(org, repo string, idx int64) ([]*models.TimelineComment, error)
|
||||
}
|
||||
|
||||
@@ -814,18 +813,6 @@ type TimelineCacheData struct {
|
||||
var giteaTimelineCache map[string]TimelineCacheData = make(map[string]TimelineCacheData)
|
||||
var giteaTimelineCacheMutex sync.RWMutex
|
||||
|
||||
func (gitea *GiteaTransport) ResetTimelineCache(org, repo string, idx int64) {
|
||||
giteaTimelineCacheMutex.Lock()
|
||||
defer giteaTimelineCacheMutex.Unlock()
|
||||
|
||||
prID := fmt.Sprintf("%s/%s!%d", org, repo, idx)
|
||||
Cache, IsCached := giteaTimelineCache[prID]
|
||||
if IsCached {
|
||||
Cache.lastCheck = Cache.lastCheck.Add(-time.Hour)
|
||||
giteaTimelineCache[prID] = Cache
|
||||
}
|
||||
}
|
||||
|
||||
// returns timeline in reverse chronological create order
|
||||
func (gitea *GiteaTransport) GetTimeline(org, repo string, idx int64) ([]*models.TimelineComment, error) {
|
||||
page := int64(1)
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"src.opensuse.org/autogits/common/gitea-generated/client/repository"
|
||||
"src.opensuse.org/autogits/common/gitea-generated/models"
|
||||
@@ -27,15 +25,12 @@ const ProjectFileKey = "_project"
|
||||
type MaintainershipMap struct {
|
||||
Data map[string][]string
|
||||
IsDir bool
|
||||
Config *AutogitConfig
|
||||
FetchPackage func(string) ([]byte, error)
|
||||
Raw []byte
|
||||
}
|
||||
|
||||
func ParseMaintainershipData(data []byte) (*MaintainershipMap, error) {
|
||||
func parseMaintainershipData(data []byte) (*MaintainershipMap, error) {
|
||||
maintainers := &MaintainershipMap{
|
||||
Data: make(map[string][]string),
|
||||
Raw: data,
|
||||
}
|
||||
if err := json.Unmarshal(data, &maintainers.Data); err != nil {
|
||||
return nil, err
|
||||
@@ -44,9 +39,7 @@ func ParseMaintainershipData(data []byte) (*MaintainershipMap, error) {
|
||||
return maintainers, nil
|
||||
}
|
||||
|
||||
func FetchProjectMaintainershipData(gitea GiteaMaintainershipReader, config *AutogitConfig) (*MaintainershipMap, error) {
|
||||
org, prjGit, branch := config.GetPrjGit()
|
||||
|
||||
func FetchProjectMaintainershipData(gitea GiteaMaintainershipReader, org, prjGit, branch string) (*MaintainershipMap, error) {
|
||||
data, _, err := gitea.FetchMaintainershipDirFile(org, prjGit, branch, ProjectFileKey)
|
||||
dir := true
|
||||
if err != nil || data == nil {
|
||||
@@ -66,9 +59,8 @@ func FetchProjectMaintainershipData(gitea GiteaMaintainershipReader, config *Aut
|
||||
}
|
||||
}
|
||||
|
||||
m, err := ParseMaintainershipData(data)
|
||||
m, err := parseMaintainershipData(data)
|
||||
if m != nil {
|
||||
m.Config = config
|
||||
m.IsDir = dir
|
||||
m.FetchPackage = func(pkg string) ([]byte, error) {
|
||||
data, _, err := gitea.FetchMaintainershipDirFile(org, prjGit, branch, pkg)
|
||||
@@ -157,10 +149,7 @@ func (data *MaintainershipMap) IsApproved(pkg string, reviews []*models.PullRevi
|
||||
}
|
||||
|
||||
LogDebug("Looking for review by:", reviewers)
|
||||
slices.Sort(reviewers)
|
||||
reviewers = slices.Compact(reviewers)
|
||||
SubmitterIdxInReviewers := slices.Index(reviewers, submitter)
|
||||
if SubmitterIdxInReviewers > -1 && (!data.Config.ReviewRequired || len(reviewers) == 1) {
|
||||
if slices.Contains(reviewers, submitter) {
|
||||
LogDebug("Submitter is maintainer. Approving.")
|
||||
return true
|
||||
}
|
||||
@@ -175,135 +164,13 @@ func (data *MaintainershipMap) IsApproved(pkg string, reviews []*models.PullRevi
|
||||
return false
|
||||
}
|
||||
|
||||
func (data *MaintainershipMap) modifyInplace(writer io.StringWriter) error {
|
||||
var original map[string][]string
|
||||
if err := json.Unmarshal(data.Raw, &original); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dec := json.NewDecoder(bytes.NewReader(data.Raw))
|
||||
_, err := dec.Token()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
output := ""
|
||||
lastPos := 0
|
||||
modified := false
|
||||
|
||||
type entry struct {
|
||||
key string
|
||||
valStart int
|
||||
valEnd int
|
||||
}
|
||||
var entries []entry
|
||||
|
||||
for dec.More() {
|
||||
kToken, _ := dec.Token()
|
||||
key := kToken.(string)
|
||||
var raw json.RawMessage
|
||||
dec.Decode(&raw)
|
||||
valEnd := int(dec.InputOffset())
|
||||
valStart := valEnd - len(raw)
|
||||
entries = append(entries, entry{key, valStart, valEnd})
|
||||
}
|
||||
|
||||
changed := make(map[string]bool)
|
||||
for k, v := range data.Data {
|
||||
if ov, ok := original[k]; !ok || !slices.Equal(v, ov) {
|
||||
changed[k] = true
|
||||
}
|
||||
}
|
||||
for k := range original {
|
||||
if _, ok := data.Data[k]; !ok {
|
||||
changed[k] = true
|
||||
}
|
||||
}
|
||||
|
||||
if len(changed) == 0 {
|
||||
_, err = writer.WriteString(string(data.Raw))
|
||||
return err
|
||||
}
|
||||
|
||||
for _, e := range entries {
|
||||
if v, ok := data.Data[e.key]; ok {
|
||||
prefix := string(data.Raw[lastPos:e.valStart])
|
||||
if modified && strings.TrimSpace(output) == "{" {
|
||||
if commaIdx := strings.Index(prefix, ","); commaIdx != -1 {
|
||||
if quoteIdx := strings.Index(prefix, "\""); quoteIdx == -1 || commaIdx < quoteIdx {
|
||||
prefix = prefix[:commaIdx] + prefix[commaIdx+1:]
|
||||
}
|
||||
}
|
||||
}
|
||||
output += prefix
|
||||
if changed[e.key] {
|
||||
slices.Sort(v)
|
||||
newVal, _ := json.Marshal(v)
|
||||
output += string(newVal)
|
||||
modified = true
|
||||
} else {
|
||||
output += string(data.Raw[e.valStart:e.valEnd])
|
||||
}
|
||||
} else {
|
||||
// Deleted
|
||||
modified = true
|
||||
}
|
||||
lastPos = e.valEnd
|
||||
}
|
||||
output += string(data.Raw[lastPos:])
|
||||
|
||||
// Handle additions (simplistic: at the end)
|
||||
for k, v := range data.Data {
|
||||
if _, ok := original[k]; !ok {
|
||||
slices.Sort(v)
|
||||
newVal, _ := json.Marshal(v)
|
||||
keyStr, _ := json.Marshal(k)
|
||||
|
||||
// Insert before closing brace
|
||||
if idx := strings.LastIndex(output, "}"); idx != -1 {
|
||||
prefix := output[:idx]
|
||||
suffix := output[idx:]
|
||||
|
||||
trimmedPrefix := strings.TrimRight(prefix, " \n\r\t")
|
||||
if !strings.HasSuffix(trimmedPrefix, "{") && !strings.HasSuffix(trimmedPrefix, ",") {
|
||||
// find the actual position of the last non-whitespace character in prefix
|
||||
lastCharIdx := strings.LastIndexAny(prefix, "]}0123456789\"")
|
||||
if lastCharIdx != -1 {
|
||||
prefix = prefix[:lastCharIdx+1] + "," + prefix[lastCharIdx+1:]
|
||||
}
|
||||
}
|
||||
|
||||
insertion := fmt.Sprintf(" %s: %s", string(keyStr), string(newVal))
|
||||
if !strings.HasSuffix(prefix, "\n") {
|
||||
insertion = "\n" + insertion
|
||||
}
|
||||
output = prefix + insertion + "\n" + suffix
|
||||
modified = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if modified {
|
||||
_, err := writer.WriteString(output)
|
||||
return err
|
||||
}
|
||||
_, err = writer.WriteString(string(data.Raw))
|
||||
return err
|
||||
}
|
||||
|
||||
func (data *MaintainershipMap) WriteMaintainershipFile(writer io.StringWriter) error {
|
||||
if data.IsDir {
|
||||
return fmt.Errorf("Not implemented")
|
||||
}
|
||||
|
||||
if len(data.Raw) > 0 {
|
||||
if err := data.modifyInplace(writer); err == nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback to full write
|
||||
writer.WriteString("{\n")
|
||||
|
||||
if d, ok := data.Data[""]; ok {
|
||||
eol := ","
|
||||
if len(data.Data) == 1 {
|
||||
@@ -314,12 +181,17 @@ func (data *MaintainershipMap) WriteMaintainershipFile(writer io.StringWriter) e
|
||||
writer.WriteString(fmt.Sprintf(" \"\": %s%s\n", string(str), eol))
|
||||
}
|
||||
|
||||
keys := make([]string, 0, len(data.Data))
|
||||
keys := make([]string, len(data.Data))
|
||||
i := 0
|
||||
for pkg := range data.Data {
|
||||
if pkg == "" {
|
||||
continue
|
||||
}
|
||||
keys = append(keys, pkg)
|
||||
keys[i] = pkg
|
||||
i++
|
||||
}
|
||||
if len(keys) >= i {
|
||||
keys = slices.Delete(keys, i, len(keys))
|
||||
}
|
||||
slices.Sort(keys)
|
||||
for i, pkg := range keys {
|
||||
|
||||
@@ -13,10 +13,10 @@ import (
|
||||
)
|
||||
|
||||
func TestMaintainership(t *testing.T) {
|
||||
config := &common.AutogitConfig{
|
||||
config := common.AutogitConfig{
|
||||
Branch: "bar",
|
||||
Organization: "foo",
|
||||
GitProjectName: common.DefaultGitPrj + "#bar",
|
||||
GitProjectName: common.DefaultGitPrj,
|
||||
}
|
||||
|
||||
packageTests := []struct {
|
||||
@@ -141,7 +141,7 @@ func TestMaintainership(t *testing.T) {
|
||||
notFoundError := repository.NewRepoGetContentsNotFound()
|
||||
for _, test := range packageTests {
|
||||
runTests := func(t *testing.T, mi common.GiteaMaintainershipReader) {
|
||||
maintainers, err := common.FetchProjectMaintainershipData(mi, config)
|
||||
maintainers, err := common.FetchProjectMaintainershipData(mi, config.Organization, config.GitProjectName, config.Branch)
|
||||
if err != nil && !test.otherError {
|
||||
if test.maintainersFileErr == nil {
|
||||
t.Fatal("Unexpected error recieved", err)
|
||||
@@ -208,7 +208,6 @@ func TestMaintainershipFileWrite(t *testing.T) {
|
||||
name string
|
||||
is_dir bool
|
||||
maintainers map[string][]string
|
||||
raw []byte
|
||||
expected_output string
|
||||
expected_error error
|
||||
}{
|
||||
@@ -232,43 +231,6 @@ func TestMaintainershipFileWrite(t *testing.T) {
|
||||
},
|
||||
expected_output: "{\n \"\": [\"one\",\"two\"],\n \"foo\": [\"byte\",\"four\"],\n \"pkg1\": []\n}\n",
|
||||
},
|
||||
{
|
||||
name: "surgical modification",
|
||||
maintainers: map[string][]string{
|
||||
"": {"one", "two"},
|
||||
"foo": {"byte", "four", "newone"},
|
||||
"pkg1": {},
|
||||
},
|
||||
raw: []byte("{\n \"\": [\"one\",\"two\"],\n \"foo\": [\"byte\",\"four\"],\n \"pkg1\": []\n}\n"),
|
||||
expected_output: "{\n \"\": [\"one\",\"two\"],\n \"foo\": [\"byte\",\"four\",\"newone\"],\n \"pkg1\": []\n}\n",
|
||||
},
|
||||
{
|
||||
name: "no change",
|
||||
maintainers: map[string][]string{
|
||||
"": {"one", "two"},
|
||||
"foo": {"byte", "four"},
|
||||
"pkg1": {},
|
||||
},
|
||||
raw: []byte("{\n \"\": [\"one\",\"two\"],\n \"foo\": [\"byte\",\"four\"],\n \"pkg1\": []\n}\n"),
|
||||
expected_output: "{\n \"\": [\"one\",\"two\"],\n \"foo\": [\"byte\",\"four\"],\n \"pkg1\": []\n}\n",
|
||||
},
|
||||
{
|
||||
name: "surgical addition",
|
||||
maintainers: map[string][]string{
|
||||
"": {"one"},
|
||||
"new": {"user"},
|
||||
},
|
||||
raw: []byte("{\n \"\": [ \"one\" ]\n}\n"),
|
||||
expected_output: "{\n \"\": [ \"one\" ],\n \"new\": [\"user\"]\n}\n",
|
||||
},
|
||||
{
|
||||
name: "surgical deletion",
|
||||
maintainers: map[string][]string{
|
||||
"": {"one"},
|
||||
},
|
||||
raw: []byte("{\n \"\": [\"one\"],\n \"old\": [\"user\"]\n}\n"),
|
||||
expected_output: "{\n \"\": [\"one\"]\n}\n",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
@@ -277,7 +239,6 @@ func TestMaintainershipFileWrite(t *testing.T) {
|
||||
data := common.MaintainershipMap{
|
||||
Data: test.maintainers,
|
||||
IsDir: test.is_dir,
|
||||
Raw: test.raw,
|
||||
}
|
||||
|
||||
if err := data.WriteMaintainershipFile(&b); err != test.expected_error {
|
||||
@@ -287,47 +248,7 @@ func TestMaintainershipFileWrite(t *testing.T) {
|
||||
output := b.String()
|
||||
|
||||
if test.expected_output != output {
|
||||
t.Fatalf("unexpected output:\n%q\nExpecting:\n%q", output, test.expected_output)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestReviewRequired(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
maintainers []string
|
||||
config *common.AutogitConfig
|
||||
is_approved bool
|
||||
}{
|
||||
{
|
||||
name: "ReviewRequired=false",
|
||||
maintainers: []string{"maintainer1", "maintainer2"},
|
||||
config: &common.AutogitConfig{ReviewRequired: false},
|
||||
is_approved: true,
|
||||
},
|
||||
{
|
||||
name: "ReviewRequired=true",
|
||||
maintainers: []string{"maintainer1", "maintainer2"},
|
||||
config: &common.AutogitConfig{ReviewRequired: true},
|
||||
is_approved: false,
|
||||
},
|
||||
{
|
||||
name: "ReviewRequired=true",
|
||||
maintainers: []string{"maintainer1"},
|
||||
config: &common.AutogitConfig{ReviewRequired: true},
|
||||
is_approved: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
m := &common.MaintainershipMap{
|
||||
Data: map[string][]string{"": test.maintainers},
|
||||
}
|
||||
m.Config = test.config
|
||||
if approved := m.IsApproved("", nil, "maintainer1", nil); approved != test.is_approved {
|
||||
t.Error("Expected m.IsApproved()->", test.is_approved, "but didn't get it")
|
||||
t.Fatal("unexpected output:", output, "Expecting:", test.expected_output)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -207,42 +207,6 @@ func (c *MockGiteaTimelineFetcherGetTimelineCall) DoAndReturn(f func(string, str
|
||||
return c
|
||||
}
|
||||
|
||||
// ResetTimelineCache mocks base method.
|
||||
func (m *MockGiteaTimelineFetcher) ResetTimelineCache(org, repo string, idx int64) {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "ResetTimelineCache", org, repo, idx)
|
||||
}
|
||||
|
||||
// ResetTimelineCache indicates an expected call of ResetTimelineCache.
|
||||
func (mr *MockGiteaTimelineFetcherMockRecorder) ResetTimelineCache(org, repo, idx any) *MockGiteaTimelineFetcherResetTimelineCacheCall {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ResetTimelineCache", reflect.TypeOf((*MockGiteaTimelineFetcher)(nil).ResetTimelineCache), org, repo, idx)
|
||||
return &MockGiteaTimelineFetcherResetTimelineCacheCall{Call: call}
|
||||
}
|
||||
|
||||
// MockGiteaTimelineFetcherResetTimelineCacheCall wrap *gomock.Call
|
||||
type MockGiteaTimelineFetcherResetTimelineCacheCall struct {
|
||||
*gomock.Call
|
||||
}
|
||||
|
||||
// Return rewrite *gomock.Call.Return
|
||||
func (c *MockGiteaTimelineFetcherResetTimelineCacheCall) Return() *MockGiteaTimelineFetcherResetTimelineCacheCall {
|
||||
c.Call = c.Call.Return()
|
||||
return c
|
||||
}
|
||||
|
||||
// Do rewrite *gomock.Call.Do
|
||||
func (c *MockGiteaTimelineFetcherResetTimelineCacheCall) Do(f func(string, string, int64)) *MockGiteaTimelineFetcherResetTimelineCacheCall {
|
||||
c.Call = c.Call.Do(f)
|
||||
return c
|
||||
}
|
||||
|
||||
// DoAndReturn rewrite *gomock.Call.DoAndReturn
|
||||
func (c *MockGiteaTimelineFetcherResetTimelineCacheCall) DoAndReturn(f func(string, string, int64)) *MockGiteaTimelineFetcherResetTimelineCacheCall {
|
||||
c.Call = c.Call.DoAndReturn(f)
|
||||
return c
|
||||
}
|
||||
|
||||
// MockGiteaComment is a mock of GiteaComment interface.
|
||||
type MockGiteaComment struct {
|
||||
ctrl *gomock.Controller
|
||||
@@ -739,42 +703,6 @@ func (c *MockGiteaPRTimelineReviewFetcherGetTimelineCall) DoAndReturn(f func(str
|
||||
return c
|
||||
}
|
||||
|
||||
// ResetTimelineCache mocks base method.
|
||||
func (m *MockGiteaPRTimelineReviewFetcher) ResetTimelineCache(org, repo string, idx int64) {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "ResetTimelineCache", org, repo, idx)
|
||||
}
|
||||
|
||||
// ResetTimelineCache indicates an expected call of ResetTimelineCache.
|
||||
func (mr *MockGiteaPRTimelineReviewFetcherMockRecorder) ResetTimelineCache(org, repo, idx any) *MockGiteaPRTimelineReviewFetcherResetTimelineCacheCall {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ResetTimelineCache", reflect.TypeOf((*MockGiteaPRTimelineReviewFetcher)(nil).ResetTimelineCache), org, repo, idx)
|
||||
return &MockGiteaPRTimelineReviewFetcherResetTimelineCacheCall{Call: call}
|
||||
}
|
||||
|
||||
// MockGiteaPRTimelineReviewFetcherResetTimelineCacheCall wrap *gomock.Call
|
||||
type MockGiteaPRTimelineReviewFetcherResetTimelineCacheCall struct {
|
||||
*gomock.Call
|
||||
}
|
||||
|
||||
// Return rewrite *gomock.Call.Return
|
||||
func (c *MockGiteaPRTimelineReviewFetcherResetTimelineCacheCall) Return() *MockGiteaPRTimelineReviewFetcherResetTimelineCacheCall {
|
||||
c.Call = c.Call.Return()
|
||||
return c
|
||||
}
|
||||
|
||||
// Do rewrite *gomock.Call.Do
|
||||
func (c *MockGiteaPRTimelineReviewFetcherResetTimelineCacheCall) Do(f func(string, string, int64)) *MockGiteaPRTimelineReviewFetcherResetTimelineCacheCall {
|
||||
c.Call = c.Call.Do(f)
|
||||
return c
|
||||
}
|
||||
|
||||
// DoAndReturn rewrite *gomock.Call.DoAndReturn
|
||||
func (c *MockGiteaPRTimelineReviewFetcherResetTimelineCacheCall) DoAndReturn(f func(string, string, int64)) *MockGiteaPRTimelineReviewFetcherResetTimelineCacheCall {
|
||||
c.Call = c.Call.DoAndReturn(f)
|
||||
return c
|
||||
}
|
||||
|
||||
// MockGiteaCommitFetcher is a mock of GiteaCommitFetcher interface.
|
||||
type MockGiteaCommitFetcher struct {
|
||||
ctrl *gomock.Controller
|
||||
@@ -1066,42 +994,6 @@ func (c *MockGiteaReviewTimelineFetcherGetTimelineCall) DoAndReturn(f func(strin
|
||||
return c
|
||||
}
|
||||
|
||||
// ResetTimelineCache mocks base method.
|
||||
func (m *MockGiteaReviewTimelineFetcher) ResetTimelineCache(org, repo string, idx int64) {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "ResetTimelineCache", org, repo, idx)
|
||||
}
|
||||
|
||||
// ResetTimelineCache indicates an expected call of ResetTimelineCache.
|
||||
func (mr *MockGiteaReviewTimelineFetcherMockRecorder) ResetTimelineCache(org, repo, idx any) *MockGiteaReviewTimelineFetcherResetTimelineCacheCall {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ResetTimelineCache", reflect.TypeOf((*MockGiteaReviewTimelineFetcher)(nil).ResetTimelineCache), org, repo, idx)
|
||||
return &MockGiteaReviewTimelineFetcherResetTimelineCacheCall{Call: call}
|
||||
}
|
||||
|
||||
// MockGiteaReviewTimelineFetcherResetTimelineCacheCall wrap *gomock.Call
|
||||
type MockGiteaReviewTimelineFetcherResetTimelineCacheCall struct {
|
||||
*gomock.Call
|
||||
}
|
||||
|
||||
// Return rewrite *gomock.Call.Return
|
||||
func (c *MockGiteaReviewTimelineFetcherResetTimelineCacheCall) Return() *MockGiteaReviewTimelineFetcherResetTimelineCacheCall {
|
||||
c.Call = c.Call.Return()
|
||||
return c
|
||||
}
|
||||
|
||||
// Do rewrite *gomock.Call.Do
|
||||
func (c *MockGiteaReviewTimelineFetcherResetTimelineCacheCall) Do(f func(string, string, int64)) *MockGiteaReviewTimelineFetcherResetTimelineCacheCall {
|
||||
c.Call = c.Call.Do(f)
|
||||
return c
|
||||
}
|
||||
|
||||
// DoAndReturn rewrite *gomock.Call.DoAndReturn
|
||||
func (c *MockGiteaReviewTimelineFetcherResetTimelineCacheCall) DoAndReturn(f func(string, string, int64)) *MockGiteaReviewTimelineFetcherResetTimelineCacheCall {
|
||||
c.Call = c.Call.DoAndReturn(f)
|
||||
return c
|
||||
}
|
||||
|
||||
// MockGiteaPRChecker is a mock of GiteaPRChecker interface.
|
||||
type MockGiteaPRChecker struct {
|
||||
ctrl *gomock.Controller
|
||||
@@ -1323,42 +1215,6 @@ func (c *MockGiteaPRCheckerGetTimelineCall) DoAndReturn(f func(string, string, i
|
||||
return c
|
||||
}
|
||||
|
||||
// ResetTimelineCache mocks base method.
|
||||
func (m *MockGiteaPRChecker) ResetTimelineCache(org, repo string, idx int64) {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "ResetTimelineCache", org, repo, idx)
|
||||
}
|
||||
|
||||
// ResetTimelineCache indicates an expected call of ResetTimelineCache.
|
||||
func (mr *MockGiteaPRCheckerMockRecorder) ResetTimelineCache(org, repo, idx any) *MockGiteaPRCheckerResetTimelineCacheCall {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ResetTimelineCache", reflect.TypeOf((*MockGiteaPRChecker)(nil).ResetTimelineCache), org, repo, idx)
|
||||
return &MockGiteaPRCheckerResetTimelineCacheCall{Call: call}
|
||||
}
|
||||
|
||||
// MockGiteaPRCheckerResetTimelineCacheCall wrap *gomock.Call
|
||||
type MockGiteaPRCheckerResetTimelineCacheCall struct {
|
||||
*gomock.Call
|
||||
}
|
||||
|
||||
// Return rewrite *gomock.Call.Return
|
||||
func (c *MockGiteaPRCheckerResetTimelineCacheCall) Return() *MockGiteaPRCheckerResetTimelineCacheCall {
|
||||
c.Call = c.Call.Return()
|
||||
return c
|
||||
}
|
||||
|
||||
// Do rewrite *gomock.Call.Do
|
||||
func (c *MockGiteaPRCheckerResetTimelineCacheCall) Do(f func(string, string, int64)) *MockGiteaPRCheckerResetTimelineCacheCall {
|
||||
c.Call = c.Call.Do(f)
|
||||
return c
|
||||
}
|
||||
|
||||
// DoAndReturn rewrite *gomock.Call.DoAndReturn
|
||||
func (c *MockGiteaPRCheckerResetTimelineCacheCall) DoAndReturn(f func(string, string, int64)) *MockGiteaPRCheckerResetTimelineCacheCall {
|
||||
c.Call = c.Call.DoAndReturn(f)
|
||||
return c
|
||||
}
|
||||
|
||||
// MockGiteaReviewFetcherAndRequesterAndUnrequester is a mock of GiteaReviewFetcherAndRequesterAndUnrequester interface.
|
||||
type MockGiteaReviewFetcherAndRequesterAndUnrequester struct {
|
||||
ctrl *gomock.Controller
|
||||
@@ -1544,42 +1400,6 @@ func (c *MockGiteaReviewFetcherAndRequesterAndUnrequesterRequestReviewsCall) DoA
|
||||
return c
|
||||
}
|
||||
|
||||
// ResetTimelineCache mocks base method.
|
||||
func (m *MockGiteaReviewFetcherAndRequesterAndUnrequester) ResetTimelineCache(org, repo string, idx int64) {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "ResetTimelineCache", org, repo, idx)
|
||||
}
|
||||
|
||||
// ResetTimelineCache indicates an expected call of ResetTimelineCache.
|
||||
func (mr *MockGiteaReviewFetcherAndRequesterAndUnrequesterMockRecorder) ResetTimelineCache(org, repo, idx any) *MockGiteaReviewFetcherAndRequesterAndUnrequesterResetTimelineCacheCall {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ResetTimelineCache", reflect.TypeOf((*MockGiteaReviewFetcherAndRequesterAndUnrequester)(nil).ResetTimelineCache), org, repo, idx)
|
||||
return &MockGiteaReviewFetcherAndRequesterAndUnrequesterResetTimelineCacheCall{Call: call}
|
||||
}
|
||||
|
||||
// MockGiteaReviewFetcherAndRequesterAndUnrequesterResetTimelineCacheCall wrap *gomock.Call
|
||||
type MockGiteaReviewFetcherAndRequesterAndUnrequesterResetTimelineCacheCall struct {
|
||||
*gomock.Call
|
||||
}
|
||||
|
||||
// Return rewrite *gomock.Call.Return
|
||||
func (c *MockGiteaReviewFetcherAndRequesterAndUnrequesterResetTimelineCacheCall) Return() *MockGiteaReviewFetcherAndRequesterAndUnrequesterResetTimelineCacheCall {
|
||||
c.Call = c.Call.Return()
|
||||
return c
|
||||
}
|
||||
|
||||
// Do rewrite *gomock.Call.Do
|
||||
func (c *MockGiteaReviewFetcherAndRequesterAndUnrequesterResetTimelineCacheCall) Do(f func(string, string, int64)) *MockGiteaReviewFetcherAndRequesterAndUnrequesterResetTimelineCacheCall {
|
||||
c.Call = c.Call.Do(f)
|
||||
return c
|
||||
}
|
||||
|
||||
// DoAndReturn rewrite *gomock.Call.DoAndReturn
|
||||
func (c *MockGiteaReviewFetcherAndRequesterAndUnrequesterResetTimelineCacheCall) DoAndReturn(f func(string, string, int64)) *MockGiteaReviewFetcherAndRequesterAndUnrequesterResetTimelineCacheCall {
|
||||
c.Call = c.Call.DoAndReturn(f)
|
||||
return c
|
||||
}
|
||||
|
||||
// UnrequestReview mocks base method.
|
||||
func (m *MockGiteaReviewFetcherAndRequesterAndUnrequester) UnrequestReview(org, repo string, id int64, reviwers ...string) error {
|
||||
m.ctrl.T.Helper()
|
||||
@@ -1686,42 +1506,6 @@ func (c *MockGiteaUnreviewTimelineFetcherGetTimelineCall) DoAndReturn(f func(str
|
||||
return c
|
||||
}
|
||||
|
||||
// ResetTimelineCache mocks base method.
|
||||
func (m *MockGiteaUnreviewTimelineFetcher) ResetTimelineCache(org, repo string, idx int64) {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "ResetTimelineCache", org, repo, idx)
|
||||
}
|
||||
|
||||
// ResetTimelineCache indicates an expected call of ResetTimelineCache.
|
||||
func (mr *MockGiteaUnreviewTimelineFetcherMockRecorder) ResetTimelineCache(org, repo, idx any) *MockGiteaUnreviewTimelineFetcherResetTimelineCacheCall {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ResetTimelineCache", reflect.TypeOf((*MockGiteaUnreviewTimelineFetcher)(nil).ResetTimelineCache), org, repo, idx)
|
||||
return &MockGiteaUnreviewTimelineFetcherResetTimelineCacheCall{Call: call}
|
||||
}
|
||||
|
||||
// MockGiteaUnreviewTimelineFetcherResetTimelineCacheCall wrap *gomock.Call
|
||||
type MockGiteaUnreviewTimelineFetcherResetTimelineCacheCall struct {
|
||||
*gomock.Call
|
||||
}
|
||||
|
||||
// Return rewrite *gomock.Call.Return
|
||||
func (c *MockGiteaUnreviewTimelineFetcherResetTimelineCacheCall) Return() *MockGiteaUnreviewTimelineFetcherResetTimelineCacheCall {
|
||||
c.Call = c.Call.Return()
|
||||
return c
|
||||
}
|
||||
|
||||
// Do rewrite *gomock.Call.Do
|
||||
func (c *MockGiteaUnreviewTimelineFetcherResetTimelineCacheCall) Do(f func(string, string, int64)) *MockGiteaUnreviewTimelineFetcherResetTimelineCacheCall {
|
||||
c.Call = c.Call.Do(f)
|
||||
return c
|
||||
}
|
||||
|
||||
// DoAndReturn rewrite *gomock.Call.DoAndReturn
|
||||
func (c *MockGiteaUnreviewTimelineFetcherResetTimelineCacheCall) DoAndReturn(f func(string, string, int64)) *MockGiteaUnreviewTimelineFetcherResetTimelineCacheCall {
|
||||
c.Call = c.Call.DoAndReturn(f)
|
||||
return c
|
||||
}
|
||||
|
||||
// UnrequestReview mocks base method.
|
||||
func (m *MockGiteaUnreviewTimelineFetcher) UnrequestReview(org, repo string, id int64, reviwers ...string) error {
|
||||
m.ctrl.T.Helper()
|
||||
@@ -3324,42 +3108,6 @@ func (c *MockGiteaRequestReviewsCall) DoAndReturn(f func(*models.PullRequest, ..
|
||||
return c
|
||||
}
|
||||
|
||||
// ResetTimelineCache mocks base method.
|
||||
func (m *MockGitea) ResetTimelineCache(org, repo string, idx int64) {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "ResetTimelineCache", org, repo, idx)
|
||||
}
|
||||
|
||||
// ResetTimelineCache indicates an expected call of ResetTimelineCache.
|
||||
func (mr *MockGiteaMockRecorder) ResetTimelineCache(org, repo, idx any) *MockGiteaResetTimelineCacheCall {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ResetTimelineCache", reflect.TypeOf((*MockGitea)(nil).ResetTimelineCache), org, repo, idx)
|
||||
return &MockGiteaResetTimelineCacheCall{Call: call}
|
||||
}
|
||||
|
||||
// MockGiteaResetTimelineCacheCall wrap *gomock.Call
|
||||
type MockGiteaResetTimelineCacheCall struct {
|
||||
*gomock.Call
|
||||
}
|
||||
|
||||
// Return rewrite *gomock.Call.Return
|
||||
func (c *MockGiteaResetTimelineCacheCall) Return() *MockGiteaResetTimelineCacheCall {
|
||||
c.Call = c.Call.Return()
|
||||
return c
|
||||
}
|
||||
|
||||
// Do rewrite *gomock.Call.Do
|
||||
func (c *MockGiteaResetTimelineCacheCall) Do(f func(string, string, int64)) *MockGiteaResetTimelineCacheCall {
|
||||
c.Call = c.Call.Do(f)
|
||||
return c
|
||||
}
|
||||
|
||||
// DoAndReturn rewrite *gomock.Call.DoAndReturn
|
||||
func (c *MockGiteaResetTimelineCacheCall) DoAndReturn(f func(string, string, int64)) *MockGiteaResetTimelineCacheCall {
|
||||
c.Call = c.Call.DoAndReturn(f)
|
||||
return c
|
||||
}
|
||||
|
||||
// SetCommitStatus mocks base method.
|
||||
func (m *MockGitea) SetCommitStatus(org, repo, hash string, status *models.CommitStatus) (*models.CommitStatus, error) {
|
||||
m.ctrl.T.Helper()
|
||||
|
||||
13
common/pr.go
13
common/pr.go
@@ -160,8 +160,6 @@ func FetchPRSet(user string, gitea GiteaPRTimelineReviewFetcher, org, repo strin
|
||||
var pr *models.PullRequest
|
||||
var err error
|
||||
|
||||
gitea.ResetTimelineCache(org, repo, num)
|
||||
|
||||
prjGitOrg, prjGitRepo, _ := config.GetPrjGit()
|
||||
if prjGitOrg == org && prjGitRepo == repo {
|
||||
if pr, err = gitea.GetPullRequest(org, repo, num); err != nil {
|
||||
@@ -186,7 +184,6 @@ func FetchPRSet(user string, gitea GiteaPRTimelineReviewFetcher, org, repo strin
|
||||
|
||||
for _, pr := range prs {
|
||||
org, repo, idx := pr.PRComponents()
|
||||
gitea.ResetTimelineCache(org, repo, idx)
|
||||
reviews, err := FetchGiteaReviews(gitea, org, repo, idx)
|
||||
if err != nil {
|
||||
LogError("Error fetching reviews for", PRtoString(pr.PR), ":", err)
|
||||
@@ -319,10 +316,7 @@ func (rs *PRSet) FindMissingAndExtraReviewers(maintainers MaintainershipData, id
|
||||
// only need project maintainer reviews if:
|
||||
// * not created by a bot and has other PRs, or
|
||||
// * not created by maintainer
|
||||
noReviewPRCreators := []string{}
|
||||
if !rs.Config.ReviewRequired {
|
||||
noReviewPRCreators = prjMaintainers
|
||||
}
|
||||
noReviewPRCreators := prjMaintainers
|
||||
if len(rs.PRs) > 1 {
|
||||
noReviewPRCreators = append(noReviewPRCreators, rs.BotUser)
|
||||
}
|
||||
@@ -345,10 +339,7 @@ func (rs *PRSet) FindMissingAndExtraReviewers(maintainers MaintainershipData, id
|
||||
pkg := pr.PR.Base.Repo.Name
|
||||
pkgMaintainers := maintainers.ListPackageMaintainers(pkg, nil)
|
||||
Maintainers := slices.Concat(prjMaintainers, pkgMaintainers)
|
||||
noReviewPkgPRCreators := []string{}
|
||||
if !rs.Config.ReviewRequired {
|
||||
noReviewPkgPRCreators = pkgMaintainers
|
||||
}
|
||||
noReviewPkgPRCreators := pkgMaintainers
|
||||
|
||||
LogDebug("packakge maintainers:", Maintainers)
|
||||
|
||||
|
||||
@@ -833,6 +833,7 @@ func TestFindMissingAndExtraReviewers(t *testing.T) {
|
||||
[]string{"autogits_obs_staging_bot", "user1"},
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
name: "Add reviewer if also maintainer where review by maintainer is not needed",
|
||||
prset: &common.PRSet{
|
||||
@@ -1094,67 +1095,8 @@ func TestFindMissingAndExtraReviewers(t *testing.T) {
|
||||
expected_missing_reviewers: [][]string{{"pkgm2", "prj2"}},
|
||||
expected_extra_reviewers: [][]string{{}, {"prj1"}},
|
||||
},
|
||||
{
|
||||
name: "Package maintainer submitter, AlwaysRequireReview=false",
|
||||
prset: &common.PRSet{
|
||||
PRs: []*common.PRInfo{
|
||||
{
|
||||
PR: &models.PullRequest{
|
||||
User: &models.User{UserName: "pkgmaintainer"},
|
||||
Base: &models.PRBranchInfo{Name: "main", Repo: &models.Repository{Name: "pkg", Owner: &models.User{UserName: "org"}}},
|
||||
},
|
||||
Reviews: &common.PRReviews{},
|
||||
},
|
||||
},
|
||||
Config: &common.AutogitConfig{
|
||||
GitProjectName: "prg/repo#main",
|
||||
Organization: "org",
|
||||
Branch: "main",
|
||||
Reviewers: []string{},
|
||||
ReviewRequired: false,
|
||||
},
|
||||
},
|
||||
maintainers: &common.MaintainershipMap{
|
||||
Data: map[string][]string{
|
||||
"pkg": {"pkgmaintainer", "pkgm1"},
|
||||
},
|
||||
},
|
||||
noAutoStaging: true,
|
||||
expected_missing_reviewers: [][]string{
|
||||
{},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Package maintainer submitter, AlwaysRequireReview=true",
|
||||
prset: &common.PRSet{
|
||||
PRs: []*common.PRInfo{
|
||||
{
|
||||
PR: &models.PullRequest{
|
||||
User: &models.User{UserName: "pkgmaintainer"},
|
||||
Base: &models.PRBranchInfo{Name: "main", Repo: &models.Repository{Name: "pkg", Owner: &models.User{UserName: "org"}}},
|
||||
},
|
||||
Reviews: &common.PRReviews{},
|
||||
},
|
||||
},
|
||||
Config: &common.AutogitConfig{
|
||||
GitProjectName: "prg/repo#main",
|
||||
Organization: "org",
|
||||
Branch: "main",
|
||||
Reviewers: []string{},
|
||||
ReviewRequired: true,
|
||||
},
|
||||
},
|
||||
maintainers: &common.MaintainershipMap{
|
||||
Data: map[string][]string{
|
||||
"pkg": {"pkgmaintainer", "pkgm1"},
|
||||
},
|
||||
},
|
||||
noAutoStaging: true,
|
||||
expected_missing_reviewers: [][]string{
|
||||
{"pkgm1"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
test.prset.HasAutoStaging = !test.noAutoStaging
|
||||
|
||||
@@ -11,7 +11,6 @@ devel:languages:lua
|
||||
devel:languages:nodejs
|
||||
devel:languages:perl
|
||||
devel:languages:python:Factory
|
||||
devel:languages:python:mailman
|
||||
devel:languages:python:pytest
|
||||
devel:openSUSE:Factory
|
||||
network:chromium
|
||||
|
||||
@@ -34,8 +34,7 @@ It's a JSON file with following syntax:
|
||||
"QA": [
|
||||
{
|
||||
"Name": "SLES",
|
||||
"Origin": "SUSE:SLFO:Products:SLES:16.0",
|
||||
"BuildDisableRepos": ["product"]
|
||||
"Origin": "SUSE:SLFO:Products:SLES:16.0"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -48,7 +47,6 @@ It's a JSON file with following syntax:
|
||||
| *QA* | Crucial for generating a product build (such as an ISO or FTP tree) that incorporates the packages. | no | array of objects | | |
|
||||
| *QA > Name* | Suffix for the QA OBS staging project. The project is named *StagingProject:<PR_Number>:Name*. | no | string | | |
|
||||
| *QA > Origin* | OBS reference project | no | string | | |
|
||||
| *QA > BuildDisableRepos* | The names of OBS repositories to build-disable, if any. | no | array of strings | | [] |
|
||||
|
||||
|
||||
Details
|
||||
@@ -67,6 +65,6 @@ Details
|
||||
* **PrjGit PR - QA staging project**
|
||||
* The QA staging project is meant for building the product; the relative build config is inherited from the `QA > Origin` project.
|
||||
* In this case, the **scmsync** tag is inherited from the `QA > Origin` project.
|
||||
* It is desirable in some cases to avoid building some specific build service repositories when not needed. In this case, `QA > BuildDisableRepos` can be specified.
|
||||
These repositories would be disabled in the project meta when generating the QA project.
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -109,11 +109,6 @@ const (
|
||||
BuildStatusSummaryUnknown = 4
|
||||
)
|
||||
|
||||
type DisableFlag struct {
|
||||
XMLName string `xml:"disable"`
|
||||
Name string `xml:"repository,attr"`
|
||||
}
|
||||
|
||||
func ProcessBuildStatus(project, refProject *common.BuildResultList) BuildStatusSummary {
|
||||
if _, finished := refProject.BuildResultSummary(); !finished {
|
||||
common.LogDebug("refProject not finished building??")
|
||||
@@ -382,7 +377,7 @@ func GenerateObsPrjMeta(git common.Git, gitea common.Gitea, pr *models.PullReque
|
||||
// stagingProject:$buildProject
|
||||
// ^- stagingProject:$buildProject:$subProjectName (based on templateProject)
|
||||
|
||||
func CreateQASubProject(stagingConfig *common.StagingConfig, git common.Git, gitea common.Gitea, pr *models.PullRequest, stagingProject, templateProject, subProjectName string, buildDisableRepos []string) error {
|
||||
func CreateQASubProject(stagingConfig *common.StagingConfig, git common.Git, gitea common.Gitea, pr *models.PullRequest, stagingProject, templateProject, subProjectName string) error {
|
||||
common.LogDebug("Setup QA sub projects")
|
||||
templateMeta, err := ObsClient.GetProjectMeta(templateProject)
|
||||
if err != nil {
|
||||
@@ -412,21 +407,7 @@ func CreateQASubProject(stagingConfig *common.StagingConfig, git common.Git, git
|
||||
repository.Fragment = branch.SHA
|
||||
templateMeta.ScmSync = repository.String()
|
||||
common.LogDebug("Setting scmsync url to ", templateMeta.ScmSync)
|
||||
}
|
||||
// Build-disable repositories if asked
|
||||
if len(buildDisableRepos) > 0 {
|
||||
toDisable := make([]DisableFlag, len(buildDisableRepos))
|
||||
for idx, repositoryName := range buildDisableRepos {
|
||||
toDisable[idx] = DisableFlag{Name: repositoryName}
|
||||
}
|
||||
|
||||
output, err := xml.Marshal(toDisable)
|
||||
if err != nil {
|
||||
common.LogError("error while marshalling, skipping BuildDisableRepos: ", err)
|
||||
} else {
|
||||
templateMeta.BuildFlags.Contents += string(output)
|
||||
}
|
||||
}
|
||||
}
|
||||
// Cleanup ReleaseTarget and modify affected path entries
|
||||
for idx, r := range templateMeta.Repositories {
|
||||
templateMeta.Repositories[idx].ReleaseTargets = nil
|
||||
@@ -941,8 +922,7 @@ func ProcessPullRequest(gitea common.Gitea, org, repo string, id int64) (bool, e
|
||||
CreateQASubProject(stagingConfig, git, gitea, pr,
|
||||
stagingProject,
|
||||
setup.Origin,
|
||||
setup.Name,
|
||||
setup.BuildDisableRepos)
|
||||
setup.Name)
|
||||
msg = msg + ObsWebHost + "/project/show/" +
|
||||
stagingProject + ":" + setup.Name + "\n"
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ const (
|
||||
AppName = "obs-status-service"
|
||||
)
|
||||
|
||||
|
||||
var obs *common.ObsClient
|
||||
|
||||
type RepoBuildCounters struct {
|
||||
@@ -271,8 +272,7 @@ func main() {
|
||||
res.WriteHeader(500)
|
||||
return
|
||||
}
|
||||
res.WriteHeader(404)
|
||||
res.Write([]byte("404 page not found\n"))
|
||||
http.ServeFile(res, req, "static/index.html")
|
||||
})
|
||||
http.HandleFunc("GET /status/{Project}", func(res http.ResponseWriter, req *http.Request) {
|
||||
mime := ParseMimeHeader(req)
|
||||
|
||||
100
obs-status-service/static/index.html
Normal file
100
obs-status-service/static/index.html
Normal file
@@ -0,0 +1,100 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>openSUSE OBS Status Service</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: sans-serif;
|
||||
max-width: 900px;
|
||||
margin: auto;
|
||||
padding: 20px;
|
||||
}
|
||||
input {
|
||||
width: 100%;
|
||||
margin: 6px 0;
|
||||
padding: 6px;
|
||||
}
|
||||
button {
|
||||
padding: 6px 12px;
|
||||
margin-top: 8px;
|
||||
}
|
||||
pre {
|
||||
background: #f5f5f5;
|
||||
padding: 10px;
|
||||
overflow-x: auto;
|
||||
}
|
||||
img {
|
||||
margin-top: 10px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>OBS Status Service</h1>
|
||||
|
||||
<p>
|
||||
This service reports build results from the openSUSE Build Service (OBS)
|
||||
as easily embeddable SVG images. Repository build results are cached to
|
||||
provide low-overhead access.
|
||||
</p>
|
||||
|
||||
<h2>Usage</h2>
|
||||
|
||||
<p>Requests for individual build results:</p>
|
||||
<pre>/status/obs:project/package/repo/arch</pre>
|
||||
<p><em>package, repo and arch are optional.</em></p>
|
||||
|
||||
<p>Requests for project results:</p>
|
||||
<pre>/status/obs:project</pre>
|
||||
|
||||
<p>
|
||||
By default, SVG output is generated. JSON and XML output are available
|
||||
by setting the <code>Accept</code> request header.
|
||||
</p>
|
||||
|
||||
<h2>Generate Build Result Image</h2>
|
||||
|
||||
<label>Project (required)</label>
|
||||
<input id="project" placeholder="devel:languages:python:Factory">
|
||||
|
||||
<label>Package (optional)</label>
|
||||
<input id="package" placeholder="python313">
|
||||
|
||||
<label>Repo & Arch (optional)</label>
|
||||
<input id="repo" placeholder="openSUSE_Tumbleweed/x86_64">
|
||||
|
||||
<button onclick="generate()">Generate</button>
|
||||
|
||||
<h3>Link</h3>
|
||||
<pre id="link"></pre>
|
||||
|
||||
<h3>Markdown</h3>
|
||||
<pre id="markdown"></pre>
|
||||
|
||||
<h3>Preview</h3>
|
||||
<img id="preview" alt="Build status preview">
|
||||
|
||||
<script>
|
||||
function generate() {
|
||||
const project = document.getElementById("project").value.trim();
|
||||
const pkg = document.getElementById("package").value.trim();
|
||||
const repo = document.getElementById("repo").value.trim();
|
||||
|
||||
if (!project) {
|
||||
alert("Project is required");
|
||||
return;
|
||||
}
|
||||
|
||||
let url = "https://br.opensuse.org/status/" + project;
|
||||
if (pkg) url += "/" + pkg;
|
||||
if (repo) url += "/" + repo;
|
||||
|
||||
document.getElementById("link").textContent = url;
|
||||
document.getElementById("markdown").textContent =
|
||||
"";
|
||||
document.getElementById("preview").src = url;
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,98 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"slices"
|
||||
|
||||
"src.opensuse.org/autogits/common"
|
||||
)
|
||||
|
||||
func WriteNewMaintainershipFile(m *common.MaintainershipMap, filename string) {
|
||||
f, err := os.Create(filename + ".new")
|
||||
common.PanicOnError(err)
|
||||
common.PanicOnError(m.WriteMaintainershipFile(f))
|
||||
common.PanicOnError(f.Sync())
|
||||
common.PanicOnError(f.Close())
|
||||
common.PanicOnError(os.Rename(filename+".new", filename))
|
||||
}
|
||||
|
||||
func run() error {
|
||||
pkg := flag.String("package", "", "Package to modify")
|
||||
rm := flag.Bool("rm", false, "Remove maintainer from package")
|
||||
add := flag.Bool("add", false, "Add maintainer to package")
|
||||
lint := flag.Bool("lint-only", false, "Reformat entire _maintainership.json only")
|
||||
flag.Parse()
|
||||
|
||||
if (*add == *rm) && !*lint {
|
||||
return fmt.Errorf("Need to either add or remove a maintainer, or lint")
|
||||
}
|
||||
|
||||
filename := common.MaintainershipFile
|
||||
if *lint {
|
||||
if len(flag.Args()) > 0 {
|
||||
filename = flag.Arg(0)
|
||||
}
|
||||
}
|
||||
|
||||
data, err := os.ReadFile(filename)
|
||||
if os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
m, err := common.ParseMaintainershipData(data)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to parse JSON: %w", err)
|
||||
}
|
||||
|
||||
if *lint {
|
||||
m.Raw = nil // forces a rewrite
|
||||
} else {
|
||||
users := flag.Args()
|
||||
if len(users) > 0 {
|
||||
maintainers, ok := m.Data[*pkg]
|
||||
if !ok && !*add {
|
||||
return fmt.Errorf("No package %s and not adding one.", *pkg)
|
||||
}
|
||||
|
||||
if *add {
|
||||
for _, u := range users {
|
||||
if !slices.Contains(maintainers, u) {
|
||||
maintainers = append(maintainers, u)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if *rm {
|
||||
newMaintainers := make([]string, 0, len(maintainers))
|
||||
for _, m := range maintainers {
|
||||
if !slices.Contains(users, m) {
|
||||
newMaintainers = append(newMaintainers, m)
|
||||
}
|
||||
}
|
||||
maintainers = newMaintainers
|
||||
}
|
||||
|
||||
if len(maintainers) > 0 {
|
||||
slices.Sort(maintainers)
|
||||
m.Data[*pkg] = maintainers
|
||||
} else {
|
||||
delete(m.Data, *pkg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WriteNewMaintainershipFile(m, filename)
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
if err := run(); err != nil {
|
||||
common.LogError(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
@@ -1,242 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"os"
|
||||
"os/exec"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"src.opensuse.org/autogits/common"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
if os.Getenv("BE_MAIN") == "1" {
|
||||
main()
|
||||
return
|
||||
}
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
func TestRun(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
inData string
|
||||
expectedOut string
|
||||
params []string
|
||||
expectedError string
|
||||
isDir bool
|
||||
}{
|
||||
{
|
||||
name: "add user to existing package",
|
||||
inData: `{"pkg1": ["user1"]}`,
|
||||
params: []string{"-package", "pkg1", "-add", "user2"},
|
||||
expectedOut: `{"pkg1": ["user1", "user2"]}`,
|
||||
},
|
||||
{
|
||||
name: "add user to new package",
|
||||
inData: `{"pkg1": ["user1"]}`,
|
||||
params: []string{"-package", "pkg2", "-add", "user2"},
|
||||
expectedOut: `{"pkg1": ["user1"], "pkg2": ["user2"]}`,
|
||||
},
|
||||
{
|
||||
name: "no-op with no users",
|
||||
inData: `{"pkg1": ["user1"]}`,
|
||||
params: []string{"-package", "pkg1", "-add"},
|
||||
expectedOut: `{"pkg1": ["user1"]}`,
|
||||
},
|
||||
{
|
||||
name: "add existing user",
|
||||
inData: `{"pkg1": ["user1", "user2"]}`,
|
||||
params: []string{"-package", "pkg1", "-add", "user2"},
|
||||
expectedOut: `{"pkg1": ["user1", "user2"]}`,
|
||||
},
|
||||
{
|
||||
name: "remove user from package",
|
||||
inData: `{"pkg1": ["user1", "user2"]}`,
|
||||
params: []string{"-package", "pkg1", "-rm", "user2"},
|
||||
expectedOut: `{"pkg1": ["user1"]}`,
|
||||
},
|
||||
{
|
||||
name: "remove last user from package",
|
||||
inData: `{"pkg1": ["user1"]}`,
|
||||
params: []string{"-package", "pkg1", "-rm", "user1"},
|
||||
expectedOut: `{}`,
|
||||
},
|
||||
{
|
||||
name: "remove non-existent user",
|
||||
inData: `{"pkg1": ["user1"]}`,
|
||||
params: []string{"-package", "pkg1", "-rm", "user2"},
|
||||
expectedOut: `{"pkg1": ["user1"]}`,
|
||||
},
|
||||
{
|
||||
name: "lint only unsorted",
|
||||
inData: `{"pkg1": ["user2", "user1"]}`,
|
||||
params: []string{"-lint-only"},
|
||||
expectedOut: `{"pkg1": ["user1", "user2"]}`,
|
||||
},
|
||||
{
|
||||
name: "lint only no changes",
|
||||
inData: `{"pkg1": ["user1", "user2"]}`,
|
||||
params: []string{"-lint-only"},
|
||||
expectedOut: `{"pkg1": ["user1", "user2"]}`,
|
||||
},
|
||||
{
|
||||
name: "no file",
|
||||
params: []string{"-add"},
|
||||
expectedError: "no such file or directory",
|
||||
},
|
||||
{
|
||||
name: "invalid json",
|
||||
inData: `{"pkg1": ["user1"`,
|
||||
params: []string{"-add"},
|
||||
expectedError: "Failed to parse JSON",
|
||||
},
|
||||
{
|
||||
name: "add",
|
||||
inData: `{"pkg1": ["user1", "user2"]}`,
|
||||
params: []string{"-package", "pkg1", "-add", "user3"},
|
||||
expectedOut: `{"pkg1": ["user1", "user2", "user3"]}`,
|
||||
},
|
||||
{
|
||||
name: "lint specific file",
|
||||
inData: `{"pkg1": ["user2", "user1"]}`,
|
||||
params: []string{"-lint-only", "other.json"},
|
||||
expectedOut: `{"pkg1": ["user1", "user2"]}`,
|
||||
},
|
||||
{
|
||||
name: "add user to package when it was not there before",
|
||||
inData: `{}`,
|
||||
params: []string{"-package", "newpkg", "-add", "user1"},
|
||||
expectedOut: `{"newpkg": ["user1"]}`,
|
||||
},
|
||||
{
|
||||
name: "unreadable file (is a directory)",
|
||||
isDir: true,
|
||||
params: []string{"-rm"},
|
||||
expectedError: "is a directory",
|
||||
},
|
||||
{
|
||||
name: "remove user from non-existent package",
|
||||
inData: `{"pkg1": ["user1"]}`,
|
||||
params: []string{"-package", "pkg2", "-rm", "user2"},
|
||||
expectedError: "No package pkg2 and not adding one.",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
oldWd, _ := os.Getwd()
|
||||
_ = os.Chdir(dir)
|
||||
defer os.Chdir(oldWd)
|
||||
|
||||
targetFile := common.MaintainershipFile
|
||||
if tt.name == "lint specific file" {
|
||||
targetFile = "other.json"
|
||||
}
|
||||
|
||||
if tt.isDir {
|
||||
_ = os.Mkdir(targetFile, 0755)
|
||||
} else if tt.inData != "" {
|
||||
_ = os.WriteFile(targetFile, []byte(tt.inData), 0644)
|
||||
}
|
||||
|
||||
flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ContinueOnError)
|
||||
|
||||
os.Args = append([]string{"cmd"}, tt.params...)
|
||||
err := run()
|
||||
|
||||
if tt.expectedError != "" {
|
||||
if err == nil {
|
||||
t.Fatalf("expected error containing %q, but got none", tt.expectedError)
|
||||
}
|
||||
if !strings.Contains(err.Error(), tt.expectedError) {
|
||||
t.Fatalf("expected error containing %q, got %q", tt.expectedError, err.Error())
|
||||
}
|
||||
} else if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if tt.expectedOut != "" {
|
||||
data, _ := os.ReadFile(targetFile)
|
||||
var got, expected map[string][]string
|
||||
_ = json.Unmarshal(data, &got)
|
||||
_ = json.Unmarshal([]byte(tt.expectedOut), &expected)
|
||||
|
||||
if len(got) == 0 && len(expected) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(got, expected) {
|
||||
t.Fatalf("expected %v, got %v", expected, got)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMainRecursive(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
inData string
|
||||
expectedOut string
|
||||
params []string
|
||||
expectExit bool
|
||||
}{
|
||||
{
|
||||
name: "test main() via recursive call",
|
||||
inData: `{"pkg1": ["user1"]}`,
|
||||
params: []string{"-package", "pkg1", "-add", "user2"},
|
||||
expectedOut: `{"pkg1": ["user1", "user2"]}`,
|
||||
},
|
||||
{
|
||||
name: "test main() failure",
|
||||
params: []string{"-package", "pkg1"},
|
||||
expectExit: true,
|
||||
},
|
||||
}
|
||||
|
||||
exe, _ := os.Executable()
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
oldWd, _ := os.Getwd()
|
||||
_ = os.Chdir(dir)
|
||||
defer os.Chdir(oldWd)
|
||||
|
||||
if tt.inData != "" {
|
||||
_ = os.WriteFile(common.MaintainershipFile, []byte(tt.inData), 0644)
|
||||
}
|
||||
|
||||
cmd := exec.Command(exe, append([]string{"-test.run=None"}, tt.params...)...)
|
||||
cmd.Env = append(os.Environ(), "BE_MAIN=1")
|
||||
out, runErr := cmd.CombinedOutput()
|
||||
|
||||
if tt.expectExit {
|
||||
if runErr == nil {
|
||||
t.Fatalf("expected exit with error, but it succeeded")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if runErr != nil {
|
||||
t.Fatalf("unexpected error: %v: %s", runErr, string(out))
|
||||
}
|
||||
|
||||
if tt.expectedOut != "" {
|
||||
data, _ := os.ReadFile(common.MaintainershipFile)
|
||||
var got, expected map[string][]string
|
||||
_ = json.Unmarshal(data, &got)
|
||||
_ = json.Unmarshal([]byte(tt.expectedOut), &expected)
|
||||
|
||||
if !reflect.DeepEqual(got, expected) {
|
||||
t.Fatalf("expected %v, got %v", expected, got)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -52,7 +52,7 @@ Config file
|
||||
| *GitProjectName* | Repository and branch where the ProjectGit lives. | no | string | **Format**: `org/project_repo#branch` | By default assumes `_ObsPrj` with default branch in the *Organization* |
|
||||
| *ManualMergeOnly* | Merges are permitted only upon receiving a "merge ok" comment from designated maintainers in the PkgGit PR. | no | bool | true, false | false |
|
||||
| *ManualMergeProject* | Merges are permitted only upon receiving a "merge ok" comment in the ProjectGit PR from project maintainers. | no | bool | true, false | false |
|
||||
| *ReviewRequired* | If submitter is a maintainer, require review from another maintainer if available. | no | bool | true, false | false |
|
||||
| *ReviewRequired* | (NOT IMPLEMENTED) If submitter is a maintainer, require review from another maintainer if available. | no | bool | true, false | false |
|
||||
| *NoProjectGitPR* | Do not create PrjGit PR, but still perform other tasks. | no | bool | true, false | false |
|
||||
| *Reviewers* | PrjGit reviewers. Additional review requests are triggered for associated PkgGit PRs. PrjGit PR is merged only when all reviews are complete. | no | array of strings | | `[]` |
|
||||
| *ReviewGroups* | If a group is specified in Reviewers, its members are listed here. | no | array of objects | | `[]` |
|
||||
@@ -160,4 +160,4 @@ Server configuration
|
||||
|
||||
| Field | Type | Notes |
|
||||
| ----- | ----- | ----- |
|
||||
| root | Array of string | Format **org/repo\#branch** |
|
||||
| root | Array of string | Format **org/repo\#branch** |
|
||||
18
workflow-pr/interfaces/state_checker.go
Normal file
18
workflow-pr/interfaces/state_checker.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package interfaces
|
||||
|
||||
import "src.opensuse.org/autogits/common"
|
||||
|
||||
//go:generate mockgen -source=state_checker.go -destination=../mock/state_checker.go -typed -package mock_main
|
||||
|
||||
|
||||
type StateChecker interface {
|
||||
VerifyProjectState(configs *common.AutogitConfig) ([]*PRToProcess, error)
|
||||
CheckRepos()
|
||||
ConsistencyCheckProcess() error
|
||||
}
|
||||
|
||||
type PRToProcess struct {
|
||||
Org, Repo, Branch string
|
||||
}
|
||||
|
||||
|
||||
@@ -2,8 +2,10 @@ package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -20,6 +22,83 @@ func TestProjectBranchName(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
const LocalCMD = "---"
|
||||
|
||||
func gitExecs(t *testing.T, git *common.GitHandlerImpl, cmds [][]string) {
|
||||
for _, cmd := range cmds {
|
||||
if cmd[0] == LocalCMD {
|
||||
command := exec.Command(cmd[2], cmd[3:]...)
|
||||
command.Dir = filepath.Join(git.GitPath, cmd[1])
|
||||
command.Stdin = nil
|
||||
command.Env = append([]string{"GIT_CONFIG_COUNT=1", "GIT_CONFIG_KEY_1=protocol.file.allow", "GIT_CONFIG_VALUE_1=always"}, common.ExtraGitParams...)
|
||||
_, err := command.CombinedOutput()
|
||||
if err != nil {
|
||||
t.Errorf(" *** error: %v\n", err)
|
||||
}
|
||||
} else {
|
||||
git.GitExecOrPanic(cmd[0], cmd[1:]...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func commandsForPackages(dir, prefix string, startN, endN int) [][]string {
|
||||
commands := make([][]string, (endN-startN+2)*6)
|
||||
|
||||
if dir == "" {
|
||||
dir = "."
|
||||
}
|
||||
cmdIdx := 0
|
||||
for idx := startN; idx <= endN; idx++ {
|
||||
pkgDir := fmt.Sprintf("%s%d", prefix, idx)
|
||||
|
||||
commands[cmdIdx+0] = []string{"", "init", "-q", "--object-format", "sha256", "-b", "testing", pkgDir}
|
||||
commands[cmdIdx+1] = []string{LocalCMD, pkgDir, "/usr/bin/touch", "testFile"}
|
||||
commands[cmdIdx+2] = []string{pkgDir, "add", "testFile"}
|
||||
commands[cmdIdx+3] = []string{pkgDir, "commit", "-m", "added testFile"}
|
||||
commands[cmdIdx+4] = []string{pkgDir, "config", "receive.denyCurrentBranch", "ignore"}
|
||||
commands[cmdIdx+5] = []string{"prj", "submodule", "add", filepath.Join("..", pkgDir), filepath.Join(dir, pkgDir)}
|
||||
|
||||
cmdIdx += 6
|
||||
}
|
||||
|
||||
// add all the submodules to the prj
|
||||
commands[cmdIdx+0] = []string{"prj", "commit", "-a", "-m", "adding subpackages"}
|
||||
|
||||
return commands
|
||||
}
|
||||
|
||||
func setupGitForTests(t *testing.T, git *common.GitHandlerImpl) {
|
||||
common.ExtraGitParams = []string{
|
||||
"GIT_CONFIG_COUNT=1",
|
||||
"GIT_CONFIG_KEY_0=protocol.file.allow",
|
||||
"GIT_CONFIG_VALUE_0=always",
|
||||
|
||||
"GIT_AUTHOR_NAME=testname",
|
||||
"GIT_AUTHOR_EMAIL=test@suse.com",
|
||||
"GIT_AUTHOR_DATE='2005-04-07T22:13:13'",
|
||||
"GIT_COMMITTER_NAME=testname",
|
||||
"GIT_COMMITTER_EMAIL=test@suse.com",
|
||||
"GIT_COMMITTER_DATE='2005-04-07T22:13:13'",
|
||||
}
|
||||
|
||||
gitExecs(t, git, [][]string{
|
||||
{"", "init", "-q", "--object-format", "sha256", "-b", "testing", "prj"},
|
||||
{"", "init", "-q", "--object-format", "sha256", "-b", "testing", "foo"},
|
||||
{LocalCMD, "foo", "/usr/bin/touch", "file1"},
|
||||
{"foo", "add", "file1"},
|
||||
{"foo", "commit", "-m", "first commit"},
|
||||
{"prj", "config", "receive.denyCurrentBranch", "ignore"},
|
||||
{"prj", "submodule", "init"},
|
||||
{"prj", "submodule", "add", "../foo", "testRepo"},
|
||||
{"prj", "add", ".gitmodules", "testRepo"},
|
||||
{"prj", "commit", "-m", "First instance"},
|
||||
{"prj", "submodule", "deinit", "testRepo"},
|
||||
{LocalCMD, "foo", "/usr/bin/touch", "file2"},
|
||||
{"foo", "add", "file2"},
|
||||
{"foo", "commit", "-m", "added file2"},
|
||||
})
|
||||
}
|
||||
|
||||
func TestUpdatePrBranch(t *testing.T) {
|
||||
var buf bytes.Buffer
|
||||
origLogger := log.Writer()
|
||||
@@ -46,7 +125,7 @@ func TestUpdatePrBranch(t *testing.T) {
|
||||
req.Pull_Request.Base.Sha = strings.TrimSpace(revs[1])
|
||||
req.Pull_Request.Head.Sha = strings.TrimSpace(revs[0])
|
||||
|
||||
updateSubmoduleInPR("testRepo", revs[0], git)
|
||||
updateSubmoduleInPR("mainRepo", revs[0], git)
|
||||
common.PanicOnError(git.GitExec(common.DefaultGitPrj, "commit", "-a", "-m", "created commit"))
|
||||
common.PanicOnError(git.GitExec(common.DefaultGitPrj, "push", "origin", "+HEAD:+testing"))
|
||||
git.GitExecOrPanic("prj", "reset", "--hard", "testing")
|
||||
|
||||
10
workflow-pr/mock/pr_processor.go
Normal file
10
workflow-pr/mock/pr_processor.go
Normal file
@@ -0,0 +1,10 @@
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: pr_processor.go
|
||||
//
|
||||
// Generated by this command:
|
||||
//
|
||||
// mockgen -source=pr_processor.go -destination=mock/pr_processor.go -typed
|
||||
//
|
||||
|
||||
// Package mock_main is a generated GoMock package.
|
||||
package mock_main
|
||||
@@ -3,18 +3,18 @@
|
||||
//
|
||||
// Generated by this command:
|
||||
//
|
||||
// mockgen -source=state_checker.go -destination=mock_state_checker.go -typed -package main
|
||||
// mockgen -source=state_checker.go -destination=../mock/state_checker.go -typed -package mock_main
|
||||
//
|
||||
|
||||
// Package main is a generated GoMock package.
|
||||
package main
|
||||
// Package mock_main is a generated GoMock package.
|
||||
package mock_main
|
||||
|
||||
import (
|
||||
reflect "reflect"
|
||||
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
common "src.opensuse.org/autogits/common"
|
||||
models "src.opensuse.org/autogits/common/gitea-generated/models"
|
||||
interfaces "src.opensuse.org/autogits/workflow-pr/interfaces"
|
||||
)
|
||||
|
||||
// MockStateChecker is a mock of StateChecker interface.
|
||||
@@ -42,9 +42,11 @@ func (m *MockStateChecker) EXPECT() *MockStateCheckerMockRecorder {
|
||||
}
|
||||
|
||||
// CheckRepos mocks base method.
|
||||
func (m *MockStateChecker) CheckRepos() {
|
||||
func (m *MockStateChecker) CheckRepos() error {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "CheckRepos")
|
||||
ret := m.ctrl.Call(m, "CheckRepos")
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// CheckRepos indicates an expected call of CheckRepos.
|
||||
@@ -60,19 +62,19 @@ type MockStateCheckerCheckReposCall struct {
|
||||
}
|
||||
|
||||
// Return rewrite *gomock.Call.Return
|
||||
func (c *MockStateCheckerCheckReposCall) Return() *MockStateCheckerCheckReposCall {
|
||||
c.Call = c.Call.Return()
|
||||
func (c *MockStateCheckerCheckReposCall) Return(arg0 error) *MockStateCheckerCheckReposCall {
|
||||
c.Call = c.Call.Return(arg0)
|
||||
return c
|
||||
}
|
||||
|
||||
// Do rewrite *gomock.Call.Do
|
||||
func (c *MockStateCheckerCheckReposCall) Do(f func()) *MockStateCheckerCheckReposCall {
|
||||
func (c *MockStateCheckerCheckReposCall) Do(f func() error) *MockStateCheckerCheckReposCall {
|
||||
c.Call = c.Call.Do(f)
|
||||
return c
|
||||
}
|
||||
|
||||
// DoAndReturn rewrite *gomock.Call.DoAndReturn
|
||||
func (c *MockStateCheckerCheckReposCall) DoAndReturn(f func()) *MockStateCheckerCheckReposCall {
|
||||
func (c *MockStateCheckerCheckReposCall) DoAndReturn(f func() error) *MockStateCheckerCheckReposCall {
|
||||
c.Call = c.Call.DoAndReturn(f)
|
||||
return c
|
||||
}
|
||||
@@ -116,10 +118,10 @@ func (c *MockStateCheckerConsistencyCheckProcessCall) DoAndReturn(f func() error
|
||||
}
|
||||
|
||||
// VerifyProjectState mocks base method.
|
||||
func (m *MockStateChecker) VerifyProjectState(configs *common.AutogitConfig) ([]*PRToProcess, error) {
|
||||
func (m *MockStateChecker) VerifyProjectState(configs *common.AutogitConfig) ([]*interfaces.PRToProcess, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "VerifyProjectState", configs)
|
||||
ret0, _ := ret[0].([]*PRToProcess)
|
||||
ret0, _ := ret[0].([]*interfaces.PRToProcess)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
@@ -137,81 +139,19 @@ type MockStateCheckerVerifyProjectStateCall struct {
|
||||
}
|
||||
|
||||
// Return rewrite *gomock.Call.Return
|
||||
func (c *MockStateCheckerVerifyProjectStateCall) Return(arg0 []*PRToProcess, arg1 error) *MockStateCheckerVerifyProjectStateCall {
|
||||
func (c *MockStateCheckerVerifyProjectStateCall) Return(arg0 []*interfaces.PRToProcess, arg1 error) *MockStateCheckerVerifyProjectStateCall {
|
||||
c.Call = c.Call.Return(arg0, arg1)
|
||||
return c
|
||||
}
|
||||
|
||||
// Do rewrite *gomock.Call.Do
|
||||
func (c *MockStateCheckerVerifyProjectStateCall) Do(f func(*common.AutogitConfig) ([]*PRToProcess, error)) *MockStateCheckerVerifyProjectStateCall {
|
||||
func (c *MockStateCheckerVerifyProjectStateCall) Do(f func(*common.AutogitConfig) ([]*interfaces.PRToProcess, error)) *MockStateCheckerVerifyProjectStateCall {
|
||||
c.Call = c.Call.Do(f)
|
||||
return c
|
||||
}
|
||||
|
||||
// DoAndReturn rewrite *gomock.Call.DoAndReturn
|
||||
func (c *MockStateCheckerVerifyProjectStateCall) DoAndReturn(f func(*common.AutogitConfig) ([]*PRToProcess, error)) *MockStateCheckerVerifyProjectStateCall {
|
||||
c.Call = c.Call.DoAndReturn(f)
|
||||
return c
|
||||
}
|
||||
|
||||
// MockPullRequestProcessor is a mock of PullRequestProcessor interface.
|
||||
type MockPullRequestProcessor struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockPullRequestProcessorMockRecorder
|
||||
isgomock struct{}
|
||||
}
|
||||
|
||||
// MockPullRequestProcessorMockRecorder is the mock recorder for MockPullRequestProcessor.
|
||||
type MockPullRequestProcessorMockRecorder struct {
|
||||
mock *MockPullRequestProcessor
|
||||
}
|
||||
|
||||
// NewMockPullRequestProcessor creates a new mock instance.
|
||||
func NewMockPullRequestProcessor(ctrl *gomock.Controller) *MockPullRequestProcessor {
|
||||
mock := &MockPullRequestProcessor{ctrl: ctrl}
|
||||
mock.recorder = &MockPullRequestProcessorMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockPullRequestProcessor) EXPECT() *MockPullRequestProcessorMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// Process mocks base method.
|
||||
func (m *MockPullRequestProcessor) Process(req *models.PullRequest) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Process", req)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Process indicates an expected call of Process.
|
||||
func (mr *MockPullRequestProcessorMockRecorder) Process(req any) *MockPullRequestProcessorProcessCall {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Process", reflect.TypeOf((*MockPullRequestProcessor)(nil).Process), req)
|
||||
return &MockPullRequestProcessorProcessCall{Call: call}
|
||||
}
|
||||
|
||||
// MockPullRequestProcessorProcessCall wrap *gomock.Call
|
||||
type MockPullRequestProcessorProcessCall struct {
|
||||
*gomock.Call
|
||||
}
|
||||
|
||||
// Return rewrite *gomock.Call.Return
|
||||
func (c *MockPullRequestProcessorProcessCall) Return(arg0 error) *MockPullRequestProcessorProcessCall {
|
||||
c.Call = c.Call.Return(arg0)
|
||||
return c
|
||||
}
|
||||
|
||||
// Do rewrite *gomock.Call.Do
|
||||
func (c *MockPullRequestProcessorProcessCall) Do(f func(*models.PullRequest) error) *MockPullRequestProcessorProcessCall {
|
||||
c.Call = c.Call.Do(f)
|
||||
return c
|
||||
}
|
||||
|
||||
// DoAndReturn rewrite *gomock.Call.DoAndReturn
|
||||
func (c *MockPullRequestProcessorProcessCall) DoAndReturn(f func(*models.PullRequest) error) *MockPullRequestProcessorProcessCall {
|
||||
func (c *MockStateCheckerVerifyProjectStateCall) DoAndReturn(f func(*common.AutogitConfig) ([]*interfaces.PRToProcess, error)) *MockStateCheckerVerifyProjectStateCall {
|
||||
c.Call = c.Call.DoAndReturn(f)
|
||||
return c
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
package main
|
||||
|
||||
//go:generate mockgen -source=pr_processor.go -destination=mock/pr_processor.go -typed
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
@@ -24,7 +26,6 @@ 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)
|
||||
|
||||
prefix := ""
|
||||
for _, pr := range prset.PRs {
|
||||
if prset.IsPrjGitPR(pr.PR) {
|
||||
continue
|
||||
@@ -33,9 +34,6 @@ func PrjGitDescription(prset *common.PRSet) (title string, desc string) {
|
||||
// remove PRs that are not open from description
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(pr.PR.Title, "WIP:") {
|
||||
prefix = "WIP: "
|
||||
}
|
||||
org, repo, idx := pr.PRComponents()
|
||||
|
||||
title_refs = append(title_refs, repo)
|
||||
@@ -46,7 +44,7 @@ func PrjGitDescription(prset *common.PRSet) (title string, desc string) {
|
||||
slices.Sort(title_refs)
|
||||
slices.Sort(refs)
|
||||
|
||||
title = prefix + "Forwarded PRs: " + strings.Join(title_refs, ", ")
|
||||
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 {
|
||||
@@ -291,9 +289,6 @@ func (pr *PRProcessor) UpdatePrjGitPR(prset *common.PRSet) error {
|
||||
|
||||
git := pr.git
|
||||
if len(prset.PRs) == 1 {
|
||||
if len(PrjGitPR.RemoteName) == 0 {
|
||||
PrjGitPR.RemoteName, _ = git.GitClone(common.DefaultGitPrj, "", PrjGitPR.PR.Base.Repo.SSHURL)
|
||||
}
|
||||
git.GitExecOrPanic(common.DefaultGitPrj, "fetch", PrjGitPR.RemoteName, PrjGitPR.PR.Head.Sha)
|
||||
common.LogDebug("Only project git in PR. Nothing to update.")
|
||||
return nil
|
||||
@@ -505,7 +500,7 @@ func (pr *PRProcessor) Process(req *models.PullRequest) error {
|
||||
// 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")
|
||||
@@ -554,7 +549,7 @@ func (pr *PRProcessor) Process(req *models.PullRequest) error {
|
||||
} else {
|
||||
common.LogInfo("* No prjgit")
|
||||
}
|
||||
maintainers, err := common.FetchProjectMaintainershipData(Gitea, config)
|
||||
maintainers, err := common.FetchProjectMaintainershipData(Gitea, org, repo, branch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -605,7 +600,7 @@ func (pr *PRProcessor) Process(req *models.PullRequest) error {
|
||||
common.LogError("merge error:", err)
|
||||
}
|
||||
} else {
|
||||
err = prset.AssignReviewers(Gitea, maintainers)
|
||||
prset.AssignReviewers(Gitea, maintainers)
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -631,15 +626,6 @@ func ProcesPullRequest(pr *models.PullRequest, configs []*common.AutogitConfig)
|
||||
return PRProcessor.Process(pr)
|
||||
}
|
||||
|
||||
func (w *RequestProcessor) Process(pr *models.PullRequest) error {
|
||||
configs, ok := w.configuredRepos[pr.Base.Repo.Owner.UserName]
|
||||
if !ok {
|
||||
common.LogError("*** Cannot find config for org:", pr.Base.Repo.Owner.UserName)
|
||||
return fmt.Errorf("*** Cannot find config for org: %s", pr.Base.Repo.Owner.UserName)
|
||||
}
|
||||
return ProcesPullRequest(pr, configs)
|
||||
}
|
||||
|
||||
func (w *RequestProcessor) ProcessFunc(request *common.Request) (err error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
|
||||
"go.uber.org/mock/gomock"
|
||||
"src.opensuse.org/autogits/common"
|
||||
"src.opensuse.org/autogits/common/gitea-generated/client/repository"
|
||||
"src.opensuse.org/autogits/common/gitea-generated/models"
|
||||
mock_common "src.opensuse.org/autogits/common/mock"
|
||||
)
|
||||
@@ -16,7 +17,7 @@ func TestOpenPR(t *testing.T) {
|
||||
Reviewers: []string{"reviewer1", "reviewer2"},
|
||||
Branch: "branch",
|
||||
Organization: "test",
|
||||
GitProjectName: "prj#testing",
|
||||
GitProjectName: "prj",
|
||||
},
|
||||
}
|
||||
|
||||
@@ -25,7 +26,6 @@ func TestOpenPR(t *testing.T) {
|
||||
Number: 1,
|
||||
Pull_Request: &common.PullRequest{
|
||||
Id: 1,
|
||||
Number: 1,
|
||||
Base: common.Head{
|
||||
Ref: "branch",
|
||||
Sha: "testing",
|
||||
@@ -53,56 +53,6 @@ func TestOpenPR(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
modelPR := &models.PullRequest{
|
||||
ID: 1,
|
||||
Index: 1,
|
||||
State: "open",
|
||||
User: &models.User{UserName: "testuser"},
|
||||
RequestedReviewers: []*models.User{},
|
||||
Base: &models.PRBranchInfo{
|
||||
Ref: "branch",
|
||||
Sha: "testing",
|
||||
Repo: &models.Repository{
|
||||
Name: "testRepo",
|
||||
Owner: &models.User{
|
||||
UserName: "test",
|
||||
},
|
||||
},
|
||||
},
|
||||
Head: &models.PRBranchInfo{
|
||||
Ref: "branch",
|
||||
Sha: "testing",
|
||||
Repo: &models.Repository{
|
||||
Name: "testRepo",
|
||||
Owner: &models.User{
|
||||
UserName: "test",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
mockCreatePR := &models.PullRequest{
|
||||
ID: 2,
|
||||
Index: 2,
|
||||
Body: "Forwarded PRs: testRepo\n\nPR: test/testRepo!1",
|
||||
User: &models.User{UserName: "testuser"},
|
||||
RequestedReviewers: []*models.User{},
|
||||
Base: &models.PRBranchInfo{
|
||||
Name: "testing",
|
||||
Repo: &models.Repository{
|
||||
Name: "prjcopy",
|
||||
Owner: &models.User{UserName: "test"},
|
||||
},
|
||||
},
|
||||
Head: &models.PRBranchInfo{
|
||||
Sha: "head",
|
||||
},
|
||||
}
|
||||
|
||||
CurrentUser = &models.User{
|
||||
UserName: "testuser",
|
||||
}
|
||||
|
||||
git := &common.GitHandlerImpl{
|
||||
GitCommiter: "tester",
|
||||
GitEmail: "test@suse.com",
|
||||
@@ -110,47 +60,14 @@ func TestOpenPR(t *testing.T) {
|
||||
|
||||
t.Run("PR git opened request against PrjGit == no action", func(t *testing.T) {
|
||||
ctl := gomock.NewController(t)
|
||||
gitea := mock_common.NewMockGitea(ctl)
|
||||
gitea.EXPECT().ResetTimelineCache(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes()
|
||||
Gitea = gitea
|
||||
Gitea = mock_common.NewMockGitea(ctl)
|
||||
|
||||
git.GitPath = t.TempDir()
|
||||
|
||||
pr.config.GitProjectName = "testRepo#testing"
|
||||
pr.config.GitProjectName = "testRepo"
|
||||
event.Repository.Name = "testRepo"
|
||||
mockGit := mock_common.NewMockGit(ctl)
|
||||
pr.git = mockGit
|
||||
|
||||
mockGitGen := mock_common.NewMockGitHandlerGenerator(ctl)
|
||||
GitHandler = mockGitGen
|
||||
mockGitGen.EXPECT().CreateGitHandler(gomock.Any()).Return(mockGit, nil).AnyTimes()
|
||||
|
||||
mockGit.EXPECT().GitClone(gomock.Any(), gomock.Any(), gomock.Any()).Return("origin", nil).AnyTimes()
|
||||
mockGit.EXPECT().GitBranchHead(gomock.Any(), gomock.Any()).Return("head", nil).AnyTimes()
|
||||
mockGit.EXPECT().GitSubmoduleList(gomock.Any(), gomock.Any()).Return(map[string]string{"testRepo": "testing"}, nil).AnyTimes()
|
||||
mockGit.EXPECT().GitExecOrPanic(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes()
|
||||
mockGit.EXPECT().GitCatFile(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, nil).AnyTimes()
|
||||
mockGit.EXPECT().Close().Return(nil).AnyTimes()
|
||||
|
||||
gitea.EXPECT().GetTimeline(gomock.Any(), gomock.Any(), gomock.Any()).Return([]*models.TimelineComment{}, nil).AnyTimes()
|
||||
gitea.EXPECT().GetPullRequest(gomock.Any(), gomock.Any(), gomock.Any()).Return(modelPR, nil).AnyTimes()
|
||||
gitea.EXPECT().UpdatePullRequest(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(modelPR, nil).AnyTimes()
|
||||
gitea.EXPECT().SetLabels(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]*models.Label{}, nil).AnyTimes()
|
||||
gitea.EXPECT().SetRepoOptions(gomock.Any(), gomock.Any(), gomock.Any()).Return(&models.Repository{SSHURL: "git@src.opensuse.org:test/prj.git"}, nil).AnyTimes()
|
||||
gitea.EXPECT().GetPullRequestReviews(gomock.Any(), gomock.Any(), gomock.Any()).Return([]*models.PullReview{}, nil).AnyTimes()
|
||||
gitea.EXPECT().GetRepository(gomock.Any(), gomock.Any()).Return(&models.Repository{
|
||||
Owner: &models.User{UserName: "test"},
|
||||
Name: "prjcopy",
|
||||
SSHURL: "git@src.opensuse.org:test/prj.git",
|
||||
}, nil).AnyTimes()
|
||||
|
||||
gitea.EXPECT().CreateRepositoryIfNotExist(gomock.Any(), gomock.Any(), gomock.Any()).Return(&models.Repository{SSHURL: "git@src.opensuse.org:test/prj.git"}, nil).AnyTimes()
|
||||
gitea.EXPECT().CreatePullRequestIfNotExist(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(mockCreatePR, nil, true).AnyTimes()
|
||||
gitea.EXPECT().RequestReviews(gomock.Any(), gomock.Any()).Return(nil, nil).AnyTimes()
|
||||
gitea.EXPECT().FetchMaintainershipDirFile(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, "", nil).AnyTimes()
|
||||
gitea.EXPECT().FetchMaintainershipFile(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, "", nil).AnyTimes()
|
||||
|
||||
if err := pr.Process(modelPR); err != nil {
|
||||
if err := pr.Process(event); err != nil {
|
||||
t.Error("Error PrjGit opened request. Should be no error.", err)
|
||||
}
|
||||
})
|
||||
@@ -158,52 +75,43 @@ func TestOpenPR(t *testing.T) {
|
||||
t.Run("Open PrjGit PR", func(t *testing.T) {
|
||||
ctl := gomock.NewController(t)
|
||||
gitea := mock_common.NewMockGitea(ctl)
|
||||
gitea.EXPECT().ResetTimelineCache(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes()
|
||||
|
||||
Gitea = gitea
|
||||
|
||||
event.Repository.Name = "testRepo"
|
||||
pr.config.GitProjectName = "prjcopy#testing"
|
||||
pr.config.GitProjectName = "prjcopy"
|
||||
git.GitPath = t.TempDir()
|
||||
|
||||
setupGitForTests(t, git)
|
||||
|
||||
gitea.EXPECT().CreateRepositoryIfNotExist(gomock.Any(), gomock.Any(), gomock.Any()).Return(&models.Repository{SSHURL: "git@src.opensuse.org:test/prj.git"}, nil).AnyTimes()
|
||||
gitea.EXPECT().CreatePullRequestIfNotExist(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(mockCreatePR, nil, true).AnyTimes()
|
||||
gitea.EXPECT().GetPullRequest(gomock.Any(), gomock.Any(), gomock.Any()).Return(modelPR, nil).AnyTimes()
|
||||
gitea.EXPECT().RequestReviews(gomock.Any(), gomock.Any()).Return(nil, nil).AnyTimes()
|
||||
gitea.EXPECT().GetPullRequestReviews(gomock.Any(), gomock.Any(), gomock.Any()).Return([]*models.PullReview{}, nil).AnyTimes()
|
||||
prjgit := &models.Repository{
|
||||
SSHURL: "./prj",
|
||||
DefaultBranch: "testing",
|
||||
}
|
||||
giteaPR := &models.PullRequest{
|
||||
Base: &models.PRBranchInfo{
|
||||
Repo: &models.Repository{
|
||||
Owner: &models.User{
|
||||
UserName: "test",
|
||||
},
|
||||
Name: "testRepo",
|
||||
},
|
||||
},
|
||||
User: &models.User{
|
||||
UserName: "test",
|
||||
},
|
||||
}
|
||||
// gitea.EXPECT().GetAssociatedPrjGitPR("test", "prjcopy", "test", "testRepo", int64(1)).Return(nil, nil)
|
||||
gitea.EXPECT().CreateRepositoryIfNotExist(git, "test", "prjcopy").Return(prjgit, nil)
|
||||
gitea.EXPECT().CreatePullRequestIfNotExist(prjgit, gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(giteaPR, nil, true)
|
||||
gitea.EXPECT().GetPullRequest("test", "testRepo", int64(1)).Return(giteaPR, nil)
|
||||
gitea.EXPECT().RequestReviews(giteaPR, "reviewer1", "reviewer2").Return(nil, nil)
|
||||
gitea.EXPECT().GetPullRequestReviews("test", "testRepo", int64(0)).Return([]*models.PullReview{}, nil)
|
||||
|
||||
gitea.EXPECT().FetchMaintainershipDirFile(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, "", nil).AnyTimes()
|
||||
gitea.EXPECT().FetchMaintainershipFile(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, "", nil).AnyTimes()
|
||||
gitea.EXPECT().FetchMaintainershipDirFile("test", "prjcopy", "branch", "_project").Return(nil, "", repository.NewRepoGetRawFileNotFound())
|
||||
gitea.EXPECT().FetchMaintainershipFile("test", "prjcopy", "branch").Return(nil, "", repository.NewRepoGetRawFileNotFound())
|
||||
|
||||
mockGit := mock_common.NewMockGit(ctl)
|
||||
pr.git = mockGit
|
||||
|
||||
mockGitGen := mock_common.NewMockGitHandlerGenerator(ctl)
|
||||
GitHandler = mockGitGen
|
||||
mockGitGen.EXPECT().CreateGitHandler(gomock.Any()).Return(mockGit, nil).AnyTimes()
|
||||
|
||||
mockGit.EXPECT().GitClone(gomock.Any(), gomock.Any(), gomock.Any()).Return("origin", nil).AnyTimes()
|
||||
mockGit.EXPECT().GitBranchHead(gomock.Any(), gomock.Any()).Return("head", nil).AnyTimes()
|
||||
mockGit.EXPECT().GitSubmoduleList(gomock.Any(), gomock.Any()).Return(map[string]string{"testRepo": "testing"}, nil).AnyTimes()
|
||||
mockGit.EXPECT().GitExecOrPanic(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes()
|
||||
mockGit.EXPECT().GitCatFile(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, nil).AnyTimes()
|
||||
mockGit.EXPECT().Close().Return(nil).AnyTimes()
|
||||
|
||||
gitea.EXPECT().GetTimeline(gomock.Any(), gomock.Any(), gomock.Any()).Return([]*models.TimelineComment{}, nil).AnyTimes()
|
||||
gitea.EXPECT().GetPullRequest(gomock.Any(), gomock.Any(), gomock.Any()).Return(modelPR, nil).AnyTimes()
|
||||
gitea.EXPECT().UpdatePullRequest(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(modelPR, nil).AnyTimes()
|
||||
gitea.EXPECT().SetLabels(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]*models.Label{}, nil).AnyTimes()
|
||||
gitea.EXPECT().SetRepoOptions(gomock.Any(), gomock.Any(), gomock.Any()).Return(&models.Repository{SSHURL: "git@src.opensuse.org:test/prj.git"}, nil).AnyTimes()
|
||||
gitea.EXPECT().GetPullRequestReviews(gomock.Any(), gomock.Any(), gomock.Any()).Return([]*models.PullReview{}, nil).AnyTimes()
|
||||
gitea.EXPECT().GetRepository(gomock.Any(), gomock.Any()).Return(&models.Repository{
|
||||
Owner: &models.User{UserName: "test"},
|
||||
Name: "prjcopy",
|
||||
SSHURL: "git@src.opensuse.org:test/prj.git",
|
||||
}, nil).AnyTimes()
|
||||
|
||||
err := pr.Process(modelPR)
|
||||
err := pr.Process(event)
|
||||
if err != nil {
|
||||
t.Error("error:", err)
|
||||
}
|
||||
@@ -212,61 +120,30 @@ func TestOpenPR(t *testing.T) {
|
||||
t.Run("Cannot create prjgit repository", func(t *testing.T) {
|
||||
ctl := gomock.NewController(t)
|
||||
gitea := mock_common.NewMockGitea(ctl)
|
||||
gitea.EXPECT().ResetTimelineCache(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes()
|
||||
|
||||
Gitea = gitea
|
||||
|
||||
event.Repository.Name = "testRepo"
|
||||
pr.config.GitProjectName = "prjcopy#testing"
|
||||
pr.config.GitProjectName = "prjcopy"
|
||||
git.GitPath = t.TempDir()
|
||||
|
||||
setupGitForTests(t, git)
|
||||
failedErr := errors.New("Returned error here")
|
||||
gitea.EXPECT().CreateRepositoryIfNotExist(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, failedErr).AnyTimes()
|
||||
gitea.EXPECT().CreatePullRequestIfNotExist(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(mockCreatePR, nil, true).AnyTimes()
|
||||
gitea.EXPECT().CreateRepositoryIfNotExist(git, "test", "prjcopy").Return(nil, failedErr)
|
||||
|
||||
mockGit := mock_common.NewMockGit(ctl)
|
||||
pr.git = mockGit
|
||||
|
||||
gitea.EXPECT().FetchMaintainershipDirFile(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, "", nil).AnyTimes()
|
||||
mockGitGen := mock_common.NewMockGitHandlerGenerator(ctl)
|
||||
GitHandler = mockGitGen
|
||||
mockGitGen.EXPECT().CreateGitHandler(gomock.Any()).Return(mockGit, nil).AnyTimes()
|
||||
|
||||
mockGit.EXPECT().GitClone(gomock.Any(), gomock.Any(), gomock.Any()).Return("origin", nil).AnyTimes()
|
||||
mockGit.EXPECT().GitBranchHead(gomock.Any(), gomock.Any()).Return("head", nil).AnyTimes()
|
||||
mockGit.EXPECT().GitSubmoduleList(gomock.Any(), gomock.Any()).Return(map[string]string{"testRepo": "testing"}, nil).AnyTimes()
|
||||
mockGit.EXPECT().GitExecOrPanic(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes()
|
||||
mockGit.EXPECT().GitCatFile(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, nil).AnyTimes()
|
||||
gitea.EXPECT().RequestReviews(gomock.Any(), gomock.Any()).Return(nil, nil).AnyTimes()
|
||||
mockGit.EXPECT().Close().Return(nil).AnyTimes()
|
||||
|
||||
gitea.EXPECT().GetTimeline(gomock.Any(), gomock.Any(), gomock.Any()).Return([]*models.TimelineComment{}, nil).AnyTimes()
|
||||
gitea.EXPECT().GetPullRequest(gomock.Any(), gomock.Any(), gomock.Any()).Return(modelPR, nil).AnyTimes()
|
||||
gitea.EXPECT().UpdatePullRequest(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(modelPR, nil).AnyTimes()
|
||||
gitea.EXPECT().SetLabels(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]*models.Label{}, nil).AnyTimes()
|
||||
gitea.EXPECT().SetRepoOptions(gomock.Any(), gomock.Any(), gomock.Any()).Return(&models.Repository{SSHURL: "git@src.opensuse.org:test/prj.git"}, nil).AnyTimes()
|
||||
gitea.EXPECT().GetPullRequestReviews(gomock.Any(), gomock.Any(), gomock.Any()).Return([]*models.PullReview{}, nil).AnyTimes()
|
||||
gitea.EXPECT().GetRepository(gomock.Any(), gomock.Any()).Return(&models.Repository{
|
||||
Owner: &models.User{UserName: "test"},
|
||||
Name: "prjcopy",
|
||||
SSHURL: "git@src.opensuse.org:test/prj.git",
|
||||
}, nil).AnyTimes()
|
||||
|
||||
err := pr.Process(modelPR)
|
||||
if err != nil {
|
||||
err := pr.Process(event)
|
||||
if err != failedErr {
|
||||
t.Error("error:", err)
|
||||
}
|
||||
})
|
||||
t.Run("Cannot create PR", func(t *testing.T) {
|
||||
ctl := gomock.NewController(t)
|
||||
gitea := mock_common.NewMockGitea(ctl)
|
||||
gitea.EXPECT().ResetTimelineCache(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes()
|
||||
|
||||
Gitea = gitea
|
||||
|
||||
event.Repository.Name = "testRepo"
|
||||
pr.config.GitProjectName = "prjcopy#testing"
|
||||
pr.config.GitProjectName = "prjcopy"
|
||||
git.GitPath = t.TempDir()
|
||||
|
||||
setupGitForTests(t, git)
|
||||
@@ -275,37 +152,10 @@ func TestOpenPR(t *testing.T) {
|
||||
DefaultBranch: "testing",
|
||||
}
|
||||
failedErr := errors.New("Returned error here")
|
||||
gitea.EXPECT().CreateRepositoryIfNotExist(gomock.Any(), gomock.Any(), gomock.Any()).Return(prjgit, nil).AnyTimes()
|
||||
gitea.EXPECT().CreatePullRequestIfNotExist(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, failedErr, false)
|
||||
gitea.EXPECT().CreateRepositoryIfNotExist(git, "test", "prjcopy").Return(prjgit, nil)
|
||||
gitea.EXPECT().CreatePullRequestIfNotExist(prjgit, gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, failedErr, false)
|
||||
|
||||
mockGit := mock_common.NewMockGit(ctl)
|
||||
pr.git = mockGit
|
||||
|
||||
gitea.EXPECT().RequestReviews(gomock.Any(), gomock.Any()).Return(nil, nil).AnyTimes()
|
||||
mockGitGen := mock_common.NewMockGitHandlerGenerator(ctl)
|
||||
GitHandler = mockGitGen
|
||||
mockGitGen.EXPECT().CreateGitHandler(gomock.Any()).Return(mockGit, nil).AnyTimes()
|
||||
|
||||
mockGit.EXPECT().GitClone(gomock.Any(), gomock.Any(), gomock.Any()).Return("origin", nil).AnyTimes()
|
||||
mockGit.EXPECT().GitBranchHead(gomock.Any(), gomock.Any()).Return("head", nil).AnyTimes()
|
||||
mockGit.EXPECT().GitSubmoduleList(gomock.Any(), gomock.Any()).Return(map[string]string{"testRepo": "testing"}, nil).AnyTimes()
|
||||
mockGit.EXPECT().GitExecOrPanic(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes()
|
||||
mockGit.EXPECT().GitCatFile(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, nil).AnyTimes()
|
||||
mockGit.EXPECT().Close().Return(nil).AnyTimes()
|
||||
|
||||
gitea.EXPECT().GetTimeline(gomock.Any(), gomock.Any(), gomock.Any()).Return([]*models.TimelineComment{}, nil).AnyTimes()
|
||||
gitea.EXPECT().GetPullRequest(gomock.Any(), gomock.Any(), gomock.Any()).Return(modelPR, nil).AnyTimes()
|
||||
gitea.EXPECT().UpdatePullRequest(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(modelPR, nil).AnyTimes()
|
||||
gitea.EXPECT().SetLabels(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]*models.Label{}, nil).AnyTimes()
|
||||
gitea.EXPECT().SetRepoOptions(gomock.Any(), gomock.Any(), gomock.Any()).Return(&models.Repository{SSHURL: "git@src.opensuse.org:test/prj.git"}, nil).AnyTimes()
|
||||
gitea.EXPECT().GetPullRequestReviews(gomock.Any(), gomock.Any(), gomock.Any()).Return([]*models.PullReview{}, nil).AnyTimes()
|
||||
gitea.EXPECT().GetRepository(gomock.Any(), gomock.Any()).Return(&models.Repository{
|
||||
Owner: &models.User{UserName: "test"},
|
||||
Name: "prjcopy",
|
||||
SSHURL: "git@src.opensuse.org:test/prj.git",
|
||||
}, nil).AnyTimes()
|
||||
|
||||
err := pr.Process(modelPR)
|
||||
err := pr.Process(event)
|
||||
if err != failedErr {
|
||||
t.Error("error:", err)
|
||||
}
|
||||
@@ -313,54 +163,44 @@ func TestOpenPR(t *testing.T) {
|
||||
t.Run("Open PrjGit PR", func(t *testing.T) {
|
||||
ctl := gomock.NewController(t)
|
||||
gitea := mock_common.NewMockGitea(ctl)
|
||||
gitea.EXPECT().ResetTimelineCache(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes()
|
||||
|
||||
Gitea = gitea
|
||||
|
||||
event.Repository.Name = "testRepo"
|
||||
pr.config.GitProjectName = "prjcopy#testing"
|
||||
pr.config.GitProjectName = "prjcopy"
|
||||
git.GitPath = t.TempDir()
|
||||
|
||||
setupGitForTests(t, git)
|
||||
prjgit := &models.Repository{
|
||||
Name: "SomeRepo",
|
||||
Owner: &models.User{
|
||||
UserName: "org",
|
||||
},
|
||||
SSHURL: "./prj",
|
||||
DefaultBranch: "testing",
|
||||
}
|
||||
giteaPR := &models.PullRequest{
|
||||
Base: &models.PRBranchInfo{
|
||||
Repo: prjgit,
|
||||
},
|
||||
Index: 13,
|
||||
User: &models.User{
|
||||
UserName: "test",
|
||||
},
|
||||
}
|
||||
failedErr := errors.New("Returned error here")
|
||||
// gitea.EXPECT().GetAssociatedPrjGitPR("test", "prjcopy", "test", "testRepo", int64(1)).Return(nil, nil)
|
||||
gitea.EXPECT().CreateRepositoryIfNotExist(git, "test", "prjcopy").Return(prjgit, nil)
|
||||
gitea.EXPECT().GetPullRequest("test", "testRepo", int64(1)).Return(giteaPR, nil)
|
||||
gitea.EXPECT().GetPullRequestReviews("org", "SomeRepo", int64(13)).Return([]*models.PullReview{}, nil)
|
||||
gitea.EXPECT().CreatePullRequestIfNotExist(prjgit, gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(giteaPR, nil, true)
|
||||
gitea.EXPECT().RequestReviews(giteaPR, "reviewer1", "reviewer2").Return(nil, failedErr)
|
||||
|
||||
gitea.EXPECT().CreateRepositoryIfNotExist(gomock.Any(), gomock.Any(), gomock.Any()).Return(&models.Repository{SSHURL: "git@src.opensuse.org:test/prj.git"}, nil).AnyTimes()
|
||||
gitea.EXPECT().GetPullRequest(gomock.Any(), gomock.Any(), gomock.Any()).Return(modelPR, nil).AnyTimes()
|
||||
gitea.EXPECT().GetPullRequestReviews(gomock.Any(), gomock.Any(), gomock.Any()).Return([]*models.PullReview{}, nil).AnyTimes()
|
||||
gitea.EXPECT().CreatePullRequestIfNotExist(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(mockCreatePR, nil, true).AnyTimes()
|
||||
gitea.EXPECT().RequestReviews(gomock.Any(), gomock.Any()).Return(nil, failedErr).AnyTimes()
|
||||
gitea.EXPECT().FetchMaintainershipDirFile("test", "prjcopy", "branch", "_project").Return(nil, "", repository.NewRepoGetRawFileNotFound())
|
||||
gitea.EXPECT().FetchMaintainershipFile("test", "prjcopy", "branch").Return(nil, "", repository.NewRepoGetRawFileNotFound())
|
||||
|
||||
gitea.EXPECT().FetchMaintainershipDirFile(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, "", nil).AnyTimes()
|
||||
gitea.EXPECT().FetchMaintainershipFile(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, "", nil).AnyTimes()
|
||||
|
||||
mockGit := mock_common.NewMockGit(ctl)
|
||||
pr.git = mockGit
|
||||
|
||||
mockGitGen := mock_common.NewMockGitHandlerGenerator(ctl)
|
||||
GitHandler = mockGitGen
|
||||
mockGitGen.EXPECT().CreateGitHandler(gomock.Any()).Return(mockGit, nil).AnyTimes()
|
||||
|
||||
mockGit.EXPECT().GitClone(gomock.Any(), gomock.Any(), gomock.Any()).Return("origin", nil).AnyTimes()
|
||||
mockGit.EXPECT().GitBranchHead(gomock.Any(), gomock.Any()).Return("head", nil).AnyTimes()
|
||||
mockGit.EXPECT().GitSubmoduleList(gomock.Any(), gomock.Any()).Return(map[string]string{"testRepo": "testing"}, nil).AnyTimes()
|
||||
mockGit.EXPECT().GitExecOrPanic(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes()
|
||||
mockGit.EXPECT().GitCatFile(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, nil).AnyTimes()
|
||||
mockGit.EXPECT().Close().Return(nil).AnyTimes()
|
||||
|
||||
gitea.EXPECT().GetTimeline(gomock.Any(), gomock.Any(), gomock.Any()).Return([]*models.TimelineComment{}, nil).AnyTimes()
|
||||
gitea.EXPECT().GetPullRequest(gomock.Any(), gomock.Any(), gomock.Any()).Return(modelPR, nil).AnyTimes()
|
||||
gitea.EXPECT().UpdatePullRequest(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(modelPR, nil).AnyTimes()
|
||||
gitea.EXPECT().SetLabels(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]*models.Label{}, nil).AnyTimes()
|
||||
gitea.EXPECT().SetRepoOptions(gomock.Any(), gomock.Any(), gomock.Any()).Return(&models.Repository{SSHURL: "git@src.opensuse.org:test/prj.git"}, nil).AnyTimes()
|
||||
gitea.EXPECT().GetPullRequestReviews(gomock.Any(), gomock.Any(), gomock.Any()).Return([]*models.PullReview{}, nil).AnyTimes()
|
||||
gitea.EXPECT().GetRepository(gomock.Any(), gomock.Any()).Return(&models.Repository{
|
||||
Owner: &models.User{UserName: "test"},
|
||||
Name: "prjcopy",
|
||||
SSHURL: "git@src.opensuse.org:test/prj.git",
|
||||
}, nil).AnyTimes()
|
||||
|
||||
err := pr.Process(modelPR)
|
||||
if err != nil {
|
||||
err := pr.Process(event)
|
||||
if errors.Unwrap(err) != failedErr {
|
||||
t.Error("error:", err)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
package main
|
||||
|
||||
/*
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"go.uber.org/mock/gomock"
|
||||
@@ -11,147 +16,217 @@ import (
|
||||
)
|
||||
|
||||
func TestSyncPR(t *testing.T) {
|
||||
config := &common.AutogitConfig{
|
||||
Reviewers: []string{"reviewer1", "reviewer2"},
|
||||
Branch: "testing",
|
||||
Organization: "test-org",
|
||||
GitProjectName: "test-prj#testing",
|
||||
pr := PRProcessor{
|
||||
config: &common.AutogitConfig{
|
||||
Reviewers: []string{"reviewer1", "reviewer2"},
|
||||
Branch: "testing",
|
||||
Organization: "test",
|
||||
GitProjectName: "prj",
|
||||
},
|
||||
}
|
||||
|
||||
git := &common.GitHandlerImpl{
|
||||
GitCommiter: "tester",
|
||||
GitEmail: "test@suse.com",
|
||||
GitPath: t.TempDir(),
|
||||
}
|
||||
|
||||
processor := &PRProcessor{
|
||||
config: config,
|
||||
git: git,
|
||||
event := &common.PullRequestWebhookEvent{
|
||||
Action: "syncronized",
|
||||
Number: 42,
|
||||
Pull_Request: &common.PullRequest{
|
||||
Number: 42,
|
||||
Base: common.Head{
|
||||
Ref: "branch",
|
||||
Sha: "8a6a69a4232cabda04a4d9563030aa888ff5482f75aa4c6519da32a951a072e2",
|
||||
Repo: &common.Repository{
|
||||
Name: "testRepo",
|
||||
Owner: &common.Organization{
|
||||
Username: pr.config.Organization,
|
||||
},
|
||||
Default_Branch: "main1",
|
||||
},
|
||||
},
|
||||
Head: common.Head{
|
||||
Ref: "branch",
|
||||
Sha: "11eb36d5a58d7bb376cac59ac729a1986c6a7bfc63e7818e14382f545ccda985",
|
||||
Repo: &common.Repository{
|
||||
Name: "testRepo",
|
||||
Default_Branch: "main1",
|
||||
},
|
||||
},
|
||||
},
|
||||
Repository: &common.Repository{
|
||||
Owner: &common.Organization{
|
||||
Username: pr.config.Organization,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
modelPR := &models.PullRequest{
|
||||
Index: 42,
|
||||
Body: "PR: test-org/test-prj#24",
|
||||
Body: "PR: test/prj#24",
|
||||
Base: &models.PRBranchInfo{
|
||||
Ref: "main",
|
||||
Ref: "branch",
|
||||
Sha: "8a6a69a4232cabda04a4d9563030aa888ff5482f75aa4c6519da32a951a072e2",
|
||||
Repo: &models.Repository{
|
||||
Name: "test-repo",
|
||||
Owner: &models.User{UserName: "test-org"},
|
||||
DefaultBranch: "main",
|
||||
Name: "testRepo",
|
||||
Owner: &models.User{
|
||||
UserName: "test",
|
||||
},
|
||||
DefaultBranch: "main1",
|
||||
},
|
||||
},
|
||||
Head: &models.PRBranchInfo{
|
||||
Ref: "branch",
|
||||
Sha: "11eb36d5a58d7bb376cac59ac729a1986c6a7bfc63e7818e14382f545ccda985",
|
||||
Repo: &models.Repository{
|
||||
Name: "test-repo",
|
||||
Owner: &models.User{UserName: "test-org"},
|
||||
DefaultBranch: "main",
|
||||
Name: "testRepo",
|
||||
Owner: &models.User{
|
||||
UserName: "test",
|
||||
},
|
||||
DefaultBranch: "main1",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
PrjGitPR := &models.PullRequest{
|
||||
Title: "some pull request",
|
||||
Body: "PR: test-org/test-repo#42",
|
||||
Body: "PR: test/testRepo#42",
|
||||
Index: 24,
|
||||
Base: &models.PRBranchInfo{
|
||||
Ref: "testing",
|
||||
Repo: &models.Repository{
|
||||
Name: "test-prj",
|
||||
Owner: &models.User{UserName: "test-org"},
|
||||
SSHURL: "url",
|
||||
},
|
||||
},
|
||||
Head: &models.PRBranchInfo{
|
||||
Name: "PR_test-repo#42",
|
||||
Name: "testing",
|
||||
Sha: "db8adab91edb476b9762097d10c6379aa71efd6b60933a1c0e355ddacf419a95",
|
||||
Repo: &models.Repository{
|
||||
SSHURL: "url",
|
||||
SSHURL: "./prj",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
t.Run("PR_sync_request_against_PrjGit_==_no_action", func(t *testing.T) {
|
||||
git := &common.GitHandlerImpl{
|
||||
GitCommiter: "tester",
|
||||
GitEmail: "test@suse.com",
|
||||
}
|
||||
|
||||
t.Run("PR sync request against PrjGit == no action", func(t *testing.T) {
|
||||
ctl := gomock.NewController(t)
|
||||
defer ctl.Finish()
|
||||
gitea := mock_common.NewMockGitea(ctl)
|
||||
gitea.EXPECT().ResetTimelineCache(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes()
|
||||
Gitea = gitea
|
||||
Gitea = mock_common.NewMockGitea(ctl)
|
||||
|
||||
// Common expectations for FetchPRSet and downstream checks
|
||||
gitea.EXPECT().GetPullRequestReviews(gomock.Any(), gomock.Any(), gomock.Any()).Return([]*models.PullReview{}, nil).AnyTimes()
|
||||
gitea.EXPECT().FetchMaintainershipFile(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, "", nil).AnyTimes()
|
||||
gitea.EXPECT().FetchMaintainershipDirFile(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, "", nil).AnyTimes()
|
||||
gitea.EXPECT().SetRepoOptions(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, nil).AnyTimes()
|
||||
git.GitPath = t.TempDir()
|
||||
|
||||
prjGitRepoPR := &models.PullRequest{
|
||||
Index: 100,
|
||||
Base: &models.PRBranchInfo{
|
||||
Ref: "testing",
|
||||
Repo: &models.Repository{
|
||||
Name: "test-prj",
|
||||
Owner: &models.User{UserName: "test-org"},
|
||||
},
|
||||
},
|
||||
Head: &models.PRBranchInfo{
|
||||
Ref: "branch",
|
||||
},
|
||||
pr.config.GitProjectName = "testRepo"
|
||||
event.Repository.Name = "testRepo"
|
||||
|
||||
if err := pr.Process(event); err != nil {
|
||||
t.Error("Error PrjGit sync request. Should be no error.", err)
|
||||
}
|
||||
})
|
||||
|
||||
gitea.EXPECT().GetPullRequest(gomock.Any(), gomock.Any(), gomock.Any()).Return(prjGitRepoPR, nil).AnyTimes()
|
||||
gitea.EXPECT().GetTimeline(gomock.Any(), gomock.Any(), gomock.Any()).Return([]*models.TimelineComment{}, nil).AnyTimes()
|
||||
t.Run("Missing submodule in prjgit", func(t *testing.T) {
|
||||
ctl := gomock.NewController(t)
|
||||
mock := mock_common.NewMockGitea(ctl)
|
||||
|
||||
if err := processor.Process(prjGitRepoPR); err != nil {
|
||||
t.Errorf("Expected nil error for PrjGit sync request, got %v", err)
|
||||
pr.gitea = mock
|
||||
git.GitPath = t.TempDir()
|
||||
|
||||
pr.config.GitProjectName = "prjGit"
|
||||
event.Repository.Name = "testRepo"
|
||||
|
||||
setupGitForTests(t, git)
|
||||
|
||||
oldSha := PrjGitPR.Head.Sha
|
||||
defer func() { PrjGitPR.Head.Sha = oldSha }()
|
||||
PrjGitPR.Head.Sha = "ab8adab91edb476b9762097d10c6379aa71efd6b60933a1c0e355ddacf419a95"
|
||||
|
||||
mock.EXPECT().GetPullRequest(pr.config.Organization, "testRepo", event.Pull_Request.Number).Return(modelPR, nil)
|
||||
mock.EXPECT().GetPullRequest(pr.config.Organization, "prj", int64(24)).Return(PrjGitPR, nil)
|
||||
|
||||
err := pr.Process(event)
|
||||
|
||||
if err == nil || err.Error() != "Cannot fetch submodule commit id in prjgit for 'testRepo'" {
|
||||
t.Error("Invalid error received.", err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Missing PrjGit PR for the sync", func(t *testing.T) {
|
||||
ctl := gomock.NewController(t)
|
||||
defer ctl.Finish()
|
||||
gitea := mock_common.NewMockGitea(ctl)
|
||||
gitea.EXPECT().ResetTimelineCache(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes()
|
||||
Gitea = gitea
|
||||
mock := mock_common.NewMockGitea(ctl)
|
||||
|
||||
gitea.EXPECT().GetPullRequestReviews(gomock.Any(), gomock.Any(), gomock.Any()).Return([]*models.PullReview{}, nil).AnyTimes()
|
||||
gitea.EXPECT().FetchMaintainershipFile(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, "", nil).AnyTimes()
|
||||
gitea.EXPECT().FetchMaintainershipDirFile(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, "", nil).AnyTimes()
|
||||
gitea.EXPECT().SetRepoOptions(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, nil).AnyTimes()
|
||||
pr.gitea = mock
|
||||
git.GitPath = t.TempDir()
|
||||
|
||||
gitea.EXPECT().GetTimeline(gomock.Any(), gomock.Any(), gomock.Any()).Return([]*models.TimelineComment{}, nil).AnyTimes()
|
||||
gitea.EXPECT().GetPullRequest(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, errors.New("not found")).AnyTimes()
|
||||
pr.config.GitProjectName = "prjGit"
|
||||
event.Repository.Name = "tester"
|
||||
|
||||
err := processor.Process(modelPR)
|
||||
// It should fail because it can't find the project PR linked in body
|
||||
if err == nil {
|
||||
t.Errorf("Expected error for missing project PR, got nil")
|
||||
setupGitForTests(t, git)
|
||||
|
||||
expectedErr := errors.New("Missing PR should throw error")
|
||||
mock.EXPECT().GetPullRequest(config.Organization, "tester", event.Pull_Request.Number).Return(modelPR, expectedErr)
|
||||
|
||||
err := pr.Process(event, git, config)
|
||||
|
||||
if err == nil || errors.Unwrap(err) != expectedErr {
|
||||
t.Error("Invalid error received.", err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("PR sync", func(t *testing.T) {
|
||||
var b bytes.Buffer
|
||||
w := log.Writer()
|
||||
log.SetOutput(&b)
|
||||
defer log.SetOutput(w)
|
||||
|
||||
ctl := gomock.NewController(t)
|
||||
defer ctl.Finish()
|
||||
gitea := mock_common.NewMockGitea(ctl)
|
||||
gitea.EXPECT().ResetTimelineCache(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes()
|
||||
Gitea = gitea
|
||||
mock := mock_common.NewMockGitea(ctl)
|
||||
|
||||
Gitea = mock
|
||||
git.GitPath = t.TempDir()
|
||||
|
||||
pr.config.GitProjectName = "prjGit"
|
||||
event.Repository.Name = "testRepo"
|
||||
|
||||
setupGitForTests(t, git)
|
||||
|
||||
gitea.EXPECT().GetPullRequest(gomock.Any(), gomock.Any(), gomock.Any()).Return(PrjGitPR, nil).AnyTimes()
|
||||
gitea.EXPECT().GetTimeline(gomock.Any(), gomock.Any(), gomock.Any()).Return([]*models.TimelineComment{}, nil).AnyTimes()
|
||||
gitea.EXPECT().GetPullRequestReviews(gomock.Any(), gomock.Any(), gomock.Any()).Return([]*models.PullReview{}, nil).AnyTimes()
|
||||
gitea.EXPECT().FetchMaintainershipFile(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, "", nil).AnyTimes()
|
||||
gitea.EXPECT().FetchMaintainershipDirFile(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, "", nil).AnyTimes()
|
||||
gitea.EXPECT().SetRepoOptions(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, nil).AnyTimes()
|
||||
// mock.EXPECT().GetAssociatedPrjGitPR(event).Return(PrjGitPR, nil)
|
||||
mock.EXPECT().GetPullRequest(pr.config.Organization, "testRepo", event.Pull_Request.Number).Return(modelPR, nil)
|
||||
mock.EXPECT().GetPullRequest(pr.config.Organization, "prj", int64(24)).Return(PrjGitPR, nil)
|
||||
|
||||
// For UpdatePrjGitPR
|
||||
gitea.EXPECT().UpdatePullRequest(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, nil).AnyTimes()
|
||||
err := pr.Process(event)
|
||||
|
||||
err := processor.Process(modelPR)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
t.Error("Invalid error received.", err)
|
||||
t.Error(b.String())
|
||||
}
|
||||
|
||||
// check that we actually created the branch in the prjgit
|
||||
id, ok := git.GitSubmoduleCommitId("prj", "testRepo", "c097b9d1d69892d0ef2afa66d4e8abf0a1612c6f95d271a6e15d6aff1ad2854c")
|
||||
if id != "11eb36d5a58d7bb376cac59ac729a1986c6a7bfc63e7818e14382f545ccda985" || !ok {
|
||||
t.Error("Failed creating PR")
|
||||
t.Error(b.String())
|
||||
}
|
||||
|
||||
// does nothing on next sync of already synced data -- PR is updated
|
||||
os.RemoveAll(path.Join(git.GitPath, common.DefaultGitPrj))
|
||||
|
||||
mock.EXPECT().GetPullRequest(pr.config.Organization, "testRepo", event.Pull_Request.Number).Return(modelPR, nil)
|
||||
mock.EXPECT().GetPullRequest(pr.config.Organization, "prj", int64(24)).Return(PrjGitPR, nil)
|
||||
err = pr.Process(event)
|
||||
|
||||
if err != nil {
|
||||
t.Error("Invalid error received.", err)
|
||||
t.Error(b.String())
|
||||
}
|
||||
|
||||
// check that we actually created the branch in the prjgit
|
||||
id, ok = git.GitSubmoduleCommitId("prj", "testRepo", "c097b9d1d69892d0ef2afa66d4e8abf0a1612c6f95d271a6e15d6aff1ad2854c")
|
||||
if id != "11eb36d5a58d7bb376cac59ac729a1986c6a7bfc63e7818e14382f545ccda985" || !ok {
|
||||
t.Error("Failed creating PR")
|
||||
t.Error(b.String())
|
||||
}
|
||||
|
||||
if id, err := git.GitBranchHead("prj", "PR_testRepo#42"); id != "c097b9d1d69892d0ef2afa66d4e8abf0a1612c6f95d271a6e15d6aff1ad2854c" || err != nil {
|
||||
t.Error("no branch?", err)
|
||||
t.Error(b.String())
|
||||
}
|
||||
|
||||
if !strings.Contains(b.String(), "commitID already match - nothing to do") {
|
||||
// os.CopyFS("/tmp/test", os.DirFS(git.GitPath))
|
||||
t.Log(b.String())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
@@ -1,945 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"go.uber.org/mock/gomock"
|
||||
"src.opensuse.org/autogits/common"
|
||||
"src.opensuse.org/autogits/common/gitea-generated/models"
|
||||
mock_common "src.opensuse.org/autogits/common/mock"
|
||||
)
|
||||
|
||||
func TestPrjGitDescription(t *testing.T) {
|
||||
config := &common.AutogitConfig{
|
||||
Organization: "test-org",
|
||||
GitProjectName: "test-prj#main",
|
||||
}
|
||||
|
||||
prset := &common.PRSet{
|
||||
Config: config,
|
||||
PRs: []*common.PRInfo{
|
||||
{
|
||||
PR: &models.PullRequest{
|
||||
State: "open",
|
||||
Index: 1,
|
||||
Base: &models.PRBranchInfo{
|
||||
Ref: "main",
|
||||
Repo: &models.Repository{
|
||||
Name: "pkg-a",
|
||||
Owner: &models.User{UserName: "test-org"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
PR: &models.PullRequest{
|
||||
State: "open",
|
||||
Index: 2,
|
||||
Base: &models.PRBranchInfo{
|
||||
Ref: "main",
|
||||
Repo: &models.Repository{
|
||||
Name: "pkg-b",
|
||||
Owner: &models.User{UserName: "test-org"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
GitAuthor = "Bot"
|
||||
title, desc := PrjGitDescription(prset)
|
||||
|
||||
expectedTitle := "Forwarded PRs: pkg-a, pkg-b"
|
||||
if title != expectedTitle {
|
||||
t.Errorf("Expected title %q, got %q", expectedTitle, title)
|
||||
}
|
||||
|
||||
if !strings.Contains(desc, "PR: test-org/pkg-a!1") || !strings.Contains(desc, "PR: test-org/pkg-b!2") {
|
||||
t.Errorf("Description missing PR references: %s", desc)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAllocatePRProcessor(t *testing.T) {
|
||||
ctl := gomock.NewController(t)
|
||||
defer ctl.Finish()
|
||||
|
||||
mockGitGen := mock_common.NewMockGitHandlerGenerator(ctl)
|
||||
GitHandler = mockGitGen
|
||||
mockGit := mock_common.NewMockGit(ctl)
|
||||
|
||||
configs := common.AutogitConfigs{
|
||||
{
|
||||
Organization: "test-org",
|
||||
Branch: "main",
|
||||
GitProjectName: "test-prj#main",
|
||||
},
|
||||
}
|
||||
|
||||
req := &models.PullRequest{
|
||||
Index: 1,
|
||||
Base: &models.PRBranchInfo{
|
||||
Ref: "main",
|
||||
Repo: &models.Repository{
|
||||
Name: "test-repo",
|
||||
Owner: &models.User{UserName: "test-org"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
mockGitGen.EXPECT().CreateGitHandler("test-org").Return(mockGit, nil)
|
||||
mockGit.EXPECT().GetPath().Return("/tmp/test")
|
||||
|
||||
processor, err := AllocatePRProcessor(req, configs)
|
||||
if err != nil {
|
||||
t.Fatalf("AllocatePRProcessor failed: %v", err)
|
||||
}
|
||||
|
||||
if processor.config.Organization != "test-org" {
|
||||
t.Errorf("Expected organization test-org, got %s", processor.config.Organization)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAllocatePRProcessor_Failures(t *testing.T) {
|
||||
ctl := gomock.NewController(t)
|
||||
defer ctl.Finish()
|
||||
|
||||
mockGitGen := mock_common.NewMockGitHandlerGenerator(ctl)
|
||||
GitHandler = mockGitGen
|
||||
|
||||
configs := common.AutogitConfigs{} // Empty configs
|
||||
|
||||
req := &models.PullRequest{
|
||||
Index: 1,
|
||||
Base: &models.PRBranchInfo{
|
||||
Ref: "main",
|
||||
Repo: &models.Repository{
|
||||
Name: "test-repo",
|
||||
Owner: &models.User{UserName: "test-org"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
t.Run("Missing config", func(t *testing.T) {
|
||||
processor, err := AllocatePRProcessor(req, configs)
|
||||
if err == nil || err.Error() != "Cannot find config for PR" {
|
||||
t.Errorf("Expected 'Cannot find config for PR' error, got %v", err)
|
||||
}
|
||||
if processor != nil {
|
||||
t.Error("Expected nil processor")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("GitHandler failure", func(t *testing.T) {
|
||||
validConfigs := common.AutogitConfigs{
|
||||
{
|
||||
Organization: "test-org",
|
||||
Branch: "main",
|
||||
GitProjectName: "test-prj#main",
|
||||
},
|
||||
}
|
||||
mockGitGen.EXPECT().CreateGitHandler("test-org").Return(nil, errors.New("git error"))
|
||||
|
||||
processor, err := AllocatePRProcessor(req, validConfigs)
|
||||
if err == nil || !strings.Contains(err.Error(), "Error allocating GitHandler") {
|
||||
t.Errorf("Expected GitHandler error, got %v", err)
|
||||
}
|
||||
if processor != nil {
|
||||
t.Error("Expected nil processor")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestSetSubmodulesToMatchPRSet_Failures(t *testing.T) {
|
||||
ctl := gomock.NewController(t)
|
||||
defer ctl.Finish()
|
||||
|
||||
mockGit := mock_common.NewMockGit(ctl)
|
||||
config := &common.AutogitConfig{
|
||||
Organization: "test-org",
|
||||
GitProjectName: "test-prj#main",
|
||||
}
|
||||
|
||||
processor := &PRProcessor{
|
||||
config: config,
|
||||
git: mockGit,
|
||||
}
|
||||
|
||||
t.Run("GitSubmoduleList failure", func(t *testing.T) {
|
||||
mockGit.EXPECT().GitSubmoduleList(gomock.Any(), "HEAD").Return(nil, errors.New("list error"))
|
||||
err := processor.SetSubmodulesToMatchPRSet(&common.PRSet{})
|
||||
if err == nil || err.Error() != "list error" {
|
||||
t.Errorf("Expected 'list error', got %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestSetSubmodulesToMatchPRSet(t *testing.T) {
|
||||
ctl := gomock.NewController(t)
|
||||
defer ctl.Finish()
|
||||
|
||||
mockGit := mock_common.NewMockGit(ctl)
|
||||
config := &common.AutogitConfig{
|
||||
Organization: "test-org",
|
||||
GitProjectName: "test-prj#main",
|
||||
}
|
||||
|
||||
processor := &PRProcessor{
|
||||
config: config,
|
||||
git: mockGit,
|
||||
}
|
||||
|
||||
prset := &common.PRSet{
|
||||
Config: config,
|
||||
PRs: []*common.PRInfo{
|
||||
{
|
||||
PR: &models.PullRequest{
|
||||
State: "open",
|
||||
Index: 1,
|
||||
Base: &models.PRBranchInfo{
|
||||
Ref: "main",
|
||||
Repo: &models.Repository{
|
||||
Name: "pkg-a",
|
||||
Owner: &models.User{UserName: "test-org"},
|
||||
},
|
||||
},
|
||||
Head: &models.PRBranchInfo{
|
||||
Sha: "new-sha",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
mockGit.EXPECT().GitSubmoduleList(gomock.Any(), "HEAD").Return(map[string]string{"pkg-a": "old-sha"}, nil)
|
||||
// Expect submodule update and commit
|
||||
mockGit.EXPECT().GitExec(gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
|
||||
mockGit.EXPECT().GitStatus(gomock.Any()).Return([]common.GitStatusData{}, nil).AnyTimes()
|
||||
|
||||
err := processor.SetSubmodulesToMatchPRSet(prset)
|
||||
if err != nil {
|
||||
t.Errorf("SetSubmodulesToMatchPRSet failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRebaseAndSkipSubmoduleCommits(t *testing.T) {
|
||||
ctl := gomock.NewController(t)
|
||||
defer ctl.Finish()
|
||||
|
||||
mockGit := mock_common.NewMockGit(ctl)
|
||||
config := &common.AutogitConfig{
|
||||
Organization: "test-org",
|
||||
GitProjectName: "test-prj#main",
|
||||
}
|
||||
|
||||
processor := &PRProcessor{
|
||||
config: config,
|
||||
git: mockGit,
|
||||
}
|
||||
|
||||
prset := &common.PRSet{
|
||||
Config: config,
|
||||
PRs: []*common.PRInfo{
|
||||
{
|
||||
RemoteName: "origin",
|
||||
PR: &models.PullRequest{
|
||||
Base: &models.PRBranchInfo{
|
||||
Name: "main",
|
||||
Repo: &models.Repository{
|
||||
Name: "test-prj",
|
||||
Owner: &models.User{UserName: "test-org"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
t.Run("Clean rebase", func(t *testing.T) {
|
||||
mockGit.EXPECT().GitExec(common.DefaultGitPrj, "rebase", "origin/main").Return(nil)
|
||||
err := processor.RebaseAndSkipSubmoduleCommits(prset, "main")
|
||||
if err != nil {
|
||||
t.Errorf("Expected nil error, got %v", err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Rebase with submodule conflict - skip", func(t *testing.T) {
|
||||
// First rebase fails
|
||||
mockGit.EXPECT().GitExec(common.DefaultGitPrj, "rebase", "origin/main").Return(errors.New("conflict"))
|
||||
// Status shows submodule change
|
||||
mockGit.EXPECT().GitStatus(common.DefaultGitPrj).Return([]common.GitStatusData{
|
||||
{SubmoduleChanges: "S..."},
|
||||
}, nil)
|
||||
// Skip called
|
||||
mockGit.EXPECT().GitExec(common.DefaultGitPrj, "rebase", "--skip").Return(nil)
|
||||
|
||||
err := processor.RebaseAndSkipSubmoduleCommits(prset, "main")
|
||||
if err != nil {
|
||||
t.Errorf("Expected nil error, got %v", err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Rebase with real conflict - abort", func(t *testing.T) {
|
||||
mockGit.EXPECT().GitExec(common.DefaultGitPrj, "rebase", "origin/main").Return(errors.New("conflict"))
|
||||
// Status shows real change
|
||||
mockGit.EXPECT().GitStatus(common.DefaultGitPrj).Return([]common.GitStatusData{
|
||||
{SubmoduleChanges: "N..."},
|
||||
}, nil)
|
||||
// Abort called
|
||||
mockGit.EXPECT().GitExecOrPanic(common.DefaultGitPrj, "rebase", "--abort").Return()
|
||||
|
||||
err := processor.RebaseAndSkipSubmoduleCommits(prset, "main")
|
||||
if err == nil || !strings.Contains(err.Error(), "Unexpected conflict in rebase") {
|
||||
t.Errorf("Expected 'Unexpected conflict' error, got %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestUpdatePrjGitPR(t *testing.T) {
|
||||
ctl := gomock.NewController(t)
|
||||
defer ctl.Finish()
|
||||
|
||||
mockGit := mock_common.NewMockGit(ctl)
|
||||
gitea := mock_common.NewMockGitea(ctl)
|
||||
gitea.EXPECT().ResetTimelineCache(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes()
|
||||
Gitea = gitea
|
||||
CurrentUser = &models.User{UserName: "bot"}
|
||||
|
||||
config := &common.AutogitConfig{
|
||||
Organization: "test-org",
|
||||
GitProjectName: "test-prj#main",
|
||||
}
|
||||
|
||||
processor := &PRProcessor{
|
||||
config: config,
|
||||
git: mockGit,
|
||||
}
|
||||
|
||||
t.Run("Only project git in PR", func(t *testing.T) {
|
||||
prset := &common.PRSet{
|
||||
Config: config,
|
||||
PRs: []*common.PRInfo{
|
||||
{
|
||||
RemoteName: "origin",
|
||||
PR: &models.PullRequest{
|
||||
Base: &models.PRBranchInfo{
|
||||
Name: "main",
|
||||
Repo: &models.Repository{
|
||||
Name: "test-prj",
|
||||
Owner: &models.User{UserName: "test-org"},
|
||||
},
|
||||
},
|
||||
Head: &models.PRBranchInfo{
|
||||
Sha: "sha1",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
mockGit.EXPECT().GitExecOrPanic(common.DefaultGitPrj, "fetch", "origin", "sha1")
|
||||
err := processor.UpdatePrjGitPR(prset)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Only project git in PR - needs clone", func(t *testing.T) {
|
||||
prset := &common.PRSet{
|
||||
Config: config,
|
||||
PRs: []*common.PRInfo{
|
||||
{
|
||||
RemoteName: "", // Triggers GitClone
|
||||
PR: &models.PullRequest{
|
||||
Base: &models.PRBranchInfo{
|
||||
Name: "main",
|
||||
Repo: &models.Repository{
|
||||
Name: "test-prj",
|
||||
Owner: &models.User{UserName: "test-org"},
|
||||
SSHURL: "ssh://git@example.com/test-prj.git",
|
||||
},
|
||||
},
|
||||
Head: &models.PRBranchInfo{
|
||||
Sha: "sha1",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
mockGit.EXPECT().GitClone(common.DefaultGitPrj, "", "ssh://git@example.com/test-prj.git").Return("origin", nil)
|
||||
mockGit.EXPECT().GitExecOrPanic(common.DefaultGitPrj, "fetch", "origin", "sha1")
|
||||
err := processor.UpdatePrjGitPR(prset)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("PR on another remote", func(t *testing.T) {
|
||||
prset := &common.PRSet{
|
||||
Config: config,
|
||||
PRs: []*common.PRInfo{
|
||||
{
|
||||
RemoteName: "origin",
|
||||
PR: &models.PullRequest{
|
||||
Base: &models.PRBranchInfo{
|
||||
Name: "main",
|
||||
RepoID: 1,
|
||||
Repo: &models.Repository{
|
||||
Name: "test-prj",
|
||||
Owner: &models.User{UserName: "test-org"},
|
||||
SSHURL: "url",
|
||||
},
|
||||
},
|
||||
Head: &models.PRBranchInfo{
|
||||
Name: "feature",
|
||||
RepoID: 2, // Different RepoID
|
||||
Sha: "sha1",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
PR: &models.PullRequest{
|
||||
Base: &models.PRBranchInfo{
|
||||
Name: "other",
|
||||
Repo: &models.Repository{
|
||||
Name: "other-pkg",
|
||||
Owner: &models.User{UserName: "test-org"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
mockGit.EXPECT().GitClone(gomock.Any(), gomock.Any(), gomock.Any()).Return("remote2", nil)
|
||||
mockGit.EXPECT().GitExecOrPanic(gomock.Any(), "fetch", "remote2", "sha1")
|
||||
mockGit.EXPECT().GitExecOrPanic(gomock.Any(), "checkout", "sha1")
|
||||
|
||||
err := processor.UpdatePrjGitPR(prset)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Standard update with rebase and force push", func(t *testing.T) {
|
||||
prset := &common.PRSet{
|
||||
Config: config,
|
||||
BotUser: "bot",
|
||||
PRs: []*common.PRInfo{
|
||||
{
|
||||
RemoteName: "origin",
|
||||
PR: &models.PullRequest{
|
||||
User: &models.User{UserName: "bot"},
|
||||
Mergeable: false, // Triggers rebase
|
||||
Base: &models.PRBranchInfo{
|
||||
Name: "main",
|
||||
RepoID: 1,
|
||||
Repo: &models.Repository{
|
||||
Name: "test-prj",
|
||||
Owner: &models.User{UserName: "test-org"},
|
||||
SSHURL: "url",
|
||||
},
|
||||
},
|
||||
Head: &models.PRBranchInfo{
|
||||
Name: "PR_branch",
|
||||
RepoID: 1,
|
||||
Sha: "old-head",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
PR: &models.PullRequest{
|
||||
State: "open",
|
||||
Base: &models.PRBranchInfo{
|
||||
Repo: &models.Repository{
|
||||
Name: "pkg-a",
|
||||
Owner: &models.User{UserName: "test-org"},
|
||||
},
|
||||
},
|
||||
Head: &models.PRBranchInfo{Sha: "pkg-sha"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
mockGit.EXPECT().GitClone(gomock.Any(), gomock.Any(), gomock.Any()).Return("origin", nil)
|
||||
mockGit.EXPECT().GitExecOrPanic(gomock.Any(), "fetch", gomock.Any(), gomock.Any())
|
||||
// Rebase expectations
|
||||
mockGit.EXPECT().GitExec(gomock.Any(), "rebase", gomock.Any()).Return(nil)
|
||||
|
||||
// First call returns old-head, second returns new-head to trigger push
|
||||
mockGit.EXPECT().GitBranchHead(gomock.Any(), gomock.Any()).Return("old-head", nil).Times(1)
|
||||
mockGit.EXPECT().GitBranchHead(gomock.Any(), gomock.Any()).Return("new-head", nil).Times(1)
|
||||
|
||||
// SetSubmodulesToMatchPRSet expectations
|
||||
mockGit.EXPECT().GitSubmoduleList(gomock.Any(), "HEAD").Return(map[string]string{"pkg-a": "old-pkg-sha"}, nil)
|
||||
// Catch all GitExec calls with any number of arguments up to 5
|
||||
mockGit.EXPECT().GitExec(gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
|
||||
mockGit.EXPECT().GitExec(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
|
||||
mockGit.EXPECT().GitExec(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
|
||||
mockGit.EXPECT().GitExec(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
|
||||
|
||||
mockGit.EXPECT().GitStatus(gomock.Any()).Return(nil, nil).AnyTimes()
|
||||
|
||||
// UpdatePullRequest expectation
|
||||
gitea.EXPECT().UpdatePullRequest(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, nil).AnyTimes()
|
||||
|
||||
err := processor.UpdatePrjGitPR(prset)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("isPrTitleSame logic", func(t *testing.T) {
|
||||
longTitle := strings.Repeat("a", 251) + "..."
|
||||
prset := &common.PRSet{
|
||||
Config: config,
|
||||
BotUser: "bot",
|
||||
PRs: []*common.PRInfo{
|
||||
{
|
||||
RemoteName: "origin",
|
||||
PR: &models.PullRequest{
|
||||
User: &models.User{UserName: "bot"},
|
||||
Title: longTitle,
|
||||
Base: &models.PRBranchInfo{
|
||||
Name: "main",
|
||||
RepoID: 1,
|
||||
Repo: &models.Repository{
|
||||
Name: "test-prj",
|
||||
Owner: &models.User{UserName: "test-org"},
|
||||
},
|
||||
},
|
||||
Head: &models.PRBranchInfo{
|
||||
Name: "PR_branch",
|
||||
RepoID: 1,
|
||||
Sha: "head",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
PR: &models.PullRequest{
|
||||
State: "open",
|
||||
Base: &models.PRBranchInfo{
|
||||
Repo: &models.Repository{
|
||||
Name: "pkg-a",
|
||||
Owner: &models.User{UserName: "test-org"},
|
||||
},
|
||||
},
|
||||
Head: &models.PRBranchInfo{Sha: "pkg-sha"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
mockGit.EXPECT().GitClone(gomock.Any(), gomock.Any(), gomock.Any()).Return("origin", nil)
|
||||
mockGit.EXPECT().GitExecOrPanic(gomock.Any(), "fetch", gomock.Any(), gomock.Any())
|
||||
mockGit.EXPECT().GitBranchHead(gomock.Any(), gomock.Any()).Return("head", nil).AnyTimes()
|
||||
mockGit.EXPECT().GitSubmoduleList(gomock.Any(), "HEAD").Return(map[string]string{"pkg-a": "pkg-sha"}, nil)
|
||||
// mockGit.EXPECT().GitExec(...) not called because no push (headCommit == newHeadCommit)
|
||||
mockGit.EXPECT().GitExec(gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
|
||||
|
||||
err := processor.UpdatePrjGitPR(prset)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestCreatePRjGitPR_Integration(t *testing.T) {
|
||||
ctl := gomock.NewController(t)
|
||||
defer ctl.Finish()
|
||||
|
||||
mockGit := mock_common.NewMockGit(ctl)
|
||||
gitea := mock_common.NewMockGitea(ctl)
|
||||
gitea.EXPECT().ResetTimelineCache(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes()
|
||||
Gitea = gitea
|
||||
|
||||
config := &common.AutogitConfig{
|
||||
Organization: "test-org",
|
||||
GitProjectName: "test-prj#main",
|
||||
}
|
||||
|
||||
processor := &PRProcessor{
|
||||
config: config,
|
||||
git: mockGit,
|
||||
}
|
||||
|
||||
prset := &common.PRSet{
|
||||
Config: config,
|
||||
PRs: []*common.PRInfo{
|
||||
{
|
||||
PR: &models.PullRequest{
|
||||
State: "open",
|
||||
Base: &models.PRBranchInfo{
|
||||
Repo: &models.Repository{Name: "pkg-a", Owner: &models.User{UserName: "test-org"}},
|
||||
},
|
||||
Head: &models.PRBranchInfo{Sha: "pkg-sha"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
t.Run("Create new project PR with label", func(t *testing.T) {
|
||||
mockGit.EXPECT().GitBranchHead(gomock.Any(), gomock.Any()).Return("head-sha", nil).AnyTimes()
|
||||
mockGit.EXPECT().GitSubmoduleList(gomock.Any(), gomock.Any()).Return(map[string]string{}, nil).AnyTimes()
|
||||
mockGit.EXPECT().GitExec(gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
|
||||
mockGit.EXPECT().GitExec(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
|
||||
mockGit.EXPECT().GitExec(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
|
||||
mockGit.EXPECT().GitExec(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
|
||||
mockGit.EXPECT().GitClone(gomock.Any(), gomock.Any(), gomock.Any()).Return("origin", nil).AnyTimes()
|
||||
mockGit.EXPECT().GitStatus(gomock.Any()).Return(nil, nil).AnyTimes()
|
||||
|
||||
prjPR := &models.PullRequest{
|
||||
Index: 10,
|
||||
Base: &models.PRBranchInfo{
|
||||
Name: "main",
|
||||
RepoID: 1,
|
||||
Repo: &models.Repository{Name: "test-prj", Owner: &models.User{UserName: "test-org"}},
|
||||
},
|
||||
Head: &models.PRBranchInfo{
|
||||
Sha: "prj-head-sha",
|
||||
},
|
||||
}
|
||||
|
||||
gitea.EXPECT().GetRepository(gomock.Any(), gomock.Any()).Return(&models.Repository{Owner: &models.User{UserName: "test-org"}}, nil).AnyTimes()
|
||||
// CreatePullRequestIfNotExist returns isNew=true
|
||||
gitea.EXPECT().CreatePullRequestIfNotExist(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(prjPR, nil, true).AnyTimes()
|
||||
// Expect SetLabels to be called for new PR
|
||||
gitea.EXPECT().SetLabels("test-org", gomock.Any(), int64(10), gomock.Any()).Return(nil, nil).AnyTimes()
|
||||
gitea.EXPECT().UpdatePullRequest(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, nil).AnyTimes()
|
||||
|
||||
mockGit.EXPECT().GitExecOrPanic(gomock.Any(), gomock.Any()).Return().AnyTimes()
|
||||
mockGit.EXPECT().GitExecOrPanic(gomock.Any(), gomock.Any(), gomock.Any()).Return().AnyTimes()
|
||||
mockGit.EXPECT().GitExecOrPanic(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return().AnyTimes()
|
||||
mockGit.EXPECT().GitExecOrPanic(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return().AnyTimes()
|
||||
mockGit.EXPECT().GitExecOrPanic(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return().AnyTimes()
|
||||
|
||||
err := processor.CreatePRjGitPR("PR_branch", prset)
|
||||
if err != nil {
|
||||
t.Errorf("CreatePRjGitPR failed: %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestMultiPackagePRSet(t *testing.T) {
|
||||
GitAuthor = "Bot" // Ensure non-empty author
|
||||
config := &common.AutogitConfig{
|
||||
Organization: "test-org",
|
||||
GitProjectName: "test-prj#main",
|
||||
}
|
||||
|
||||
prset := &common.PRSet{
|
||||
Config: config,
|
||||
}
|
||||
|
||||
for i := 1; i <= 5; i++ {
|
||||
name := fmt.Sprintf("pkg-%d", i)
|
||||
prset.PRs = append(prset.PRs, &common.PRInfo{
|
||||
PR: &models.PullRequest{
|
||||
Index: int64(i),
|
||||
State: "open",
|
||||
Base: &models.PRBranchInfo{
|
||||
Ref: "main",
|
||||
Repo: &models.Repository{Name: name, Owner: &models.User{UserName: "test-org"}},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
GitAuthor = "Bot"
|
||||
title, desc := PrjGitDescription(prset)
|
||||
|
||||
// PrjGitDescription generates title like "Forwarded PRs: pkg-1, pkg-2, pkg-3, pkg-4, pkg-5"
|
||||
for i := 1; i <= 5; i++ {
|
||||
name := fmt.Sprintf("pkg-%d", i)
|
||||
if !strings.Contains(title, name) {
|
||||
t.Errorf("Title missing package %s: %s", name, title)
|
||||
}
|
||||
}
|
||||
|
||||
for i := 1; i <= 5; i++ {
|
||||
ref := fmt.Sprintf("PR: test-org/pkg-%d!%d", i, i)
|
||||
if !strings.Contains(desc, ref) {
|
||||
t.Errorf("Description missing reference %s", ref)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPRProcessor_Process_EdgeCases(t *testing.T) {
|
||||
ctl := gomock.NewController(t)
|
||||
defer ctl.Finish()
|
||||
|
||||
mockGit := mock_common.NewMockGit(ctl)
|
||||
gitea := mock_common.NewMockGitea(ctl)
|
||||
gitea.EXPECT().ResetTimelineCache(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes()
|
||||
Gitea = gitea
|
||||
CurrentUser = &models.User{UserName: "bot"}
|
||||
|
||||
config := &common.AutogitConfig{
|
||||
Organization: "test-org",
|
||||
GitProjectName: "test-prj#main",
|
||||
}
|
||||
|
||||
processor := &PRProcessor{
|
||||
config: config,
|
||||
git: mockGit,
|
||||
}
|
||||
|
||||
t.Run("Merged project PR - update downstream", func(t *testing.T) {
|
||||
prjPR := &models.PullRequest{
|
||||
State: "closed",
|
||||
HasMerged: true,
|
||||
Index: 100,
|
||||
Base: &models.PRBranchInfo{
|
||||
Name: "main",
|
||||
Repo: &models.Repository{Name: "test-prj", Owner: &models.User{UserName: "test-org"}, SSHURL: "url"},
|
||||
},
|
||||
Head: &models.PRBranchInfo{Name: "PR_branch"},
|
||||
}
|
||||
|
||||
pkgPR := &models.PullRequest{
|
||||
State: "open",
|
||||
Index: 1,
|
||||
Base: &models.PRBranchInfo{Name: "main", Repo: &models.Repository{Name: "pkg-a", Owner: &models.User{UserName: "test-org"}}},
|
||||
Head: &models.PRBranchInfo{Sha: "pkg-sha"},
|
||||
}
|
||||
|
||||
prset := &common.PRSet{
|
||||
BotUser: "bot",
|
||||
Config: config,
|
||||
PRs: []*common.PRInfo{
|
||||
{PR: prjPR},
|
||||
{PR: pkgPR},
|
||||
},
|
||||
}
|
||||
_ = prset // Suppress unused for now if it's really unused, but it's likely used by common.FetchPRSet internally if we weren't mocking everything
|
||||
|
||||
// Mock expectations for Process setup
|
||||
gitea.EXPECT().GetTimeline(gomock.Any(), gomock.Any(), gomock.Any()).Return([]*models.TimelineComment{}, nil).AnyTimes()
|
||||
gitea.EXPECT().GetPullRequest(gomock.Any(), gomock.Any(), gomock.Any()).Return(prjPR, nil).AnyTimes()
|
||||
gitea.EXPECT().GetPullRequestReviews(gomock.Any(), gomock.Any(), gomock.Any()).Return([]*models.PullReview{}, nil).AnyTimes()
|
||||
|
||||
// Mock maintainership file calls
|
||||
gitea.EXPECT().FetchMaintainershipFile(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, "", nil).AnyTimes()
|
||||
gitea.EXPECT().FetchMaintainershipDirFile(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, "", nil).AnyTimes()
|
||||
// Mock expectations for the merged path
|
||||
mockGit.EXPECT().GitClone(gomock.Any(), gomock.Any(), gomock.Any()).Return("origin", nil)
|
||||
mockGit.EXPECT().GitSubmoduleList(gomock.Any(), gomock.Any()).Return(map[string]string{"pkg-a": "old-sha"}, nil).AnyTimes()
|
||||
gitea.EXPECT().GetRecentCommits(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]*models.Commit{{SHA: "pkg-sha"}}, nil).AnyTimes()
|
||||
|
||||
// Downstream update expectations
|
||||
gitea.EXPECT().AddComment(gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
|
||||
gitea.EXPECT().ManualMergePR(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
|
||||
err := processor.Process(pkgPR)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Superfluous PR - close it", func(t *testing.T) {
|
||||
prjPR := &models.PullRequest{
|
||||
State: "open",
|
||||
Index: 100,
|
||||
User: &models.User{UserName: "bot"},
|
||||
Body: "Forwarded PRs: \n", // No PRs linked
|
||||
Base: &models.PRBranchInfo{
|
||||
Name: "main",
|
||||
Repo: &models.Repository{Name: "test-prj", Owner: &models.User{UserName: "test-org"}},
|
||||
},
|
||||
Head: &models.PRBranchInfo{Name: "PR_branch", Sha: "head-sha"},
|
||||
MergeBase: "base-sha",
|
||||
}
|
||||
|
||||
prset := &common.PRSet{
|
||||
BotUser: "bot",
|
||||
Config: config,
|
||||
PRs: []*common.PRInfo{
|
||||
{PR: prjPR},
|
||||
},
|
||||
}
|
||||
_ = prset
|
||||
|
||||
gitea.EXPECT().GetTimeline(gomock.Any(), gomock.Any(), gomock.Any()).Return([]*models.TimelineComment{}, nil).AnyTimes()
|
||||
gitea.EXPECT().GetPullRequest(gomock.Any(), gomock.Any(), gomock.Any()).Return(prjPR, nil).AnyTimes()
|
||||
gitea.EXPECT().GetPullRequestReviews(gomock.Any(), gomock.Any(), gomock.Any()).Return([]*models.PullReview{}, nil).AnyTimes()
|
||||
gitea.EXPECT().GetRepository(gomock.Any(), gomock.Any()).Return(&models.Repository{Owner: &models.User{UserName: "test-org"}}, nil).AnyTimes()
|
||||
|
||||
// Mock maintainership file calls
|
||||
gitea.EXPECT().FetchMaintainershipFile(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, "", nil).AnyTimes()
|
||||
gitea.EXPECT().FetchMaintainershipDirFile(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, "", nil).AnyTimes()
|
||||
// Standard update calls within Process
|
||||
mockGit.EXPECT().GitClone(gomock.Any(), gomock.Any(), gomock.Any()).Return("origin", nil).AnyTimes()
|
||||
mockGit.EXPECT().GitExecOrPanic(gomock.Any(), "fetch", gomock.Any(), gomock.Any()).AnyTimes()
|
||||
mockGit.EXPECT().GitBranchHead(gomock.Any(), gomock.Any()).Return("head-sha", nil).AnyTimes()
|
||||
mockGit.EXPECT().GitSubmoduleList(gomock.Any(), gomock.Any()).Return(map[string]string{}, nil).AnyTimes()
|
||||
mockGit.EXPECT().GitExec(gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
|
||||
mockGit.EXPECT().GitStatus(gomock.Any()).Return(nil, nil).AnyTimes()
|
||||
gitea.EXPECT().SetRepoOptions(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, nil).AnyTimes()
|
||||
|
||||
// Diff check for superfluous
|
||||
mockGit.EXPECT().GitDiff(gomock.Any(), gomock.Any(), gomock.Any()).Return("", nil).AnyTimes()
|
||||
|
||||
// Expectations for closing
|
||||
gitea.EXPECT().AddComment(gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
|
||||
gitea.EXPECT().UpdatePullRequest(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, nil).AnyTimes()
|
||||
err := processor.Process(prjPR)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestVerifyRepositoryConfiguration(t *testing.T) {
|
||||
ctl := gomock.NewController(t)
|
||||
defer ctl.Finish()
|
||||
|
||||
gitea := mock_common.NewMockGitea(ctl)
|
||||
gitea.EXPECT().ResetTimelineCache(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes()
|
||||
Gitea = gitea
|
||||
|
||||
repo := &models.Repository{
|
||||
Name: "test-repo",
|
||||
Owner: &models.User{
|
||||
UserName: "test-user",
|
||||
},
|
||||
AutodetectManualMerge: true,
|
||||
AllowManualMerge: true,
|
||||
}
|
||||
|
||||
t.Run("Config already correct", func(t *testing.T) {
|
||||
err := verifyRepositoryConfiguration(repo)
|
||||
if err != nil {
|
||||
t.Errorf("Expected nil error, got %v", err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Config incorrect - trigger update", func(t *testing.T) {
|
||||
repo.AllowManualMerge = false
|
||||
gitea.EXPECT().SetRepoOptions("test-user", "test-repo", true).Return(&models.Repository{}, nil)
|
||||
|
||||
err := verifyRepositoryConfiguration(repo)
|
||||
if err != nil {
|
||||
t.Errorf("Expected nil error, got %v", err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Update failure", func(t *testing.T) {
|
||||
repo.AllowManualMerge = false
|
||||
expectedErr := errors.New("update failed")
|
||||
gitea.EXPECT().SetRepoOptions("test-user", "test-repo", true).Return(nil, expectedErr)
|
||||
|
||||
err := verifyRepositoryConfiguration(repo)
|
||||
if err != expectedErr {
|
||||
t.Errorf("Expected %v, got %v", expectedErr, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestProcessFunc(t *testing.T) {
|
||||
ctl := gomock.NewController(t)
|
||||
defer ctl.Finish()
|
||||
|
||||
gitea := mock_common.NewMockGitea(ctl)
|
||||
gitea.EXPECT().ResetTimelineCache(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes()
|
||||
Gitea = gitea
|
||||
mockGit := mock_common.NewMockGit(ctl)
|
||||
mockGitGen := mock_common.NewMockGitHandlerGenerator(ctl)
|
||||
GitHandler = mockGitGen
|
||||
|
||||
config := &common.AutogitConfig{
|
||||
Organization: "test-org",
|
||||
GitProjectName: "test-prj#main",
|
||||
}
|
||||
|
||||
reqProc := &RequestProcessor{
|
||||
configuredRepos: map[string][]*common.AutogitConfig{
|
||||
"test-org": {config},
|
||||
},
|
||||
}
|
||||
|
||||
modelPR := &models.PullRequest{
|
||||
Index: 1,
|
||||
Base: &models.PRBranchInfo{
|
||||
Ref: "main",
|
||||
Repo: &models.Repository{
|
||||
Name: "test-repo",
|
||||
DefaultBranch: "main",
|
||||
Owner: &models.User{UserName: "test-org"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
t.Run("PullRequestWebhookEvent", func(t *testing.T) {
|
||||
event := &common.PullRequestWebhookEvent{
|
||||
Pull_Request: &common.PullRequest{
|
||||
Number: 1,
|
||||
Base: common.Head{
|
||||
Ref: "main",
|
||||
Repo: &common.Repository{
|
||||
Name: "test-repo",
|
||||
Owner: &common.Organization{
|
||||
Username: "test-org",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
gitea.EXPECT().GetPullRequest("test-org", "test-repo", int64(1)).Return(modelPR, nil).AnyTimes()
|
||||
// AllocatePRProcessor and ProcesPullRequest calls inside
|
||||
mockGitGen.EXPECT().CreateGitHandler(gomock.Any()).Return(mockGit, nil)
|
||||
mockGit.EXPECT().GetPath().Return("/tmp").AnyTimes()
|
||||
mockGit.EXPECT().Close().Return(nil)
|
||||
|
||||
// Expect Process calls (mocked via mockGit mostly)
|
||||
gitea.EXPECT().GetTimeline(gomock.Any(), gomock.Any(), gomock.Any()).Return([]*models.TimelineComment{}, nil).AnyTimes()
|
||||
gitea.EXPECT().GetPullRequestReviews(gomock.Any(), gomock.Any(), gomock.Any()).Return([]*models.PullReview{}, nil).AnyTimes()
|
||||
gitea.EXPECT().FetchMaintainershipFile(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, "", nil).AnyTimes()
|
||||
gitea.EXPECT().FetchMaintainershipDirFile(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, "", nil).AnyTimes()
|
||||
gitea.EXPECT().SetRepoOptions(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, nil).AnyTimes()
|
||||
|
||||
err := reqProc.ProcessFunc(&common.Request{Data: event})
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("IssueCommentWebhookEvent", func(t *testing.T) {
|
||||
event := &common.IssueCommentWebhookEvent{
|
||||
Issue: &common.IssueDetail{Number: 1},
|
||||
Repository: &common.Repository{
|
||||
Name: "test-repo",
|
||||
Owner: &common.Organization{Username: "test-org"},
|
||||
},
|
||||
}
|
||||
|
||||
gitea.EXPECT().GetPullRequest("test-org", "test-repo", int64(1)).Return(modelPR, nil).AnyTimes()
|
||||
mockGitGen.EXPECT().CreateGitHandler(gomock.Any()).Return(mockGit, nil)
|
||||
mockGit.EXPECT().Close().Return(nil)
|
||||
|
||||
err := reqProc.ProcessFunc(&common.Request{Data: event})
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Recursion limit", func(t *testing.T) {
|
||||
reqProc.recursive = 3
|
||||
err := reqProc.ProcessFunc(&common.Request{})
|
||||
if err != nil {
|
||||
t.Errorf("Expected nil error on recursion limit, got %v", err)
|
||||
}
|
||||
if reqProc.recursive != 3 {
|
||||
t.Errorf("Expected recursive to be 3, got %d", reqProc.recursive)
|
||||
}
|
||||
reqProc.recursive = 0 // Reset
|
||||
})
|
||||
|
||||
t.Run("Invalid data format", func(t *testing.T) {
|
||||
err := reqProc.ProcessFunc(&common.Request{Data: nil})
|
||||
if err == nil || !strings.Contains(err.Error(), "Invalid data format") {
|
||||
t.Errorf("Expected 'Invalid data format' error, got %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
|
||||
"src.opensuse.org/autogits/common"
|
||||
"src.opensuse.org/autogits/common/gitea-generated/models"
|
||||
"src.opensuse.org/autogits/workflow-pr/interfaces"
|
||||
)
|
||||
|
||||
type DefaultStateChecker struct {
|
||||
@@ -17,11 +18,11 @@ type DefaultStateChecker struct {
|
||||
checkOnStart bool
|
||||
checkInterval time.Duration
|
||||
|
||||
processor PullRequestProcessor
|
||||
i StateChecker
|
||||
processor *RequestProcessor
|
||||
i interfaces.StateChecker
|
||||
}
|
||||
|
||||
func CreateDefaultStateChecker(checkOnStart bool, processor PullRequestProcessor, gitea common.Gitea, interval time.Duration) *DefaultStateChecker {
|
||||
func CreateDefaultStateChecker(checkOnStart bool, processor *RequestProcessor, gitea common.Gitea, interval time.Duration) *DefaultStateChecker {
|
||||
var s = &DefaultStateChecker{
|
||||
checkInterval: interval,
|
||||
checkOnStart: checkOnStart,
|
||||
@@ -53,7 +54,7 @@ func (s *DefaultStateChecker) ProcessPR(pr *models.PullRequest, config *common.A
|
||||
return ProcesPullRequest(pr, common.AutogitConfigs{config})
|
||||
}
|
||||
|
||||
func PrjGitSubmoduleCheck(config *common.AutogitConfig, git common.Git, repo string, submodules map[string]string) (prsToProcess []*PRToProcess, err error) {
|
||||
func PrjGitSubmoduleCheck(config *common.AutogitConfig, git common.Git, repo string, submodules map[string]string) (prsToProcess []*interfaces.PRToProcess, err error) {
|
||||
nextSubmodule:
|
||||
for sub, commitID := range submodules {
|
||||
common.LogDebug(" + checking", sub, commitID)
|
||||
@@ -73,7 +74,7 @@ nextSubmodule:
|
||||
|
||||
branch = repo.DefaultBranch
|
||||
}
|
||||
prsToProcess = append(prsToProcess, &PRToProcess{
|
||||
prsToProcess = append(prsToProcess, &interfaces.PRToProcess{
|
||||
Org: config.Organization,
|
||||
Repo: submoduleName,
|
||||
Branch: branch,
|
||||
@@ -116,7 +117,7 @@ nextSubmodule:
|
||||
return prsToProcess, nil
|
||||
}
|
||||
|
||||
func (s *DefaultStateChecker) VerifyProjectState(config *common.AutogitConfig) ([]*PRToProcess, error) {
|
||||
func (s *DefaultStateChecker) VerifyProjectState(config *common.AutogitConfig) ([]*interfaces.PRToProcess, error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
common.LogError("panic caught")
|
||||
@@ -127,7 +128,7 @@ func (s *DefaultStateChecker) VerifyProjectState(config *common.AutogitConfig) (
|
||||
}
|
||||
}()
|
||||
|
||||
prsToProcess := []*PRToProcess{}
|
||||
prsToProcess := []*interfaces.PRToProcess{}
|
||||
|
||||
prjGitOrg, prjGitRepo, prjGitBranch := config.GetPrjGit()
|
||||
common.LogInfo(" checking", prjGitOrg+"/"+prjGitRepo+"#"+prjGitBranch)
|
||||
@@ -147,7 +148,7 @@ func (s *DefaultStateChecker) VerifyProjectState(config *common.AutogitConfig) (
|
||||
_, err = git.GitClone(prjGitRepo, prjGitBranch, repo.SSHURL)
|
||||
common.PanicOnError(err)
|
||||
|
||||
prsToProcess = append(prsToProcess, &PRToProcess{
|
||||
prsToProcess = append(prsToProcess, &interfaces.PRToProcess{
|
||||
Org: prjGitOrg,
|
||||
Repo: prjGitRepo,
|
||||
Branch: prjGitBranch,
|
||||
@@ -155,8 +156,7 @@ func (s *DefaultStateChecker) VerifyProjectState(config *common.AutogitConfig) (
|
||||
submodules, err := git.GitSubmoduleList(prjGitRepo, "HEAD")
|
||||
|
||||
// forward any package-gits referred by the project git, but don't go back
|
||||
subPrs, err := PrjGitSubmoduleCheck(config, git, prjGitRepo, submodules)
|
||||
return append(prsToProcess, subPrs...), err
|
||||
return PrjGitSubmoduleCheck(config, git, prjGitRepo, submodules)
|
||||
}
|
||||
|
||||
func (s *DefaultStateChecker) CheckRepos() {
|
||||
@@ -170,8 +170,7 @@ func (s *DefaultStateChecker) CheckRepos() {
|
||||
}
|
||||
}()
|
||||
|
||||
processor := s.processor.(*RequestProcessor)
|
||||
for org, configs := range processor.configuredRepos {
|
||||
for org, configs := range s.processor.configuredRepos {
|
||||
for _, config := range configs {
|
||||
if s.checkInterval > 0 {
|
||||
sleepInterval := (s.checkInterval - s.checkInterval/2) + time.Duration(rand.Int63n(int64(s.checkInterval)))
|
||||
|
||||
@@ -1,338 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"go.uber.org/mock/gomock"
|
||||
"src.opensuse.org/autogits/common"
|
||||
"src.opensuse.org/autogits/common/gitea-generated/models"
|
||||
mock_common "src.opensuse.org/autogits/common/mock"
|
||||
)
|
||||
|
||||
func TestPrjGitSubmoduleCheck(t *testing.T) {
|
||||
ctl := gomock.NewController(t)
|
||||
defer ctl.Finish()
|
||||
|
||||
gitea := mock_common.NewMockGitea(ctl)
|
||||
gitea.EXPECT().ResetTimelineCache(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes()
|
||||
mockGit := mock_common.NewMockGit(ctl)
|
||||
Gitea = gitea
|
||||
|
||||
config := &common.AutogitConfig{
|
||||
Organization: "test-org",
|
||||
Branch: "main",
|
||||
}
|
||||
|
||||
t.Run("Submodule up to date", func(t *testing.T) {
|
||||
submodules := map[string]string{
|
||||
"pkg-a": "sha-1",
|
||||
}
|
||||
|
||||
gitea.EXPECT().GetRecentCommits("test-org", "pkg-a", "main", int64(10)).Return([]*models.Commit{
|
||||
{SHA: "sha-1"},
|
||||
}, nil)
|
||||
|
||||
prs, err := PrjGitSubmoduleCheck(config, mockGit, "prj-repo", submodules)
|
||||
if err != nil {
|
||||
t.Fatalf("PrjGitSubmoduleCheck failed: %v", err)
|
||||
}
|
||||
|
||||
if len(prs) != 1 || prs[0].Repo != "pkg-a" {
|
||||
t.Errorf("Expected 1 PR to process for pkg-a, got %v", prs)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Submodule behind branch", func(t *testing.T) {
|
||||
submodules := map[string]string{
|
||||
"pkg-a": "sha-old",
|
||||
}
|
||||
|
||||
// sha-old is the second commit, meaning it's behind the head (sha-new)
|
||||
gitea.EXPECT().GetRecentCommits("test-org", "pkg-a", "main", int64(10)).Return([]*models.Commit{
|
||||
{SHA: "sha-new"},
|
||||
{SHA: "sha-old"},
|
||||
}, nil)
|
||||
|
||||
prs, err := PrjGitSubmoduleCheck(config, mockGit, "prj-repo", submodules)
|
||||
if err != nil {
|
||||
t.Fatalf("PrjGitSubmoduleCheck failed: %v", err)
|
||||
}
|
||||
|
||||
if len(prs) != 1 || prs[0].Repo != "pkg-a" {
|
||||
t.Errorf("Expected 1 PR to process for pkg-a, got %v", prs)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Submodule with new commits - advance branch", func(t *testing.T) {
|
||||
submodules := map[string]string{
|
||||
"pkg-a": "sha-very-new",
|
||||
}
|
||||
|
||||
// sha-very-new is NOT in recent commits
|
||||
gitea.EXPECT().GetRecentCommits("test-org", "pkg-a", "main", int64(10)).Return([]*models.Commit{
|
||||
{SHA: "sha-new"},
|
||||
{SHA: "sha-old"},
|
||||
}, nil)
|
||||
|
||||
mockGit.EXPECT().GitExec(gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
|
||||
mockGit.EXPECT().GitExecWithOutputOrPanic(gomock.Any(), "rev-list", gomock.Any(), gomock.Any()).Return("commit-1\n").AnyTimes()
|
||||
mockGit.EXPECT().GitExecWithOutputOrPanic(gomock.Any(), "remote", gomock.Any(), gomock.Any(), gomock.Any()).Return("https://src.opensuse.org/test-org/pkg-a.git\n").AnyTimes()
|
||||
mockGit.EXPECT().GitExecOrPanic(gomock.Any(), gomock.Any()).Return().AnyTimes()
|
||||
|
||||
prs, err := PrjGitSubmoduleCheck(config, mockGit, "prj-repo", submodules)
|
||||
if err != nil {
|
||||
t.Fatalf("PrjGitSubmoduleCheck failed: %v", err)
|
||||
}
|
||||
|
||||
if len(prs) != 1 || prs[0].Repo != "pkg-a" {
|
||||
t.Errorf("Expected 1 PR to process for pkg-a, got %v", prs)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestPrjGitSubmoduleCheck_Failures(t *testing.T) {
|
||||
ctl := gomock.NewController(t)
|
||||
defer ctl.Finish()
|
||||
|
||||
gitea := mock_common.NewMockGitea(ctl)
|
||||
gitea.EXPECT().ResetTimelineCache(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes()
|
||||
mockGit := mock_common.NewMockGit(ctl)
|
||||
Gitea = gitea
|
||||
|
||||
config := &common.AutogitConfig{
|
||||
Organization: "test-org",
|
||||
Branch: "main",
|
||||
}
|
||||
|
||||
t.Run("GetRecentCommits failure", func(t *testing.T) {
|
||||
submodules := map[string]string{"pkg-a": "sha-1"}
|
||||
gitea.EXPECT().GetRecentCommits("test-org", "pkg-a", "main", int64(10)).Return(nil, errors.New("gitea error"))
|
||||
|
||||
_, err := PrjGitSubmoduleCheck(config, mockGit, "prj-repo", submodules)
|
||||
if err == nil || !strings.Contains(err.Error(), "Error fetching recent commits") {
|
||||
t.Errorf("Expected gitea error, got %v", err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("SSH translation failure", func(t *testing.T) {
|
||||
submodules := map[string]string{"pkg-a": "sha-new"}
|
||||
gitea.EXPECT().GetRecentCommits("test-org", "pkg-a", "main", int64(10)).Return([]*models.Commit{{SHA: "sha-old"}}, nil)
|
||||
|
||||
mockGit.EXPECT().GitExec(gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
|
||||
mockGit.EXPECT().GitExecOrPanic(gomock.Any(), gomock.Any()).Return().AnyTimes()
|
||||
mockGit.EXPECT().GitExecWithOutputOrPanic(gomock.Any(), "rev-list", gomock.Any(), gomock.Any()).Return("commit-1\n").AnyTimes()
|
||||
// Return invalid URL that cannot be translated to SSH
|
||||
mockGit.EXPECT().GitExecWithOutputOrPanic(gomock.Any(), "remote", gomock.Any(), gomock.Any(), gomock.Any()).Return("not-a-url").AnyTimes()
|
||||
|
||||
_, err := PrjGitSubmoduleCheck(config, mockGit, "prj-repo", submodules)
|
||||
if err == nil || !strings.Contains(err.Error(), "Cannot traslate HTTPS git URL to SSH_URL") {
|
||||
t.Errorf("Expected SSH translation error, got %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestPullRequestToEventState(t *testing.T) {
|
||||
tests := []struct {
|
||||
state models.StateType
|
||||
expected string
|
||||
}{
|
||||
{"open", "opened"},
|
||||
{"closed", "closed"},
|
||||
{"merged", "merged"},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
if got := pullRequestToEventState(tt.state); got != tt.expected {
|
||||
t.Errorf("pullRequestToEventState(%v) = %v; want %v", tt.state, got, tt.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDefaultStateChecker_ProcessPR(t *testing.T) {
|
||||
ctl := gomock.NewController(t)
|
||||
defer ctl.Finish()
|
||||
|
||||
gitea := mock_common.NewMockGitea(ctl)
|
||||
gitea.EXPECT().ResetTimelineCache(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes()
|
||||
Gitea = gitea
|
||||
mockGit := mock_common.NewMockGit(ctl)
|
||||
mockGitGen := mock_common.NewMockGitHandlerGenerator(ctl)
|
||||
GitHandler = mockGitGen
|
||||
|
||||
config := &common.AutogitConfig{
|
||||
Organization: "test-org",
|
||||
GitProjectName: "test-prj#main",
|
||||
}
|
||||
|
||||
checker := CreateDefaultStateChecker(false, nil, gitea, time.Duration(0))
|
||||
|
||||
pr := &models.PullRequest{
|
||||
Index: 1,
|
||||
Base: &models.PRBranchInfo{
|
||||
Ref: "main",
|
||||
Repo: &models.Repository{
|
||||
Name: "test-repo",
|
||||
DefaultBranch: "main",
|
||||
Owner: &models.User{UserName: "test-org"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
mockGitGen.EXPECT().CreateGitHandler(gomock.Any()).Return(mockGit, nil)
|
||||
mockGit.EXPECT().GetPath().Return("/tmp").AnyTimes()
|
||||
mockGit.EXPECT().Close().Return(nil)
|
||||
|
||||
// Expectations for ProcesPullRequest
|
||||
gitea.EXPECT().GetPullRequest(gomock.Any(), gomock.Any(), gomock.Any()).Return(pr, nil).AnyTimes()
|
||||
gitea.EXPECT().GetTimeline(gomock.Any(), gomock.Any(), gomock.Any()).Return([]*models.TimelineComment{}, nil).AnyTimes()
|
||||
gitea.EXPECT().GetPullRequestReviews(gomock.Any(), gomock.Any(), gomock.Any()).Return([]*models.PullReview{}, nil).AnyTimes()
|
||||
gitea.EXPECT().FetchMaintainershipFile(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, "", nil).AnyTimes()
|
||||
gitea.EXPECT().FetchMaintainershipDirFile(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, "", nil).AnyTimes()
|
||||
gitea.EXPECT().SetRepoOptions(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, nil).AnyTimes()
|
||||
|
||||
err := checker.ProcessPR(pr, config)
|
||||
if err != nil {
|
||||
t.Errorf("ProcessPR failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDefaultStateChecker_VerifyProjectState(t *testing.T) {
|
||||
ctl := gomock.NewController(t)
|
||||
defer ctl.Finish()
|
||||
|
||||
gitea := mock_common.NewMockGitea(ctl)
|
||||
gitea.EXPECT().ResetTimelineCache(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes()
|
||||
Gitea = gitea
|
||||
mockGit := mock_common.NewMockGit(ctl)
|
||||
mockGitGen := mock_common.NewMockGitHandlerGenerator(ctl)
|
||||
GitHandler = mockGitGen
|
||||
|
||||
config := &common.AutogitConfig{
|
||||
Organization: "test-org",
|
||||
GitProjectName: "test-prj#main",
|
||||
}
|
||||
|
||||
checker := CreateDefaultStateChecker(false, nil, gitea, 0)
|
||||
|
||||
t.Run("VerifyProjectState success", func(t *testing.T) {
|
||||
mockGitGen.EXPECT().CreateGitHandler("test-org").Return(mockGit, nil)
|
||||
mockGit.EXPECT().GetPath().Return("/tmp").AnyTimes()
|
||||
mockGit.EXPECT().Close().Return(nil)
|
||||
|
||||
gitea.EXPECT().CreateRepositoryIfNotExist(gomock.Any(), "test-org", "test-prj").Return(&models.Repository{SSHURL: "url"}, nil)
|
||||
mockGit.EXPECT().GitClone("test-prj", "main", "url").Return("origin", nil)
|
||||
mockGit.EXPECT().GitSubmoduleList("test-prj", "HEAD").Return(map[string]string{"pkg-a": "sha-1"}, nil)
|
||||
|
||||
// PrjGitSubmoduleCheck call inside
|
||||
gitea.EXPECT().GetRepository(gomock.Any(), gomock.Any()).Return(&models.Repository{DefaultBranch: "main"}, nil).AnyTimes()
|
||||
// Return commits where sha-1 is NOT present
|
||||
gitea.EXPECT().GetRecentCommits("test-org", "pkg-a", "main", int64(10)).Return([]*models.Commit{
|
||||
{SHA: "sha-new"},
|
||||
}, nil).AnyTimes()
|
||||
|
||||
// rev-list returns empty string, so no new commits on branch relative to submodule commitID
|
||||
mockGit.EXPECT().GitExecWithOutputOrPanic(gomock.Any(), "rev-list", gomock.Any(), "sha-1").Return("").AnyTimes()
|
||||
// And ensure submodule update is called
|
||||
mockGit.EXPECT().GitExecOrPanic(gomock.Any(), "submodule", "update", gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return().AnyTimes()
|
||||
|
||||
prs, err := checker.VerifyProjectState(config)
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("VerifyProjectState failed: %v", err)
|
||||
}
|
||||
// Expect project git + pkg-a
|
||||
if len(prs) != 2 {
|
||||
t.Errorf("Expected 2 PRs to process, got %d", len(prs))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("VerifyProjectState failure - CreateRepository", func(t *testing.T) {
|
||||
mockGitGen.EXPECT().CreateGitHandler("test-org").Return(mockGit, nil)
|
||||
mockGit.EXPECT().GetPath().Return("/tmp").AnyTimes()
|
||||
mockGit.EXPECT().Close().Return(nil)
|
||||
|
||||
gitea.EXPECT().CreateRepositoryIfNotExist(gomock.Any(), "test-org", "test-prj").Return(nil, errors.New("gitea error"))
|
||||
|
||||
_, err := checker.VerifyProjectState(config)
|
||||
if err == nil || !strings.Contains(err.Error(), "Error fetching or creating") {
|
||||
t.Errorf("Expected gitea error, got %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestDefaultStateChecker_CheckRepos(t *testing.T) {
|
||||
ctl := gomock.NewController(t)
|
||||
defer ctl.Finish()
|
||||
|
||||
gitea := mock_common.NewMockGitea(ctl)
|
||||
gitea.EXPECT().ResetTimelineCache(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes()
|
||||
Gitea = gitea
|
||||
mockGit := mock_common.NewMockGit(ctl)
|
||||
mockGitGen := mock_common.NewMockGitHandlerGenerator(ctl)
|
||||
GitHandler = mockGitGen
|
||||
|
||||
config := &common.AutogitConfig{
|
||||
Organization: "test-org",
|
||||
GitProjectName: "test-prj#main",
|
||||
}
|
||||
|
||||
reqProc := &RequestProcessor{
|
||||
configuredRepos: map[string][]*common.AutogitConfig{
|
||||
"test-org": {config},
|
||||
},
|
||||
}
|
||||
|
||||
checker := CreateDefaultStateChecker(false, nil, gitea, 0)
|
||||
checker.processor = reqProc
|
||||
|
||||
t.Run("CheckRepos success with PRs", func(t *testing.T) {
|
||||
// Mock VerifyProjectState results
|
||||
// TODO: fix below
|
||||
// Since we can't easily mock the internal call s.i.VerifyProjectState because s.i is the checker itself
|
||||
// and VerifyProjectState is not a separate interface method in repo_check.go (it is, but used internally).
|
||||
// Actually DefaultStateChecker implements i (StateChecker interface).
|
||||
|
||||
mockGitGen.EXPECT().CreateGitHandler("test-org").Return(mockGit, nil).AnyTimes()
|
||||
mockGit.EXPECT().GetPath().Return("/tmp").AnyTimes()
|
||||
mockGit.EXPECT().Close().Return(nil).AnyTimes()
|
||||
|
||||
gitea.EXPECT().CreateRepositoryIfNotExist(gomock.Any(), gomock.Any(), gomock.Any()).Return(&models.Repository{SSHURL: "url"}, nil).AnyTimes()
|
||||
mockGit.EXPECT().GitClone(gomock.Any(), gomock.Any(), gomock.Any()).Return("origin", nil).AnyTimes()
|
||||
mockGit.EXPECT().GitSubmoduleList(gomock.Any(), gomock.Any()).Return(map[string]string{}, nil).AnyTimes()
|
||||
|
||||
// GetRecentPullRequests for the project git
|
||||
gitea.EXPECT().GetRecentPullRequests("test-org", "test-prj", "main").Return([]*models.PullRequest{
|
||||
{Index: 1, Base: &models.PRBranchInfo{Repo: &models.Repository{Name: "test-prj", Owner: &models.User{UserName: "test-org"}}}},
|
||||
}, nil).AnyTimes()
|
||||
|
||||
// ProcessPR calls for the found PR
|
||||
gitea.EXPECT().GetPullRequest(gomock.Any(), gomock.Any(), gomock.Any()).Return(&models.PullRequest{
|
||||
Index: 1,
|
||||
Base: &models.PRBranchInfo{
|
||||
Ref: "main",
|
||||
Repo: &models.Repository{Name: "test-prj", Owner: &models.User{UserName: "test-org"}},
|
||||
},
|
||||
}, nil).AnyTimes()
|
||||
gitea.EXPECT().GetTimeline(gomock.Any(), gomock.Any(), gomock.Any()).Return([]*models.TimelineComment{}, nil).AnyTimes()
|
||||
gitea.EXPECT().GetPullRequestReviews(gomock.Any(), gomock.Any(), gomock.Any()).Return([]*models.PullReview{}, nil).AnyTimes()
|
||||
gitea.EXPECT().FetchMaintainershipFile(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, "", nil).AnyTimes()
|
||||
gitea.EXPECT().FetchMaintainershipDirFile(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, "", nil).AnyTimes()
|
||||
gitea.EXPECT().SetRepoOptions(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, nil).AnyTimes()
|
||||
|
||||
checker.CheckRepos()
|
||||
})
|
||||
|
||||
t.Run("CheckRepos failure - GetRecentPullRequests", func(t *testing.T) {
|
||||
gitea.EXPECT().CreateRepositoryIfNotExist(gomock.Any(), gomock.Any(), gomock.Any()).Return(&models.Repository{SSHURL: "url"}, nil).AnyTimes()
|
||||
mockGit.EXPECT().GitClone(gomock.Any(), gomock.Any(), gomock.Any()).Return("origin", nil).AnyTimes()
|
||||
mockGit.EXPECT().GitSubmoduleList(gomock.Any(), gomock.Any()).Return(map[string]string{}, nil).AnyTimes()
|
||||
|
||||
gitea.EXPECT().GetRecentPullRequests("test-org", "test-prj", "main").Return(nil, errors.New("gitea error")).AnyTimes()
|
||||
|
||||
checker.CheckRepos()
|
||||
// Should log error and continue (no panic)
|
||||
})
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"src.opensuse.org/autogits/common"
|
||||
"src.opensuse.org/autogits/common/gitea-generated/models"
|
||||
mock_common "src.opensuse.org/autogits/common/mock"
|
||||
mock_main "src.opensuse.org/autogits/workflow-pr/mock"
|
||||
)
|
||||
|
||||
func TestRepoCheck(t *testing.T) {
|
||||
@@ -21,15 +22,16 @@ func TestRepoCheck(t *testing.T) {
|
||||
t.Run("Consistency Check On Start", func(t *testing.T) {
|
||||
c := CreateDefaultStateChecker(true, nil, nil, 100)
|
||||
ctl := gomock.NewController(t)
|
||||
state := NewMockStateChecker(ctl)
|
||||
state := mock_main.NewMockStateChecker(ctl)
|
||||
c.i = state
|
||||
state.EXPECT().CheckRepos().Do(func() {
|
||||
state.EXPECT().CheckRepos().Do(func() error {
|
||||
// only checkOnStart has checkInterval = 0
|
||||
if c.checkInterval != 0 {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
c.exitCheckLoop = true
|
||||
return nil
|
||||
})
|
||||
|
||||
c.ConsistencyCheckProcess()
|
||||
@@ -41,11 +43,11 @@ func TestRepoCheck(t *testing.T) {
|
||||
t.Run("No consistency Check On Start", func(t *testing.T) {
|
||||
c := CreateDefaultStateChecker(true, nil, nil, 100)
|
||||
ctl := gomock.NewController(t)
|
||||
state := NewMockStateChecker(ctl)
|
||||
state := mock_main.NewMockStateChecker(ctl)
|
||||
c.i = state
|
||||
|
||||
nCalls := 10
|
||||
state.EXPECT().CheckRepos().Do(func() {
|
||||
state.EXPECT().CheckRepos().Do(func() error {
|
||||
// only checkOnStart has checkInterval = 0
|
||||
if c.checkInterval != 100 {
|
||||
t.Fail()
|
||||
@@ -55,6 +57,7 @@ func TestRepoCheck(t *testing.T) {
|
||||
if nCalls == 0 {
|
||||
c.exitCheckLoop = true
|
||||
}
|
||||
return nil
|
||||
}).Times(nCalls)
|
||||
c.checkOnStart = false
|
||||
|
||||
@@ -63,9 +66,8 @@ func TestRepoCheck(t *testing.T) {
|
||||
|
||||
t.Run("CheckRepos() calls CheckProjectState() for each project", func(t *testing.T) {
|
||||
ctl := gomock.NewController(t)
|
||||
state := NewMockStateChecker(ctl)
|
||||
state := mock_main.NewMockStateChecker(ctl)
|
||||
gitea := mock_common.NewMockGitea(ctl)
|
||||
gitea.EXPECT().ResetTimelineCache(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes()
|
||||
|
||||
config1 := &common.AutogitConfig{
|
||||
GitProjectName: "git_repo1",
|
||||
@@ -95,14 +97,15 @@ func TestRepoCheck(t *testing.T) {
|
||||
state.EXPECT().VerifyProjectState(configs.configuredRepos["repo2_org"][0])
|
||||
state.EXPECT().VerifyProjectState(configs.configuredRepos["repo3_org"][0])
|
||||
|
||||
c.CheckRepos()
|
||||
if err := c.CheckRepos(); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("CheckRepos errors", func(t *testing.T) {
|
||||
ctl := gomock.NewController(t)
|
||||
state := NewMockStateChecker(ctl)
|
||||
state := mock_main.NewMockStateChecker(ctl)
|
||||
gitea := mock_common.NewMockGitea(ctl)
|
||||
gitea.EXPECT().ResetTimelineCache(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes()
|
||||
|
||||
config1 := &common.AutogitConfig{
|
||||
GitProjectName: "git_repo1",
|
||||
@@ -122,7 +125,11 @@ func TestRepoCheck(t *testing.T) {
|
||||
err := errors.New("test error")
|
||||
state.EXPECT().VerifyProjectState(configs.configuredRepos["repo1_org"][0]).Return(nil, err)
|
||||
|
||||
c.CheckRepos()
|
||||
r := c.CheckRepos()
|
||||
|
||||
if !errors.Is(r, err) {
|
||||
t.Error(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -147,7 +154,6 @@ func TestVerifyProjectState(t *testing.T) {
|
||||
t.Run("Project state with no PRs", func(t *testing.T) {
|
||||
ctl := gomock.NewController(t)
|
||||
gitea := mock_common.NewMockGitea(ctl)
|
||||
gitea.EXPECT().ResetTimelineCache(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes()
|
||||
|
||||
git := &common.GitHandlerImpl{
|
||||
GitCommiter: "TestCommiter",
|
||||
@@ -171,11 +177,11 @@ func TestVerifyProjectState(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
gitea.EXPECT().CreateRepositoryIfNotExist(gomock.Any(), gomock.Any(), gomock.Any()).Return(&models.Repository{
|
||||
gitea.EXPECT().CreateRepositoryIfNotExist(gomock.Any(), gomock.Any(), config1.GitProjectName).Return(&models.Repository{
|
||||
SSHURL: "./prj",
|
||||
}, nil).AnyTimes()
|
||||
gitea.EXPECT().GetRecentPullRequests(gomock.Any(), gomock.Any(), gomock.Any()).Return([]*models.PullRequest{}, nil).AnyTimes()
|
||||
gitea.EXPECT().GetRecentCommits(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]*models.Commit{}, nil).AnyTimes()
|
||||
}, nil)
|
||||
gitea.EXPECT().GetRecentPullRequests(org, "testRepo", "testing")
|
||||
gitea.EXPECT().GetRecentCommits(org, "testRepo", "testing", gomock.Any())
|
||||
|
||||
c := CreateDefaultStateChecker(false, configs, gitea, 0)
|
||||
/*
|
||||
@@ -193,7 +199,7 @@ func TestVerifyProjectState(t *testing.T) {
|
||||
t.Run("Project state with 1 PRs that doesn't trigger updates", func(t *testing.T) {
|
||||
ctl := gomock.NewController(t)
|
||||
gitea := mock_common.NewMockGitea(ctl)
|
||||
gitea.EXPECT().ResetTimelineCache(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes()
|
||||
process := mock_main.NewMockPullRequestProcessor(ctl)
|
||||
|
||||
git := &common.GitHandlerImpl{
|
||||
GitCommiter: "TestCommiter",
|
||||
@@ -217,11 +223,11 @@ func TestVerifyProjectState(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
gitea.EXPECT().CreateRepositoryIfNotExist(gomock.Any(), gomock.Any(), gomock.Any()).Return(&models.Repository{
|
||||
gitea.EXPECT().CreateRepositoryIfNotExist(gomock.Any(), gomock.Any(), config1.GitProjectName).Return(&models.Repository{
|
||||
SSHURL: "./prj",
|
||||
}, nil).AnyTimes()
|
||||
}, nil)
|
||||
|
||||
gitea.EXPECT().GetRecentPullRequests(gomock.Any(), gomock.Any(), gomock.Any()).Return([]*models.PullRequest{
|
||||
gitea.EXPECT().GetRecentPullRequests(org, "testRepo", "testing").Return([]*models.PullRequest{
|
||||
&models.PullRequest{
|
||||
ID: 1234,
|
||||
URL: "url here",
|
||||
@@ -253,16 +259,16 @@ func TestVerifyProjectState(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
}, nil).AnyTimes()
|
||||
}, nil)
|
||||
|
||||
gitea.EXPECT().GetRecentCommits(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]*models.Commit{}, nil).AnyTimes()
|
||||
gitea.EXPECT().GetRecentCommits(org, "testRepo", "testing", gomock.Any())
|
||||
|
||||
c := CreateDefaultStateChecker(false, configs, gitea, 0)
|
||||
/*
|
||||
c.git = &testGit{
|
||||
git: git,
|
||||
}*/
|
||||
// process.EXPECT().Process(gomock.Any())
|
||||
process.EXPECT().Process(gomock.Any(), gomock.Any(), gomock.Any())
|
||||
// c.processor.Opened = process
|
||||
|
||||
_, err := c.VerifyProjectState(configs.configuredRepos[org][0])
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"src.opensuse.org/autogits/common"
|
||||
"src.opensuse.org/autogits/common/gitea-generated/models"
|
||||
)
|
||||
|
||||
//go:generate mockgen -source=state_checker.go -destination=mock_state_checker.go -typed -package main
|
||||
|
||||
|
||||
type StateChecker interface {
|
||||
VerifyProjectState(configs *common.AutogitConfig) ([]*PRToProcess, error)
|
||||
CheckRepos()
|
||||
ConsistencyCheckProcess() error
|
||||
}
|
||||
|
||||
type PullRequestProcessor interface {
|
||||
Process(req *models.PullRequest) error
|
||||
}
|
||||
|
||||
type PRToProcess struct {
|
||||
Org, Repo, Branch string
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"src.opensuse.org/autogits/common"
|
||||
)
|
||||
|
||||
const LocalCMD = "---"
|
||||
|
||||
func gitExecs(t *testing.T, git *common.GitHandlerImpl, cmds [][]string) {
|
||||
for _, cmd := range cmds {
|
||||
if cmd[0] == LocalCMD {
|
||||
command := exec.Command(cmd[2], cmd[3:]...)
|
||||
command.Dir = filepath.Join(git.GitPath, cmd[1])
|
||||
command.Stdin = nil
|
||||
command.Env = append([]string{"GIT_CONFIG_COUNT=1", "GIT_CONFIG_KEY_1=protocol.file.allow", "GIT_CONFIG_VALUE_1=always"}, common.ExtraGitParams...)
|
||||
_, err := command.CombinedOutput()
|
||||
if err != nil {
|
||||
t.Errorf(" *** error: %v\n", err)
|
||||
}
|
||||
} else {
|
||||
git.GitExecOrPanic(cmd[0], cmd[1:]...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func commandsForPackages(dir, prefix string, startN, endN int) [][]string {
|
||||
commands := make([][]string, (endN-startN+2)*6)
|
||||
|
||||
if dir == "" {
|
||||
dir = "."
|
||||
}
|
||||
cmdIdx := 0
|
||||
for idx := startN; idx <= endN; idx++ {
|
||||
pkgDir := fmt.Sprintf("%s%d", prefix, idx)
|
||||
|
||||
commands[cmdIdx+0] = []string{"", "init", "-q", "--object-format", "sha256", "-b", "testing", pkgDir}
|
||||
commands[cmdIdx+1] = []string{LocalCMD, pkgDir, "/usr/bin/touch", "testFile"}
|
||||
commands[cmdIdx+2] = []string{pkgDir, "add", "testFile"}
|
||||
commands[cmdIdx+3] = []string{pkgDir, "commit", "-m", "added testFile"}
|
||||
commands[cmdIdx+4] = []string{pkgDir, "config", "receive.denyCurrentBranch", "ignore"}
|
||||
commands[cmdIdx+5] = []string{"prj", "submodule", "add", filepath.Join("..", pkgDir), filepath.Join(dir, pkgDir)}
|
||||
|
||||
cmdIdx += 6
|
||||
}
|
||||
|
||||
// add all the submodules to the prj
|
||||
commands[cmdIdx+0] = []string{"prj", "commit", "-a", "-m", "adding subpackages"}
|
||||
|
||||
return commands
|
||||
}
|
||||
|
||||
func setupGitForTests(t *testing.T, git *common.GitHandlerImpl) {
|
||||
common.ExtraGitParams = []string{
|
||||
"GIT_CONFIG_COUNT=1",
|
||||
"GIT_CONFIG_KEY_0=protocol.file.allow",
|
||||
"GIT_CONFIG_VALUE_0=always",
|
||||
|
||||
"GIT_AUTHOR_NAME=testname",
|
||||
"GIT_AUTHOR_EMAIL=test@suse.com",
|
||||
"GIT_AUTHOR_DATE='2005-04-07T22:13:13'",
|
||||
"GIT_COMMITTER_NAME=testname",
|
||||
"GIT_COMMITTER_EMAIL=test@suse.com",
|
||||
"GIT_COMMITTER_DATE='2005-04-07T22:13:13'",
|
||||
}
|
||||
|
||||
gitExecs(t, git, [][]string{
|
||||
{"", "init", "-q", "--object-format", "sha256", "-b", "testing", "prj"},
|
||||
{"", "init", "-q", "--object-format", "sha256", "-b", "testing", "foo"},
|
||||
{LocalCMD, "foo", "/usr/bin/touch", "file1"},
|
||||
{"foo", "add", "file1"},
|
||||
{"foo", "commit", "-m", "first commit"},
|
||||
{"prj", "config", "receive.denyCurrentBranch", "ignore"},
|
||||
{"prj", "submodule", "init"},
|
||||
{"prj", "submodule", "add", "../foo", "testRepo"},
|
||||
{"prj", "add", ".gitmodules", "testRepo"},
|
||||
{"prj", "commit", "-m", "First instance"},
|
||||
{"prj", "submodule", "deinit", "testRepo"},
|
||||
{LocalCMD, "foo", "/usr/bin/touch", "file2"},
|
||||
{"foo", "add", "file2"},
|
||||
{"foo", "commit", "-m", "added file2"},
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user