2 Commits

Author SHA256 Message Date
Jan Zerebecki
151a38d163 WIP: testpr
Some checks failed
go-generate / go-generate (pull_request) Failing after 8s
go-generate / go-generate (pull_request_target) Failing after 8s
2025-08-13 20:29:19 +02:00
Jan Zerebecki
c4dc21ac10 WIP: Add ci job to git push any diff from go generate
Some checks failed
go-generate / go-generate (push) Failing after 8s
2025-08-13 20:27:43 +02:00
32 changed files with 229 additions and 5043 deletions

View File

@@ -0,0 +1,26 @@
name: go-generate
on:
push:
branches: ['main']
pull_request:
paths:
- '**.go'
- '**foo'
workflow_dispatch:
jobs:
go-generate:
name: go-generate
container:
image: registry.opensuse.org/home/jzerebecki/branches/devel/factory/git-workflow/containers/opensuse/bci/golang-extended:latest
steps:
- run: git clone --no-checkout --depth 1 ${{ gitea.server_url }}/${{ gitea.repository }} .
- run: git fetch origin ${{ gitea.ref }}
- run: git checkout FETCH_HEAD
- run: go generate -C common; go generate -C workflow-pr
- run: echo ${{ github.event.number }}
- run: echo ${{ github.event.pull_request.author_association }}
- name: Check access
if: ${{ github.event.pull_request.author_association != 'MEMBER' }}
run: exit 1
- run: 'git status --short; git status --porcelain=2|grep --quiet -v . || ( git add .; git config user.name "Gitea Actions"; git config user.email "gitea_noreply@opensuse.org"; git commit -m "CI run result of: go generate"; git show; git show --numstat; git push origin ${{ gitea.ref }} )'
- run: git diff --numstat FETCH_HEAD HEAD

View File

@@ -23,7 +23,6 @@ Summary: GitWorkflow utilities
License: GPL-2.0-or-later License: GPL-2.0-or-later
URL: https://src.opensuse.org/adamm/autogits URL: https://src.opensuse.org/adamm/autogits
Source1: vendor.tar.zst Source1: vendor.tar.zst
BuildRequires: git
BuildRequires: golang-packaging BuildRequires: golang-packaging
BuildRequires: systemd-rpm-macros BuildRequires: systemd-rpm-macros
BuildRequires: zstd BuildRequires: zstd
@@ -34,22 +33,6 @@ Git Workflow tooling and utilities enabling automated handing of OBS projects
as git repositories as git repositories
%package -n devel-importer
Summary: Imports devel projects from obs to git
%description -n devel-importer
Command-line tool to import devel projects from obs to git
%package -n doc
Summary: Common documentation files
%description -n doc
Common documentation files
%package -n gitea-events-rabbitmq-publisher %package -n gitea-events-rabbitmq-publisher
Summary: Publishes Gitea webhook data via RabbitMQ Summary: Publishes Gitea webhook data via RabbitMQ
@@ -59,10 +42,18 @@ with a topic
<scope>.src.$organization.$webhook_type.[$webhook_action_type] <scope>.src.$organization.$webhook_type.[$webhook_action_type]
%package -n gitea-status-proxy %package -n doc
Summary: gitea-status-proxy Summary: Common documentation files
%description -n gitea-status-proxy %description -n doc
Common documentation files
%package -n devel-importer
Summary: Imports devel projects from obs to git
%description -n devel-importer
Command-line tool to import devel projects from obs to git
%package -n group-review %package -n group-review
@@ -73,12 +64,6 @@ Is used to handle reviews associated with groups defined in the
ProjectGit. ProjectGit.
%package -n obs-forward-bot
Summary: obs-forward-bot
%description -n obs-forward-bot
%package -n obs-staging-bot %package -n obs-staging-bot
Summary: Build a PR against a ProjectGit, if review is requested Summary: Build a PR against a ProjectGit, if review is requested
@@ -113,26 +98,18 @@ cp -r /home/abuild/rpmbuild/SOURCES/* ./
tar x --zstd -f %{SOURCE1} tar x --zstd -f %{SOURCE1}
%build %build
go build \
-C devel-importer \
-mod=vendor \
-buildmode=pie
go build \ go build \
-C gitea-events-rabbitmq-publisher \ -C gitea-events-rabbitmq-publisher \
-mod=vendor \ -mod=vendor \
-buildmode=pie -buildmode=pie
go build \ go build \
-C gitea_status_proxy \ -C devel-importer \
-mod=vendor \ -mod=vendor \
-buildmode=pie -buildmode=pie
go build \ go build \
-C group-review \ -C group-review \
-mod=vendor \ -mod=vendor \
-buildmode=pie -buildmode=pie
go build \
-C obs-forward-bot \
-mod=vendor \
-buildmode=pie
go build \ go build \
-C obs-staging-bot \ -C obs-staging-bot \
-mod=vendor \ -mod=vendor \
@@ -141,36 +118,24 @@ go build \
-C obs-status-service \ -C obs-status-service \
-mod=vendor \ -mod=vendor \
-buildmode=pie -buildmode=pie
go build \ #go build \
-C workflow-direct \ # -C workflow-direct \
-mod=vendor \ # -mod=vendor \
-buildmode=pie # -buildmode=pie
go build \ #go build \
-C workflow-pr \ # -C workflow-pr \
-mod=vendor \ # -mod=vendor \
-buildmode=pie # -buildmode=pie
%check
# TODO currently needs the source git history, maybe rewrite to create a git repo in the test?
#go test -C common
go test -C group-review
go test -C obs-staging-bot
go test -C obs-status-service
go test -C workflow-direct
# TODO build fails
go test -C workflow-pr
%install %install
install -D -m0755 devel-importer/devel-importer %{buildroot}%{_bindir}/devel-importer
install -D -m0755 gitea-events-rabbitmq-publisher/gitea-events-rabbitmq-publisher %{buildroot}%{_bindir}/gitea-events-rabbitmq-publisher install -D -m0755 gitea-events-rabbitmq-publisher/gitea-events-rabbitmq-publisher %{buildroot}%{_bindir}/gitea-events-rabbitmq-publisher
install -D -m0644 systemd/gitea-events-rabbitmq-publisher.service %{buildroot}%{_unitdir}/gitea-events-rabbitmq-publisher.service install -D -m0644 systemd/gitea-events-rabbitmq-publisher.service %{buildroot}%{_unitdir}/gitea-events-rabbitmq-publisher.service
install -D -m0755 gitea_status_proxy/gitea_status_proxy %{buildroot}%{_bindir}/gitea_status_proxy install -D -m0755 devel-importer/devel-importer %{buildroot}%{_bindir}/devel-importer
install -D -m0755 group-review/group-review %{buildroot}%{_bindir}/group-review install -D -m0755 group-review/group-review %{buildroot}%{_bindir}/group-review
install -D -m0755 obs-forward-bot/obs-forward-bot %{buildroot}%{_bindir}/obs-forward-bot
install -D -m0755 obs-staging-bot/obs-staging-bot %{buildroot}%{_bindir}/obs-staging-bot install -D -m0755 obs-staging-bot/obs-staging-bot %{buildroot}%{_bindir}/obs-staging-bot
install -D -m0755 obs-status-service/obs-status-service %{buildroot}%{_bindir}/obs-status-service install -D -m0755 obs-status-service/obs-status-service %{buildroot}%{_bindir}/obs-status-service
install -D -m0755 workflow-direct/workflow-direct %{buildroot}%{_bindir}/workflow-direct #install -D -m0755 workflow-direct/workflow-direct %{buildroot}%{_bindir}/workflow-direct
install -D -m0755 workflow-pr/workflow-pr %{buildroot}%{_bindir}/workflow-pr #install -D -m0755 workflow-pr/workflow-pr %{buildroot}%{_bindir}/workflow-pr
%pre -n gitea-events-rabbitmq-publisher %pre -n gitea-events-rabbitmq-publisher
%service_add_pre gitea-events-rabbitmq-publisher.service %service_add_pre gitea-events-rabbitmq-publisher.service
@@ -184,35 +149,27 @@ install -D -m0755 workflow-pr/workflow-pr
%postun -n gitea-events-rabbitmq-publisher %postun -n gitea-events-rabbitmq-publisher
%service_del_postun gitea-events-rabbitmq-publisher.service %service_del_postun gitea-events-rabbitmq-publisher.service
%files -n devel-importer
%license COPYING
%doc devel-importer/README.md
%{_bindir}/devel-importer
%files -n doc
%license COPYING
%doc doc/README.md
%doc doc/workflows.md
%files -n gitea-events-rabbitmq-publisher %files -n gitea-events-rabbitmq-publisher
%license COPYING %license COPYING
%doc gitea-events-rabbitmq-publisher/README.md %doc gitea-events-rabbitmq-publisher/README.md
%{_bindir}/gitea-events-rabbitmq-publisher %{_bindir}/gitea-events-rabbitmq-publisher
%{_unitdir}/gitea-events-rabbitmq-publisher.service %{_unitdir}/gitea-events-rabbitmq-publisher.service
%files -n gitea-status-proxy %files -n doc
%license COPYING %license COPYING
%{_bindir}/gitea_status_proxy %doc doc/README.md
%doc doc/workflows.md
%files -n devel-importer
%license COPYING
%doc devel-importer/README.md
%{_bindir}/devel-importer
%files -n group-review %files -n group-review
%license COPYING %license COPYING
%doc group-review/README.md %doc group-review/README.md
%{_bindir}/group-review %{_bindir}/group-review
%files -n obs-forward-bot
%license COPYING
%{_bindir}/obs-forward-bot
%files -n obs-staging-bot %files -n obs-staging-bot
%license COPYING %license COPYING
%doc obs-staging-bot/README.md %doc obs-staging-bot/README.md
@@ -226,10 +183,10 @@ install -D -m0755 workflow-pr/workflow-pr
%files -n workflow-direct %files -n workflow-direct
%license COPYING %license COPYING
%doc workflow-direct/README.md %doc workflow-direct/README.md
%{_bindir}/workflow-direct #%{_bindir}/workflow-direct
%files -n workflow-pr %files -n workflow-pr
%license COPYING %license COPYING
%doc workflow-pr/README.md %doc workflow-pr/README.md
%{_bindir}/workflow-pr #%{_bindir}/workflow-pr

View File

@@ -43,7 +43,6 @@ type ConfigFile struct {
type ReviewGroup struct { type ReviewGroup struct {
Name string Name string
Silent bool // will not request reviews from group members
Reviewers []string Reviewers []string
} }
@@ -58,7 +57,7 @@ type AutogitConfig struct {
GitProjectName string // Organization/GitProjectName.git is PrjGit GitProjectName string // Organization/GitProjectName.git is PrjGit
Branch string // branch name of PkgGit that aligns with PrjGit submodules Branch string // branch name of PkgGit that aligns with PrjGit submodules
Reviewers []string // only used by `pr` workflow Reviewers []string // only used by `pr` workflow
ReviewGroups []*ReviewGroup ReviewGroups []ReviewGroup
Committers []string // group in addition to Reviewers and Maintainers that can order the bot around, mostly as helper for factory-maintainers Committers []string // group in addition to Reviewers and Maintainers that can order the bot around, mostly as helper for factory-maintainers
Subdirs []string // list of directories to sort submodules into. Needed b/c _manifest cannot list non-existent directories Subdirs []string // list of directories to sort submodules into. Needed b/c _manifest cannot list non-existent directories
@@ -195,19 +194,10 @@ func (config *AutogitConfig) GetReviewGroupMembers(reviewer string) ([]string, e
return nil, errors.New("User " + reviewer + " not found as group reviewer for " + config.GitProjectName) return nil, errors.New("User " + reviewer + " not found as group reviewer for " + config.GitProjectName)
} }
func (config *AutogitConfig) GetReviewGroup(reviewer string) (*ReviewGroup, error) {
for _, g := range config.ReviewGroups {
if g.Name == reviewer {
return g, nil
}
}
return nil, errors.New("User " + reviewer + " not found as group reviewer for " + config.GitProjectName)
}
func (config *AutogitConfig) GetPrjGit() (string, string, string) { func (config *AutogitConfig) GetPrjGit() (string, string, string) {
org := config.Organization org := config.Organization
repo := DefaultGitPrj repo := DefaultGitPrj
branch := "" branch := "master"
a := strings.Split(config.GitProjectName, "/") a := strings.Split(config.GitProjectName, "/")
if len(a[0]) > 0 { if len(a[0]) > 0 {
@@ -231,9 +221,6 @@ func (config *AutogitConfig) GetPrjGit() (string, string, string) {
} }
} }
if len(branch) == 0 {
panic("branch for project is undefined. Should not happend." + org + "/" + repo)
}
return org, repo, branch return org, repo, branch
} }

View File

@@ -274,17 +274,12 @@ func (e *GitHandlerImpl) GitClone(repo, branch, remoteUrl string) (string, error
} }
func (e *GitHandlerImpl) GitBranchHead(gitDir, branchName string) (string, error) { func (e *GitHandlerImpl) GitBranchHead(gitDir, branchName string) (string, error) {
id, err := e.GitExecWithOutput(gitDir, "show-ref", "--branch", "--hash", branchName) id, err := e.GitExecWithOutput(gitDir, "show-ref", "--hash", "--verify", "refs/heads/"+branchName)
if err != nil { if err != nil {
return "", fmt.Errorf("Can't find default branch: %s", branchName) return "", fmt.Errorf("Can't find default branch: %s", branchName)
} }
id = strings.TrimSpace(SplitLines(id)[0]) return strings.TrimSpace(id), nil
if len(id) < 10 {
return "", fmt.Errorf("Can't find branch: %s", branchName)
}
return id, nil
} }
func (e *GitHandlerImpl) GitRemoteHead(gitDir, remote, branchName string) (string, error) { func (e *GitHandlerImpl) GitRemoteHead(gitDir, remote, branchName string) (string, error) {
@@ -350,7 +345,6 @@ func (e *GitHandlerImpl) GitExecWithOutput(cwd string, params ...string) (string
"GIT_COMMITTER_NAME=" + e.GitCommiter, "GIT_COMMITTER_NAME=" + e.GitCommiter,
"EMAIL=not@exist@src.opensuse.org", "EMAIL=not@exist@src.opensuse.org",
"GIT_LFS_SKIP_SMUDGE=1", "GIT_LFS_SKIP_SMUDGE=1",
"GIT_LFS_SKIP_PUSH=1",
"GIT_SSH_COMMAND=/usr/bin/ssh -o StrictHostKeyChecking=yes", "GIT_SSH_COMMAND=/usr/bin/ssh -o StrictHostKeyChecking=yes",
} }
if len(ExtraGitParams) > 0 { if len(ExtraGitParams) > 0 {

View File

@@ -160,10 +160,6 @@ type GiteaCommitStatusGetter interface {
GetCommitStatus(org, repo, hash string) ([]*models.CommitStatus, error) GetCommitStatus(org, repo, hash string) ([]*models.CommitStatus, error)
} }
type GiteaMerger interface {
ManualMergePR(org, repo string, id int64, commitid string, delBranch bool) error
}
type Gitea interface { type Gitea interface {
GiteaComment GiteaComment
GiteaRepoFetcher GiteaRepoFetcher
@@ -172,7 +168,6 @@ type Gitea interface {
GiteaReviewer GiteaReviewer
GiteaPRFetcher GiteaPRFetcher
GiteaPRUpdater GiteaPRUpdater
GiteaMerger
GiteaCommitFetcher GiteaCommitFetcher
GiteaReviewFetcher GiteaReviewFetcher
GiteaCommentFetcher GiteaCommentFetcher
@@ -238,11 +233,6 @@ func (gitea *GiteaTransport) GetPullRequest(org, project string, num int64) (*mo
gitea.transport.DefaultAuthentication, gitea.transport.DefaultAuthentication,
) )
if err != nil {
LogError(err)
return nil, err
}
return pr.Payload, err return pr.Payload, err
} }
@@ -256,36 +246,9 @@ func (gitea *GiteaTransport) UpdatePullRequest(org, repo string, num int64, opti
gitea.transport.DefaultAuthentication, gitea.transport.DefaultAuthentication,
) )
if err != nil {
LogError(err)
return nil, err
}
return pr.Payload, err return pr.Payload, err
} }
func (gitea *GiteaTransport) ManualMergePR(org, repo string, num int64, commitid string, delBranch bool) error {
manual_merge := "manually-merged"
_, err := gitea.client.Repository.RepoMergePullRequest(
repository.NewRepoMergePullRequestParams().
WithOwner(org).
WithRepo(repo).
WithIndex(num).
WithBody(&models.MergePullRequestForm{
Do: &manual_merge,
DeleteBranchAfterMerge: delBranch,
HeadCommitID: commitid,
}), gitea.transport.DefaultAuthentication,
)
if err != nil {
LogError(err)
return err
}
return nil
}
func (gitea *GiteaTransport) GetPullRequests(org, repo string) ([]*models.PullRequest, error) { func (gitea *GiteaTransport) GetPullRequests(org, repo string) ([]*models.PullRequest, error) {
var page, limit int64 var page, limit int64
@@ -647,11 +610,7 @@ func (gitea *GiteaTransport) CreatePullRequestIfNotExist(repo *models.Repository
} }
if pr, err := gitea.client.Repository.RepoGetPullRequestByBaseHead( if pr, err := gitea.client.Repository.RepoGetPullRequestByBaseHead(
repository.NewRepoGetPullRequestByBaseHeadParams(). repository.NewRepoGetPullRequestByBaseHeadParams().WithOwner(repo.Owner.UserName).WithRepo(repo.Name).WithBase(targetId).WithHead(srcId),
WithOwner(repo.Owner.UserName).
WithRepo(repo.Name).
WithBase(targetId).
WithHead(srcId),
gitea.transport.DefaultAuthentication, gitea.transport.DefaultAuthentication,
); err == nil { ); err == nil {
return pr.Payload, nil return pr.Payload, nil

View File

@@ -1,120 +0,0 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: config.go
//
// Generated by this command:
//
// mockgen -source=config.go -destination=mock/config.go -typed
//
// Package mock_common is a generated GoMock package.
package mock_common
import (
reflect "reflect"
gomock "go.uber.org/mock/gomock"
models "src.opensuse.org/autogits/common/gitea-generated/models"
)
// MockGiteaFileContentAndRepoFetcher is a mock of GiteaFileContentAndRepoFetcher interface.
type MockGiteaFileContentAndRepoFetcher struct {
ctrl *gomock.Controller
recorder *MockGiteaFileContentAndRepoFetcherMockRecorder
isgomock struct{}
}
// MockGiteaFileContentAndRepoFetcherMockRecorder is the mock recorder for MockGiteaFileContentAndRepoFetcher.
type MockGiteaFileContentAndRepoFetcherMockRecorder struct {
mock *MockGiteaFileContentAndRepoFetcher
}
// NewMockGiteaFileContentAndRepoFetcher creates a new mock instance.
func NewMockGiteaFileContentAndRepoFetcher(ctrl *gomock.Controller) *MockGiteaFileContentAndRepoFetcher {
mock := &MockGiteaFileContentAndRepoFetcher{ctrl: ctrl}
mock.recorder = &MockGiteaFileContentAndRepoFetcherMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockGiteaFileContentAndRepoFetcher) EXPECT() *MockGiteaFileContentAndRepoFetcherMockRecorder {
return m.recorder
}
// GetRepository mocks base method.
func (m *MockGiteaFileContentAndRepoFetcher) GetRepository(org, repo string) (*models.Repository, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetRepository", org, repo)
ret0, _ := ret[0].(*models.Repository)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetRepository indicates an expected call of GetRepository.
func (mr *MockGiteaFileContentAndRepoFetcherMockRecorder) GetRepository(org, repo any) *MockGiteaFileContentAndRepoFetcherGetRepositoryCall {
mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRepository", reflect.TypeOf((*MockGiteaFileContentAndRepoFetcher)(nil).GetRepository), org, repo)
return &MockGiteaFileContentAndRepoFetcherGetRepositoryCall{Call: call}
}
// MockGiteaFileContentAndRepoFetcherGetRepositoryCall wrap *gomock.Call
type MockGiteaFileContentAndRepoFetcherGetRepositoryCall struct {
*gomock.Call
}
// Return rewrite *gomock.Call.Return
func (c *MockGiteaFileContentAndRepoFetcherGetRepositoryCall) Return(arg0 *models.Repository, arg1 error) *MockGiteaFileContentAndRepoFetcherGetRepositoryCall {
c.Call = c.Call.Return(arg0, arg1)
return c
}
// Do rewrite *gomock.Call.Do
func (c *MockGiteaFileContentAndRepoFetcherGetRepositoryCall) Do(f func(string, string) (*models.Repository, error)) *MockGiteaFileContentAndRepoFetcherGetRepositoryCall {
c.Call = c.Call.Do(f)
return c
}
// DoAndReturn rewrite *gomock.Call.DoAndReturn
func (c *MockGiteaFileContentAndRepoFetcherGetRepositoryCall) DoAndReturn(f func(string, string) (*models.Repository, error)) *MockGiteaFileContentAndRepoFetcherGetRepositoryCall {
c.Call = c.Call.DoAndReturn(f)
return c
}
// GetRepositoryFileContent mocks base method.
func (m *MockGiteaFileContentAndRepoFetcher) GetRepositoryFileContent(org, repo, hash, path string) ([]byte, string, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetRepositoryFileContent", org, repo, hash, path)
ret0, _ := ret[0].([]byte)
ret1, _ := ret[1].(string)
ret2, _ := ret[2].(error)
return ret0, ret1, ret2
}
// GetRepositoryFileContent indicates an expected call of GetRepositoryFileContent.
func (mr *MockGiteaFileContentAndRepoFetcherMockRecorder) GetRepositoryFileContent(org, repo, hash, path any) *MockGiteaFileContentAndRepoFetcherGetRepositoryFileContentCall {
mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRepositoryFileContent", reflect.TypeOf((*MockGiteaFileContentAndRepoFetcher)(nil).GetRepositoryFileContent), org, repo, hash, path)
return &MockGiteaFileContentAndRepoFetcherGetRepositoryFileContentCall{Call: call}
}
// MockGiteaFileContentAndRepoFetcherGetRepositoryFileContentCall wrap *gomock.Call
type MockGiteaFileContentAndRepoFetcherGetRepositoryFileContentCall struct {
*gomock.Call
}
// Return rewrite *gomock.Call.Return
func (c *MockGiteaFileContentAndRepoFetcherGetRepositoryFileContentCall) Return(arg0 []byte, arg1 string, arg2 error) *MockGiteaFileContentAndRepoFetcherGetRepositoryFileContentCall {
c.Call = c.Call.Return(arg0, arg1, arg2)
return c
}
// Do rewrite *gomock.Call.Do
func (c *MockGiteaFileContentAndRepoFetcherGetRepositoryFileContentCall) Do(f func(string, string, string, string) ([]byte, string, error)) *MockGiteaFileContentAndRepoFetcherGetRepositoryFileContentCall {
c.Call = c.Call.Do(f)
return c
}
// DoAndReturn rewrite *gomock.Call.DoAndReturn
func (c *MockGiteaFileContentAndRepoFetcherGetRepositoryFileContentCall) DoAndReturn(f func(string, string, string, string) ([]byte, string, error)) *MockGiteaFileContentAndRepoFetcherGetRepositoryFileContentCall {
c.Call = c.Call.DoAndReturn(f)
return c
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,155 +0,0 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: maintainership.go
//
// Generated by this command:
//
// mockgen -source=maintainership.go -destination=mock/maintainership.go -typed
//
// Package mock_common is a generated GoMock package.
package mock_common
import (
reflect "reflect"
gomock "go.uber.org/mock/gomock"
models "src.opensuse.org/autogits/common/gitea-generated/models"
)
// MockMaintainershipData is a mock of MaintainershipData interface.
type MockMaintainershipData struct {
ctrl *gomock.Controller
recorder *MockMaintainershipDataMockRecorder
isgomock struct{}
}
// MockMaintainershipDataMockRecorder is the mock recorder for MockMaintainershipData.
type MockMaintainershipDataMockRecorder struct {
mock *MockMaintainershipData
}
// NewMockMaintainershipData creates a new mock instance.
func NewMockMaintainershipData(ctrl *gomock.Controller) *MockMaintainershipData {
mock := &MockMaintainershipData{ctrl: ctrl}
mock.recorder = &MockMaintainershipDataMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockMaintainershipData) EXPECT() *MockMaintainershipDataMockRecorder {
return m.recorder
}
// IsApproved mocks base method.
func (m *MockMaintainershipData) IsApproved(pkg string, reviews []*models.PullReview, submitter string) bool {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "IsApproved", pkg, reviews, submitter)
ret0, _ := ret[0].(bool)
return ret0
}
// IsApproved indicates an expected call of IsApproved.
func (mr *MockMaintainershipDataMockRecorder) IsApproved(pkg, reviews, submitter any) *MockMaintainershipDataIsApprovedCall {
mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsApproved", reflect.TypeOf((*MockMaintainershipData)(nil).IsApproved), pkg, reviews, submitter)
return &MockMaintainershipDataIsApprovedCall{Call: call}
}
// MockMaintainershipDataIsApprovedCall wrap *gomock.Call
type MockMaintainershipDataIsApprovedCall struct {
*gomock.Call
}
// Return rewrite *gomock.Call.Return
func (c *MockMaintainershipDataIsApprovedCall) Return(arg0 bool) *MockMaintainershipDataIsApprovedCall {
c.Call = c.Call.Return(arg0)
return c
}
// Do rewrite *gomock.Call.Do
func (c *MockMaintainershipDataIsApprovedCall) Do(f func(string, []*models.PullReview, string) bool) *MockMaintainershipDataIsApprovedCall {
c.Call = c.Call.Do(f)
return c
}
// DoAndReturn rewrite *gomock.Call.DoAndReturn
func (c *MockMaintainershipDataIsApprovedCall) DoAndReturn(f func(string, []*models.PullReview, string) bool) *MockMaintainershipDataIsApprovedCall {
c.Call = c.Call.DoAndReturn(f)
return c
}
// ListPackageMaintainers mocks base method.
func (m *MockMaintainershipData) ListPackageMaintainers(pkg string) []string {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ListPackageMaintainers", pkg)
ret0, _ := ret[0].([]string)
return ret0
}
// ListPackageMaintainers indicates an expected call of ListPackageMaintainers.
func (mr *MockMaintainershipDataMockRecorder) ListPackageMaintainers(pkg any) *MockMaintainershipDataListPackageMaintainersCall {
mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListPackageMaintainers", reflect.TypeOf((*MockMaintainershipData)(nil).ListPackageMaintainers), pkg)
return &MockMaintainershipDataListPackageMaintainersCall{Call: call}
}
// MockMaintainershipDataListPackageMaintainersCall wrap *gomock.Call
type MockMaintainershipDataListPackageMaintainersCall struct {
*gomock.Call
}
// Return rewrite *gomock.Call.Return
func (c *MockMaintainershipDataListPackageMaintainersCall) Return(arg0 []string) *MockMaintainershipDataListPackageMaintainersCall {
c.Call = c.Call.Return(arg0)
return c
}
// Do rewrite *gomock.Call.Do
func (c *MockMaintainershipDataListPackageMaintainersCall) Do(f func(string) []string) *MockMaintainershipDataListPackageMaintainersCall {
c.Call = c.Call.Do(f)
return c
}
// DoAndReturn rewrite *gomock.Call.DoAndReturn
func (c *MockMaintainershipDataListPackageMaintainersCall) DoAndReturn(f func(string) []string) *MockMaintainershipDataListPackageMaintainersCall {
c.Call = c.Call.DoAndReturn(f)
return c
}
// ListProjectMaintainers mocks base method.
func (m *MockMaintainershipData) ListProjectMaintainers() []string {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ListProjectMaintainers")
ret0, _ := ret[0].([]string)
return ret0
}
// ListProjectMaintainers indicates an expected call of ListProjectMaintainers.
func (mr *MockMaintainershipDataMockRecorder) ListProjectMaintainers() *MockMaintainershipDataListProjectMaintainersCall {
mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListProjectMaintainers", reflect.TypeOf((*MockMaintainershipData)(nil).ListProjectMaintainers))
return &MockMaintainershipDataListProjectMaintainersCall{Call: call}
}
// MockMaintainershipDataListProjectMaintainersCall wrap *gomock.Call
type MockMaintainershipDataListProjectMaintainersCall struct {
*gomock.Call
}
// Return rewrite *gomock.Call.Return
func (c *MockMaintainershipDataListProjectMaintainersCall) Return(arg0 []string) *MockMaintainershipDataListProjectMaintainersCall {
c.Call = c.Call.Return(arg0)
return c
}
// Do rewrite *gomock.Call.Do
func (c *MockMaintainershipDataListProjectMaintainersCall) Do(f func() []string) *MockMaintainershipDataListProjectMaintainersCall {
c.Call = c.Call.Do(f)
return c
}
// DoAndReturn rewrite *gomock.Call.DoAndReturn
func (c *MockMaintainershipDataListProjectMaintainersCall) DoAndReturn(f func() []string) *MockMaintainershipDataListProjectMaintainersCall {
c.Call = c.Call.DoAndReturn(f)
return c
}

View File

@@ -1,85 +0,0 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: obs_utils.go
//
// Generated by this command:
//
// mockgen -source=obs_utils.go -destination=mock/obs_utils.go -typed
//
// Package mock_common is a generated GoMock package.
package mock_common
import (
reflect "reflect"
gomock "go.uber.org/mock/gomock"
common "src.opensuse.org/autogits/common"
)
// MockObsStatusFetcherWithState is a mock of ObsStatusFetcherWithState interface.
type MockObsStatusFetcherWithState struct {
ctrl *gomock.Controller
recorder *MockObsStatusFetcherWithStateMockRecorder
isgomock struct{}
}
// MockObsStatusFetcherWithStateMockRecorder is the mock recorder for MockObsStatusFetcherWithState.
type MockObsStatusFetcherWithStateMockRecorder struct {
mock *MockObsStatusFetcherWithState
}
// NewMockObsStatusFetcherWithState creates a new mock instance.
func NewMockObsStatusFetcherWithState(ctrl *gomock.Controller) *MockObsStatusFetcherWithState {
mock := &MockObsStatusFetcherWithState{ctrl: ctrl}
mock.recorder = &MockObsStatusFetcherWithStateMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockObsStatusFetcherWithState) EXPECT() *MockObsStatusFetcherWithStateMockRecorder {
return m.recorder
}
// BuildStatusWithState mocks base method.
func (m *MockObsStatusFetcherWithState) BuildStatusWithState(project string, opts *common.BuildResultOptions, packages ...string) (*common.BuildResultList, error) {
m.ctrl.T.Helper()
varargs := []any{project, opts}
for _, a := range packages {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "BuildStatusWithState", varargs...)
ret0, _ := ret[0].(*common.BuildResultList)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// BuildStatusWithState indicates an expected call of BuildStatusWithState.
func (mr *MockObsStatusFetcherWithStateMockRecorder) BuildStatusWithState(project, opts any, packages ...any) *MockObsStatusFetcherWithStateBuildStatusWithStateCall {
mr.mock.ctrl.T.Helper()
varargs := append([]any{project, opts}, packages...)
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BuildStatusWithState", reflect.TypeOf((*MockObsStatusFetcherWithState)(nil).BuildStatusWithState), varargs...)
return &MockObsStatusFetcherWithStateBuildStatusWithStateCall{Call: call}
}
// MockObsStatusFetcherWithStateBuildStatusWithStateCall wrap *gomock.Call
type MockObsStatusFetcherWithStateBuildStatusWithStateCall struct {
*gomock.Call
}
// Return rewrite *gomock.Call.Return
func (c *MockObsStatusFetcherWithStateBuildStatusWithStateCall) Return(arg0 *common.BuildResultList, arg1 error) *MockObsStatusFetcherWithStateBuildStatusWithStateCall {
c.Call = c.Call.Return(arg0, arg1)
return c
}
// Do rewrite *gomock.Call.Do
func (c *MockObsStatusFetcherWithStateBuildStatusWithStateCall) Do(f func(string, *common.BuildResultOptions, ...string) (*common.BuildResultList, error)) *MockObsStatusFetcherWithStateBuildStatusWithStateCall {
c.Call = c.Call.Do(f)
return c
}
// DoAndReturn rewrite *gomock.Call.DoAndReturn
func (c *MockObsStatusFetcherWithStateBuildStatusWithStateCall) DoAndReturn(f func(string, *common.BuildResultOptions, ...string) (*common.BuildResultList, error)) *MockObsStatusFetcherWithStateBuildStatusWithStateCall {
c.Call = c.Call.DoAndReturn(f)
return c
}

View File

@@ -583,12 +583,6 @@ type PackageBuildStatus struct {
Package string `xml:"package,attr"` Package string `xml:"package,attr"`
Code string `xml:"code,attr"` Code string `xml:"code,attr"`
Details string `xml:"details"` Details string `xml:"details"`
LastUpdate time.Time
}
func PackageBuildStatusComp(A, B *PackageBuildStatus) int {
return strings.Compare(A.Package, B.Package)
} }
type BuildResult struct { type BuildResult struct {
@@ -599,20 +593,8 @@ type BuildResult struct {
Dirty bool `xml:"dirty,attr"` Dirty bool `xml:"dirty,attr"`
ScmSync string `xml:"scmsync"` ScmSync string `xml:"scmsync"`
ScmInfo string `xml:"scminfo"` ScmInfo string `xml:"scminfo"`
Status []*PackageBuildStatus `xml:"status"` Status []PackageBuildStatus `xml:"status"`
Binaries []BinaryList `xml:"binarylist"` Binaries []BinaryList `xml:"binarylist"`
LastUpdate time.Time
}
func BuildResultComp(A, B *BuildResult) int {
if cmp := strings.Compare(A.Project, B.Project); cmp != 0 {
return cmp
}
if cmp := strings.Compare(A.Repository, B.Repository); cmp != 0 {
return cmp
}
return strings.Compare(A.Arch, B.Arch)
} }
type Binary struct { type Binary struct {
@@ -629,7 +611,7 @@ type BinaryList struct {
type BuildResultList struct { type BuildResultList struct {
XMLName xml.Name `xml:"resultlist"` XMLName xml.Name `xml:"resultlist"`
State string `xml:"state,attr"` State string `xml:"state,attr"`
Result []*BuildResult `xml:"result"` Result []BuildResult `xml:"result"`
isLastBuild bool isLastBuild bool
} }

View File

@@ -1,8 +0,0 @@
all: ../workflow-direct/workflow-direct
cp ../workflow-direct/workflow-direct workflow-direct
podman build --pull=always -t workflow-direct workflow-direct
pr:
cp ../workflow-pr/workflow-pr workflow-pr
podman build --pull=always -t workflow-pr workflow-pr

View File

@@ -1 +0,0 @@
workflow-direct

View File

@@ -1,14 +0,0 @@
FROM registry.suse.com/bci/bci-base
RUN zypper install -y openssh-clients git-core
RUN mkdir /root/.ssh
RUN mkdir /repos
RUN ln -s /data/workflow-direct.key /root/.ssh/id_ed25519
RUN ln -s /data/workflow-direct.key.pub /root/.ssh/id_ed25519.pub
ADD known_hosts /root/.ssh/known_hosts
ADD workflow-direct /srv/workflow-direct
ENV AMQP_USERNAME=opensuse
ENV AMQP_PASSWORD=opensuse
VOLUME /data
VOLUME /repos
ENTRYPOINT /srv/workflow-direct -config /data/config.json -repo-path /repos -debug -check-on-start

View File

@@ -1,4 +0,0 @@
src.opensuse.org,195.135.223.224 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBDJ8V51MVIFUkQqQOdHwC3SP9NPqp1ZWYoEbcjvZ7HhSFi2XF8ALo/h1Mk+q8kT2O75/goeTsKFbcU8zrYFeOh0=
src.opensuse.org,195.135.223.224 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCkVeXePin0haffC085V2L0jvILfwbB2Mt1fpVe21QAOcWNM+/jOC5RwtWweV/LigHImB39/KvkuPa9yLoDf+eLhdZQckSSauRfDjxtlKeFLPrfJKSA0XeVJT3kJcOvDT/3ANFhYeBbAUBTAeQt5bi2hHC1twMPbaaEdJ2jiMaIBztFf6aE9K58uoS+7Y2tTv87Mv/7lqoBW6BFMoDmjQFWgjik6ZMCvIM/7bj7AgqHk/rjmr5zKS4ag5wtHtYLm1L3LBmHdj7d0VFsOpPQexIOEnnjzKqlwmAxT6eYJ/t3qgBlT8KRfshBFgEuUZ5GJOC7TOne4PfB0bboPMZzIRo3WE9dPGRR8kAIme8XqhFbmjdJ+WsTjg0Lj+415tIbyRQoNkLtawrJxozvevs6wFEFcA/YG6o03Z577tiLT3WxOguCcD5vrALH48SyZb8jDUtcVgTWMW0to/n63S8JGUNyF7Bkw9HQWUx+GO1cv2GNzKpk22KS5dlNUVGE9E/7Ydc=
src.opensuse.org,195.135.223.224 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFKNThLRPznU5Io1KrAYHmYpaoLQEMGM9nwpKyYQCkPx

View File

@@ -1 +0,0 @@
workflow-pr

View File

@@ -1,14 +0,0 @@
FROM registry.suse.com/bci/bci-base
RUN zypper install -y openssh-clients git-core
RUN mkdir /root/.ssh
RUN mkdir /repos
RUN ln -s /data/workflow-pr.key /root/.ssh/id_ed25519
RUN ln -s /data/workflow-pr.key.pub /root/.ssh/id_ed25519.pub
ADD known_hosts /root/.ssh/known_hosts
ADD workflow-pr /srv/workflow-pr
ENV AMQP_USERNAME=opensuse
ENV AMQP_PASSWORD=opensuse
VOLUME /data
VOLUME /repos
ENTRYPOINT /srv/workflow-pr -config /data/config.json -repo-path /repos -debug -check-on-start

View File

@@ -1,4 +0,0 @@
src.opensuse.org,195.135.223.224 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBDJ8V51MVIFUkQqQOdHwC3SP9NPqp1ZWYoEbcjvZ7HhSFi2XF8ALo/h1Mk+q8kT2O75/goeTsKFbcU8zrYFeOh0=
src.opensuse.org,195.135.223.224 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCkVeXePin0haffC085V2L0jvILfwbB2Mt1fpVe21QAOcWNM+/jOC5RwtWweV/LigHImB39/KvkuPa9yLoDf+eLhdZQckSSauRfDjxtlKeFLPrfJKSA0XeVJT3kJcOvDT/3ANFhYeBbAUBTAeQt5bi2hHC1twMPbaaEdJ2jiMaIBztFf6aE9K58uoS+7Y2tTv87Mv/7lqoBW6BFMoDmjQFWgjik6ZMCvIM/7bj7AgqHk/rjmr5zKS4ag5wtHtYLm1L3LBmHdj7d0VFsOpPQexIOEnnjzKqlwmAxT6eYJ/t3qgBlT8KRfshBFgEuUZ5GJOC7TOne4PfB0bboPMZzIRo3WE9dPGRR8kAIme8XqhFbmjdJ+WsTjg0Lj+415tIbyRQoNkLtawrJxozvevs6wFEFcA/YG6o03Z577tiLT3WxOguCcD5vrALH48SyZb8jDUtcVgTWMW0to/n63S8JGUNyF7Bkw9HQWUx+GO1cv2GNzKpk22KS5dlNUVGE9E/7Ydc=
src.opensuse.org,195.135.223.224 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFKNThLRPznU5Io1KrAYHmYpaoLQEMGM9nwpKyYQCkPx

View File

@@ -146,10 +146,8 @@ func listMaintainers(obs *common.ObsClient, prj string, pkgs []string) {
log.Panicln(err) log.Panicln(err)
} }
if user != nil {
contact_email = append(contact_email, fmt.Sprintf("%s <%s>", user.Name, user.Email)) contact_email = append(contact_email, fmt.Sprintf("%s <%s>", user.Name, user.Email))
} }
}
log.Println(strings.Join(contact_email, ", ")) log.Println(strings.Join(contact_email, ", "))
} }
@@ -216,8 +214,8 @@ func findMissingDevelBranch(git common.Git, pkg, project string) {
} }
func importFactoryRepoAndCheckHistory(pkg string, meta *common.PackageMeta) (factoryRepo *models.Repository, retErr error) { func importFactoryRepoAndCheckHistory(pkg string, meta *common.PackageMeta) (factoryRepo *models.Repository, retErr error) {
if repo, err := client.Repository.RepoGet(repository.NewRepoGetParams().WithDefaults().WithOwner("pool").WithRepo(giteaPackage(pkg)), r.DefaultAuthentication); err != nil || repo.Payload.ObjectFormatName != "sha256" { if repo, err := client.Repository.RepoGet(repository.NewRepoGetParams().WithDefaults().WithOwner("pool").WithRepo(giteaPackage(pkg)), r.DefaultAuthentication); err != nil {
if err != nil && !errors.Is(err, &repository.RepoGetNotFound{}) { if !errors.Is(err, &repository.RepoGetNotFound{}) {
log.Panicln(err) log.Panicln(err)
} }
@@ -243,14 +241,14 @@ func importFactoryRepoAndCheckHistory(pkg string, meta *common.PackageMeta) (fac
} }
roots := 0 roots := 0
if _, err := git.GitRemoteHead(pkg, "pool", "devel"); err == nil { if _, err := git.GitBranchHead(pkg, "pool/devel"); err == nil {
factory_roots := strings.TrimSpace(git.GitExecWithOutputOrPanic(pkg, "rev-list", "pool/factory", "--max-parents=0")) factory_roots := strings.TrimSpace(git.GitExecWithOutputOrPanic(pkg, "rev-list", "pool/factory", "--max-parents=0"))
devel_roots := strings.TrimSpace(git.GitExecWithOutputOrPanic(pkg, "rev-list", "pool/devel", "--max-parents=0")) devel_roots := strings.TrimSpace(git.GitExecWithOutputOrPanic(pkg, "rev-list", "pool/devel", "--max-parents=0"))
roots = len(common.SplitLines(factory_roots)) roots = len(common.SplitLines(factory_roots))
if devel_roots != factory_roots || len(common.SplitLines(factory_roots)) != 1 { if devel_roots != factory_roots || len(common.SplitLines(factory_roots)) != 1 {
roots = 10 roots = 10
} }
} else if _, err := git.GitRemoteHead(pkg, "pool", "factory"); err == nil { } else if _, err := git.GitBranchHead(pkg, "pool/factory"); err == nil {
items := strings.TrimSpace(git.GitExecWithOutputOrPanic(pkg, "rev-list", "pool/factory", "--max-parents=0")) items := strings.TrimSpace(git.GitExecWithOutputOrPanic(pkg, "rev-list", "pool/factory", "--max-parents=0"))
roots = len(common.SplitLines(items)) roots = len(common.SplitLines(items))
} else { } else {
@@ -396,38 +394,38 @@ func PushRepository(factoryRepo, develRepo *models.Repository, pkg string) (repo
SetRepoOptions(repo) SetRepoOptions(repo)
git.GitExec(pkg, "push", "develorigin", "--delete", "factory") git.GitExec(pkg, "push", "develorigin", "--delete", "factory")
git.GitExec(pkg, "push", "develorigin", "--delete", "devel") git.GitExec(pkg, "push", "develorigin", "--delete", "devel")
git.GitExec(pkg, "push", "develorigin", "--delete", "leap-16.0")
return repo return repo
} }
func importDevelRepoAndCheckHistory(pkg string, meta *common.PackageMeta) *models.Repository { func importDevelRepoAndCheckHistory(pkg string, meta *common.PackageMeta) *models.Repository {
repo := CreateDevelOnlyPackage(pkg) repo := CreateDevelOnlyPackage(pkg)
log.Println("setting main branch for devel package:", pkg)
if meta == nil {
log.Println(" **** pkg meta is nil? ****")
} else if len(meta.ScmSync) > 0 {
if _, err := os.Stat(path.Join(git.GetPath(), pkg)); os.IsNotExist(err) {
u, _ := url.Parse(meta.ScmSync)
if err2 := cloneDevel(git, "", pkg, meta.ScmSync, "origin", true); err2 != nil {
log.Panicln(err2)
}
git.GitExecOrPanic(pkg, "checkout", "-B", "main", u.Fragment)
}
common.LogDebug("skip check for scmsync")
return repo
}
if _, err := os.Stat(filepath.Join(git.GetPath(), pkg)); os.IsNotExist(err) { if _, err := os.Stat(filepath.Join(git.GetPath(), pkg)); os.IsNotExist(err) {
cloneDevel(git, "", pkg, repo.SSHURL, "develorigin", false) // in case we have imported cloneDevel(git, "", pkg, repo.SSHURL, "develorigin", false) // in case we have imported
} }
if CloneScmsync(pkg, meta) {
return repo
}
var p, dp string var p, dp string
factory_branch, fhe := git.GitRemoteHead(pkg, "develorigin", "factory") factory_branch, fhe := git.GitBranchHead(pkg, "factory")
if fhe == nil { if fhe == nil {
p = strings.TrimSpace(git.GitExecWithOutputOrPanic(pkg, "rev-list", "--max-parents=0", "--count", factory_branch)) p = strings.TrimSpace(git.GitExecWithOutputOrPanic(pkg, "rev-list", "--max-parents=0", "--count", factory_branch))
} else { } else {
common.LogError(fhe) common.LogError(fhe)
} }
devel_branch, dhe := git.GitRemoteHead(pkg, "develorigin", "devel") devel_branch, dhe := git.GitBranchHead(pkg, "devel")
if dhe != nil {
devel_project, err := devel_projects.GetDevelProject(pkg)
common.LogDebug("Devel project:", devel_project, err)
if err == common.DevelProjectNotFound {
// assume it's this project, maybe removed from factory
devel_project = prj
}
common.LogDebug("finding missing branches in", pkg, devel_project)
findMissingDevelBranch(git, pkg, devel_project)
devel_branch, dhe = git.GitBranchHead(pkg, "devel")
}
if dhe == nil { if dhe == nil {
dp = strings.TrimSpace(git.GitExecWithOutputOrPanic(pkg, "rev-list", "--max-parents=0", "--count", devel_branch)) dp = strings.TrimSpace(git.GitExecWithOutputOrPanic(pkg, "rev-list", "--max-parents=0", "--count", devel_branch))
} else { } else {
@@ -456,32 +454,6 @@ func importDevelRepoAndCheckHistory(pkg string, meta *common.PackageMeta) *model
return repo return repo
} }
return repo
}
func SetMainBranch(pkg string, meta *common.PackageMeta) {
// scnsync, follow that and don't care
common.LogDebug("Setting main branch...")
remotes := common.SplitStringNoEmpty(git.GitExecWithOutputOrPanic(pkg, "remote", "show"), "\n")
if slices.Contains(remotes, "origin") {
u, err := url.Parse(meta.ScmSync)
common.PanicOnError(err)
if len(u.Fragment) == 0 {
u.Fragment = "HEAD"
}
if err := git.GitExec(pkg, "checkout", "-B", "main", u.Fragment); err != nil {
git.GitExecOrPanic(pkg, "checkout", "-B", "main", "origin/"+u.Fragment)
}
return
}
// check if we have factory
if _, err := git.GitBranchHead(pkg, "factory"); err != nil {
if len(git.GitExecWithOutputOrPanic(pkg, "show-ref", "pool/factory")) > 20 {
git.GitExecOrPanic(pkg, "branch", "factory", "pool/factory")
}
}
// mark newer branch as main // mark newer branch as main
branch := "factory" branch := "factory"
if len(common.SplitStringNoEmpty(git.GitExecWithOutputOrPanic(pkg, "rev-list", "^factory", "devel"), "\n")) > 0 { if len(common.SplitStringNoEmpty(git.GitExecWithOutputOrPanic(pkg, "rev-list", "^factory", "devel"), "\n")) > 0 {
@@ -489,67 +461,13 @@ func SetMainBranch(pkg string, meta *common.PackageMeta) {
} }
common.LogInfo("setting main to", branch) common.LogInfo("setting main to", branch)
git.GitExecOrPanic(pkg, "checkout", "-B", "main", branch) git.GitExecOrPanic(pkg, "checkout", "-B", "main", branch)
return repo
} }
func ObsToRepoName(obspkg string) string { func ObsToRepoName(obspkg string) string {
return strings.ReplaceAll(obspkg, "+", "_") return strings.ReplaceAll(obspkg, "+", "_")
} }
func ImportSha1Sync(pkg string, url *url.URL) {
common.LogDebug("Converting SHA1", url.String())
branch := url.Fragment
url.Fragment = ""
p := path.Join(pkg, "sha1stuff")
common.PanicOnError(os.RemoveAll(path.Join(git.GetPath(), p)))
git.GitExecOrPanic(pkg, "clone", "--mirror", url.String(), "sha1stuff")
git.GitExecOrPanic(p, "fetch", "origin", branch)
gitexport := exec.Command("/usr/bin/git", "fast-export", "--signed-tags=strip", "--tag-of-filtered-object=drop", "--all")
gitexport.Dir = path.Join(git.GetPath(), p)
gitexportData, err := gitexport.Output()
common.LogDebug("Got export data size:", len(gitexportData))
common.PanicOnError(err)
gitimport := exec.Command("/usr/bin/git", "fast-import", "--allow-unsafe-features")
gitimport.Dir = path.Join(git.GetPath(), pkg)
gitimport.Stdin = bytes.NewReader(gitexportData)
data, err := gitimport.CombinedOutput()
common.LogError(string(data))
common.PanicOnError(err)
common.PanicOnError(os.RemoveAll(path.Join(git.GetPath(), p)))
git.GitExecOrPanic(pkg, "checkout", branch)
}
func LfsImport(pkg string) {
git.GitExecOrPanic(pkg, "lfs", "migrate", "import", "--everything",
"--include=*.7z,*.bsp,*.bz2,*.gem,*.gz,*.jar,*.lz,*.lzma,*.obscpio,*.oxt,*.pdf,*.png,*.rpm,*.tar,*.tbz,*.tbz2,*.tgz,*.ttf,*.txz,*.whl,*.xz,*.zip,*.zst")
}
func CloneScmsync(pkg string, meta *common.PackageMeta) bool {
if len(meta.ScmSync) > 0 {
u, _ := url.Parse(meta.ScmSync)
if remotes := common.SplitStringNoEmpty(git.GitExecWithOutputOrPanic(pkg, "remote", "show"), "\n"); !slices.Contains(remotes, "origin") {
branch := u.Fragment
if len(branch) == 0 {
branch = "HEAD"
}
u.Fragment = ""
git.GitExecOrPanic(pkg, "remote", "add", "origin", u.String())
u.Fragment = branch
}
if err := git.GitExec(pkg, "fetch", "origin"); err != nil && strings.Contains(err.Error(), "fatal: mismatched algorithms: client sha256; server sha1") {
ImportSha1Sync(pkg, u)
} else if err != nil {
panic(err)
}
LfsImport(pkg)
return true
}
return false
}
func importRepo(pkg string) (BrokenFactoryPackage, FailedImport bool) { func importRepo(pkg string) (BrokenFactoryPackage, FailedImport bool) {
BrokenFactoryPackage = false BrokenFactoryPackage = false
FailedImport = false FailedImport = false
@@ -569,9 +487,6 @@ func importRepo(pkg string) (BrokenFactoryPackage, FailedImport bool) {
if err != nil { if err != nil {
common.PanicOnError(err) common.PanicOnError(err)
} }
if meta == nil {
panic("package meta is nil...")
}
factoryRepo, err = importFactoryRepoAndCheckHistory(pkg, meta) factoryRepo, err = importFactoryRepoAndCheckHistory(pkg, meta)
if factoryRepo != nil && err != nil { if factoryRepo != nil && err != nil {
@@ -583,11 +498,8 @@ func importRepo(pkg string) (BrokenFactoryPackage, FailedImport bool) {
if factoryRepo == nil || BrokenFactoryPackage { if factoryRepo == nil || BrokenFactoryPackage {
develRepo = importDevelRepoAndCheckHistory(pkg, meta) develRepo = importDevelRepoAndCheckHistory(pkg, meta)
} else {
CloneScmsync(pkg, meta)
} }
SetMainBranch(pkg, meta)
PushRepository(factoryRepo, develRepo, pkg) PushRepository(factoryRepo, develRepo, pkg)
return return
} }

1
foo Normal file
View File

@@ -0,0 +1 @@
test

View File

@@ -15,23 +15,6 @@ Target Usage
Projects where policy reviews are required. Projects where policy reviews are required.
Configiuration
--------------
Groups are defined in the workflow.config inside the project git. They take following options,
{
...
ReviewGroups: [
{
"Name": "name of the group user",
"Reviewers": ["members", "of", "group"],
"Silent": (true, false) -- if true, do not explicitly require review requests of group members
},
],
...
}
Requirements Requirements
------------ ------------
* Gitea token to: * Gitea token to:

View File

@@ -205,14 +205,13 @@ func ProcessNotifications(notification *models.NotificationThread, gitea common.
return return
} }
groupConfig, err := config.GetReviewGroup(groupName) requestReviewers, err := config.GetReviewGroupMembers(groupName)
if err != nil { if err != nil {
common.LogError(err) common.LogError(err)
return return
} }
// submitter cannot be reviewer // submitter cannot be reviewer
requestReviewers := groupConfig.Reviewers
requestReviewers = slices.DeleteFunc(requestReviewers, func(u string) bool { return u == pr.User.UserName }) requestReviewers = slices.DeleteFunc(requestReviewers, func(u string) bool { return u == pr.User.UserName })
// pr.Head.Sha // pr.Head.Sha
@@ -247,7 +246,7 @@ func ProcessNotifications(notification *models.NotificationThread, gitea common.
// request group member reviews, if missing // request group member reviews, if missing
common.LogDebug(" Review incomplete...") common.LogDebug(" Review incomplete...")
if !groupConfig.Silent && len(requestReviewers) > 0 { if len(requestReviewers) > 0 {
common.LogDebug(" Requesting reviews for:", requestReviewers) common.LogDebug(" Requesting reviews for:", requestReviewers)
if !common.IsDryRun { if !common.IsDryRun {
if _, err := gitea.RequestReviews(pr, requestReviewers...); err != nil { if _, err := gitea.RequestReviews(pr, requestReviewers...); err != nil {
@@ -271,9 +270,6 @@ func ProcessNotifications(notification *models.NotificationThread, gitea common.
if !found_help_comment && !common.IsDryRun { if !found_help_comment && !common.IsDryRun {
helpComment := fmt.Sprintln("Review by", groupName, "represents a group of reviewers:", strings.Join(requestReviewers, ", "), ". To review as part of this group, create a comment with contents @"+groupName+": LGTM on a separate line to accept a review. To request changes, write @"+groupName+": followed by reason for rejection. Do not use reviews to review as a group. Editing a comment invalidates that comment.") helpComment := fmt.Sprintln("Review by", groupName, "represents a group of reviewers:", strings.Join(requestReviewers, ", "), ". To review as part of this group, create a comment with contents @"+groupName+": LGTM on a separate line to accept a review. To request changes, write @"+groupName+": followed by reason for rejection. Do not use reviews to review as a group. Editing a comment invalidates that comment.")
if slices.Contains(groupConfig.Reviewers, pr.User.UserName) {
helpComment = helpComment + "\n\n" + fmt.Sprintln("Submitter is member of this review group, hence they are excluded from being one of the reviewers here")
}
gitea.AddComment(pr, helpComment) gitea.AddComment(pr, helpComment)
} }
} }
@@ -375,19 +371,19 @@ func main() {
config_modified: make(chan *common.AutogitConfig), config_modified: make(chan *common.AutogitConfig),
} }
configUpdates := &common.RabbitMQGiteaEventsProcessor{ configUpdates := &common.ListenDefinitions{
RabbitURL: u,
Orgs: []string{}, Orgs: []string{},
Handlers: map[string]common.RequestProcessor{ Handlers: map[string]common.RequestProcessor{
common.RequestType_Push: &config_update, common.RequestType_Push: &config_update,
}, },
} }
configUpdates.Connection().RabbitURL = u
for _, c := range configs { for _, c := range configs {
if org, _, _ := c.GetPrjGit(); !slices.Contains(configUpdates.Orgs, org) { if org, _, _ := c.GetPrjGit(); !slices.Contains(configUpdates.Orgs, org) {
configUpdates.Orgs = append(configUpdates.Orgs, org) configUpdates.Orgs = append(configUpdates.Orgs, org)
} }
} }
go common.ProcessRabbitMQEvents(configUpdates) go configUpdates.ProcessRabbitMQEvents()
for { for {
config_update_loop: config_update_loop:

View File

@@ -120,7 +120,7 @@ func ProcessBuildStatus(project, refProject *common.BuildResultList) BuildStatus
// the repositories should be setup equally between the projects. We // the repositories should be setup equally between the projects. We
// need to verify that packages that are building in `refProject` are not // need to verify that packages that are building in `refProject` are not
// failing in the `project` // failing in the `project`
BuildResultSorter := func(a, b *common.BuildResult) int { BuildResultSorter := func(a, b common.BuildResult) int {
if c := strings.Compare(a.Repository, b.Repository); c != 0 { if c := strings.Compare(a.Repository, b.Repository); c != 0 {
return c return c
} }
@@ -136,7 +136,7 @@ func ProcessBuildStatus(project, refProject *common.BuildResultList) BuildStatus
common.LogInfo("New package. Only need some success...") common.LogInfo("New package. Only need some success...")
SomeSuccess := false SomeSuccess := false
for i := 0; i < len(project.Result); i++ { for i := 0; i < len(project.Result); i++ {
repoRes := project.Result[i] repoRes := &project.Result[i]
repoResStatus, ok := common.ObsRepoStatusDetails[repoRes.Code] repoResStatus, ok := common.ObsRepoStatusDetails[repoRes.Code]
if !ok { if !ok {
common.LogDebug("cannot find code:", repoRes.Code) common.LogDebug("cannot find code:", repoRes.Code)
@@ -205,8 +205,8 @@ func ProcessBuildStatus(project, refProject *common.BuildResultList) BuildStatus
return BuildStatusSummaryFailed return BuildStatusSummaryFailed
} }
func ProcessRepoBuildStatus(results, ref []*common.PackageBuildStatus) (status BuildStatusSummary, SomeSuccess bool) { func ProcessRepoBuildStatus(results, ref []common.PackageBuildStatus) (status BuildStatusSummary, SomeSuccess bool) {
PackageBuildStatusSorter := func(a, b *common.PackageBuildStatus) int { PackageBuildStatusSorter := func(a, b common.PackageBuildStatus) int {
return strings.Compare(a.Package, b.Package) return strings.Compare(a.Package, b.Package)
} }

View File

@@ -100,7 +100,7 @@ func (svg *SvgWriter) WritePackageStatus(loglink, arch, status, detail string) {
svg.out.WriteString(`<text fill="#113" x="5ex" y="` + fmt.Sprint(svg.ypos-.6) + `em">` + arch + `</text>`) svg.out.WriteString(`<text fill="#113" x="5ex" y="` + fmt.Sprint(svg.ypos-.6) + `em">` + arch + `</text>`)
svg.out.WriteString(`<g>`) svg.out.WriteString(`<g>`)
if len(loglink) > 0 { if len(loglink) > 0 {
svg.out.WriteString(`<a href="` + loglink + `" target="_blank" rel="noopener">`) svg.out.WriteString(`<a href="` + loglink + `">`)
} }
svg.out.WriteString(`<use href="#` + StatusToSVG(status) + `" x="20ex" y="` + fmt.Sprint(svg.ypos-1.7) + `em"/>`) svg.out.WriteString(`<use href="#` + StatusToSVG(status) + `" x="20ex" y="` + fmt.Sprint(svg.ypos-1.7) + `em"/>`)
if len(loglink) > 0 { if len(loglink) > 0 {

BIN
vendor.tar.zst (Stored with Git LFS)

Binary file not shown.

View File

@@ -7,24 +7,14 @@ Areas of responsibility
1. Keep ProjectGit in sync with packages in the organization 1. Keep ProjectGit in sync with packages in the organization
* on pushes to package, updates the submodule commit id * on pushes to package, updates the submodule commit id
to the default branch HEAD (as configured in Gitea) to the default branch HEAD (as configured in Gitea)
* on repository adds, creates a new submodule (if non empty) * on package adds, creates a new submodule
* on repository removal, removes the submodule * on package removal, removes the submodule
NOTE: reverts (push HEAD^) are not supported as they would step-on the 2. Assumes:
work of the workflow-pr bot. Manual update of the project git is * config.GitProjectName == project name (default: `_ObsPrj`)
required in this case. * Other repositories == packages (similar to OBS project)
* config.Branch == "" => default branch from Gitea
Configuration
-------------
Uses `workflow.config` for configuration. Parameters
* _Workflows_: ["direct"] -- direct entry enables direct workflow. **Mandatory**
* _Organization_: organization that holds all the packages. **Mandatory**
* _Branch_: branch updated in repo's, or blank for default package branch
* _GitProjectName_: package in above org, or `org/package#branch` for PrjGit. By default assumes `_ObsPrj` with default branch and in the `Organization`
NOTE: `-rm`, `-removed`, `-deleted` are all removed suffixes used to indicate current branch is a placeholder for previously existing package. These branches will be ignored by the bot, and if default, the package will be removed and will not be added to the project.
Target Usage Target Usage
------------ ------------

View File

@@ -23,18 +23,16 @@ Any project (devel, etc) that accepts PR
Config file Config file
----------- -----------
JSON JSON
* _Workflows_: ["pr"] -- pr entry enables pr workflow. **Mandatory** * _Workflows_: "pr" -- pr workflow enabled
* _Organization_: organization that holds all the packages **Mandatory** * _Organization_: organization that holds all the packages
* _Branch_: branch updated in repo's **Mandatory** * _Branch_: branch updated in repo's
* _GitProjectName_: package in above org, or `org/package#branch` for PrjGit. By default assumes `_ObsPrj` with default branch and in the `Organization` * _GitProjectName_: package in above org, or `org/package` for PrjGit
* _Reviewers_: accounts associated with mandatory reviews for PrjGit. Can trigger additional * _Reviewers_: accounts associated with mandatory reviews for PrjGit. Can trigger additional
review requests for PrjGit or associated PkgGit repos. Only when all reviews are review requests for PrjGit or associated PkgGit repos. Only when all reviews are
satisfied, will the PrjGit PR be merged. See Reviewers below. satisfied, will the PrjGit PR be merged. See Reviewers below.
* _ManualMergeOnly_: (true, false) only merge if "merge ok" comment/review by package or project maintainers or reviewers * _ManualMergeOnly_: (true, false) only merge if "merge ok" comment/review by package or project maintainers or reviewers
* _ManualMergeProject_: (true, false) only merge if "merge ok" by project maintainers or reviewers * _ManualMergeProject_: (true, false) only merge if "merge ok" by project maintainers or reviewers
* _ReviewRequired_: (true, false) ignores that submitter is a maintainer and require a review from other maintainer IFF available
NOTE: `-rm`, `-removed`, `-deleted` are all removed suffixes used to indicate current branch is a placeholder for previously existing package. These branches will be ignored by the bot, and if default, the package will be removed and will not be added to the project.
example: example:
[ [

View File

@@ -121,12 +121,6 @@ func main() {
req.configuredRepos[c.Organization] = configs req.configuredRepos[c.Organization] = configs
orgs = append(orgs, c.Organization) orgs = append(orgs, c.Organization)
// add project git organization, if different
if prjOrg, _, _ := c.GetPrjGit(); prjOrg != c.Organization {
orgs = append(orgs, prjOrg)
req.configuredRepos[prjOrg] = configs
}
} }
} }
@@ -170,12 +164,12 @@ func main() {
listenDefs := &common.RabbitMQGiteaEventsProcessor{ listenDefs := &common.RabbitMQGiteaEventsProcessor{
Orgs: orgs, Orgs: orgs,
// GitAuthor: GitAuthor,
Handlers: map[string]common.RequestProcessor{ Handlers: map[string]common.RequestProcessor{
common.RequestType_PR: req, common.RequestType_PR: req,
common.RequestType_PRSync: req, common.RequestType_PRSync: req,
common.RequestType_PRReviewAccepted: req, common.RequestType_PRReviewAccepted: req,
common.RequestType_PRReviewRejected: req, common.RequestType_PRReviewRejected: req,
common.RequestType_IssueComment: req,
}, },
} }
listenDefs.Connection().RabbitURL, _ = url.Parse(*rabbitUrl) listenDefs.Connection().RabbitURL, _ = url.Parse(*rabbitUrl)

View File

@@ -1,10 +0,0 @@
// 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

View File

@@ -1,157 +0,0 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: state_checker.go
//
// Generated by this command:
//
// mockgen -source=state_checker.go -destination=../mock/state_checker.go -typed -package mock_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"
interfaces "src.opensuse.org/autogits/workflow-pr/interfaces"
)
// MockStateChecker is a mock of StateChecker interface.
type MockStateChecker struct {
ctrl *gomock.Controller
recorder *MockStateCheckerMockRecorder
isgomock struct{}
}
// MockStateCheckerMockRecorder is the mock recorder for MockStateChecker.
type MockStateCheckerMockRecorder struct {
mock *MockStateChecker
}
// NewMockStateChecker creates a new mock instance.
func NewMockStateChecker(ctrl *gomock.Controller) *MockStateChecker {
mock := &MockStateChecker{ctrl: ctrl}
mock.recorder = &MockStateCheckerMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockStateChecker) EXPECT() *MockStateCheckerMockRecorder {
return m.recorder
}
// CheckRepos mocks base method.
func (m *MockStateChecker) CheckRepos() error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "CheckRepos")
ret0, _ := ret[0].(error)
return ret0
}
// CheckRepos indicates an expected call of CheckRepos.
func (mr *MockStateCheckerMockRecorder) CheckRepos() *MockStateCheckerCheckReposCall {
mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CheckRepos", reflect.TypeOf((*MockStateChecker)(nil).CheckRepos))
return &MockStateCheckerCheckReposCall{Call: call}
}
// MockStateCheckerCheckReposCall wrap *gomock.Call
type MockStateCheckerCheckReposCall struct {
*gomock.Call
}
// Return rewrite *gomock.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() error) *MockStateCheckerCheckReposCall {
c.Call = c.Call.Do(f)
return c
}
// DoAndReturn rewrite *gomock.Call.DoAndReturn
func (c *MockStateCheckerCheckReposCall) DoAndReturn(f func() error) *MockStateCheckerCheckReposCall {
c.Call = c.Call.DoAndReturn(f)
return c
}
// ConsistencyCheckProcess mocks base method.
func (m *MockStateChecker) ConsistencyCheckProcess() error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ConsistencyCheckProcess")
ret0, _ := ret[0].(error)
return ret0
}
// ConsistencyCheckProcess indicates an expected call of ConsistencyCheckProcess.
func (mr *MockStateCheckerMockRecorder) ConsistencyCheckProcess() *MockStateCheckerConsistencyCheckProcessCall {
mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ConsistencyCheckProcess", reflect.TypeOf((*MockStateChecker)(nil).ConsistencyCheckProcess))
return &MockStateCheckerConsistencyCheckProcessCall{Call: call}
}
// MockStateCheckerConsistencyCheckProcessCall wrap *gomock.Call
type MockStateCheckerConsistencyCheckProcessCall struct {
*gomock.Call
}
// Return rewrite *gomock.Call.Return
func (c *MockStateCheckerConsistencyCheckProcessCall) Return(arg0 error) *MockStateCheckerConsistencyCheckProcessCall {
c.Call = c.Call.Return(arg0)
return c
}
// Do rewrite *gomock.Call.Do
func (c *MockStateCheckerConsistencyCheckProcessCall) Do(f func() error) *MockStateCheckerConsistencyCheckProcessCall {
c.Call = c.Call.Do(f)
return c
}
// DoAndReturn rewrite *gomock.Call.DoAndReturn
func (c *MockStateCheckerConsistencyCheckProcessCall) DoAndReturn(f func() error) *MockStateCheckerConsistencyCheckProcessCall {
c.Call = c.Call.DoAndReturn(f)
return c
}
// VerifyProjectState mocks base method.
func (m *MockStateChecker) VerifyProjectState(configs *common.AutogitConfig) ([]*interfaces.PRToProcess, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "VerifyProjectState", configs)
ret0, _ := ret[0].([]*interfaces.PRToProcess)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// VerifyProjectState indicates an expected call of VerifyProjectState.
func (mr *MockStateCheckerMockRecorder) VerifyProjectState(configs any) *MockStateCheckerVerifyProjectStateCall {
mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "VerifyProjectState", reflect.TypeOf((*MockStateChecker)(nil).VerifyProjectState), configs)
return &MockStateCheckerVerifyProjectStateCall{Call: call}
}
// MockStateCheckerVerifyProjectStateCall wrap *gomock.Call
type MockStateCheckerVerifyProjectStateCall struct {
*gomock.Call
}
// Return rewrite *gomock.Call.Return
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) ([]*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) ([]*interfaces.PRToProcess, error)) *MockStateCheckerVerifyProjectStateCall {
c.Call = c.Call.DoAndReturn(f)
return c
}

View File

@@ -11,11 +11,10 @@ import (
"github.com/opentracing/opentracing-go/log" "github.com/opentracing/opentracing-go/log"
"src.opensuse.org/autogits/common" "src.opensuse.org/autogits/common"
"src.opensuse.org/autogits/common/gitea-generated/client/repository"
"src.opensuse.org/autogits/common/gitea-generated/models" "src.opensuse.org/autogits/common/gitea-generated/models"
) )
func prGitBranchNameForPR(repo string, prNo int64) string { func prGitBranchNameForPR(repo string, prNo int) string {
return fmt.Sprintf("PR_%s#%d", repo, prNo) return fmt.Sprintf("PR_%s#%d", repo, prNo)
} }
@@ -24,9 +23,6 @@ func PrjGitDescription(prset *common.PRSet) (title string, desc string) {
refs := make([]string, 0, len(prset.PRs)-1) refs := make([]string, 0, len(prset.PRs)-1)
for _, pr := range prset.PRs { for _, pr := range prset.PRs {
if prset.IsPrjGitPR(pr.PR) {
continue
}
org, repo, idx := pr.PRComponents() org, repo, idx := pr.PRComponents()
title_refs = append(title_refs, repo) title_refs = append(title_refs, repo)
@@ -35,16 +31,16 @@ func PrjGitDescription(prset *common.PRSet) (title string, desc string) {
} }
title = "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" desc = fmt.Sprintf("This is a forwarded pull request by %s\nreferencing the following pull request(s):\n\n", GitAuthor) + strings.Join(refs, ",\n")
if prset.Config.ManualMergeOnly { if prset.Config.ManualMergeOnly {
desc = desc + "\n### ManualMergeOnly enabled. To merge, 'merge ok' is required in either the project PR or every package PR." desc = desc + "\n\nManualMergeOnly enabled. To merge, 'merge ok' is required in either the project PR or every package PR."
} }
if prset.Config.ManualMergeProject { if prset.Config.ManualMergeProject {
desc = desc + "\n### ManualMergeProject enabled. To merge, 'merge ok' is required by project maintainer in the project PR." desc = desc + "\nManualMergeProject enabled. To merge, 'merge ok' is required by project maintainer in the project PR."
} }
if !prset.Config.ManualMergeOnly && !prset.Config.ManualMergeProject { if !prset.Config.ManualMergeOnly && !prset.Config.ManualMergeProject {
desc = desc + "\n### Automatic merge enabled. This will merge when all review requirements are satisfied." desc = desc + "\nAutomatic merge enabled. This will merge when all review requirements are satisfied."
} }
return return
} }
@@ -77,19 +73,19 @@ type PRProcessor struct {
git common.Git git common.Git
} }
func AllocatePRProcessor(req *models.PullRequest, configs common.AutogitConfigs) (*PRProcessor, error) { func AllocatePRProcessor(req *common.PullRequestWebhookEvent, configs common.AutogitConfigs) (*PRProcessor, error) {
org := req.Base.Repo.Owner.UserName org := req.Pull_Request.Base.Repo.Owner.Username
repo := req.Base.Repo.Name repo := req.Pull_Request.Base.Repo.Name
id := req.Index id := req.Pull_Request.Number
branch := req.Base.Ref branch := req.Pull_Request.Base.Ref
PRstr := fmt.Sprintf("%s/%s#%d", org, repo, id) PRstr := fmt.Sprintf("%s/%s#%d", org, repo, id)
common.LogInfo("*** Starting processing PR:", PRstr, "branch:", branch) common.LogInfo("*** Starting processing PR:", PRstr, "branch:", branch)
config := configs.GetPrjGitConfig(org, repo, branch) config := configs.GetPrjGitConfig(org, repo, branch)
if config == nil { if config == nil {
if req.Base.Repo.DefaultBranch == branch { if req.Pull_Request.Base.Repo.Default_Branch == branch {
common.LogDebug("Default branch submission...", org, repo) common.LogDebug("Default branch submission...", org, repo)
config = configs.GetPrjGitConfig(org, repo, "") config = configs.GetPrjGitConfig(org, repo, "")
} }
@@ -101,8 +97,8 @@ func AllocatePRProcessor(req *models.PullRequest, configs common.AutogitConfigs)
common.LogDebug("found config", config) common.LogDebug("found config", config)
if config == nil { if config == nil {
common.LogError("Cannot find config for branch '%s'", req.Base.Ref) common.LogError("Cannot find config for branch '%s'", req.Pull_Request.Base.Ref)
return nil, fmt.Errorf("Cannot find config for branch '%s'", req.Base.Ref) return nil, fmt.Errorf("Cannot find config for branch '%s'", req.Pull_Request.Base.Ref)
} }
git, err := GitHandler.CreateGitHandler(config.Organization) git, err := GitHandler.CreateGitHandler(config.Organization)
@@ -209,11 +205,8 @@ func (pr *PRProcessor) CreatePRjGitPR(prjGitPRbranch string, prset *common.PRSet
return err return err
} }
if !common.IsDryRun { if !common.IsDryRun && headCommit != newHeadCommit {
if headCommit != newHeadCommit {
common.PanicOnError(git.GitExec(common.DefaultGitPrj, "push", RemoteName, "+HEAD:"+prjGitPRbranch)) common.PanicOnError(git.GitExec(common.DefaultGitPrj, "push", RemoteName, "+HEAD:"+prjGitPRbranch))
}
title, desc := PrjGitDescription(prset) title, desc := PrjGitDescription(prset)
pr, err := Gitea.CreatePullRequestIfNotExist(PrjGit, prjGitPRbranch, PrjGitBranch, title, desc) pr, err := Gitea.CreatePullRequestIfNotExist(PrjGit, prjGitPRbranch, PrjGitBranch, title, desc)
if err != nil { if err != nil {
@@ -293,41 +286,37 @@ func (pr *PRProcessor) UpdatePrjGitPR(prset *common.PRSet) error {
return err return err
} }
if !common.IsDryRun { if !common.IsDryRun && headCommit != newHeadCommit {
if headCommit != newHeadCommit {
params := []string{"push", PrjGitPR.RemoteName, "+HEAD:" + prjGitPRbranch} params := []string{"push", PrjGitPR.RemoteName, "+HEAD:" + prjGitPRbranch}
if forcePush { if forcePush {
params = slices.Insert(params, 1, "-f") params = slices.Insert(params, 1, "-f")
} }
common.PanicOnError(git.GitExec(common.DefaultGitPrj, params...)) common.PanicOnError(git.GitExec(common.DefaultGitPrj, params...))
}
// update PR // update PR
PrjGitTitle, PrjGitBody := PrjGitDescription(prset) PrjGitTitle, PrjGitBody := PrjGitDescription(prset)
if PrjGitPR.PR.Body != PrjGitBody || PrjGitPR.PR.Title != PrjGitTitle {
Gitea.UpdatePullRequest(PrjGit.Owner.UserName, PrjGit.Name, PrjGitPR.PR.Index, &models.EditPullRequestOption{ Gitea.UpdatePullRequest(PrjGit.Owner.UserName, PrjGit.Name, PrjGitPR.PR.Index, &models.EditPullRequestOption{
RemoveDeadline: true, RemoveDeadline: true,
Title: PrjGitTitle, Title: PrjGitTitle,
Body: PrjGitBody, Body: PrjGitBody,
}) })
} }
}
return nil return nil
} }
func (pr *PRProcessor) Process(req *models.PullRequest) error { func (pr *PRProcessor) Process(req *common.PullRequestWebhookEvent) error {
config := pr.config config := pr.config
git := pr.git git := pr.git
// requests against project are not handled here // requests against project are not handled here
common.LogInfo("processing opened PR:", req.URL) common.LogInfo("processing opened PR:", req.Pull_Request.Url)
prOrg := req.Base.Repo.Owner.UserName prOrg := req.Pull_Request.Base.Repo.Owner.Username
prRepo := req.Base.Repo.Name prRepo := req.Pull_Request.Base.Repo.Name
prNo := req.Index prNo := int(req.Pull_Request.Number)
common.LogError(req) common.LogError(req)
prset, err := common.FetchPRSet(CurrentUser.UserName, Gitea, prOrg, prRepo, prNo, config) prset, err := common.FetchPRSet(CurrentUser.UserName, Gitea, prOrg, prRepo, req.Number, config)
if err != nil { if err != nil {
common.LogError("Cannot fetch PRSet:", err) common.LogError("Cannot fetch PRSet:", err)
return err return err
@@ -347,55 +336,16 @@ func (pr *PRProcessor) Process(req *models.PullRequest) error {
prjGitPRbranch = prjGitPR.PR.Head.Name prjGitPRbranch = prjGitPR.PR.Head.Name
if prjGitPR.PR.State != "open" { if prjGitPR.PR.State != "open" {
if prjGitPR.PR.HasMerged { // close entire prset
// update branches in project common.LogInfo("PR State is closed:", prjGitPR.PR.State)
prjGitPR.RemoteName, err = git.GitClone(common.DefaultGitPrj, prjGitPRbranch, prjGitPR.PR.Base.Repo.SSHURL)
common.PanicOnError(err)
old_pkgs, err := git.GitSubmoduleList(common.DefaultGitPrj, prjGitPR.PR.MergeBase)
common.PanicOnError(err)
new_pkgs, err := git.GitSubmoduleList(common.DefaultGitPrj, prjGitPRbranch)
common.PanicOnError(err)
pkgs := make(map[string]string)
for pkg, old_commit := range old_pkgs {
if new_commit, found := new_pkgs[pkg]; found {
// pkg modified
if new_commit != old_commit {
pkgs[pkg] = new_commit
}
} else { // not found, pkg removed
pkgs[pkg] = ""
}
}
for pkg, commit := range new_pkgs {
if _, found := old_pkgs[pkg]; !found {
// pkg added
pkgs[pkg] = commit
}
}
PrjGitSubmoduleCheck(config, git, common.DefaultGitPrj, pkgs)
}
// manually merge or close entire prset that is still open
for _, pr := range prset.PRs { for _, pr := range prset.PRs {
if pr.PR.State == "open" { if pr.PR.State == "open" {
org, repo, idx := pr.PRComponents() org, repo, idx := pr.PRComponents()
if prjGitPR.PR.HasMerged {
Gitea.AddComment(pr.PR, "This PR is merged via the associated Project PR.")
err = Gitea.ManualMergePR(org, repo, idx, pr.PR.Head.Sha, false)
if _, ok := err.(*repository.RepoMergePullRequestConflict); !ok {
common.PanicOnError(err)
}
} else {
Gitea.AddComment(pr.PR, "Closing here because the associated Project PR has been closed.")
Gitea.UpdatePullRequest(org, repo, idx, &models.EditPullRequestOption{ Gitea.UpdatePullRequest(org, repo, idx, &models.EditPullRequestOption{
State: "closed", State: "closed",
}) })
} }
} }
}
return nil return nil
} }
@@ -517,23 +467,7 @@ type RequestProcessor struct {
configuredRepos map[string][]*common.AutogitConfig configuredRepos map[string][]*common.AutogitConfig
} }
func ProcesPullRequest(pr *models.PullRequest, configs []*common.AutogitConfig) error { func ProcesPullRequest(req *common.PullRequestWebhookEvent, configs []*common.AutogitConfig) error {
if len(configs) < 1 {
// ignoring pull request against unconfigured project (could be just regular sources?)
return nil
}
PRProcessor, err := AllocatePRProcessor(pr, configs)
if err != nil {
log.Error(err)
return err
}
defer PRProcessor.git.Close()
return PRProcessor.Process(pr)
}
func (w *RequestProcessor) ProcessFunc(request *common.Request) error {
defer func() { defer func() {
if r := recover(); r != nil { if r := recover(); r != nil {
common.LogInfo("panic cought --- recovered") common.LogInfo("panic cought --- recovered")
@@ -541,28 +475,36 @@ func (w *RequestProcessor) ProcessFunc(request *common.Request) error {
} }
}() }()
var pr *models.PullRequest if len(configs) < 1 {
var err error // ignoring pull request against unconfigured project (could be just regular sources?)
if req, ok := request.Data.(*common.PullRequestWebhookEvent); ok { return nil
pr, err = Gitea.GetPullRequest(req.Pull_Request.Base.Repo.Owner.Username, req.Pull_Request.Base.Repo.Name, req.Pull_Request.Number) }
pr, err := AllocatePRProcessor(req, configs)
if err != nil { if err != nil {
common.LogError("Cannot find PR for issue:", req.Pull_Request.Base.Repo.Owner.Username, req.Pull_Request.Base.Repo.Name, req.Pull_Request.Number) log.Error(err)
return err return err
} }
} else if req, ok := request.Data.(*common.IssueWebhookEvent); ok { defer pr.git.Close()
pr, err = Gitea.GetPullRequest(req.Repository.Owner.Username, req.Repository.Name, int64(req.Issue.Number))
if err != nil { switch req.Action {
common.LogError("Cannot find PR for issue:", req.Repository.Owner.Username, req.Repository.Name, int64(req.Issue.Number)) case "opened", "reopened", "synchronized", "edited", "closed", "reviewed":
return err return pr.Process(req)
} }
} else {
common.LogError("Unhandled pull request action:", req.Action)
return nil
}
func (w *RequestProcessor) ProcessFunc(request *common.Request) error {
req, ok := request.Data.(*common.PullRequestWebhookEvent)
if !ok {
common.LogError("*** Invalid data format for PR processing.") common.LogError("*** Invalid data format for PR processing.")
return fmt.Errorf("*** Invalid data format for PR processing.") return fmt.Errorf("*** Invalid data format for PR processing.")
} }
configs, ok := w.configuredRepos[pr.Base.Repo.Owner.UserName] org := req.Repository.Owner.Username
if !ok { configs := w.configuredRepos[org]
common.LogError("*** Cannot find config for org:", pr.Base.Repo.Owner.UserName) return ProcesPullRequest(req, configs)
}
return ProcesPullRequest(pr, configs)
} }

View File

@@ -55,7 +55,44 @@ func (s *DefaultStateChecker) ProcessPR(pr *models.PullRequest, config *common.A
return ProcesPullRequest(&event, common.AutogitConfigs{config}) return ProcesPullRequest(&event, common.AutogitConfigs{config})
} }
func PrjGitSubmoduleCheck(config *common.AutogitConfig, git common.Git, repo string, submodules map[string]string) (prsToProcess []*interfaces.PRToProcess, err error) { func (s *DefaultStateChecker) VerifyProjectState(config *common.AutogitConfig) ([]*interfaces.PRToProcess, error) {
defer func() {
if r := recover(); r != nil {
common.LogError("panic caught")
if err, ok := r.(error); !ok {
common.LogError(err)
}
common.LogError(string(debug.Stack()))
}
}()
prsToProcess := []*interfaces.PRToProcess{}
prjGitOrg, prjGitRepo, prjGitBranch := config.GetPrjGit()
common.LogInfo(" checking", prjGitOrg+"/"+prjGitRepo+"#"+prjGitBranch)
git, err := GitHandler.CreateGitHandler(config.Organization)
common.LogDebug("Git Path:", git.GetPath())
if err != nil {
return nil, fmt.Errorf("Cannot create git handler: %w", err)
}
defer git.Close()
repo, err := Gitea.CreateRepositoryIfNotExist(git, prjGitOrg, prjGitRepo)
if err != nil {
return nil, fmt.Errorf("Error fetching or creating '%s/%s#%s' -- aborting verifyProjectState(). Err: %w", prjGitBranch, prjGitRepo, prjGitBranch, err)
}
_, err = git.GitClone(prjGitRepo, prjGitBranch, repo.SSHURL)
common.PanicOnError(err)
prsToProcess = append(prsToProcess, &interfaces.PRToProcess{
Org: prjGitOrg,
Repo: prjGitRepo,
Branch: prjGitBranch,
})
submodules, err := git.GitSubmoduleList(prjGitRepo, "HEAD")
nextSubmodule: nextSubmodule:
for sub, commitID := range submodules { for sub, commitID := range submodules {
common.LogDebug(" + checking", sub, commitID) common.LogDebug(" + checking", sub, commitID)
@@ -98,8 +135,8 @@ nextSubmodule:
} }
// not found in past, check if we should advance the branch label ... pull the submodule // not found in past, check if we should advance the branch label ... pull the submodule
git.GitExecOrPanic(repo, "submodule", "update", "--init", "--filter", "blob:none", "--", sub) git.GitExecOrPanic(prjGitRepo, "submodule", "update", "--init", "--filter", "blob:none", "--", sub)
subDir := path.Join(repo, sub) subDir := path.Join(prjGitRepo, sub)
newCommits := common.SplitStringNoEmpty(git.GitExecWithOutputOrPanic(subDir, "rev-list", "^origin/"+branch, commitID), "\n") newCommits := common.SplitStringNoEmpty(git.GitExecWithOutputOrPanic(subDir, "rev-list", "^origin/"+branch, commitID), "\n")
if len(newCommits) >= 1 { if len(newCommits) >= 1 {
@@ -115,49 +152,8 @@ nextSubmodule:
} }
} }
return prsToProcess, nil
}
func (s *DefaultStateChecker) VerifyProjectState(config *common.AutogitConfig) ([]*interfaces.PRToProcess, error) {
defer func() {
if r := recover(); r != nil {
common.LogError("panic caught")
if err, ok := r.(error); !ok {
common.LogError(err)
}
common.LogError(string(debug.Stack()))
}
}()
prsToProcess := []*interfaces.PRToProcess{}
prjGitOrg, prjGitRepo, prjGitBranch := config.GetPrjGit()
common.LogInfo(" checking", prjGitOrg+"/"+prjGitRepo+"#"+prjGitBranch)
git, err := GitHandler.CreateGitHandler(config.Organization)
common.LogDebug("Git Path:", git.GetPath())
if err != nil {
return nil, fmt.Errorf("Cannot create git handler: %w", err)
}
defer git.Close()
repo, err := Gitea.CreateRepositoryIfNotExist(git, prjGitOrg, prjGitRepo)
if err != nil {
return nil, fmt.Errorf("Error fetching or creating '%s/%s#%s' -- aborting verifyProjectState(). Err: %w", prjGitBranch, prjGitRepo, prjGitBranch, err)
}
_, err = git.GitClone(prjGitRepo, prjGitBranch, repo.SSHURL)
common.PanicOnError(err)
prsToProcess = append(prsToProcess, &interfaces.PRToProcess{
Org: prjGitOrg,
Repo: prjGitRepo,
Branch: prjGitBranch,
})
submodules, err := git.GitSubmoduleList(prjGitRepo, "HEAD")
// forward any package-gits referred by the project git, but don't go back // forward any package-gits referred by the project git, but don't go back
return PrjGitSubmoduleCheck(config, git, prjGitRepo, submodules) return prsToProcess, nil
} }
func (s *DefaultStateChecker) CheckRepos() error { func (s *DefaultStateChecker) CheckRepos() error {