forked from forgejo/forgejo
Move some repository related code into sub package (#19711)
* Move some repository related code into sub package * Move more repository functions out of models * Fix lint * Some performance optimization for webhooks and others * some refactors * Fix lint * Fix * Update modules/repository/delete.go Co-authored-by: delvh <dev.lh@web.de> * Fix test * Merge * Fix test * Fix test * Fix test * Fix test Co-authored-by: delvh <dev.lh@web.de>
This commit is contained in:
parent
ebeb6e7c71
commit
26095115f4
76 changed files with 1756 additions and 1674 deletions
|
@ -2,12 +2,13 @@
|
|||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package repo
|
||||
package repo_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
@ -16,7 +17,7 @@ import (
|
|||
func TestIncreaseDownloadCount(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
attachment, err := GetAttachmentByUUID(db.DefaultContext, "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11")
|
||||
attachment, err := repo_model.GetAttachmentByUUID(db.DefaultContext, "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, int64(0), attachment.DownloadCount)
|
||||
|
||||
|
@ -24,7 +25,7 @@ func TestIncreaseDownloadCount(t *testing.T) {
|
|||
err = attachment.IncreaseDownloadCount()
|
||||
assert.NoError(t, err)
|
||||
|
||||
attachment, err = GetAttachmentByUUID(db.DefaultContext, "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11")
|
||||
attachment, err = repo_model.GetAttachmentByUUID(db.DefaultContext, "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, int64(1), attachment.DownloadCount)
|
||||
}
|
||||
|
@ -33,11 +34,11 @@ func TestGetByCommentOrIssueID(t *testing.T) {
|
|||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
// count of attachments from issue ID
|
||||
attachments, err := GetAttachmentsByIssueID(db.DefaultContext, 1)
|
||||
attachments, err := repo_model.GetAttachmentsByIssueID(db.DefaultContext, 1)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, attachments, 1)
|
||||
|
||||
attachments, err = GetAttachmentsByCommentID(db.DefaultContext, 1)
|
||||
attachments, err = repo_model.GetAttachmentsByCommentID(db.DefaultContext, 1)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, attachments, 2)
|
||||
}
|
||||
|
@ -45,33 +46,33 @@ func TestGetByCommentOrIssueID(t *testing.T) {
|
|||
func TestDeleteAttachments(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
count, err := DeleteAttachmentsByIssue(4, false)
|
||||
count, err := repo_model.DeleteAttachmentsByIssue(4, false)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 2, count)
|
||||
|
||||
count, err = DeleteAttachmentsByComment(2, false)
|
||||
count, err = repo_model.DeleteAttachmentsByComment(2, false)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 2, count)
|
||||
|
||||
err = DeleteAttachment(&Attachment{ID: 8}, false)
|
||||
err = repo_model.DeleteAttachment(&repo_model.Attachment{ID: 8}, false)
|
||||
assert.NoError(t, err)
|
||||
|
||||
attachment, err := GetAttachmentByUUID(db.DefaultContext, "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a18")
|
||||
attachment, err := repo_model.GetAttachmentByUUID(db.DefaultContext, "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a18")
|
||||
assert.Error(t, err)
|
||||
assert.True(t, IsErrAttachmentNotExist(err))
|
||||
assert.True(t, repo_model.IsErrAttachmentNotExist(err))
|
||||
assert.Nil(t, attachment)
|
||||
}
|
||||
|
||||
func TestGetAttachmentByID(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
attach, err := GetAttachmentByID(db.DefaultContext, 1)
|
||||
attach, err := repo_model.GetAttachmentByID(db.DefaultContext, 1)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11", attach.UUID)
|
||||
}
|
||||
|
||||
func TestAttachment_DownloadURL(t *testing.T) {
|
||||
attach := &Attachment{
|
||||
attach := &repo_model.Attachment{
|
||||
UUID: "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11",
|
||||
ID: 1,
|
||||
}
|
||||
|
@ -81,20 +82,20 @@ func TestAttachment_DownloadURL(t *testing.T) {
|
|||
func TestUpdateAttachment(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
attach, err := GetAttachmentByID(db.DefaultContext, 1)
|
||||
attach, err := repo_model.GetAttachmentByID(db.DefaultContext, 1)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11", attach.UUID)
|
||||
|
||||
attach.Name = "new_name"
|
||||
assert.NoError(t, UpdateAttachment(db.DefaultContext, attach))
|
||||
assert.NoError(t, repo_model.UpdateAttachment(db.DefaultContext, attach))
|
||||
|
||||
unittest.AssertExistsAndLoadBean(t, &Attachment{Name: "new_name"})
|
||||
unittest.AssertExistsAndLoadBean(t, &repo_model.Attachment{Name: "new_name"})
|
||||
}
|
||||
|
||||
func TestGetAttachmentsByUUIDs(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
attachList, err := GetAttachmentsByUUIDs(db.DefaultContext, []string{"a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11", "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a17", "not-existing-uuid"})
|
||||
attachList, err := repo_model.GetAttachmentsByUUIDs(db.DefaultContext, []string{"a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11", "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a17", "not-existing-uuid"})
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, attachList, 2)
|
||||
assert.Equal(t, "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11", attachList[0].UUID)
|
||||
|
|
|
@ -2,12 +2,13 @@
|
|||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package repo
|
||||
package repo_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
@ -16,10 +17,10 @@ import (
|
|||
func TestRepository_GetCollaborators(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
test := func(repoID int64) {
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: repoID}).(*Repository)
|
||||
collaborators, err := GetCollaborators(db.DefaultContext, repo.ID, db.ListOptions{})
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID}).(*repo_model.Repository)
|
||||
collaborators, err := repo_model.GetCollaborators(db.DefaultContext, repo.ID, db.ListOptions{})
|
||||
assert.NoError(t, err)
|
||||
expectedLen, err := db.GetEngine(db.DefaultContext).Count(&Collaboration{RepoID: repoID})
|
||||
expectedLen, err := db.GetEngine(db.DefaultContext).Count(&repo_model.Collaboration{RepoID: repoID})
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, collaborators, int(expectedLen))
|
||||
for _, collaborator := range collaborators {
|
||||
|
@ -37,8 +38,8 @@ func TestRepository_IsCollaborator(t *testing.T) {
|
|||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
test := func(repoID, userID int64, expected bool) {
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: repoID}).(*Repository)
|
||||
actual, err := IsCollaborator(db.DefaultContext, repo.ID, userID)
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID}).(*repo_model.Repository)
|
||||
actual, err := repo_model.IsCollaborator(db.DefaultContext, repo.ID, userID)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, expected, actual)
|
||||
}
|
||||
|
|
|
@ -8,6 +8,8 @@ import (
|
|||
"context"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"xorm.io/builder"
|
||||
)
|
||||
|
||||
// GetRepositoriesByForkID returns all repositories with given fork ID.
|
||||
|
@ -63,3 +65,51 @@ func GetForks(repo *Repository, listOptions db.ListOptions) ([]*Repository, erro
|
|||
forks := make([]*Repository, 0, listOptions.PageSize)
|
||||
return forks, sess.Find(&forks, &Repository{ForkID: repo.ID})
|
||||
}
|
||||
|
||||
// IncrementRepoForkNum increment repository fork number
|
||||
func IncrementRepoForkNum(ctx context.Context, repoID int64) error {
|
||||
_, err := db.GetEngine(ctx).Exec("UPDATE `repository` SET num_forks=num_forks+1 WHERE id=?", repoID)
|
||||
return err
|
||||
}
|
||||
|
||||
// DecrementRepoForkNum decrement repository fork number
|
||||
func DecrementRepoForkNum(ctx context.Context, repoID int64) error {
|
||||
_, err := db.GetEngine(ctx).Exec("UPDATE `repository` SET num_forks=num_forks-1 WHERE id=?", repoID)
|
||||
return err
|
||||
}
|
||||
|
||||
// FindUserOrgForks returns the forked repositories for one user from a repository
|
||||
func FindUserOrgForks(ctx context.Context, repoID, userID int64) ([]*Repository, error) {
|
||||
cond := builder.And(
|
||||
builder.Eq{"fork_id": repoID},
|
||||
builder.In("owner_id",
|
||||
builder.Select("org_id").
|
||||
From("org_user").
|
||||
Where(builder.Eq{"uid": userID}),
|
||||
),
|
||||
)
|
||||
|
||||
var repos []*Repository
|
||||
return repos, db.GetEngine(ctx).Table("repository").Where(cond).Find(&repos)
|
||||
}
|
||||
|
||||
// GetForksByUserAndOrgs return forked repos of the user and owned orgs
|
||||
func GetForksByUserAndOrgs(ctx context.Context, user *user_model.User, repo *Repository) ([]*Repository, error) {
|
||||
var repoList []*Repository
|
||||
if user == nil {
|
||||
return repoList, nil
|
||||
}
|
||||
forkedRepo, err := GetUserFork(ctx, repo.ID, user.ID)
|
||||
if err != nil {
|
||||
return repoList, err
|
||||
}
|
||||
if forkedRepo != nil {
|
||||
repoList = append(repoList, forkedRepo)
|
||||
}
|
||||
orgForks, err := FindUserOrgForks(ctx, repo.ID, user.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
repoList = append(repoList, orgForks...)
|
||||
return repoList, nil
|
||||
}
|
||||
|
|
|
@ -2,12 +2,13 @@
|
|||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package repo
|
||||
package repo_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
@ -17,17 +18,17 @@ func TestGetUserFork(t *testing.T) {
|
|||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
// User13 has repo 11 forked from repo10
|
||||
repo, err := GetRepositoryByID(10)
|
||||
repo, err := repo_model.GetRepositoryByID(10)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, repo)
|
||||
repo, err = GetUserFork(db.DefaultContext, repo.ID, 13)
|
||||
repo, err = repo_model.GetUserFork(db.DefaultContext, repo.ID, 13)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, repo)
|
||||
|
||||
repo, err = GetRepositoryByID(9)
|
||||
repo, err = repo_model.GetRepositoryByID(9)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, repo)
|
||||
repo, err = GetUserFork(db.DefaultContext, repo.ID, 13)
|
||||
repo, err = repo_model.GetUserFork(db.DefaultContext, repo.ID, 13)
|
||||
assert.NoError(t, err)
|
||||
assert.Nil(t, repo)
|
||||
}
|
||||
|
|
|
@ -2,31 +2,22 @@
|
|||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package repo
|
||||
package repo_test
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
_ "code.gitea.io/gitea/models" // register table model
|
||||
_ "code.gitea.io/gitea/models/perm/access" // register table model
|
||||
_ "code.gitea.io/gitea/models/repo" // register table model
|
||||
_ "code.gitea.io/gitea/models/user" // register table model
|
||||
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
unittest.MainTest(m, &unittest.TestOptions{
|
||||
GiteaRootPath: filepath.Join("..", ".."),
|
||||
FixtureFiles: []string{
|
||||
"attachment.yml",
|
||||
"repo_archiver.yml",
|
||||
"repository.yml",
|
||||
"repo_unit.yml",
|
||||
"repo_indexer_status.yml",
|
||||
"repo_redirect.yml",
|
||||
"watch.yml",
|
||||
"star.yml",
|
||||
"topic.yml",
|
||||
"repo_topic.yml",
|
||||
"user.yml",
|
||||
"collaboration.yml",
|
||||
},
|
||||
})
|
||||
}
|
||||
|
|
|
@ -123,8 +123,8 @@ func MirrorsIterate(limit int, f func(idx int, bean interface{}) error) error {
|
|||
}
|
||||
|
||||
// InsertMirror inserts a mirror to database
|
||||
func InsertMirror(mirror *Mirror) error {
|
||||
_, err := db.GetEngine(db.DefaultContext).Insert(mirror)
|
||||
func InsertMirror(ctx context.Context, mirror *Mirror) error {
|
||||
_, err := db.GetEngine(ctx).Insert(mirror)
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -168,3 +168,12 @@ func (repos MirrorRepositoryList) loadAttributes(ctx context.Context) error {
|
|||
func (repos MirrorRepositoryList) LoadAttributes() error {
|
||||
return repos.loadAttributes(db.DefaultContext)
|
||||
}
|
||||
|
||||
// GetUserMirrorRepositories returns a list of mirror repositories of given user.
|
||||
func GetUserMirrorRepositories(userID int64) ([]*Repository, error) {
|
||||
repos := make([]*Repository, 0, 10)
|
||||
return repos, db.GetEngine(db.DefaultContext).
|
||||
Where("owner_id = ?", userID).
|
||||
And("is_mirror = ?", true).
|
||||
Find(&repos)
|
||||
}
|
||||
|
|
|
@ -2,12 +2,13 @@
|
|||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package repo
|
||||
package repo_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
|
||||
|
@ -19,20 +20,20 @@ func TestPushMirrorsIterate(t *testing.T) {
|
|||
|
||||
now := timeutil.TimeStampNow()
|
||||
|
||||
InsertPushMirror(&PushMirror{
|
||||
repo_model.InsertPushMirror(&repo_model.PushMirror{
|
||||
RemoteName: "test-1",
|
||||
LastUpdateUnix: now,
|
||||
Interval: 1,
|
||||
})
|
||||
|
||||
long, _ := time.ParseDuration("24h")
|
||||
InsertPushMirror(&PushMirror{
|
||||
repo_model.InsertPushMirror(&repo_model.PushMirror{
|
||||
RemoteName: "test-2",
|
||||
LastUpdateUnix: now,
|
||||
Interval: long,
|
||||
})
|
||||
|
||||
InsertPushMirror(&PushMirror{
|
||||
repo_model.InsertPushMirror(&repo_model.PushMirror{
|
||||
RemoteName: "test-3",
|
||||
LastUpdateUnix: now,
|
||||
Interval: 0,
|
||||
|
@ -40,8 +41,8 @@ func TestPushMirrorsIterate(t *testing.T) {
|
|||
|
||||
time.Sleep(1 * time.Millisecond)
|
||||
|
||||
PushMirrorsIterate(1, func(idx int, bean interface{}) error {
|
||||
m, ok := bean.(*PushMirror)
|
||||
repo_model.PushMirrorsIterate(1, func(idx int, bean interface{}) error {
|
||||
m, ok := bean.(*repo_model.PushMirror)
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, "test-1", m.RemoteName)
|
||||
assert.Equal(t, m.RemoteName, m.GetRemoteName())
|
||||
|
|
|
@ -2,12 +2,13 @@
|
|||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package repo
|
||||
package repo_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
@ -16,27 +17,27 @@ import (
|
|||
func TestLookupRedirect(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
repoID, err := LookupRedirect(2, "oldrepo1")
|
||||
repoID, err := repo_model.LookupRedirect(2, "oldrepo1")
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, repoID)
|
||||
|
||||
_, err = LookupRedirect(unittest.NonexistentID, "doesnotexist")
|
||||
assert.True(t, IsErrRedirectNotExist(err))
|
||||
_, err = repo_model.LookupRedirect(unittest.NonexistentID, "doesnotexist")
|
||||
assert.True(t, repo_model.IsErrRedirectNotExist(err))
|
||||
}
|
||||
|
||||
func TestNewRedirect(t *testing.T) {
|
||||
// redirect to a completely new name
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository)
|
||||
assert.NoError(t, NewRedirect(db.DefaultContext, repo.OwnerID, repo.ID, repo.Name, "newreponame"))
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository)
|
||||
assert.NoError(t, repo_model.NewRedirect(db.DefaultContext, repo.OwnerID, repo.ID, repo.Name, "newreponame"))
|
||||
|
||||
unittest.AssertExistsAndLoadBean(t, &Redirect{
|
||||
unittest.AssertExistsAndLoadBean(t, &repo_model.Redirect{
|
||||
OwnerID: repo.OwnerID,
|
||||
LowerName: repo.LowerName,
|
||||
RedirectRepoID: repo.ID,
|
||||
})
|
||||
unittest.AssertExistsAndLoadBean(t, &Redirect{
|
||||
unittest.AssertExistsAndLoadBean(t, &repo_model.Redirect{
|
||||
OwnerID: repo.OwnerID,
|
||||
LowerName: "oldrepo1",
|
||||
RedirectRepoID: repo.ID,
|
||||
|
@ -47,15 +48,15 @@ func TestNewRedirect2(t *testing.T) {
|
|||
// redirect to previously used name
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository)
|
||||
assert.NoError(t, NewRedirect(db.DefaultContext, repo.OwnerID, repo.ID, repo.Name, "oldrepo1"))
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository)
|
||||
assert.NoError(t, repo_model.NewRedirect(db.DefaultContext, repo.OwnerID, repo.ID, repo.Name, "oldrepo1"))
|
||||
|
||||
unittest.AssertExistsAndLoadBean(t, &Redirect{
|
||||
unittest.AssertExistsAndLoadBean(t, &repo_model.Redirect{
|
||||
OwnerID: repo.OwnerID,
|
||||
LowerName: repo.LowerName,
|
||||
RedirectRepoID: repo.ID,
|
||||
})
|
||||
unittest.AssertNotExistsBean(t, &Redirect{
|
||||
unittest.AssertNotExistsBean(t, &repo_model.Redirect{
|
||||
OwnerID: repo.OwnerID,
|
||||
LowerName: "oldrepo1",
|
||||
RedirectRepoID: repo.ID,
|
||||
|
@ -66,10 +67,10 @@ func TestNewRedirect3(t *testing.T) {
|
|||
// redirect for a previously-unredirected repo
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 2}).(*Repository)
|
||||
assert.NoError(t, NewRedirect(db.DefaultContext, repo.OwnerID, repo.ID, repo.Name, "newreponame"))
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}).(*repo_model.Repository)
|
||||
assert.NoError(t, repo_model.NewRedirect(db.DefaultContext, repo.OwnerID, repo.ID, repo.Name, "newreponame"))
|
||||
|
||||
unittest.AssertExistsAndLoadBean(t, &Redirect{
|
||||
unittest.AssertExistsAndLoadBean(t, &repo_model.Redirect{
|
||||
OwnerID: repo.OwnerID,
|
||||
LowerName: repo.LowerName,
|
||||
RedirectRepoID: repo.ID,
|
||||
|
|
|
@ -5,18 +5,21 @@
|
|||
package repo
|
||||
|
||||
import (
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
)
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
// GetUserMirrorRepositories returns a list of mirror repositories of given user.
|
||||
func GetUserMirrorRepositories(userID int64) ([]*Repository, error) {
|
||||
repos := make([]*Repository, 0, 10)
|
||||
return repos, db.GetEngine(db.DefaultContext).
|
||||
Where("owner_id = ?", userID).
|
||||
And("is_mirror = ?", true).
|
||||
Find(&repos)
|
||||
}
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/models/perm"
|
||||
"code.gitea.io/gitea/models/unit"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/container"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
|
||||
"xorm.io/builder"
|
||||
)
|
||||
|
||||
// IterateRepository iterate repositories
|
||||
func IterateRepository(f func(repo *Repository) error) error {
|
||||
|
@ -45,3 +48,643 @@ func IterateRepository(f func(repo *Repository) error) error {
|
|||
func FindReposMapByIDs(repoIDs []int64, res map[int64]*Repository) error {
|
||||
return db.GetEngine(db.DefaultContext).In("id", repoIDs).Find(&res)
|
||||
}
|
||||
|
||||
// RepositoryListDefaultPageSize is the default number of repositories
|
||||
// to load in memory when running administrative tasks on all (or almost
|
||||
// all) of them.
|
||||
// The number should be low enough to avoid filling up all RAM with
|
||||
// repository data...
|
||||
const RepositoryListDefaultPageSize = 64
|
||||
|
||||
// RepositoryList contains a list of repositories
|
||||
type RepositoryList []*Repository
|
||||
|
||||
func (repos RepositoryList) Len() int {
|
||||
return len(repos)
|
||||
}
|
||||
|
||||
func (repos RepositoryList) Less(i, j int) bool {
|
||||
return repos[i].FullName() < repos[j].FullName()
|
||||
}
|
||||
|
||||
func (repos RepositoryList) Swap(i, j int) {
|
||||
repos[i], repos[j] = repos[j], repos[i]
|
||||
}
|
||||
|
||||
// ValuesRepository converts a repository map to a list
|
||||
// FIXME: Remove in favor of maps.values when MIN_GO_VERSION >= 1.18
|
||||
func ValuesRepository(m map[int64]*Repository) []*Repository {
|
||||
values := make([]*Repository, 0, len(m))
|
||||
for _, v := range m {
|
||||
values = append(values, v)
|
||||
}
|
||||
return values
|
||||
}
|
||||
|
||||
// RepositoryListOfMap make list from values of map
|
||||
func RepositoryListOfMap(repoMap map[int64]*Repository) RepositoryList {
|
||||
return RepositoryList(ValuesRepository(repoMap))
|
||||
}
|
||||
|
||||
func (repos RepositoryList) loadAttributes(ctx context.Context) error {
|
||||
if len(repos) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
set := make(map[int64]struct{})
|
||||
repoIDs := make([]int64, len(repos))
|
||||
for i := range repos {
|
||||
set[repos[i].OwnerID] = struct{}{}
|
||||
repoIDs[i] = repos[i].ID
|
||||
}
|
||||
|
||||
// Load owners.
|
||||
users := make(map[int64]*user_model.User, len(set))
|
||||
if err := db.GetEngine(ctx).
|
||||
Where("id > 0").
|
||||
In("id", container.KeysInt64(set)).
|
||||
Find(&users); err != nil {
|
||||
return fmt.Errorf("find users: %v", err)
|
||||
}
|
||||
for i := range repos {
|
||||
repos[i].Owner = users[repos[i].OwnerID]
|
||||
}
|
||||
|
||||
// Load primary language.
|
||||
stats := make(LanguageStatList, 0, len(repos))
|
||||
if err := db.GetEngine(ctx).
|
||||
Where("`is_primary` = ? AND `language` != ?", true, "other").
|
||||
In("`repo_id`", repoIDs).
|
||||
Find(&stats); err != nil {
|
||||
return fmt.Errorf("find primary languages: %v", err)
|
||||
}
|
||||
stats.LoadAttributes()
|
||||
for i := range repos {
|
||||
for _, st := range stats {
|
||||
if st.RepoID == repos[i].ID {
|
||||
repos[i].PrimaryLanguage = st
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// LoadAttributes loads the attributes for the given RepositoryList
|
||||
func (repos RepositoryList) LoadAttributes() error {
|
||||
return repos.loadAttributes(db.DefaultContext)
|
||||
}
|
||||
|
||||
// SearchRepoOptions holds the search options
|
||||
type SearchRepoOptions struct {
|
||||
db.ListOptions
|
||||
Actor *user_model.User
|
||||
Keyword string
|
||||
OwnerID int64
|
||||
PriorityOwnerID int64
|
||||
TeamID int64
|
||||
OrderBy db.SearchOrderBy
|
||||
Private bool // Include private repositories in results
|
||||
StarredByID int64
|
||||
WatchedByID int64
|
||||
AllPublic bool // Include also all public repositories of users and public organisations
|
||||
AllLimited bool // Include also all public repositories of limited organisations
|
||||
// None -> include public and private
|
||||
// True -> include just private
|
||||
// False -> include just public
|
||||
IsPrivate util.OptionalBool
|
||||
// None -> include collaborative AND non-collaborative
|
||||
// True -> include just collaborative
|
||||
// False -> include just non-collaborative
|
||||
Collaborate util.OptionalBool
|
||||
// None -> include forks AND non-forks
|
||||
// True -> include just forks
|
||||
// False -> include just non-forks
|
||||
Fork util.OptionalBool
|
||||
// None -> include templates AND non-templates
|
||||
// True -> include just templates
|
||||
// False -> include just non-templates
|
||||
Template util.OptionalBool
|
||||
// None -> include mirrors AND non-mirrors
|
||||
// True -> include just mirrors
|
||||
// False -> include just non-mirrors
|
||||
Mirror util.OptionalBool
|
||||
// None -> include archived AND non-archived
|
||||
// True -> include just archived
|
||||
// False -> include just non-archived
|
||||
Archived util.OptionalBool
|
||||
// only search topic name
|
||||
TopicOnly bool
|
||||
// only search repositories with specified primary language
|
||||
Language string
|
||||
// include description in keyword search
|
||||
IncludeDescription bool
|
||||
// None -> include has milestones AND has no milestone
|
||||
// True -> include just has milestones
|
||||
// False -> include just has no milestone
|
||||
HasMilestones util.OptionalBool
|
||||
// LowerNames represents valid lower names to restrict to
|
||||
LowerNames []string
|
||||
}
|
||||
|
||||
// SearchOrderBy is used to sort the result
|
||||
type SearchOrderBy string
|
||||
|
||||
func (s SearchOrderBy) String() string {
|
||||
return string(s)
|
||||
}
|
||||
|
||||
// Strings for sorting result
|
||||
const (
|
||||
SearchOrderByAlphabetically SearchOrderBy = "name ASC"
|
||||
SearchOrderByAlphabeticallyReverse SearchOrderBy = "name DESC"
|
||||
SearchOrderByLeastUpdated SearchOrderBy = "updated_unix ASC"
|
||||
SearchOrderByRecentUpdated SearchOrderBy = "updated_unix DESC"
|
||||
SearchOrderByOldest SearchOrderBy = "created_unix ASC"
|
||||
SearchOrderByNewest SearchOrderBy = "created_unix DESC"
|
||||
SearchOrderBySize SearchOrderBy = "size ASC"
|
||||
SearchOrderBySizeReverse SearchOrderBy = "size DESC"
|
||||
SearchOrderByID SearchOrderBy = "id ASC"
|
||||
SearchOrderByIDReverse SearchOrderBy = "id DESC"
|
||||
SearchOrderByStars SearchOrderBy = "num_stars ASC"
|
||||
SearchOrderByStarsReverse SearchOrderBy = "num_stars DESC"
|
||||
SearchOrderByForks SearchOrderBy = "num_forks ASC"
|
||||
SearchOrderByForksReverse SearchOrderBy = "num_forks DESC"
|
||||
)
|
||||
|
||||
// UserOwnedRepoCond returns user ownered repositories
|
||||
func UserOwnedRepoCond(userID int64) builder.Cond {
|
||||
return builder.Eq{
|
||||
"repository.owner_id": userID,
|
||||
}
|
||||
}
|
||||
|
||||
// UserAssignedRepoCond return user as assignee repositories list
|
||||
func UserAssignedRepoCond(id string, userID int64) builder.Cond {
|
||||
return builder.And(
|
||||
builder.Eq{
|
||||
"repository.is_private": false,
|
||||
},
|
||||
builder.In(id,
|
||||
builder.Select("issue.repo_id").From("issue_assignees").
|
||||
InnerJoin("issue", "issue.id = issue_assignees.issue_id").
|
||||
Where(builder.Eq{
|
||||
"issue_assignees.assignee_id": userID,
|
||||
}),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
// UserCreateIssueRepoCond return user created issues repositories list
|
||||
func UserCreateIssueRepoCond(id string, userID int64, isPull bool) builder.Cond {
|
||||
return builder.And(
|
||||
builder.Eq{
|
||||
"repository.is_private": false,
|
||||
},
|
||||
builder.In(id,
|
||||
builder.Select("issue.repo_id").From("issue").
|
||||
Where(builder.Eq{
|
||||
"issue.poster_id": userID,
|
||||
"issue.is_pull": isPull,
|
||||
}),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
// UserMentionedRepoCond return user metinoed repositories list
|
||||
func UserMentionedRepoCond(id string, userID int64) builder.Cond {
|
||||
return builder.And(
|
||||
builder.Eq{
|
||||
"repository.is_private": false,
|
||||
},
|
||||
builder.In(id,
|
||||
builder.Select("issue.repo_id").From("issue_user").
|
||||
InnerJoin("issue", "issue.id = issue_user.issue_id").
|
||||
Where(builder.Eq{
|
||||
"issue_user.is_mentioned": true,
|
||||
"issue_user.uid": userID,
|
||||
}),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
// UserCollaborationRepoCond returns user as collabrators repositories list
|
||||
func UserCollaborationRepoCond(idStr string, userID int64) builder.Cond {
|
||||
return builder.In(idStr, builder.Select("repo_id").
|
||||
From("`access`").
|
||||
Where(builder.And(
|
||||
builder.Eq{"`access`.user_id": userID},
|
||||
builder.Gt{"`access`.mode": int(perm.AccessModeNone)},
|
||||
)),
|
||||
)
|
||||
}
|
||||
|
||||
// userOrgTeamRepoCond selects repos that the given user has access to through team membership
|
||||
func userOrgTeamRepoCond(idStr string, userID int64) builder.Cond {
|
||||
return builder.In(idStr, userOrgTeamRepoBuilder(userID))
|
||||
}
|
||||
|
||||
// userOrgTeamRepoBuilder returns repo ids where user's teams can access.
|
||||
func userOrgTeamRepoBuilder(userID int64) *builder.Builder {
|
||||
return builder.Select("`team_repo`.repo_id").
|
||||
From("team_repo").
|
||||
Join("INNER", "team_user", "`team_user`.team_id = `team_repo`.team_id").
|
||||
Where(builder.Eq{"`team_user`.uid": userID})
|
||||
}
|
||||
|
||||
// userOrgTeamUnitRepoBuilder returns repo ids where user's teams can access the special unit.
|
||||
func userOrgTeamUnitRepoBuilder(userID int64, unitType unit.Type) *builder.Builder {
|
||||
return userOrgTeamRepoBuilder(userID).
|
||||
Join("INNER", "team_unit", "`team_unit`.team_id = `team_repo`.team_id").
|
||||
Where(builder.Eq{"`team_unit`.`type`": unitType})
|
||||
}
|
||||
|
||||
// UserOrgUnitRepoCond selects repos that the given user has access to through org and the special unit
|
||||
func UserOrgUnitRepoCond(idStr string, userID, orgID int64, unitType unit.Type) builder.Cond {
|
||||
return builder.In(idStr,
|
||||
userOrgTeamUnitRepoBuilder(userID, unitType).
|
||||
And(builder.Eq{"`team_unit`.org_id": orgID}),
|
||||
)
|
||||
}
|
||||
|
||||
// userOrgPublicRepoCond returns the condition that one user could access all public repositories in organizations
|
||||
func userOrgPublicRepoCond(userID int64) builder.Cond {
|
||||
return builder.And(
|
||||
builder.Eq{"`repository`.is_private": false},
|
||||
builder.In("`repository`.owner_id",
|
||||
builder.Select("`org_user`.org_id").
|
||||
From("org_user").
|
||||
Where(builder.Eq{"`org_user`.uid": userID}),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
// userOrgPublicRepoCondPrivate returns the condition that one user could access all public repositories in private organizations
|
||||
func userOrgPublicRepoCondPrivate(userID int64) builder.Cond {
|
||||
return builder.And(
|
||||
builder.Eq{"`repository`.is_private": false},
|
||||
builder.In("`repository`.owner_id",
|
||||
builder.Select("`org_user`.org_id").
|
||||
From("org_user").
|
||||
Join("INNER", "`user`", "`user`.id = `org_user`.org_id").
|
||||
Where(builder.Eq{
|
||||
"`org_user`.uid": userID,
|
||||
"`user`.`type`": user_model.UserTypeOrganization,
|
||||
"`user`.visibility": structs.VisibleTypePrivate,
|
||||
}),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
// UserOrgPublicUnitRepoCond returns the condition that one user could access all public repositories in the special organization
|
||||
func UserOrgPublicUnitRepoCond(userID, orgID int64) builder.Cond {
|
||||
return userOrgPublicRepoCond(userID).
|
||||
And(builder.Eq{"`repository`.owner_id": orgID})
|
||||
}
|
||||
|
||||
// SearchRepositoryCondition creates a query condition according search repository options
|
||||
func SearchRepositoryCondition(opts *SearchRepoOptions) builder.Cond {
|
||||
cond := builder.NewCond()
|
||||
|
||||
if opts.Private {
|
||||
if opts.Actor != nil && !opts.Actor.IsAdmin && opts.Actor.ID != opts.OwnerID {
|
||||
// OK we're in the context of a User
|
||||
cond = cond.And(AccessibleRepositoryCondition(opts.Actor))
|
||||
}
|
||||
} else {
|
||||
// Not looking at private organisations and users
|
||||
// We should be able to see all non-private repositories that
|
||||
// isn't in a private or limited organisation.
|
||||
cond = cond.And(
|
||||
builder.Eq{"is_private": false},
|
||||
builder.NotIn("owner_id", builder.Select("id").From("`user`").Where(
|
||||
builder.Or(builder.Eq{"visibility": structs.VisibleTypeLimited}, builder.Eq{"visibility": structs.VisibleTypePrivate}),
|
||||
)))
|
||||
}
|
||||
|
||||
if opts.IsPrivate != util.OptionalBoolNone {
|
||||
cond = cond.And(builder.Eq{"is_private": opts.IsPrivate.IsTrue()})
|
||||
}
|
||||
|
||||
if opts.Template != util.OptionalBoolNone {
|
||||
cond = cond.And(builder.Eq{"is_template": opts.Template == util.OptionalBoolTrue})
|
||||
}
|
||||
|
||||
// Restrict to starred repositories
|
||||
if opts.StarredByID > 0 {
|
||||
cond = cond.And(builder.In("id", builder.Select("repo_id").From("star").Where(builder.Eq{"uid": opts.StarredByID})))
|
||||
}
|
||||
|
||||
// Restrict to watched repositories
|
||||
if opts.WatchedByID > 0 {
|
||||
cond = cond.And(builder.In("id", builder.Select("repo_id").From("watch").Where(builder.Eq{"user_id": opts.WatchedByID})))
|
||||
}
|
||||
|
||||
// Restrict repositories to those the OwnerID owns or contributes to as per opts.Collaborate
|
||||
if opts.OwnerID > 0 {
|
||||
accessCond := builder.NewCond()
|
||||
if opts.Collaborate != util.OptionalBoolTrue {
|
||||
accessCond = builder.Eq{"owner_id": opts.OwnerID}
|
||||
}
|
||||
|
||||
if opts.Collaborate != util.OptionalBoolFalse {
|
||||
// A Collaboration is:
|
||||
collaborateCond := builder.And(
|
||||
// 1. Repository we don't own
|
||||
builder.Neq{"owner_id": opts.OwnerID},
|
||||
// 2. But we can see because of:
|
||||
builder.Or(
|
||||
// A. We have access
|
||||
UserCollaborationRepoCond("`repository`.id", opts.OwnerID),
|
||||
// B. We are in a team for
|
||||
userOrgTeamRepoCond("`repository`.id", opts.OwnerID),
|
||||
// C. Public repositories in organizations that we are member of
|
||||
userOrgPublicRepoCondPrivate(opts.OwnerID),
|
||||
),
|
||||
)
|
||||
if !opts.Private {
|
||||
collaborateCond = collaborateCond.And(builder.Expr("owner_id NOT IN (SELECT org_id FROM org_user WHERE org_user.uid = ? AND org_user.is_public = ?)", opts.OwnerID, false))
|
||||
}
|
||||
|
||||
accessCond = accessCond.Or(collaborateCond)
|
||||
}
|
||||
|
||||
if opts.AllPublic {
|
||||
accessCond = accessCond.Or(builder.Eq{"is_private": false}.And(builder.In("owner_id", builder.Select("`user`.id").From("`user`").Where(builder.Eq{"`user`.visibility": structs.VisibleTypePublic}))))
|
||||
}
|
||||
|
||||
if opts.AllLimited {
|
||||
accessCond = accessCond.Or(builder.Eq{"is_private": false}.And(builder.In("owner_id", builder.Select("`user`.id").From("`user`").Where(builder.Eq{"`user`.visibility": structs.VisibleTypeLimited}))))
|
||||
}
|
||||
|
||||
cond = cond.And(accessCond)
|
||||
}
|
||||
|
||||
if opts.TeamID > 0 {
|
||||
cond = cond.And(builder.In("`repository`.id", builder.Select("`team_repo`.repo_id").From("team_repo").Where(builder.Eq{"`team_repo`.team_id": opts.TeamID})))
|
||||
}
|
||||
|
||||
if opts.Keyword != "" {
|
||||
// separate keyword
|
||||
subQueryCond := builder.NewCond()
|
||||
for _, v := range strings.Split(opts.Keyword, ",") {
|
||||
if opts.TopicOnly {
|
||||
subQueryCond = subQueryCond.Or(builder.Eq{"topic.name": strings.ToLower(v)})
|
||||
} else {
|
||||
subQueryCond = subQueryCond.Or(builder.Like{"topic.name", strings.ToLower(v)})
|
||||
}
|
||||
}
|
||||
subQuery := builder.Select("repo_topic.repo_id").From("repo_topic").
|
||||
Join("INNER", "topic", "topic.id = repo_topic.topic_id").
|
||||
Where(subQueryCond).
|
||||
GroupBy("repo_topic.repo_id")
|
||||
|
||||
keywordCond := builder.In("id", subQuery)
|
||||
if !opts.TopicOnly {
|
||||
likes := builder.NewCond()
|
||||
for _, v := range strings.Split(opts.Keyword, ",") {
|
||||
likes = likes.Or(builder.Like{"lower_name", strings.ToLower(v)})
|
||||
|
||||
// If the string looks like "org/repo", match against that pattern too
|
||||
if opts.TeamID == 0 && strings.Count(opts.Keyword, "/") == 1 {
|
||||
pieces := strings.Split(opts.Keyword, "/")
|
||||
ownerName := pieces[0]
|
||||
repoName := pieces[1]
|
||||
likes = likes.Or(builder.And(builder.Like{"owner_name", strings.ToLower(ownerName)}, builder.Like{"lower_name", strings.ToLower(repoName)}))
|
||||
}
|
||||
|
||||
if opts.IncludeDescription {
|
||||
likes = likes.Or(builder.Like{"LOWER(description)", strings.ToLower(v)})
|
||||
}
|
||||
}
|
||||
keywordCond = keywordCond.Or(likes)
|
||||
}
|
||||
cond = cond.And(keywordCond)
|
||||
}
|
||||
|
||||
if opts.Language != "" {
|
||||
cond = cond.And(builder.In("id", builder.
|
||||
Select("repo_id").
|
||||
From("language_stat").
|
||||
Where(builder.Eq{"language": opts.Language}).And(builder.Eq{"is_primary": true})))
|
||||
}
|
||||
|
||||
if opts.Fork != util.OptionalBoolNone {
|
||||
cond = cond.And(builder.Eq{"is_fork": opts.Fork == util.OptionalBoolTrue})
|
||||
}
|
||||
|
||||
if opts.Mirror != util.OptionalBoolNone {
|
||||
cond = cond.And(builder.Eq{"is_mirror": opts.Mirror == util.OptionalBoolTrue})
|
||||
}
|
||||
|
||||
if opts.Actor != nil && opts.Actor.IsRestricted {
|
||||
cond = cond.And(AccessibleRepositoryCondition(opts.Actor))
|
||||
}
|
||||
|
||||
if opts.Archived != util.OptionalBoolNone {
|
||||
cond = cond.And(builder.Eq{"is_archived": opts.Archived == util.OptionalBoolTrue})
|
||||
}
|
||||
|
||||
switch opts.HasMilestones {
|
||||
case util.OptionalBoolTrue:
|
||||
cond = cond.And(builder.Gt{"num_milestones": 0})
|
||||
case util.OptionalBoolFalse:
|
||||
cond = cond.And(builder.Eq{"num_milestones": 0}.Or(builder.IsNull{"num_milestones"}))
|
||||
}
|
||||
|
||||
return cond
|
||||
}
|
||||
|
||||
// SearchRepository returns repositories based on search options,
|
||||
// it returns results in given range and number of total results.
|
||||
func SearchRepository(opts *SearchRepoOptions) (RepositoryList, int64, error) {
|
||||
cond := SearchRepositoryCondition(opts)
|
||||
return SearchRepositoryByCondition(opts, cond, true)
|
||||
}
|
||||
|
||||
// SearchRepositoryByCondition search repositories by condition
|
||||
func SearchRepositoryByCondition(opts *SearchRepoOptions, cond builder.Cond, loadAttributes bool) (RepositoryList, int64, error) {
|
||||
ctx := db.DefaultContext
|
||||
sess, count, err := searchRepositoryByCondition(ctx, opts, cond)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
defaultSize := 50
|
||||
if opts.PageSize > 0 {
|
||||
defaultSize = opts.PageSize
|
||||
}
|
||||
repos := make(RepositoryList, 0, defaultSize)
|
||||
if err := sess.Find(&repos); err != nil {
|
||||
return nil, 0, fmt.Errorf("Repo: %v", err)
|
||||
}
|
||||
|
||||
if opts.PageSize <= 0 {
|
||||
count = int64(len(repos))
|
||||
}
|
||||
|
||||
if loadAttributes {
|
||||
if err := repos.loadAttributes(ctx); err != nil {
|
||||
return nil, 0, fmt.Errorf("LoadAttributes: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
return repos, count, nil
|
||||
}
|
||||
|
||||
func searchRepositoryByCondition(ctx context.Context, opts *SearchRepoOptions, cond builder.Cond) (db.Engine, int64, error) {
|
||||
if opts.Page <= 0 {
|
||||
opts.Page = 1
|
||||
}
|
||||
|
||||
if len(opts.OrderBy) == 0 {
|
||||
opts.OrderBy = db.SearchOrderByAlphabetically
|
||||
}
|
||||
|
||||
args := make([]interface{}, 0)
|
||||
if opts.PriorityOwnerID > 0 {
|
||||
opts.OrderBy = db.SearchOrderBy(fmt.Sprintf("CASE WHEN owner_id = ? THEN 0 ELSE owner_id END, %s", opts.OrderBy))
|
||||
args = append(args, opts.PriorityOwnerID)
|
||||
} else if strings.Count(opts.Keyword, "/") == 1 {
|
||||
// With "owner/repo" search times, prioritise results which match the owner field
|
||||
orgName := strings.Split(opts.Keyword, "/")[0]
|
||||
opts.OrderBy = db.SearchOrderBy(fmt.Sprintf("CASE WHEN owner_name LIKE ? THEN 0 ELSE 1 END, %s", opts.OrderBy))
|
||||
args = append(args, orgName)
|
||||
}
|
||||
|
||||
sess := db.GetEngine(ctx)
|
||||
|
||||
var count int64
|
||||
if opts.PageSize > 0 {
|
||||
var err error
|
||||
count, err = sess.
|
||||
Where(cond).
|
||||
Count(new(Repository))
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("Count: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
sess = sess.Where(cond).OrderBy(opts.OrderBy.String(), args...)
|
||||
if opts.PageSize > 0 {
|
||||
sess = sess.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize)
|
||||
}
|
||||
return sess, count, nil
|
||||
}
|
||||
|
||||
// AccessibleRepositoryCondition takes a user a returns a condition for checking if a repository is accessible
|
||||
func AccessibleRepositoryCondition(user *user_model.User) builder.Cond {
|
||||
cond := builder.NewCond()
|
||||
|
||||
if user == nil || !user.IsRestricted || user.ID <= 0 {
|
||||
orgVisibilityLimit := []structs.VisibleType{structs.VisibleTypePrivate}
|
||||
if user == nil || user.ID <= 0 {
|
||||
orgVisibilityLimit = append(orgVisibilityLimit, structs.VisibleTypeLimited)
|
||||
}
|
||||
// 1. Be able to see all non-private repositories that either:
|
||||
cond = cond.Or(builder.And(
|
||||
builder.Eq{"`repository`.is_private": false},
|
||||
// 2. Aren't in an private organisation or limited organisation if we're not logged in
|
||||
builder.NotIn("`repository`.owner_id", builder.Select("id").From("`user`").Where(
|
||||
builder.And(
|
||||
builder.Eq{"type": user_model.UserTypeOrganization},
|
||||
builder.In("visibility", orgVisibilityLimit)),
|
||||
))))
|
||||
}
|
||||
|
||||
if user != nil {
|
||||
cond = cond.Or(
|
||||
// 2. Be able to see all repositories that we have access to
|
||||
UserCollaborationRepoCond("`repository`.id", user.ID),
|
||||
// 3. Repositories that we directly own
|
||||
builder.Eq{"`repository`.owner_id": user.ID},
|
||||
// 4. Be able to see all repositories that we are in a team
|
||||
userOrgTeamRepoCond("`repository`.id", user.ID),
|
||||
// 5. Be able to see all public repos in private organizations that we are an org_user of
|
||||
userOrgPublicRepoCond(user.ID),
|
||||
)
|
||||
}
|
||||
|
||||
return cond
|
||||
}
|
||||
|
||||
// SearchRepositoryByName takes keyword and part of repository name to search,
|
||||
// it returns results in given range and number of total results.
|
||||
func SearchRepositoryByName(opts *SearchRepoOptions) (RepositoryList, int64, error) {
|
||||
opts.IncludeDescription = false
|
||||
return SearchRepository(opts)
|
||||
}
|
||||
|
||||
// SearchRepositoryIDs takes keyword and part of repository name to search,
|
||||
// it returns results in given range and number of total results.
|
||||
func SearchRepositoryIDs(opts *SearchRepoOptions) ([]int64, int64, error) {
|
||||
opts.IncludeDescription = false
|
||||
|
||||
cond := SearchRepositoryCondition(opts)
|
||||
|
||||
sess, count, err := searchRepositoryByCondition(db.DefaultContext, opts, cond)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
defaultSize := 50
|
||||
if opts.PageSize > 0 {
|
||||
defaultSize = opts.PageSize
|
||||
}
|
||||
|
||||
ids := make([]int64, 0, defaultSize)
|
||||
err = sess.Select("id").Table("repository").Find(&ids)
|
||||
if opts.PageSize <= 0 {
|
||||
count = int64(len(ids))
|
||||
}
|
||||
|
||||
return ids, count, err
|
||||
}
|
||||
|
||||
// AccessibleRepoIDsQuery queries accessible repository ids. Usable as a subquery wherever repo ids need to be filtered.
|
||||
func AccessibleRepoIDsQuery(user *user_model.User) *builder.Builder {
|
||||
// NB: Please note this code needs to still work if user is nil
|
||||
return builder.Select("id").From("repository").Where(AccessibleRepositoryCondition(user))
|
||||
}
|
||||
|
||||
// FindUserAccessibleRepoIDs find all accessible repositories' ID by user's id
|
||||
func FindUserAccessibleRepoIDs(user *user_model.User) ([]int64, error) {
|
||||
repoIDs := make([]int64, 0, 10)
|
||||
if err := db.GetEngine(db.DefaultContext).
|
||||
Table("repository").
|
||||
Cols("id").
|
||||
Where(AccessibleRepositoryCondition(user)).
|
||||
Find(&repoIDs); err != nil {
|
||||
return nil, fmt.Errorf("FindUserAccesibleRepoIDs: %v", err)
|
||||
}
|
||||
return repoIDs, nil
|
||||
}
|
||||
|
||||
// GetUserRepositories returns a list of repositories of given user.
|
||||
func GetUserRepositories(opts *SearchRepoOptions) (RepositoryList, int64, error) {
|
||||
if len(opts.OrderBy) == 0 {
|
||||
opts.OrderBy = "updated_unix DESC"
|
||||
}
|
||||
|
||||
cond := builder.NewCond()
|
||||
cond = cond.And(builder.Eq{"owner_id": opts.Actor.ID})
|
||||
if !opts.Private {
|
||||
cond = cond.And(builder.Eq{"is_private": false})
|
||||
}
|
||||
|
||||
if opts.LowerNames != nil && len(opts.LowerNames) > 0 {
|
||||
cond = cond.And(builder.In("lower_name", opts.LowerNames))
|
||||
}
|
||||
|
||||
sess := db.GetEngine(db.DefaultContext)
|
||||
|
||||
count, err := sess.Where(cond).Count(new(Repository))
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("Count: %v", err)
|
||||
}
|
||||
|
||||
sess = sess.Where(cond).OrderBy(opts.OrderBy.String())
|
||||
repos := make(RepositoryList, 0, opts.PageSize)
|
||||
return repos, count, db.SetSessionPagination(sess, opts).Find(&repos)
|
||||
}
|
||||
|
|
385
models/repo/repo_list_test.go
Normal file
385
models/repo/repo_list_test.go
Normal file
|
@ -0,0 +1,385 @@
|
|||
// Copyright 2017 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package repo_test
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestSearchRepository(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
// test search public repository on explore page
|
||||
repos, count, err := repo_model.SearchRepositoryByName(&repo_model.SearchRepoOptions{
|
||||
ListOptions: db.ListOptions{
|
||||
Page: 1,
|
||||
PageSize: 10,
|
||||
},
|
||||
Keyword: "repo_12",
|
||||
Collaborate: util.OptionalBoolFalse,
|
||||
})
|
||||
|
||||
assert.NoError(t, err)
|
||||
if assert.Len(t, repos, 1) {
|
||||
assert.Equal(t, "test_repo_12", repos[0].Name)
|
||||
}
|
||||
assert.Equal(t, int64(1), count)
|
||||
|
||||
repos, count, err = repo_model.SearchRepositoryByName(&repo_model.SearchRepoOptions{
|
||||
ListOptions: db.ListOptions{
|
||||
Page: 1,
|
||||
PageSize: 10,
|
||||
},
|
||||
Keyword: "test_repo",
|
||||
Collaborate: util.OptionalBoolFalse,
|
||||
})
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, int64(2), count)
|
||||
assert.Len(t, repos, 2)
|
||||
|
||||
// test search private repository on explore page
|
||||
repos, count, err = repo_model.SearchRepositoryByName(&repo_model.SearchRepoOptions{
|
||||
ListOptions: db.ListOptions{
|
||||
Page: 1,
|
||||
PageSize: 10,
|
||||
},
|
||||
Keyword: "repo_13",
|
||||
Private: true,
|
||||
Collaborate: util.OptionalBoolFalse,
|
||||
})
|
||||
|
||||
assert.NoError(t, err)
|
||||
if assert.Len(t, repos, 1) {
|
||||
assert.Equal(t, "test_repo_13", repos[0].Name)
|
||||
}
|
||||
assert.Equal(t, int64(1), count)
|
||||
|
||||
repos, count, err = repo_model.SearchRepositoryByName(&repo_model.SearchRepoOptions{
|
||||
ListOptions: db.ListOptions{
|
||||
Page: 1,
|
||||
PageSize: 10,
|
||||
},
|
||||
Keyword: "test_repo",
|
||||
Private: true,
|
||||
Collaborate: util.OptionalBoolFalse,
|
||||
})
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, int64(3), count)
|
||||
assert.Len(t, repos, 3)
|
||||
|
||||
// Test non existing owner
|
||||
repos, count, err = repo_model.SearchRepositoryByName(&repo_model.SearchRepoOptions{OwnerID: unittest.NonexistentID})
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Empty(t, repos)
|
||||
assert.Equal(t, int64(0), count)
|
||||
|
||||
// Test search within description
|
||||
repos, count, err = repo_model.SearchRepository(&repo_model.SearchRepoOptions{
|
||||
ListOptions: db.ListOptions{
|
||||
Page: 1,
|
||||
PageSize: 10,
|
||||
},
|
||||
Keyword: "description_14",
|
||||
Collaborate: util.OptionalBoolFalse,
|
||||
IncludeDescription: true,
|
||||
})
|
||||
|
||||
assert.NoError(t, err)
|
||||
if assert.Len(t, repos, 1) {
|
||||
assert.Equal(t, "test_repo_14", repos[0].Name)
|
||||
}
|
||||
assert.Equal(t, int64(1), count)
|
||||
|
||||
// Test NOT search within description
|
||||
repos, count, err = repo_model.SearchRepository(&repo_model.SearchRepoOptions{
|
||||
ListOptions: db.ListOptions{
|
||||
Page: 1,
|
||||
PageSize: 10,
|
||||
},
|
||||
Keyword: "description_14",
|
||||
Collaborate: util.OptionalBoolFalse,
|
||||
IncludeDescription: false,
|
||||
})
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Empty(t, repos)
|
||||
assert.Equal(t, int64(0), count)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
opts *repo_model.SearchRepoOptions
|
||||
count int
|
||||
}{
|
||||
{
|
||||
name: "PublicRepositoriesByName",
|
||||
opts: &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{PageSize: 10}, Collaborate: util.OptionalBoolFalse},
|
||||
count: 7,
|
||||
},
|
||||
{
|
||||
name: "PublicAndPrivateRepositoriesByName",
|
||||
opts: &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 1, PageSize: 10}, Private: true, Collaborate: util.OptionalBoolFalse},
|
||||
count: 14,
|
||||
},
|
||||
{
|
||||
name: "PublicAndPrivateRepositoriesByNameWithPagesizeLimitFirstPage",
|
||||
opts: &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 1, PageSize: 5}, Private: true, Collaborate: util.OptionalBoolFalse},
|
||||
count: 14,
|
||||
},
|
||||
{
|
||||
name: "PublicAndPrivateRepositoriesByNameWithPagesizeLimitSecondPage",
|
||||
opts: &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 2, PageSize: 5}, Private: true, Collaborate: util.OptionalBoolFalse},
|
||||
count: 14,
|
||||
},
|
||||
{
|
||||
name: "PublicAndPrivateRepositoriesByNameWithPagesizeLimitThirdPage",
|
||||
opts: &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 3, PageSize: 5}, Private: true, Collaborate: util.OptionalBoolFalse},
|
||||
count: 14,
|
||||
},
|
||||
{
|
||||
name: "PublicAndPrivateRepositoriesByNameWithPagesizeLimitFourthPage",
|
||||
opts: &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 3, PageSize: 5}, Private: true, Collaborate: util.OptionalBoolFalse},
|
||||
count: 14,
|
||||
},
|
||||
{
|
||||
name: "PublicRepositoriesOfUser",
|
||||
opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, Collaborate: util.OptionalBoolFalse},
|
||||
count: 2,
|
||||
},
|
||||
{
|
||||
name: "PublicRepositoriesOfUser2",
|
||||
opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 18, Collaborate: util.OptionalBoolFalse},
|
||||
count: 0,
|
||||
},
|
||||
{
|
||||
name: "PublicRepositoriesOfUser3",
|
||||
opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 20, Collaborate: util.OptionalBoolFalse},
|
||||
count: 2,
|
||||
},
|
||||
{
|
||||
name: "PublicAndPrivateRepositoriesOfUser",
|
||||
opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, Private: true, Collaborate: util.OptionalBoolFalse},
|
||||
count: 4,
|
||||
},
|
||||
{
|
||||
name: "PublicAndPrivateRepositoriesOfUser2",
|
||||
opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 18, Private: true, Collaborate: util.OptionalBoolFalse},
|
||||
count: 0,
|
||||
},
|
||||
{
|
||||
name: "PublicAndPrivateRepositoriesOfUser3",
|
||||
opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 20, Private: true, Collaborate: util.OptionalBoolFalse},
|
||||
count: 4,
|
||||
},
|
||||
{
|
||||
name: "PublicRepositoriesOfUserIncludingCollaborative",
|
||||
opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15},
|
||||
count: 5,
|
||||
},
|
||||
{
|
||||
name: "PublicRepositoriesOfUser2IncludingCollaborative",
|
||||
opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 18},
|
||||
count: 1,
|
||||
},
|
||||
{
|
||||
name: "PublicRepositoriesOfUser3IncludingCollaborative",
|
||||
opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 20},
|
||||
count: 3,
|
||||
},
|
||||
{
|
||||
name: "PublicAndPrivateRepositoriesOfUserIncludingCollaborative",
|
||||
opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, Private: true},
|
||||
count: 9,
|
||||
},
|
||||
{
|
||||
name: "PublicAndPrivateRepositoriesOfUser2IncludingCollaborative",
|
||||
opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 18, Private: true},
|
||||
count: 4,
|
||||
},
|
||||
{
|
||||
name: "PublicAndPrivateRepositoriesOfUser3IncludingCollaborative",
|
||||
opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 20, Private: true},
|
||||
count: 7,
|
||||
},
|
||||
{
|
||||
name: "PublicRepositoriesOfOrganization",
|
||||
opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 17, Collaborate: util.OptionalBoolFalse},
|
||||
count: 1,
|
||||
},
|
||||
{
|
||||
name: "PublicAndPrivateRepositoriesOfOrganization",
|
||||
opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 17, Private: true, Collaborate: util.OptionalBoolFalse},
|
||||
count: 2,
|
||||
},
|
||||
{
|
||||
name: "AllPublic/PublicRepositoriesByName",
|
||||
opts: &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{PageSize: 10}, AllPublic: true, Collaborate: util.OptionalBoolFalse},
|
||||
count: 7,
|
||||
},
|
||||
{
|
||||
name: "AllPublic/PublicAndPrivateRepositoriesByName",
|
||||
opts: &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 1, PageSize: 10}, Private: true, AllPublic: true, Collaborate: util.OptionalBoolFalse},
|
||||
count: 14,
|
||||
},
|
||||
{
|
||||
name: "AllPublic/PublicRepositoriesOfUserIncludingCollaborative",
|
||||
opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, AllPublic: true, Template: util.OptionalBoolFalse},
|
||||
count: 28,
|
||||
},
|
||||
{
|
||||
name: "AllPublic/PublicAndPrivateRepositoriesOfUserIncludingCollaborative",
|
||||
opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, Private: true, AllPublic: true, AllLimited: true, Template: util.OptionalBoolFalse},
|
||||
count: 33,
|
||||
},
|
||||
{
|
||||
name: "AllPublic/PublicAndPrivateRepositoriesOfUserIncludingCollaborativeByName",
|
||||
opts: &repo_model.SearchRepoOptions{Keyword: "test", ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, Private: true, AllPublic: true},
|
||||
count: 15,
|
||||
},
|
||||
{
|
||||
name: "AllPublic/PublicAndPrivateRepositoriesOfUser2IncludingCollaborativeByName",
|
||||
opts: &repo_model.SearchRepoOptions{Keyword: "test", ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 18, Private: true, AllPublic: true},
|
||||
count: 13,
|
||||
},
|
||||
{
|
||||
name: "AllPublic/PublicRepositoriesOfOrganization",
|
||||
opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 17, AllPublic: true, Collaborate: util.OptionalBoolFalse, Template: util.OptionalBoolFalse},
|
||||
count: 28,
|
||||
},
|
||||
{
|
||||
name: "AllTemplates",
|
||||
opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, Template: util.OptionalBoolTrue},
|
||||
count: 2,
|
||||
},
|
||||
{
|
||||
name: "OwnerSlashRepoSearch",
|
||||
opts: &repo_model.SearchRepoOptions{Keyword: "user/repo2", ListOptions: db.ListOptions{Page: 1, PageSize: 10}, Private: true, OwnerID: 0},
|
||||
count: 3,
|
||||
},
|
||||
{
|
||||
name: "OwnerSlashSearch",
|
||||
opts: &repo_model.SearchRepoOptions{Keyword: "user20/", ListOptions: db.ListOptions{Page: 1, PageSize: 10}, Private: true, OwnerID: 0},
|
||||
count: 4,
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
repos, count, err := repo_model.SearchRepositoryByName(testCase.opts)
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, int64(testCase.count), count)
|
||||
|
||||
page := testCase.opts.Page
|
||||
if page <= 0 {
|
||||
page = 1
|
||||
}
|
||||
expectedLen := testCase.opts.PageSize
|
||||
if testCase.opts.PageSize*page > testCase.count+testCase.opts.PageSize {
|
||||
expectedLen = 0
|
||||
} else if testCase.opts.PageSize*page > testCase.count {
|
||||
expectedLen = testCase.count % testCase.opts.PageSize
|
||||
}
|
||||
if assert.Len(t, repos, expectedLen) {
|
||||
for _, repo := range repos {
|
||||
assert.NotEmpty(t, repo.Name)
|
||||
|
||||
if len(testCase.opts.Keyword) > 0 {
|
||||
// Keyword match condition is different for search terms of form "owner/repo"
|
||||
if strings.Count(testCase.opts.Keyword, "/") == 1 {
|
||||
// May still match as a whole...
|
||||
wholeMatch := strings.Contains(repo.Name, testCase.opts.Keyword)
|
||||
|
||||
pieces := strings.Split(testCase.opts.Keyword, "/")
|
||||
ownerName := pieces[0]
|
||||
repoName := pieces[1]
|
||||
// ... or match in parts
|
||||
splitMatch := strings.Contains(repo.OwnerName, ownerName) && strings.Contains(repo.Name, repoName)
|
||||
|
||||
assert.True(t, wholeMatch || splitMatch, "Keyword '%s' does not match repo '%s/%s'", testCase.opts.Keyword, repo.Owner.Name, repo.Name)
|
||||
} else {
|
||||
assert.Contains(t, repo.Name, testCase.opts.Keyword)
|
||||
}
|
||||
}
|
||||
|
||||
if !testCase.opts.Private {
|
||||
assert.False(t, repo.IsPrivate)
|
||||
}
|
||||
|
||||
if testCase.opts.Fork == util.OptionalBoolTrue && testCase.opts.Mirror == util.OptionalBoolTrue {
|
||||
assert.True(t, repo.IsFork || repo.IsMirror)
|
||||
} else {
|
||||
switch testCase.opts.Fork {
|
||||
case util.OptionalBoolFalse:
|
||||
assert.False(t, repo.IsFork)
|
||||
case util.OptionalBoolTrue:
|
||||
assert.True(t, repo.IsFork)
|
||||
}
|
||||
|
||||
switch testCase.opts.Mirror {
|
||||
case util.OptionalBoolFalse:
|
||||
assert.False(t, repo.IsMirror)
|
||||
case util.OptionalBoolTrue:
|
||||
assert.True(t, repo.IsMirror)
|
||||
}
|
||||
}
|
||||
|
||||
if testCase.opts.OwnerID > 0 && !testCase.opts.AllPublic {
|
||||
switch testCase.opts.Collaborate {
|
||||
case util.OptionalBoolFalse:
|
||||
assert.Equal(t, testCase.opts.OwnerID, repo.Owner.ID)
|
||||
case util.OptionalBoolTrue:
|
||||
assert.NotEqual(t, testCase.opts.OwnerID, repo.Owner.ID)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSearchRepositoryByTopicName(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
opts *repo_model.SearchRepoOptions
|
||||
count int
|
||||
}{
|
||||
{
|
||||
name: "AllPublic/SearchPublicRepositoriesFromTopicAndName",
|
||||
opts: &repo_model.SearchRepoOptions{OwnerID: 21, AllPublic: true, Keyword: "graphql"},
|
||||
count: 2,
|
||||
},
|
||||
{
|
||||
name: "AllPublic/OnlySearchPublicRepositoriesFromTopic",
|
||||
opts: &repo_model.SearchRepoOptions{OwnerID: 21, AllPublic: true, Keyword: "graphql", TopicOnly: true},
|
||||
count: 1,
|
||||
},
|
||||
{
|
||||
name: "AllPublic/OnlySearchMultipleKeywordPublicRepositoriesFromTopic",
|
||||
opts: &repo_model.SearchRepoOptions{OwnerID: 21, AllPublic: true, Keyword: "graphql,golang", TopicOnly: true},
|
||||
count: 2,
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
_, count, err := repo_model.SearchRepositoryByName(testCase.opts)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, int64(testCase.count), count)
|
||||
})
|
||||
}
|
||||
}
|
|
@ -2,12 +2,13 @@
|
|||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package repo
|
||||
package repo_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
|
||||
|
@ -15,18 +16,18 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
countRepospts = CountRepositoryOptions{OwnerID: 10}
|
||||
countReposptsPublic = CountRepositoryOptions{OwnerID: 10, Private: util.OptionalBoolFalse}
|
||||
countReposptsPrivate = CountRepositoryOptions{OwnerID: 10, Private: util.OptionalBoolTrue}
|
||||
countRepospts = repo_model.CountRepositoryOptions{OwnerID: 10}
|
||||
countReposptsPublic = repo_model.CountRepositoryOptions{OwnerID: 10, Private: util.OptionalBoolFalse}
|
||||
countReposptsPrivate = repo_model.CountRepositoryOptions{OwnerID: 10, Private: util.OptionalBoolTrue}
|
||||
)
|
||||
|
||||
func TestGetRepositoryCount(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
ctx := db.DefaultContext
|
||||
count, err1 := CountRepositories(ctx, countRepospts)
|
||||
privateCount, err2 := CountRepositories(ctx, countReposptsPrivate)
|
||||
publicCount, err3 := CountRepositories(ctx, countReposptsPublic)
|
||||
count, err1 := repo_model.CountRepositories(ctx, countRepospts)
|
||||
privateCount, err2 := repo_model.CountRepositories(ctx, countReposptsPrivate)
|
||||
publicCount, err3 := repo_model.CountRepositories(ctx, countReposptsPublic)
|
||||
assert.NoError(t, err1)
|
||||
assert.NoError(t, err2)
|
||||
assert.NoError(t, err3)
|
||||
|
@ -37,7 +38,7 @@ func TestGetRepositoryCount(t *testing.T) {
|
|||
func TestGetPublicRepositoryCount(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
count, err := CountRepositories(db.DefaultContext, countReposptsPublic)
|
||||
count, err := repo_model.CountRepositories(db.DefaultContext, countReposptsPublic)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, int64(1), count)
|
||||
}
|
||||
|
@ -45,14 +46,14 @@ func TestGetPublicRepositoryCount(t *testing.T) {
|
|||
func TestGetPrivateRepositoryCount(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
count, err := CountRepositories(db.DefaultContext, countReposptsPrivate)
|
||||
count, err := repo_model.CountRepositories(db.DefaultContext, countReposptsPrivate)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, int64(2), count)
|
||||
}
|
||||
|
||||
func TestRepoAPIURL(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 10}).(*Repository)
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 10}).(*repo_model.Repository)
|
||||
|
||||
assert.Equal(t, "https://try.gitea.io/api/v1/repos/user12/repo10", repo.APIURL())
|
||||
}
|
||||
|
|
|
@ -2,12 +2,13 @@
|
|||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package repo
|
||||
package repo_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
@ -17,26 +18,26 @@ func TestStarRepo(t *testing.T) {
|
|||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
const userID = 2
|
||||
const repoID = 1
|
||||
unittest.AssertNotExistsBean(t, &Star{UID: userID, RepoID: repoID})
|
||||
assert.NoError(t, StarRepo(userID, repoID, true))
|
||||
unittest.AssertExistsAndLoadBean(t, &Star{UID: userID, RepoID: repoID})
|
||||
assert.NoError(t, StarRepo(userID, repoID, true))
|
||||
unittest.AssertExistsAndLoadBean(t, &Star{UID: userID, RepoID: repoID})
|
||||
assert.NoError(t, StarRepo(userID, repoID, false))
|
||||
unittest.AssertNotExistsBean(t, &Star{UID: userID, RepoID: repoID})
|
||||
unittest.AssertNotExistsBean(t, &repo_model.Star{UID: userID, RepoID: repoID})
|
||||
assert.NoError(t, repo_model.StarRepo(userID, repoID, true))
|
||||
unittest.AssertExistsAndLoadBean(t, &repo_model.Star{UID: userID, RepoID: repoID})
|
||||
assert.NoError(t, repo_model.StarRepo(userID, repoID, true))
|
||||
unittest.AssertExistsAndLoadBean(t, &repo_model.Star{UID: userID, RepoID: repoID})
|
||||
assert.NoError(t, repo_model.StarRepo(userID, repoID, false))
|
||||
unittest.AssertNotExistsBean(t, &repo_model.Star{UID: userID, RepoID: repoID})
|
||||
}
|
||||
|
||||
func TestIsStaring(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
assert.True(t, IsStaring(db.DefaultContext, 2, 4))
|
||||
assert.False(t, IsStaring(db.DefaultContext, 3, 4))
|
||||
assert.True(t, repo_model.IsStaring(db.DefaultContext, 2, 4))
|
||||
assert.False(t, repo_model.IsStaring(db.DefaultContext, 3, 4))
|
||||
}
|
||||
|
||||
func TestRepository_GetStargazers(t *testing.T) {
|
||||
// repo with stargazers
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 4}).(*Repository)
|
||||
gazers, err := GetStargazers(repo, db.ListOptions{Page: 0})
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4}).(*repo_model.Repository)
|
||||
gazers, err := repo_model.GetStargazers(repo, db.ListOptions{Page: 0})
|
||||
assert.NoError(t, err)
|
||||
if assert.Len(t, gazers, 1) {
|
||||
assert.Equal(t, int64(2), gazers[0].ID)
|
||||
|
@ -46,8 +47,8 @@ func TestRepository_GetStargazers(t *testing.T) {
|
|||
func TestRepository_GetStargazers2(t *testing.T) {
|
||||
// repo with stargazers
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 3}).(*Repository)
|
||||
gazers, err := GetStargazers(repo, db.ListOptions{Page: 0})
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}).(*repo_model.Repository)
|
||||
gazers, err := repo_model.GetStargazers(repo, db.ListOptions{Page: 0})
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, gazers, 0)
|
||||
}
|
||||
|
|
|
@ -2,12 +2,13 @@
|
|||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package repo
|
||||
package repo_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
@ -19,47 +20,47 @@ func TestAddTopic(t *testing.T) {
|
|||
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
topics, _, err := FindTopics(&FindTopicOptions{})
|
||||
topics, _, err := repo_model.FindTopics(&repo_model.FindTopicOptions{})
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, topics, totalNrOfTopics)
|
||||
|
||||
topics, total, err := FindTopics(&FindTopicOptions{
|
||||
topics, total, err := repo_model.FindTopics(&repo_model.FindTopicOptions{
|
||||
ListOptions: db.ListOptions{Page: 1, PageSize: 2},
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, topics, 2)
|
||||
assert.EqualValues(t, 6, total)
|
||||
|
||||
topics, _, err = FindTopics(&FindTopicOptions{
|
||||
topics, _, err = repo_model.FindTopics(&repo_model.FindTopicOptions{
|
||||
RepoID: 1,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, topics, repo1NrOfTopics)
|
||||
|
||||
assert.NoError(t, SaveTopics(2, "golang"))
|
||||
assert.NoError(t, repo_model.SaveTopics(2, "golang"))
|
||||
repo2NrOfTopics := 1
|
||||
topics, _, err = FindTopics(&FindTopicOptions{})
|
||||
topics, _, err = repo_model.FindTopics(&repo_model.FindTopicOptions{})
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, topics, totalNrOfTopics)
|
||||
|
||||
topics, _, err = FindTopics(&FindTopicOptions{
|
||||
topics, _, err = repo_model.FindTopics(&repo_model.FindTopicOptions{
|
||||
RepoID: 2,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, topics, repo2NrOfTopics)
|
||||
|
||||
assert.NoError(t, SaveTopics(2, "golang", "gitea"))
|
||||
assert.NoError(t, repo_model.SaveTopics(2, "golang", "gitea"))
|
||||
repo2NrOfTopics = 2
|
||||
totalNrOfTopics++
|
||||
topic, err := GetTopicByName("gitea")
|
||||
topic, err := repo_model.GetTopicByName("gitea")
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 1, topic.RepoCount)
|
||||
|
||||
topics, _, err = FindTopics(&FindTopicOptions{})
|
||||
topics, _, err = repo_model.FindTopics(&repo_model.FindTopicOptions{})
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, topics, totalNrOfTopics)
|
||||
|
||||
topics, _, err = FindTopics(&FindTopicOptions{
|
||||
topics, _, err = repo_model.FindTopics(&repo_model.FindTopicOptions{
|
||||
RepoID: 2,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
|
@ -67,14 +68,14 @@ func TestAddTopic(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestTopicValidator(t *testing.T) {
|
||||
assert.True(t, ValidateTopic("12345"))
|
||||
assert.True(t, ValidateTopic("2-test"))
|
||||
assert.True(t, ValidateTopic("test-3"))
|
||||
assert.True(t, ValidateTopic("first"))
|
||||
assert.True(t, ValidateTopic("second-test-topic"))
|
||||
assert.True(t, ValidateTopic("third-project-topic-with-max-length"))
|
||||
assert.True(t, repo_model.ValidateTopic("12345"))
|
||||
assert.True(t, repo_model.ValidateTopic("2-test"))
|
||||
assert.True(t, repo_model.ValidateTopic("test-3"))
|
||||
assert.True(t, repo_model.ValidateTopic("first"))
|
||||
assert.True(t, repo_model.ValidateTopic("second-test-topic"))
|
||||
assert.True(t, repo_model.ValidateTopic("third-project-topic-with-max-length"))
|
||||
|
||||
assert.False(t, ValidateTopic("$fourth-test,topic"))
|
||||
assert.False(t, ValidateTopic("-fifth-test-topic"))
|
||||
assert.False(t, ValidateTopic("sixth-go-project-topic-with-excess-length"))
|
||||
assert.False(t, repo_model.ValidateTopic("$fourth-test,topic"))
|
||||
assert.False(t, repo_model.ValidateTopic("-fifth-test-topic"))
|
||||
assert.False(t, repo_model.ValidateTopic("sixth-go-project-topic-with-excess-length"))
|
||||
}
|
||||
|
|
|
@ -172,3 +172,11 @@ func ChangeRepositoryName(doer *user_model.User, repo *Repository, newRepoName s
|
|||
|
||||
return committer.Commit()
|
||||
}
|
||||
|
||||
// UpdateRepoSize updates the repository size, calculating it using util.GetDirectorySize
|
||||
func UpdateRepoSize(ctx context.Context, repoID, size int64) error {
|
||||
_, err := db.GetEngine(ctx).ID(repoID).Cols("size").NoAutoTime().Update(&Repository{
|
||||
Size: size,
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -5,7 +5,14 @@
|
|||
package repo
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/models/perm"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
|
||||
"xorm.io/builder"
|
||||
)
|
||||
|
||||
// GetStarredRepos returns the repos starred by a particular user
|
||||
|
@ -48,3 +55,118 @@ func GetWatchedRepos(userID int64, private bool, listOptions db.ListOptions) ([]
|
|||
total, err := sess.FindAndCount(&repos)
|
||||
return repos, total, err
|
||||
}
|
||||
|
||||
// GetRepoAssignees returns all users that have write access and can be assigned to issues
|
||||
// of the repository,
|
||||
func GetRepoAssignees(ctx context.Context, repo *Repository) (_ []*user_model.User, err error) {
|
||||
if err = repo.GetOwner(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
e := db.GetEngine(ctx)
|
||||
userIDs := make([]int64, 0, 10)
|
||||
if err = e.Table("access").
|
||||
Where("repo_id = ? AND mode >= ?", repo.ID, perm.AccessModeWrite).
|
||||
Select("user_id").
|
||||
Find(&userIDs); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
additionalUserIDs := make([]int64, 0, 10)
|
||||
if err = e.Table("team_user").
|
||||
Join("INNER", "team_repo", "`team_repo`.team_id = `team_user`.team_id").
|
||||
Join("INNER", "team_unit", "`team_unit`.team_id = `team_user`.team_id").
|
||||
Where("`team_repo`.repo_id = ? AND `team_unit`.access_mode >= ?", repo.ID, perm.AccessModeWrite).
|
||||
Distinct("`team_user`.uid").
|
||||
Select("`team_user`.uid").
|
||||
Find(&additionalUserIDs); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
uidMap := map[int64]bool{}
|
||||
i := 0
|
||||
for _, uid := range userIDs {
|
||||
if uidMap[uid] {
|
||||
continue
|
||||
}
|
||||
uidMap[uid] = true
|
||||
userIDs[i] = uid
|
||||
i++
|
||||
}
|
||||
userIDs = userIDs[:i]
|
||||
userIDs = append(userIDs, additionalUserIDs...)
|
||||
|
||||
for _, uid := range additionalUserIDs {
|
||||
if uidMap[uid] {
|
||||
continue
|
||||
}
|
||||
userIDs[i] = uid
|
||||
i++
|
||||
}
|
||||
userIDs = userIDs[:i]
|
||||
|
||||
// Leave a seat for owner itself to append later, but if owner is an organization
|
||||
// and just waste 1 unit is cheaper than re-allocate memory once.
|
||||
users := make([]*user_model.User, 0, len(userIDs)+1)
|
||||
if len(userIDs) > 0 {
|
||||
if err = e.In("id", userIDs).Find(&users); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if !repo.Owner.IsOrganization() && !uidMap[repo.OwnerID] {
|
||||
users = append(users, repo.Owner)
|
||||
}
|
||||
|
||||
return users, nil
|
||||
}
|
||||
|
||||
// GetReviewers get all users can be requested to review:
|
||||
// * for private repositories this returns all users that have read access or higher to the repository.
|
||||
// * for public repositories this returns all users that have read access or higher to the repository,
|
||||
// all repo watchers and all organization members.
|
||||
// TODO: may be we should have a busy choice for users to block review request to them.
|
||||
func GetReviewers(ctx context.Context, repo *Repository, doerID, posterID int64) ([]*user_model.User, error) {
|
||||
// Get the owner of the repository - this often already pre-cached and if so saves complexity for the following queries
|
||||
if err := repo.GetOwner(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cond := builder.And(builder.Neq{"`user`.id": posterID})
|
||||
|
||||
if repo.IsPrivate || repo.Owner.Visibility == api.VisibleTypePrivate {
|
||||
// This a private repository:
|
||||
// Anyone who can read the repository is a requestable reviewer
|
||||
|
||||
cond = cond.And(builder.In("`user`.id",
|
||||
builder.Select("user_id").From("access").Where(
|
||||
builder.Eq{"repo_id": repo.ID}.
|
||||
And(builder.Gte{"mode": perm.AccessModeRead}),
|
||||
),
|
||||
))
|
||||
|
||||
if repo.Owner.Type == user_model.UserTypeIndividual && repo.Owner.ID != posterID {
|
||||
// as private *user* repos don't generate an entry in the `access` table,
|
||||
// the owner of a private repo needs to be explicitly added.
|
||||
cond = cond.Or(builder.Eq{"`user`.id": repo.Owner.ID})
|
||||
}
|
||||
|
||||
} else {
|
||||
// This is a "public" repository:
|
||||
// Any user that has read access, is a watcher or organization member can be requested to review
|
||||
cond = cond.And(builder.And(builder.In("`user`.id",
|
||||
builder.Select("user_id").From("access").
|
||||
Where(builder.Eq{"repo_id": repo.ID}.
|
||||
And(builder.Gte{"mode": perm.AccessModeRead})),
|
||||
).Or(builder.In("`user`.id",
|
||||
builder.Select("user_id").From("watch").
|
||||
Where(builder.Eq{"repo_id": repo.ID}.
|
||||
And(builder.In("mode", WatchModeNormal, WatchModeAuto))),
|
||||
).Or(builder.In("`user`.id",
|
||||
builder.Select("uid").From("org_user").
|
||||
Where(builder.Eq{"org_id": repo.OwnerID}),
|
||||
)))))
|
||||
}
|
||||
|
||||
users := make([]*user_model.User, 0, 8)
|
||||
return users, db.GetEngine(ctx).Where(cond).OrderBy("name").Find(&users)
|
||||
}
|
||||
|
|
74
models/repo/user_repo_test.go
Normal file
74
models/repo/user_repo_test.go
Normal file
|
@ -0,0 +1,74 @@
|
|||
// Copyright 2017 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package repo_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestRepoAssignees(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}).(*repo_model.Repository)
|
||||
users, err := repo_model.GetRepoAssignees(db.DefaultContext, repo2)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, users, 1)
|
||||
assert.Equal(t, users[0].ID, int64(2))
|
||||
|
||||
repo21 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 21}).(*repo_model.Repository)
|
||||
users, err = repo_model.GetRepoAssignees(db.DefaultContext, repo21)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, users, 3)
|
||||
assert.Equal(t, users[0].ID, int64(15))
|
||||
assert.Equal(t, users[1].ID, int64(18))
|
||||
assert.Equal(t, users[2].ID, int64(16))
|
||||
}
|
||||
|
||||
func TestRepoGetReviewers(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
// test public repo
|
||||
repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository)
|
||||
|
||||
ctx := db.DefaultContext
|
||||
reviewers, err := repo_model.GetReviewers(ctx, repo1, 2, 2)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, reviewers, 4)
|
||||
|
||||
// should include doer if doer is not PR poster.
|
||||
reviewers, err = repo_model.GetReviewers(ctx, repo1, 11, 2)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, reviewers, 4)
|
||||
|
||||
// should not include PR poster, if PR poster would be otherwise eligible
|
||||
reviewers, err = repo_model.GetReviewers(ctx, repo1, 11, 4)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, reviewers, 3)
|
||||
|
||||
// test private user repo
|
||||
repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}).(*repo_model.Repository)
|
||||
|
||||
reviewers, err = repo_model.GetReviewers(ctx, repo2, 2, 4)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, reviewers, 1)
|
||||
assert.EqualValues(t, reviewers[0].ID, 2)
|
||||
|
||||
// test private org repo
|
||||
repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}).(*repo_model.Repository)
|
||||
|
||||
reviewers, err = repo_model.GetReviewers(ctx, repo3, 2, 1)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, reviewers, 2)
|
||||
|
||||
reviewers, err = repo_model.GetReviewers(ctx, repo3, 2, 2)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, reviewers, 1)
|
||||
}
|
|
@ -2,12 +2,13 @@
|
|||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package repo
|
||||
package repo_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
|
||||
|
@ -17,20 +18,20 @@ import (
|
|||
func TestIsWatching(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
assert.True(t, IsWatching(1, 1))
|
||||
assert.True(t, IsWatching(4, 1))
|
||||
assert.True(t, IsWatching(11, 1))
|
||||
assert.True(t, repo_model.IsWatching(1, 1))
|
||||
assert.True(t, repo_model.IsWatching(4, 1))
|
||||
assert.True(t, repo_model.IsWatching(11, 1))
|
||||
|
||||
assert.False(t, IsWatching(1, 5))
|
||||
assert.False(t, IsWatching(8, 1))
|
||||
assert.False(t, IsWatching(unittest.NonexistentID, unittest.NonexistentID))
|
||||
assert.False(t, repo_model.IsWatching(1, 5))
|
||||
assert.False(t, repo_model.IsWatching(8, 1))
|
||||
assert.False(t, repo_model.IsWatching(unittest.NonexistentID, unittest.NonexistentID))
|
||||
}
|
||||
|
||||
func TestGetWatchers(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository)
|
||||
watches, err := GetWatchers(db.DefaultContext, repo.ID)
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository)
|
||||
watches, err := repo_model.GetWatchers(db.DefaultContext, repo.ID)
|
||||
assert.NoError(t, err)
|
||||
// One watchers are inactive, thus minus 1
|
||||
assert.Len(t, watches, repo.NumWatches-1)
|
||||
|
@ -38,7 +39,7 @@ func TestGetWatchers(t *testing.T) {
|
|||
assert.EqualValues(t, repo.ID, watch.RepoID)
|
||||
}
|
||||
|
||||
watches, err = GetWatchers(db.DefaultContext, unittest.NonexistentID)
|
||||
watches, err = repo_model.GetWatchers(db.DefaultContext, unittest.NonexistentID)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, watches, 0)
|
||||
}
|
||||
|
@ -46,16 +47,16 @@ func TestGetWatchers(t *testing.T) {
|
|||
func TestRepository_GetWatchers(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository)
|
||||
watchers, err := GetRepoWatchers(repo.ID, db.ListOptions{Page: 1})
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository)
|
||||
watchers, err := repo_model.GetRepoWatchers(repo.ID, db.ListOptions{Page: 1})
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, watchers, repo.NumWatches)
|
||||
for _, watcher := range watchers {
|
||||
unittest.AssertExistsAndLoadBean(t, &Watch{UserID: watcher.ID, RepoID: repo.ID})
|
||||
unittest.AssertExistsAndLoadBean(t, &repo_model.Watch{UserID: watcher.ID, RepoID: repo.ID})
|
||||
}
|
||||
|
||||
repo = unittest.AssertExistsAndLoadBean(t, &Repository{ID: 9}).(*Repository)
|
||||
watchers, err = GetRepoWatchers(repo.ID, db.ListOptions{Page: 1})
|
||||
repo = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 9}).(*repo_model.Repository)
|
||||
watchers, err = repo_model.GetRepoWatchers(repo.ID, db.ListOptions{Page: 1})
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, watchers, 0)
|
||||
}
|
||||
|
@ -63,8 +64,8 @@ func TestRepository_GetWatchers(t *testing.T) {
|
|||
func TestWatchIfAuto(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository)
|
||||
watchers, err := GetRepoWatchers(repo.ID, db.ListOptions{Page: 1})
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository)
|
||||
watchers, err := repo_model.GetRepoWatchers(repo.ID, db.ListOptions{Page: 1})
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, watchers, repo.NumWatches)
|
||||
|
||||
|
@ -73,46 +74,46 @@ func TestWatchIfAuto(t *testing.T) {
|
|||
prevCount := repo.NumWatches
|
||||
|
||||
// Must not add watch
|
||||
assert.NoError(t, WatchIfAuto(db.DefaultContext, 8, 1, true))
|
||||
watchers, err = GetRepoWatchers(repo.ID, db.ListOptions{Page: 1})
|
||||
assert.NoError(t, repo_model.WatchIfAuto(db.DefaultContext, 8, 1, true))
|
||||
watchers, err = repo_model.GetRepoWatchers(repo.ID, db.ListOptions{Page: 1})
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, watchers, prevCount)
|
||||
|
||||
// Should not add watch
|
||||
assert.NoError(t, WatchIfAuto(db.DefaultContext, 10, 1, true))
|
||||
watchers, err = GetRepoWatchers(repo.ID, db.ListOptions{Page: 1})
|
||||
assert.NoError(t, repo_model.WatchIfAuto(db.DefaultContext, 10, 1, true))
|
||||
watchers, err = repo_model.GetRepoWatchers(repo.ID, db.ListOptions{Page: 1})
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, watchers, prevCount)
|
||||
|
||||
setting.Service.AutoWatchOnChanges = true
|
||||
|
||||
// Must not add watch
|
||||
assert.NoError(t, WatchIfAuto(db.DefaultContext, 8, 1, true))
|
||||
watchers, err = GetRepoWatchers(repo.ID, db.ListOptions{Page: 1})
|
||||
assert.NoError(t, repo_model.WatchIfAuto(db.DefaultContext, 8, 1, true))
|
||||
watchers, err = repo_model.GetRepoWatchers(repo.ID, db.ListOptions{Page: 1})
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, watchers, prevCount)
|
||||
|
||||
// Should not add watch
|
||||
assert.NoError(t, WatchIfAuto(db.DefaultContext, 12, 1, false))
|
||||
watchers, err = GetRepoWatchers(repo.ID, db.ListOptions{Page: 1})
|
||||
assert.NoError(t, repo_model.WatchIfAuto(db.DefaultContext, 12, 1, false))
|
||||
watchers, err = repo_model.GetRepoWatchers(repo.ID, db.ListOptions{Page: 1})
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, watchers, prevCount)
|
||||
|
||||
// Should add watch
|
||||
assert.NoError(t, WatchIfAuto(db.DefaultContext, 12, 1, true))
|
||||
watchers, err = GetRepoWatchers(repo.ID, db.ListOptions{Page: 1})
|
||||
assert.NoError(t, repo_model.WatchIfAuto(db.DefaultContext, 12, 1, true))
|
||||
watchers, err = repo_model.GetRepoWatchers(repo.ID, db.ListOptions{Page: 1})
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, watchers, prevCount+1)
|
||||
|
||||
// Should remove watch, inhibit from adding auto
|
||||
assert.NoError(t, WatchRepo(db.DefaultContext, 12, 1, false))
|
||||
watchers, err = GetRepoWatchers(repo.ID, db.ListOptions{Page: 1})
|
||||
assert.NoError(t, repo_model.WatchRepo(db.DefaultContext, 12, 1, false))
|
||||
watchers, err = repo_model.GetRepoWatchers(repo.ID, db.ListOptions{Page: 1})
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, watchers, prevCount)
|
||||
|
||||
// Must not add watch
|
||||
assert.NoError(t, WatchIfAuto(db.DefaultContext, 12, 1, true))
|
||||
watchers, err = GetRepoWatchers(repo.ID, db.ListOptions{Page: 1})
|
||||
assert.NoError(t, repo_model.WatchIfAuto(db.DefaultContext, 12, 1, true))
|
||||
watchers, err = repo_model.GetRepoWatchers(repo.ID, db.ListOptions{Page: 1})
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, watchers, prevCount)
|
||||
}
|
||||
|
@ -120,20 +121,20 @@ func TestWatchIfAuto(t *testing.T) {
|
|||
func TestWatchRepoMode(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
unittest.AssertCount(t, &Watch{UserID: 12, RepoID: 1}, 0)
|
||||
unittest.AssertCount(t, &repo_model.Watch{UserID: 12, RepoID: 1}, 0)
|
||||
|
||||
assert.NoError(t, WatchRepoMode(12, 1, WatchModeAuto))
|
||||
unittest.AssertCount(t, &Watch{UserID: 12, RepoID: 1}, 1)
|
||||
unittest.AssertCount(t, &Watch{UserID: 12, RepoID: 1, Mode: WatchModeAuto}, 1)
|
||||
assert.NoError(t, repo_model.WatchRepoMode(12, 1, repo_model.WatchModeAuto))
|
||||
unittest.AssertCount(t, &repo_model.Watch{UserID: 12, RepoID: 1}, 1)
|
||||
unittest.AssertCount(t, &repo_model.Watch{UserID: 12, RepoID: 1, Mode: repo_model.WatchModeAuto}, 1)
|
||||
|
||||
assert.NoError(t, WatchRepoMode(12, 1, WatchModeNormal))
|
||||
unittest.AssertCount(t, &Watch{UserID: 12, RepoID: 1}, 1)
|
||||
unittest.AssertCount(t, &Watch{UserID: 12, RepoID: 1, Mode: WatchModeNormal}, 1)
|
||||
assert.NoError(t, repo_model.WatchRepoMode(12, 1, repo_model.WatchModeNormal))
|
||||
unittest.AssertCount(t, &repo_model.Watch{UserID: 12, RepoID: 1}, 1)
|
||||
unittest.AssertCount(t, &repo_model.Watch{UserID: 12, RepoID: 1, Mode: repo_model.WatchModeNormal}, 1)
|
||||
|
||||
assert.NoError(t, WatchRepoMode(12, 1, WatchModeDont))
|
||||
unittest.AssertCount(t, &Watch{UserID: 12, RepoID: 1}, 1)
|
||||
unittest.AssertCount(t, &Watch{UserID: 12, RepoID: 1, Mode: WatchModeDont}, 1)
|
||||
assert.NoError(t, repo_model.WatchRepoMode(12, 1, repo_model.WatchModeDont))
|
||||
unittest.AssertCount(t, &repo_model.Watch{UserID: 12, RepoID: 1}, 1)
|
||||
unittest.AssertCount(t, &repo_model.Watch{UserID: 12, RepoID: 1, Mode: repo_model.WatchModeDont}, 1)
|
||||
|
||||
assert.NoError(t, WatchRepoMode(12, 1, WatchModeNone))
|
||||
unittest.AssertCount(t, &Watch{UserID: 12, RepoID: 1}, 0)
|
||||
assert.NoError(t, repo_model.WatchRepoMode(12, 1, repo_model.WatchModeNone))
|
||||
unittest.AssertCount(t, &repo_model.Watch{UserID: 12, RepoID: 1}, 0)
|
||||
}
|
||||
|
|
|
@ -2,12 +2,13 @@
|
|||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package repo
|
||||
package repo_test
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
|
||||
|
@ -17,7 +18,7 @@ import (
|
|||
func TestRepository_WikiCloneLink(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository)
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository)
|
||||
cloneLink := repo.WikiCloneLink()
|
||||
assert.Equal(t, "ssh://sshuser@try.gitea.io:3000/user2/repo1.wiki.git", cloneLink.SSH)
|
||||
assert.Equal(t, "https://try.gitea.io/user2/repo1.wiki.git", cloneLink.HTTPS)
|
||||
|
@ -26,20 +27,20 @@ func TestRepository_WikiCloneLink(t *testing.T) {
|
|||
func TestWikiPath(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
expected := filepath.Join(setting.RepoRootPath, "user2/repo1.wiki.git")
|
||||
assert.Equal(t, expected, WikiPath("user2", "repo1"))
|
||||
assert.Equal(t, expected, repo_model.WikiPath("user2", "repo1"))
|
||||
}
|
||||
|
||||
func TestRepository_WikiPath(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository)
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository)
|
||||
expected := filepath.Join(setting.RepoRootPath, "user2/repo1.wiki.git")
|
||||
assert.Equal(t, expected, repo.WikiPath())
|
||||
}
|
||||
|
||||
func TestRepository_HasWiki(t *testing.T) {
|
||||
unittest.PrepareTestEnv(t)
|
||||
repo1 := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository)
|
||||
repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository)
|
||||
assert.True(t, repo1.HasWiki())
|
||||
repo2 := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 2}).(*Repository)
|
||||
repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}).(*repo_model.Repository)
|
||||
assert.False(t, repo2.HasWiki())
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue