add support for maintainership directories
This commit is contained in:
parent
e63a450c5d
commit
fbaeddfcd8
@ -22,6 +22,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"slices"
|
"slices"
|
||||||
"time"
|
"time"
|
||||||
@ -38,7 +39,10 @@ import (
|
|||||||
//go:generate mockgen -source=gitea_utils.go -destination=mock/gitea_utils.go -typed
|
//go:generate mockgen -source=gitea_utils.go -destination=mock/gitea_utils.go -typed
|
||||||
|
|
||||||
// maintainer list file in ProjectGit
|
// maintainer list file in ProjectGit
|
||||||
const MaintainershipFile = "_maitnainership.json"
|
const (
|
||||||
|
MaintainershipFile = "_maitnainership.json"
|
||||||
|
MaintainershipDir = "maintaineirship"
|
||||||
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// from Gitea
|
// from Gitea
|
||||||
@ -58,6 +62,7 @@ const (
|
|||||||
|
|
||||||
type GiteaMaintainershipInterface interface {
|
type GiteaMaintainershipInterface interface {
|
||||||
FetchMaintainershipFile(org, prjGit, branch string) ([]byte, error)
|
FetchMaintainershipFile(org, prjGit, branch string) ([]byte, error)
|
||||||
|
FetchMaintainershipDirFile(org, prjGit, branch, pkg string) ([]byte, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type GiteaPRFetcher interface {
|
type GiteaPRFetcher interface {
|
||||||
@ -115,6 +120,10 @@ func (gitea *GiteaTransport) FetchMaintainershipFile(org, repo, branch string) (
|
|||||||
return gitea.GetRepositoryFileContent(org, repo, branch, MaintainershipFile)
|
return gitea.GetRepositoryFileContent(org, repo, branch, MaintainershipFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (gitea *GiteaTransport) FetchMaintainershipDirFile(org, repo, branch, pkg string) ([]byte, error) {
|
||||||
|
return gitea.GetRepositoryFileContent(org, repo, branch, path.Join(MaintainershipDir, pkg))
|
||||||
|
}
|
||||||
|
|
||||||
func (gitea *GiteaTransport) GetPullRequest(org, project string, num int64) (*models.PullRequest, error) {
|
func (gitea *GiteaTransport) GetPullRequest(org, project string, num int64) (*models.PullRequest, error) {
|
||||||
pr, err := gitea.client.Repository.RepoGetPullRequest(
|
pr, err := gitea.client.Repository.RepoGetPullRequest(
|
||||||
repository.NewRepoGetPullRequestParams().
|
repository.NewRepoGetPullRequestParams().
|
||||||
|
@ -14,25 +14,44 @@ type MaintainershipData interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const ProjectKey = ""
|
const ProjectKey = ""
|
||||||
|
const ProjectFileKey = "_project"
|
||||||
|
|
||||||
type MaintainershipMap map[string][]string
|
type MaintainershipMap struct {
|
||||||
|
data map[string][]string
|
||||||
|
is_dir bool
|
||||||
|
fetchPackage func(string) ([]byte, error)
|
||||||
|
}
|
||||||
|
|
||||||
func parseMaintainershipData(data []byte) (*MaintainershipMap, error) {
|
func parseMaintainershipData(data []byte) (*MaintainershipMap, error) {
|
||||||
maintainers := make(MaintainershipMap)
|
maintainers := &MaintainershipMap{
|
||||||
if err := json.Unmarshal(data, &maintainers); err != nil {
|
data: make(map[string][]string),
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(data, &maintainers.data); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return &maintainers, nil
|
return maintainers, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func FetchProjectMaintainershipData(gitea common.GiteaMaintainershipInterface, org, prjGit, branch string) (*MaintainershipMap, error) {
|
func FetchProjectMaintainershipData(gitea common.GiteaMaintainershipInterface, org, prjGit, branch string) (*MaintainershipMap, error) {
|
||||||
data, err := gitea.FetchMaintainershipFile(org, prjGit, branch)
|
data, err := gitea.FetchMaintainershipDirFile(org, prjGit, branch, ProjectFileKey)
|
||||||
|
dir := true
|
||||||
|
if err != nil || data == nil {
|
||||||
|
dir = false
|
||||||
|
data, err = gitea.FetchMaintainershipFile(org, prjGit, branch)
|
||||||
if err != nil || data == nil {
|
if err != nil || data == nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return parseMaintainershipData(data)
|
m, err := parseMaintainershipData(data)
|
||||||
|
if m != nil {
|
||||||
|
m.is_dir = dir
|
||||||
|
m.fetchPackage = func(pkg string) ([]byte, error) {
|
||||||
|
return gitea.FetchMaintainershipDirFile(org, prjGit, branch, pkg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return m, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (data *MaintainershipMap) ListProjectMaintainers() []string {
|
func (data *MaintainershipMap) ListProjectMaintainers() []string {
|
||||||
@ -40,7 +59,7 @@ func (data *MaintainershipMap) ListProjectMaintainers() []string {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
m, found := (*data)[ProjectKey]
|
m, found := data.data[ProjectKey]
|
||||||
if !found {
|
if !found {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -48,12 +67,34 @@ func (data *MaintainershipMap) ListProjectMaintainers() []string {
|
|||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parsePkgDirData(pkg string, data []byte) []string {
|
||||||
|
m := make(map[string][]string)
|
||||||
|
if err := json.Unmarshal(data, &m); err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
pkgMaintainers, found := m[pkg]
|
||||||
|
if !found {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return pkgMaintainers
|
||||||
|
}
|
||||||
|
|
||||||
func (data *MaintainershipMap) ListPackageMaintainers(pkg string) []string {
|
func (data *MaintainershipMap) ListPackageMaintainers(pkg string) []string {
|
||||||
if data == nil {
|
if data == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
pkgMaintainers := (*data)[pkg]
|
pkgMaintainers, found := data.data[pkg]
|
||||||
|
if !found && data.is_dir {
|
||||||
|
pkgData, err := data.fetchPackage(pkg)
|
||||||
|
if err == nil {
|
||||||
|
pkgMaintainers = parsePkgDirData(pkg, pkgData)
|
||||||
|
if len(pkgMaintainers) > 0 {
|
||||||
|
data.data[pkg] = pkgMaintainers
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
prjMaintainers := data.ListProjectMaintainers()
|
prjMaintainers := data.ListProjectMaintainers()
|
||||||
|
|
||||||
prjMaintainer:
|
prjMaintainer:
|
||||||
@ -68,4 +109,3 @@ prjMaintainer:
|
|||||||
|
|
||||||
return pkgMaintainers
|
return pkgMaintainers
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,11 +19,14 @@ func TestMaintainership(t *testing.T) {
|
|||||||
|
|
||||||
packageTests := []struct {
|
packageTests := []struct {
|
||||||
name string
|
name string
|
||||||
maintainersFile []byte
|
|
||||||
maintainersFileErr error
|
|
||||||
maintainers []string
|
maintainers []string
|
||||||
otherError bool
|
otherError bool
|
||||||
packageName string
|
packageName string
|
||||||
|
|
||||||
|
maintainersFile []byte
|
||||||
|
maintainersFileErr error
|
||||||
|
|
||||||
|
maintainersDir map[string][]byte
|
||||||
}{
|
}{
|
||||||
/* PACKAGE MAINTAINERS */
|
/* PACKAGE MAINTAINERS */
|
||||||
// package tests have packageName, projects do not
|
// package tests have packageName, projects do not
|
||||||
@ -39,23 +42,33 @@ func TestMaintainership(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "Multiple package maintainers",
|
name: "Multiple package maintainers",
|
||||||
maintainersFile: []byte(`{"pkg": ["user1", "user2"], "": ["user1", "user3"]}`),
|
maintainersFile: []byte(`{"pkg": ["user1", "user2"], "": ["user1", "user3"]}`),
|
||||||
|
maintainersDir: map[string][]byte{
|
||||||
|
"_project": []byte(`{"": ["user1", "user3"]}`),
|
||||||
|
"pkg": []byte(`{"pkg": ["user1", "user2"]}`),
|
||||||
|
},
|
||||||
maintainers: []string{"user1", "user2", "user3"},
|
maintainers: []string{"user1", "user2", "user3"},
|
||||||
packageName: "pkg",
|
packageName: "pkg",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "No package maintainers and only project maintainer",
|
name: "No package maintainers and only project maintainer",
|
||||||
maintainersFile: []byte(`{"pkg2": ["user1", "user2"], "": ["user1", "user3"]}`),
|
maintainersFile: []byte(`{"pkg2": ["user1", "user2"], "": ["user1", "user3"]}`),
|
||||||
|
maintainersDir: map[string][]byte{
|
||||||
|
"_project": []byte(`{"": ["user1", "user3"]}`),
|
||||||
|
},
|
||||||
maintainers: []string{"user1", "user3"},
|
maintainers: []string{"user1", "user3"},
|
||||||
packageName: "pkg",
|
packageName: "pkg",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Invalid list of package maintainers",
|
name: "Invalid list of package maintainers",
|
||||||
maintainersFile: []byte(`{"pkg": 3,"": ["user", 4]}`),
|
maintainersFile: []byte(`{"pkg": 3,"": ["user", 4]}`),
|
||||||
|
maintainersDir: map[string][]byte{
|
||||||
|
"_project": []byte(`{"": ["user1", 4]}`),
|
||||||
|
"pkg": []byte(`"pkg": 3`),
|
||||||
|
},
|
||||||
otherError: true,
|
otherError: true,
|
||||||
packageName: "pkg",
|
packageName: "pkg",
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
/* PROJECT MAINTAINERS */
|
/* PROJECT MAINTAINERS */
|
||||||
{
|
{
|
||||||
name: "No maintainer for empty project",
|
name: "No maintainer for empty project",
|
||||||
@ -63,6 +76,9 @@ func TestMaintainership(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "No maintainer for empty project maintainer file",
|
name: "No maintainer for empty project maintainer file",
|
||||||
maintainersFile: []byte("{}"),
|
maintainersFile: []byte("{}"),
|
||||||
|
maintainersDir: map[string][]byte{
|
||||||
|
"_project": []byte(`{}`),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Error in MaintainerListForProject when remote has an error",
|
name: "Error in MaintainerListForProject when remote has an error",
|
||||||
@ -71,33 +87,40 @@ func TestMaintainership(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "Multiple project maintainers",
|
name: "Multiple project maintainers",
|
||||||
maintainersFile: []byte(`{"": ["user1", "user2"]}`),
|
maintainersFile: []byte(`{"": ["user1", "user2"]}`),
|
||||||
|
maintainersDir: map[string][]byte{
|
||||||
|
"_project": []byte(`{"": ["user1", "user2"]}`),
|
||||||
|
},
|
||||||
maintainers: []string{"user1", "user2"},
|
maintainers: []string{"user1", "user2"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Single project maintainer",
|
name: "Single project maintainer",
|
||||||
maintainersFile: []byte(`{"": ["user"]}`),
|
maintainersFile: []byte(`{"": ["user"]}`),
|
||||||
|
maintainersDir: map[string][]byte{
|
||||||
|
"_project": []byte(`{"": ["user"]}`),
|
||||||
|
},
|
||||||
maintainers: []string{"user"},
|
maintainers: []string{"user"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Invalid list of project maintainers",
|
name: "Invalid list of project maintainers",
|
||||||
maintainersFile: []byte(`{"": ["user", 4]}`),
|
maintainersFile: []byte(`{"": ["user", 4]}`),
|
||||||
|
maintainersDir: map[string][]byte{
|
||||||
|
"_project": []byte(`{"": ["user", 4]}`),
|
||||||
|
},
|
||||||
otherError: true,
|
otherError: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Invalid list of project maintainers",
|
name: "Invalid list of project maintainers",
|
||||||
maintainersFile: []byte(`{"": 4}`),
|
maintainersFile: []byte(`{"": 4}`),
|
||||||
|
maintainersDir: map[string][]byte{
|
||||||
|
"_project": []byte(`{"": 4}`),
|
||||||
|
},
|
||||||
otherError: true,
|
otherError: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
notFoundError := errors.New("not found")
|
||||||
for _, test := range packageTests {
|
for _, test := range packageTests {
|
||||||
t.Run(test.name, func(t *testing.T) {
|
runTests := func(t *testing.T, mi common.GiteaMaintainershipInterface) {
|
||||||
ctl := gomock.NewController(t)
|
|
||||||
mi := mock_common.NewMockGiteaMaintainershipInterface(ctl)
|
|
||||||
|
|
||||||
mi.EXPECT().FetchMaintainershipFile("foo", common.DefaultGitPrj, "bar").
|
|
||||||
Return(test.maintainersFile, test.maintainersFileErr)
|
|
||||||
|
|
||||||
maintainers, err := FetchProjectMaintainershipData(mi, config.Organization, config.GitProjectName, config.Branch)
|
maintainers, err := FetchProjectMaintainershipData(mi, config.Organization, config.GitProjectName, config.Branch)
|
||||||
if err != nil && !test.otherError {
|
if err != nil && !test.otherError {
|
||||||
if test.maintainersFileErr == nil {
|
if test.maintainersFileErr == nil {
|
||||||
@ -119,14 +142,46 @@ func TestMaintainership(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(m) != len(test.maintainers) {
|
if len(m) != len(test.maintainers) {
|
||||||
t.Error("Invalid number of maintainers for package", err)
|
t.Error("Invalid number of maintainers for package", test.packageName, len(m), "vs", len(test.maintainers))
|
||||||
}
|
}
|
||||||
for i := range m {
|
for i := range m {
|
||||||
if !slices.Contains(test.maintainers, m[i]) {
|
if !slices.Contains(test.maintainers, m[i]) {
|
||||||
t.Fatal("Can't find expected users. Found:", m)
|
t.Fatal("Can't find expected users. Found:", m)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run(test.name+"_File", func(t *testing.T) {
|
||||||
|
ctl := gomock.NewController(t)
|
||||||
|
mi := mock_common.NewMockGiteaMaintainershipInterface(ctl)
|
||||||
|
|
||||||
|
// tests with maintainership file
|
||||||
|
mi.EXPECT().FetchMaintainershipFile("foo", common.DefaultGitPrj, "bar").
|
||||||
|
Return(test.maintainersFile, test.maintainersFileErr)
|
||||||
|
mi.EXPECT().FetchMaintainershipDirFile("foo", common.DefaultGitPrj, "bar", ProjectFileKey).
|
||||||
|
Return(nil, notFoundError)
|
||||||
|
|
||||||
|
runTests(t, mi)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run(test.name+"_Dir", func(t *testing.T) {
|
||||||
|
ctl := gomock.NewController(t)
|
||||||
|
mi := mock_common.NewMockGiteaMaintainershipInterface(ctl)
|
||||||
|
|
||||||
|
// run same tests with directory maintainership data
|
||||||
|
for filename, data := range test.maintainersDir {
|
||||||
|
mi.EXPECT().FetchMaintainershipDirFile("foo", common.DefaultGitPrj, "bar", filename).Return(data, test.maintainersFileErr).AnyTimes()
|
||||||
|
}
|
||||||
|
if _, found := test.maintainersDir[ProjectFileKey]; !found {
|
||||||
|
mi.EXPECT().FetchMaintainershipDirFile("foo", common.DefaultGitPrj, "bar", ProjectFileKey).Return(nil, test.maintainersFileErr).AnyTimes()
|
||||||
|
mi.EXPECT().FetchMaintainershipFile("foo", common.DefaultGitPrj, "bar").Return(nil, test.maintainersFileErr).AnyTimes()
|
||||||
|
}
|
||||||
|
mi.EXPECT().FetchMaintainershipDirFile("foo", common.DefaultGitPrj, "bar", gomock.Any()).Return(nil, notFoundError).AnyTimes()
|
||||||
|
|
||||||
|
runTests(t, mi)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMaintainershipDir(t *testing.T) {
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user