aboutsummaryrefslogtreecommitdiffstats
path: root/models/repo
diff options
context:
space:
mode:
Diffstat (limited to 'models/repo')
-rw-r--r--models/repo/archiver.go6
-rw-r--r--models/repo/attachment.go2
-rw-r--r--models/repo/avatar.go3
-rw-r--r--models/repo/collaboration_test.go10
-rw-r--r--models/repo/org_repo.go56
-rw-r--r--models/repo/pushmirror_test.go2
-rw-r--r--models/repo/release.go68
-rw-r--r--models/repo/repo.go124
-rw-r--r--models/repo/repo_list.go45
-rw-r--r--models/repo/repo_list_test.go86
-rw-r--r--models/repo/repo_test.go22
-rw-r--r--models/repo/repo_unit.go28
-rw-r--r--models/repo/repo_unit_test.go10
-rw-r--r--models/repo/topic_test.go2
-rw-r--r--models/repo/transfer.go71
-rw-r--r--models/repo/update.go30
-rw-r--r--models/repo/upload.go16
-rw-r--r--models/repo/user_repo.go5
-rw-r--r--models/repo/user_repo_test.go17
-rw-r--r--models/repo/watch_test.go2
-rw-r--r--models/repo/wiki.go4
-rw-r--r--models/repo/wiki_test.go3
22 files changed, 328 insertions, 284 deletions
diff --git a/models/repo/archiver.go b/models/repo/archiver.go
index 5a3eac9f14..d06e94e5ac 100644
--- a/models/repo/archiver.go
+++ b/models/repo/archiver.go
@@ -50,15 +50,15 @@ func (archiver *RepoArchiver) RelativePath() string {
func repoArchiverForRelativePath(relativePath string) (*RepoArchiver, error) {
parts := strings.SplitN(relativePath, "/", 3)
if len(parts) != 3 {
- return nil, util.SilentWrap{Message: fmt.Sprintf("invalid storage path: %s", relativePath), Err: util.ErrInvalidArgument}
+ return nil, util.NewInvalidArgumentErrorf("invalid storage path: must have 3 parts")
}
repoID, err := strconv.ParseInt(parts[0], 10, 64)
if err != nil {
- return nil, util.SilentWrap{Message: fmt.Sprintf("invalid storage path: %s", relativePath), Err: util.ErrInvalidArgument}
+ return nil, util.NewInvalidArgumentErrorf("invalid storage path: invalid repo id")
}
commitID, archiveType := git.SplitArchiveNameType(parts[2])
if archiveType == git.ArchiveUnknown {
- return nil, util.SilentWrap{Message: fmt.Sprintf("invalid storage path: %s", relativePath), Err: util.ErrInvalidArgument}
+ return nil, util.NewInvalidArgumentErrorf("invalid storage path: invalid archive type")
}
return &RepoArchiver{RepoID: repoID, CommitID: commitID, Type: archiveType}, nil
}
diff --git a/models/repo/attachment.go b/models/repo/attachment.go
index fa4f6c47e6..835bee5402 100644
--- a/models/repo/attachment.go
+++ b/models/repo/attachment.go
@@ -224,7 +224,7 @@ func DeleteAttachmentsByComment(ctx context.Context, commentID int64, remove boo
// UpdateAttachmentByUUID Updates attachment via uuid
func UpdateAttachmentByUUID(ctx context.Context, attach *Attachment, cols ...string) error {
if attach.UUID == "" {
- return fmt.Errorf("attachment uuid should be not blank")
+ return errors.New("attachment uuid should be not blank")
}
_, err := db.GetEngine(ctx).Where("uuid=?", attach.UUID).Cols(cols...).Update(attach)
return err
diff --git a/models/repo/avatar.go b/models/repo/avatar.go
index ccfac12cad..eff64bd239 100644
--- a/models/repo/avatar.go
+++ b/models/repo/avatar.go
@@ -9,6 +9,7 @@ import (
"image/png"
"io"
"net/url"
+ "strconv"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/avatar"
@@ -37,7 +38,7 @@ func (repo *Repository) RelAvatarLink(ctx context.Context) string {
// generateRandomAvatar generates a random avatar for repository.
func generateRandomAvatar(ctx context.Context, repo *Repository) error {
- idToString := fmt.Sprintf("%d", repo.ID)
+ idToString := strconv.FormatInt(repo.ID, 10)
seed := idToString
img, err := avatar.RandomImage([]byte(seed))
diff --git a/models/repo/collaboration_test.go b/models/repo/collaboration_test.go
index 639050f5fd..7b07dbffdf 100644
--- a/models/repo/collaboration_test.go
+++ b/models/repo/collaboration_test.go
@@ -25,8 +25,8 @@ func TestRepository_GetCollaborators(t *testing.T) {
assert.NoError(t, err)
assert.Len(t, collaborators, int(expectedLen))
for _, collaborator := range collaborators {
- assert.EqualValues(t, collaborator.User.ID, collaborator.Collaboration.UserID)
- assert.EqualValues(t, repoID, collaborator.Collaboration.RepoID)
+ assert.Equal(t, collaborator.User.ID, collaborator.Collaboration.UserID)
+ assert.Equal(t, repoID, collaborator.Collaboration.RepoID)
}
}
test(1)
@@ -51,7 +51,7 @@ func TestRepository_GetCollaborators(t *testing.T) {
assert.NoError(t, err)
assert.Len(t, collaborators2, 1)
- assert.NotEqualValues(t, collaborators1[0].ID, collaborators2[0].ID)
+ assert.NotEqual(t, collaborators1[0].ID, collaborators2[0].ID)
}
func TestRepository_IsCollaborator(t *testing.T) {
@@ -76,10 +76,10 @@ func TestRepository_ChangeCollaborationAccessMode(t *testing.T) {
assert.NoError(t, repo_model.ChangeCollaborationAccessMode(db.DefaultContext, repo, 4, perm.AccessModeAdmin))
collaboration := unittest.AssertExistsAndLoadBean(t, &repo_model.Collaboration{RepoID: repo.ID, UserID: 4})
- assert.EqualValues(t, perm.AccessModeAdmin, collaboration.Mode)
+ assert.Equal(t, perm.AccessModeAdmin, collaboration.Mode)
access := unittest.AssertExistsAndLoadBean(t, &access_model.Access{UserID: 4, RepoID: repo.ID})
- assert.EqualValues(t, perm.AccessModeAdmin, access.Mode)
+ assert.Equal(t, perm.AccessModeAdmin, access.Mode)
assert.NoError(t, repo_model.ChangeCollaborationAccessMode(db.DefaultContext, repo, 4, perm.AccessModeAdmin))
diff --git a/models/repo/org_repo.go b/models/repo/org_repo.go
index 5f0af2d475..96f21ba2ac 100644
--- a/models/repo/org_repo.go
+++ b/models/repo/org_repo.go
@@ -47,10 +47,9 @@ func GetTeamRepositories(ctx context.Context, opts *SearchTeamRepoOptions) (Repo
// AccessibleReposEnvironment operations involving the repositories that are
// accessible to a particular user
type AccessibleReposEnvironment interface {
- CountRepos() (int64, error)
- RepoIDs(page, pageSize int) ([]int64, error)
- Repos(page, pageSize int) (RepositoryList, error)
- MirrorRepos() (RepositoryList, error)
+ CountRepos(ctx context.Context) (int64, error)
+ RepoIDs(ctx context.Context) ([]int64, error)
+ MirrorRepos(ctx context.Context) (RepositoryList, error)
AddKeyword(keyword string)
SetSort(db.SearchOrderBy)
}
@@ -60,7 +59,6 @@ type accessibleReposEnv struct {
user *user_model.User
team *org_model.Team
teamIDs []int64
- ctx context.Context
keyword string
orderBy db.SearchOrderBy
}
@@ -86,18 +84,16 @@ func AccessibleReposEnv(ctx context.Context, org *org_model.Organization, userID
org: org,
user: user,
teamIDs: teamIDs,
- ctx: ctx,
orderBy: db.SearchOrderByRecentUpdated,
}, nil
}
// AccessibleTeamReposEnv an AccessibleReposEnvironment for the repositories in `org`
// that are accessible to the specified team.
-func AccessibleTeamReposEnv(ctx context.Context, org *org_model.Organization, team *org_model.Team) AccessibleReposEnvironment {
+func AccessibleTeamReposEnv(org *org_model.Organization, team *org_model.Team) AccessibleReposEnvironment {
return &accessibleReposEnv{
org: org,
team: team,
- ctx: ctx,
orderBy: db.SearchOrderByRecentUpdated,
}
}
@@ -123,8 +119,8 @@ func (env *accessibleReposEnv) cond() builder.Cond {
return cond
}
-func (env *accessibleReposEnv) CountRepos() (int64, error) {
- repoCount, err := db.GetEngine(env.ctx).
+func (env *accessibleReposEnv) CountRepos(ctx context.Context) (int64, error) {
+ repoCount, err := db.GetEngine(ctx).
Join("INNER", "team_repo", "`team_repo`.repo_id=`repository`.id").
Where(env.cond()).
Distinct("`repository`.id").
@@ -135,43 +131,21 @@ func (env *accessibleReposEnv) CountRepos() (int64, error) {
return repoCount, nil
}
-func (env *accessibleReposEnv) RepoIDs(page, pageSize int) ([]int64, error) {
- if page <= 0 {
- page = 1
- }
-
- repoIDs := make([]int64, 0, pageSize)
- return repoIDs, db.GetEngine(env.ctx).
+func (env *accessibleReposEnv) RepoIDs(ctx context.Context) ([]int64, error) {
+ var repoIDs []int64
+ return repoIDs, db.GetEngine(ctx).
Table("repository").
Join("INNER", "team_repo", "`team_repo`.repo_id=`repository`.id").
Where(env.cond()).
- GroupBy("`repository`.id,`repository`."+strings.Fields(string(env.orderBy))[0]).
+ GroupBy("`repository`.id,`repository`." + strings.Fields(string(env.orderBy))[0]).
OrderBy(string(env.orderBy)).
- Limit(pageSize, (page-1)*pageSize).
Cols("`repository`.id").
Find(&repoIDs)
}
-func (env *accessibleReposEnv) Repos(page, pageSize int) (RepositoryList, error) {
- repoIDs, err := env.RepoIDs(page, pageSize)
- if err != nil {
- return nil, fmt.Errorf("GetUserRepositoryIDs: %w", err)
- }
-
- repos := make([]*Repository, 0, len(repoIDs))
- if len(repoIDs) == 0 {
- return repos, nil
- }
-
- return repos, db.GetEngine(env.ctx).
- In("`repository`.id", repoIDs).
- OrderBy(string(env.orderBy)).
- Find(&repos)
-}
-
-func (env *accessibleReposEnv) MirrorRepoIDs() ([]int64, error) {
+func (env *accessibleReposEnv) MirrorRepoIDs(ctx context.Context) ([]int64, error) {
repoIDs := make([]int64, 0, 10)
- return repoIDs, db.GetEngine(env.ctx).
+ return repoIDs, db.GetEngine(ctx).
Table("repository").
Join("INNER", "team_repo", "`team_repo`.repo_id=`repository`.id AND `repository`.is_mirror=?", true).
Where(env.cond()).
@@ -181,8 +155,8 @@ func (env *accessibleReposEnv) MirrorRepoIDs() ([]int64, error) {
Find(&repoIDs)
}
-func (env *accessibleReposEnv) MirrorRepos() (RepositoryList, error) {
- repoIDs, err := env.MirrorRepoIDs()
+func (env *accessibleReposEnv) MirrorRepos(ctx context.Context) (RepositoryList, error) {
+ repoIDs, err := env.MirrorRepoIDs(ctx)
if err != nil {
return nil, fmt.Errorf("MirrorRepoIDs: %w", err)
}
@@ -192,7 +166,7 @@ func (env *accessibleReposEnv) MirrorRepos() (RepositoryList, error) {
return repos, nil
}
- return repos, db.GetEngine(env.ctx).
+ return repos, db.GetEngine(ctx).
In("`repository`.id", repoIDs).
Find(&repos)
}
diff --git a/models/repo/pushmirror_test.go b/models/repo/pushmirror_test.go
index e19749d93a..9fb7471147 100644
--- a/models/repo/pushmirror_test.go
+++ b/models/repo/pushmirror_test.go
@@ -39,8 +39,6 @@ func TestPushMirrorsIterate(t *testing.T) {
Interval: 0,
})
- time.Sleep(1 * time.Millisecond)
-
repo_model.PushMirrorsIterate(db.DefaultContext, 1, func(idx int, bean any) error {
m, ok := bean.(*repo_model.PushMirror)
assert.True(t, ok)
diff --git a/models/repo/release.go b/models/repo/release.go
index 1c2e4a48e3..59f4caf5aa 100644
--- a/models/repo/release.go
+++ b/models/repo/release.go
@@ -161,6 +161,11 @@ func UpdateRelease(ctx context.Context, rel *Release) error {
return err
}
+func UpdateReleaseNumCommits(ctx context.Context, rel *Release) error {
+ _, err := db.GetEngine(ctx).ID(rel.ID).Cols("num_commits").Update(rel)
+ return err
+}
+
// AddReleaseAttachments adds a release attachments
func AddReleaseAttachments(ctx context.Context, releaseID int64, attachmentUUIDs []string) (err error) {
// Check attachments
@@ -175,7 +180,7 @@ func AddReleaseAttachments(ctx context.Context, releaseID int64, attachmentUUIDs
}
attachments[i].ReleaseID = releaseID
// No assign value could be 0, so ignore AllCols().
- if _, err = db.GetEngine(ctx).ID(attachments[i].ID).Update(attachments[i]); err != nil {
+ if _, err = db.GetEngine(ctx).ID(attachments[i].ID).Cols("release_id").Update(attachments[i]); err != nil {
return fmt.Errorf("update attachment [%d]: %w", attachments[i].ID, err)
}
}
@@ -418,8 +423,8 @@ func UpdateReleasesMigrationsByType(ctx context.Context, gitServiceType structs.
return err
}
-// PushUpdateDeleteTagsContext updates a number of delete tags with context
-func PushUpdateDeleteTagsContext(ctx context.Context, repo *Repository, tags []string) error {
+// PushUpdateDeleteTags updates a number of delete tags with context
+func PushUpdateDeleteTags(ctx context.Context, repo *Repository, tags []string) error {
if len(tags) == 0 {
return nil
}
@@ -448,58 +453,6 @@ func PushUpdateDeleteTagsContext(ctx context.Context, repo *Repository, tags []s
return nil
}
-// PushUpdateDeleteTag must be called for any push actions to delete tag
-func PushUpdateDeleteTag(ctx context.Context, repo *Repository, tagName string) error {
- rel, err := GetRelease(ctx, repo.ID, tagName)
- if err != nil {
- if IsErrReleaseNotExist(err) {
- return nil
- }
- return fmt.Errorf("GetRelease: %w", err)
- }
- if rel.IsTag {
- if _, err = db.DeleteByID[Release](ctx, rel.ID); err != nil {
- return fmt.Errorf("Delete: %w", err)
- }
- } else {
- rel.IsDraft = true
- rel.NumCommits = 0
- rel.Sha1 = ""
- if _, err = db.GetEngine(ctx).ID(rel.ID).AllCols().Update(rel); err != nil {
- return fmt.Errorf("Update: %w", err)
- }
- }
-
- return nil
-}
-
-// SaveOrUpdateTag must be called for any push actions to add tag
-func SaveOrUpdateTag(ctx context.Context, repo *Repository, newRel *Release) error {
- rel, err := GetRelease(ctx, repo.ID, newRel.TagName)
- if err != nil && !IsErrReleaseNotExist(err) {
- return fmt.Errorf("GetRelease: %w", err)
- }
-
- if rel == nil {
- rel = newRel
- if _, err = db.GetEngine(ctx).Insert(rel); err != nil {
- return fmt.Errorf("InsertOne: %w", err)
- }
- } else {
- rel.Sha1 = newRel.Sha1
- rel.CreatedUnix = newRel.CreatedUnix
- rel.NumCommits = newRel.NumCommits
- rel.IsDraft = false
- if rel.IsTag && newRel.PublisherID > 0 {
- rel.PublisherID = newRel.PublisherID
- }
- if _, err = db.GetEngine(ctx).ID(rel.ID).AllCols().Update(rel); err != nil {
- return fmt.Errorf("Update: %w", err)
- }
- }
- return nil
-}
-
// RemapExternalUser ExternalUserRemappable interface
func (r *Release) RemapExternalUser(externalName string, externalID, userID int64) error {
r.OriginalAuthor = externalName
@@ -558,3 +511,8 @@ func FindTagsByCommitIDs(ctx context.Context, repoID int64, commitIDs ...string)
}
return res, nil
}
+
+func DeleteRepoReleases(ctx context.Context, repoID int64) error {
+ _, err := db.GetEngine(ctx).Where("repo_id = ?", repoID).Delete(new(Release))
+ return err
+}
diff --git a/models/repo/repo.go b/models/repo/repo.go
index fb8a6642f5..34d1bf55f6 100644
--- a/models/repo/repo.go
+++ b/models/repo/repo.go
@@ -5,6 +5,7 @@ package repo
import (
"context"
+ "errors"
"fmt"
"html/template"
"maps"
@@ -14,6 +15,7 @@ import (
"regexp"
"strconv"
"strings"
+ "sync"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/unit"
@@ -58,23 +60,42 @@ type ErrRepoIsArchived struct {
}
func (err ErrRepoIsArchived) Error() string {
- return fmt.Sprintf("%s is archived", err.Repo.LogString())
+ return err.Repo.LogString() + " is archived"
}
-var (
- validRepoNamePattern = regexp.MustCompile(`[-.\w]+`)
- invalidRepoNamePattern = regexp.MustCompile(`[.]{2,}`)
- reservedRepoNames = []string{".", "..", "-"}
- reservedRepoPatterns = []string{"*.git", "*.wiki", "*.rss", "*.atom"}
-)
+type globalVarsStruct struct {
+ validRepoNamePattern *regexp.Regexp
+ invalidRepoNamePattern *regexp.Regexp
+ reservedRepoNames []string
+ reservedRepoNamePatterns []string
+}
+
+var globalVars = sync.OnceValue(func() *globalVarsStruct {
+ return &globalVarsStruct{
+ validRepoNamePattern: regexp.MustCompile(`^[-.\w]+$`),
+ invalidRepoNamePattern: regexp.MustCompile(`[.]{2,}`),
+ reservedRepoNames: []string{".", "..", "-"},
+ reservedRepoNamePatterns: []string{"*.wiki", "*.git", "*.rss", "*.atom"},
+ }
+})
// IsUsableRepoName returns true when name is usable
func IsUsableRepoName(name string) error {
- if !validRepoNamePattern.MatchString(name) || invalidRepoNamePattern.MatchString(name) {
+ vars := globalVars()
+ if !vars.validRepoNamePattern.MatchString(name) || vars.invalidRepoNamePattern.MatchString(name) {
// Note: usually this error is normally caught up earlier in the UI
return db.ErrNameCharsNotAllowed{Name: name}
}
- return db.IsUsableName(reservedRepoNames, reservedRepoPatterns, name)
+ return db.IsUsableName(vars.reservedRepoNames, vars.reservedRepoNamePatterns, name)
+}
+
+// IsValidSSHAccessRepoName is like IsUsableRepoName, but it allows "*.wiki" because wiki repo needs to be accessed in SSH code
+func IsValidSSHAccessRepoName(name string) bool {
+ vars := globalVars()
+ if !vars.validRepoNamePattern.MatchString(name) || vars.invalidRepoNamePattern.MatchString(name) {
+ return false
+ }
+ return db.IsUsableName(vars.reservedRepoNames, vars.reservedRepoNamePatterns[1:], name) == nil
}
// TrustModelType defines the types of trust model for this repository
@@ -204,12 +225,24 @@ func init() {
db.RegisterModel(new(Repository))
}
-func (repo *Repository) GetName() string {
- return repo.Name
+func RelativePath(ownerName, repoName string) string {
+ return strings.ToLower(ownerName) + "/" + strings.ToLower(repoName) + ".git"
}
-func (repo *Repository) GetOwnerName() string {
- return repo.OwnerName
+// RelativePath should be an unix style path like username/reponame.git
+func (repo *Repository) RelativePath() string {
+ return RelativePath(repo.OwnerName, repo.Name)
+}
+
+type StorageRepo string
+
+// RelativePath should be an unix style path like username/reponame.git
+func (sr StorageRepo) RelativePath() string {
+ return string(sr)
+}
+
+func (repo *Repository) WikiStorageRepo() StorageRepo {
+ return StorageRepo(strings.ToLower(repo.OwnerName) + "/" + strings.ToLower(repo.Name) + ".wiki.git")
}
// SanitizedOriginalURL returns a sanitized OriginalURL
@@ -402,32 +435,33 @@ func (repo *Repository) MustGetUnit(ctx context.Context, tp unit.Type) *RepoUnit
return ru
}
- if tp == unit.TypeExternalWiki {
+ switch tp {
+ case unit.TypeExternalWiki:
return &RepoUnit{
Type: tp,
Config: new(ExternalWikiConfig),
}
- } else if tp == unit.TypeExternalTracker {
+ case unit.TypeExternalTracker:
return &RepoUnit{
Type: tp,
Config: new(ExternalTrackerConfig),
}
- } else if tp == unit.TypePullRequests {
+ case unit.TypePullRequests:
return &RepoUnit{
Type: tp,
Config: new(PullRequestsConfig),
}
- } else if tp == unit.TypeIssues {
+ case unit.TypeIssues:
return &RepoUnit{
Type: tp,
Config: new(IssuesConfig),
}
- } else if tp == unit.TypeActions {
+ case unit.TypeActions:
return &RepoUnit{
Type: tp,
Config: new(ActionsConfig),
}
- } else if tp == unit.TypeProjects {
+ case unit.TypeProjects:
cfg := new(ProjectsConfig)
cfg.ProjectsMode = ProjectsModeNone
return &RepoUnit{
@@ -487,15 +521,15 @@ func (repo *Repository) composeCommonMetas(ctx context.Context) map[string]strin
"repo": repo.Name,
}
- unit, err := repo.GetUnit(ctx, unit.TypeExternalTracker)
+ unitExternalTracker, err := repo.GetUnit(ctx, unit.TypeExternalTracker)
if err == nil {
- metas["format"] = unit.ExternalTrackerConfig().ExternalTrackerFormat
- switch unit.ExternalTrackerConfig().ExternalTrackerStyle {
+ metas["format"] = unitExternalTracker.ExternalTrackerConfig().ExternalTrackerFormat
+ switch unitExternalTracker.ExternalTrackerConfig().ExternalTrackerStyle {
case markup.IssueNameStyleAlphanumeric:
metas["style"] = markup.IssueNameStyleAlphanumeric
case markup.IssueNameStyleRegexp:
metas["style"] = markup.IssueNameStyleRegexp
- metas["regexp"] = unit.ExternalTrackerConfig().ExternalTrackerRegexpPattern
+ metas["regexp"] = unitExternalTracker.ExternalTrackerConfig().ExternalTrackerRegexpPattern
default:
metas["style"] = markup.IssueNameStyleNumeric
}
@@ -519,11 +553,11 @@ func (repo *Repository) composeCommonMetas(ctx context.Context) map[string]strin
return repo.commonRenderingMetas
}
-// ComposeMetas composes a map of metas for properly rendering comments or comment-like contents (commit message)
-func (repo *Repository) ComposeMetas(ctx context.Context) map[string]string {
+// ComposeCommentMetas composes a map of metas for properly rendering comments or comment-like contents (commit message)
+func (repo *Repository) ComposeCommentMetas(ctx context.Context) map[string]string {
metas := maps.Clone(repo.composeCommonMetas(ctx))
- metas["markdownLineBreakStyle"] = "comment"
- metas["markupAllowShortIssuePattern"] = "true"
+ metas["markdownNewLineHardBreak"] = strconv.FormatBool(setting.Markdown.RenderOptionsComment.NewLineHardBreak)
+ metas["markupAllowShortIssuePattern"] = strconv.FormatBool(setting.Markdown.RenderOptionsComment.ShortIssuePattern)
return metas
}
@@ -531,16 +565,17 @@ func (repo *Repository) ComposeMetas(ctx context.Context) map[string]string {
func (repo *Repository) ComposeWikiMetas(ctx context.Context) map[string]string {
// does wiki need the "teams" and "org" from common metas?
metas := maps.Clone(repo.composeCommonMetas(ctx))
- metas["markdownLineBreakStyle"] = "document"
- metas["markupAllowShortIssuePattern"] = "true"
+ metas["markdownNewLineHardBreak"] = strconv.FormatBool(setting.Markdown.RenderOptionsWiki.NewLineHardBreak)
+ metas["markupAllowShortIssuePattern"] = strconv.FormatBool(setting.Markdown.RenderOptionsWiki.ShortIssuePattern)
return metas
}
-// ComposeDocumentMetas composes a map of metas for properly rendering documents (repo files)
-func (repo *Repository) ComposeDocumentMetas(ctx context.Context) map[string]string {
+// ComposeRepoFileMetas composes a map of metas for properly rendering documents (repo files)
+func (repo *Repository) ComposeRepoFileMetas(ctx context.Context) map[string]string {
// does document(file) need the "teams" and "org" from common metas?
metas := maps.Clone(repo.composeCommonMetas(ctx))
- metas["markdownLineBreakStyle"] = "document"
+ metas["markdownNewLineHardBreak"] = strconv.FormatBool(setting.Markdown.RenderOptionsRepoFile.NewLineHardBreak)
+ metas["markupAllowShortIssuePattern"] = strconv.FormatBool(setting.Markdown.RenderOptionsRepoFile.ShortIssuePattern)
return metas
}
@@ -618,7 +653,7 @@ func (repo *Repository) AllowsPulls(ctx context.Context) bool {
// CanEnableEditor returns true if repository meets the requirements of web editor.
func (repo *Repository) CanEnableEditor() bool {
- return !repo.IsMirror
+ return !repo.IsMirror && !repo.IsArchived
}
// DescriptionHTML does special handles to description and return HTML string.
@@ -635,13 +670,15 @@ func (repo *Repository) DescriptionHTML(ctx context.Context) template.HTML {
type CloneLink struct {
SSH string
HTTPS string
+ Tea string
}
-// ComposeHTTPSCloneURL returns HTTPS clone URL based on given owner and repository name.
+// ComposeHTTPSCloneURL returns HTTPS clone URL based on the given owner and repository name.
func ComposeHTTPSCloneURL(ctx context.Context, owner, repo string) string {
return fmt.Sprintf("%s%s/%s.git", httplib.GuessCurrentAppURL(ctx), url.PathEscape(owner), url.PathEscape(repo))
}
+// ComposeSSHCloneURL returns SSH clone URL based on the given owner and repository name.
func ComposeSSHCloneURL(doer *user_model.User, ownerName, repoName string) string {
sshUser := setting.SSH.User
sshDomain := setting.SSH.Domain
@@ -675,11 +712,17 @@ func ComposeSSHCloneURL(doer *user_model.User, ownerName, repoName string) strin
return fmt.Sprintf("%s@%s:%s/%s.git", sshUser, sshHost, url.PathEscape(ownerName), url.PathEscape(repoName))
}
+// ComposeTeaCloneCommand returns Tea CLI clone command based on the given owner and repository name.
+func ComposeTeaCloneCommand(ctx context.Context, owner, repo string) string {
+ return fmt.Sprintf("tea clone %s/%s", url.PathEscape(owner), url.PathEscape(repo))
+}
+
func (repo *Repository) cloneLink(ctx context.Context, doer *user_model.User, repoPathName string) *CloneLink {
- cl := new(CloneLink)
- cl.SSH = ComposeSSHCloneURL(doer, repo.OwnerName, repoPathName)
- cl.HTTPS = ComposeHTTPSCloneURL(ctx, repo.OwnerName, repoPathName)
- return cl
+ return &CloneLink{
+ SSH: ComposeSSHCloneURL(doer, repo.OwnerName, repoPathName),
+ HTTPS: ComposeHTTPSCloneURL(ctx, repo.OwnerName, repoPathName),
+ Tea: ComposeTeaCloneCommand(ctx, repo.OwnerName, repoPathName),
+ }
}
// CloneLink returns clone URLs of repository.
@@ -788,7 +831,7 @@ func GetRepositoryByName(ctx context.Context, ownerID int64, name string) (*Repo
func GetRepositoryByURL(ctx context.Context, repoURL string) (*Repository, error) {
ret, err := giturl.ParseRepositoryURL(ctx, repoURL)
if err != nil || ret.OwnerName == "" {
- return nil, fmt.Errorf("unknown or malformed repository URL")
+ return nil, errors.New("unknown or malformed repository URL")
}
return GetRepositoryByOwnerAndName(ctx, ret.OwnerName, ret.RepoName)
}
@@ -820,6 +863,9 @@ func GetRepositoryByID(ctx context.Context, id int64) (*Repository, error) {
// GetRepositoriesMapByIDs returns the repositories by given id slice.
func GetRepositoriesMapByIDs(ctx context.Context, ids []int64) (map[int64]*Repository, error) {
repos := make(map[int64]*Repository, len(ids))
+ if len(ids) == 0 {
+ return repos, nil
+ }
return repos, db.GetEngine(ctx).In("id", ids).Find(&repos)
}
diff --git a/models/repo/repo_list.go b/models/repo/repo_list.go
index 9bed2e9197..f2cdd2f284 100644
--- a/models/repo/repo_list.go
+++ b/models/repo/repo_list.go
@@ -21,11 +21,6 @@ import (
"xorm.io/builder"
)
-// FindReposMapByIDs find repos as map
-func FindReposMapByIDs(ctx context.Context, repoIDs []int64, res map[int64]*Repository) error {
- return db.GetEngine(ctx).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.
@@ -364,7 +359,7 @@ func UserOrgPublicUnitRepoCond(userID, orgID int64) builder.Cond {
}
// SearchRepositoryCondition creates a query condition according search repository options
-func SearchRepositoryCondition(opts *SearchRepoOptions) builder.Cond {
+func SearchRepositoryCondition(opts SearchRepoOptions) builder.Cond {
cond := builder.NewCond()
if opts.Private {
@@ -454,7 +449,7 @@ func SearchRepositoryCondition(opts *SearchRepoOptions) builder.Cond {
if opts.Keyword != "" {
// separate keyword
subQueryCond := builder.NewCond()
- for _, v := range strings.Split(opts.Keyword, ",") {
+ for v := range strings.SplitSeq(opts.Keyword, ",") {
if opts.TopicOnly {
subQueryCond = subQueryCond.Or(builder.Eq{"topic.name": strings.ToLower(v)})
} else {
@@ -469,7 +464,7 @@ func SearchRepositoryCondition(opts *SearchRepoOptions) builder.Cond {
keywordCond := builder.In("id", subQuery)
if !opts.TopicOnly {
likes := builder.NewCond()
- for _, v := range strings.Split(opts.Keyword, ",") {
+ for v := range strings.SplitSeq(opts.Keyword, ",") {
likes = likes.Or(builder.Like{"lower_name", strings.ToLower(v)})
// If the string looks like "org/repo", match against that pattern too
@@ -556,18 +551,18 @@ func SearchRepositoryCondition(opts *SearchRepoOptions) builder.Cond {
// SearchRepository returns repositories based on search options,
// it returns results in given range and number of total results.
-func SearchRepository(ctx context.Context, opts *SearchRepoOptions) (RepositoryList, int64, error) {
+func SearchRepository(ctx context.Context, opts SearchRepoOptions) (RepositoryList, int64, error) {
cond := SearchRepositoryCondition(opts)
return SearchRepositoryByCondition(ctx, opts, cond, true)
}
// CountRepository counts repositories based on search options,
-func CountRepository(ctx context.Context, opts *SearchRepoOptions) (int64, error) {
+func CountRepository(ctx context.Context, opts SearchRepoOptions) (int64, error) {
return db.GetEngine(ctx).Where(SearchRepositoryCondition(opts)).Count(new(Repository))
}
// SearchRepositoryByCondition search repositories by condition
-func SearchRepositoryByCondition(ctx context.Context, opts *SearchRepoOptions, cond builder.Cond, loadAttributes bool) (RepositoryList, int64, error) {
+func SearchRepositoryByCondition(ctx context.Context, opts SearchRepoOptions, cond builder.Cond, loadAttributes bool) (RepositoryList, int64, error) {
sess, count, err := searchRepositoryByCondition(ctx, opts, cond)
if err != nil {
return nil, 0, err
@@ -595,23 +590,25 @@ func SearchRepositoryByCondition(ctx context.Context, opts *SearchRepoOptions, c
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
+func searchRepositoryByCondition(ctx context.Context, opts SearchRepoOptions, cond builder.Cond) (db.Engine, int64, error) {
+ page := opts.Page
+ if page <= 0 {
+ page = 1
}
- if len(opts.OrderBy) == 0 {
- opts.OrderBy = db.SearchOrderByAlphabetically
+ orderBy := opts.OrderBy
+ if len(orderBy) == 0 {
+ orderBy = db.SearchOrderByAlphabetically
}
args := make([]any, 0)
if opts.PriorityOwnerID > 0 {
- opts.OrderBy = db.SearchOrderBy(fmt.Sprintf("CASE WHEN owner_id = ? THEN 0 ELSE owner_id END, %s", opts.OrderBy))
+ orderBy = db.SearchOrderBy(fmt.Sprintf("CASE WHEN owner_id = ? THEN 0 ELSE owner_id END, %s", 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))
+ orderBy = db.SearchOrderBy(fmt.Sprintf("CASE WHEN owner_name LIKE ? THEN 0 ELSE 1 END, %s", orderBy))
args = append(args, orgName)
}
@@ -628,9 +625,9 @@ func searchRepositoryByCondition(ctx context.Context, opts *SearchRepoOptions, c
}
}
- sess = sess.Where(cond).OrderBy(opts.OrderBy.String(), args...)
+ sess = sess.Where(cond).OrderBy(orderBy.String(), args...)
if opts.PageSize > 0 {
- sess = sess.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize)
+ sess = sess.Limit(opts.PageSize, (page-1)*opts.PageSize)
}
return sess, count, nil
}
@@ -694,14 +691,14 @@ func AccessibleRepositoryCondition(user *user_model.User, unitType unit.Type) bu
// SearchRepositoryByName takes keyword and part of repository name to search,
// it returns results in given range and number of total results.
-func SearchRepositoryByName(ctx context.Context, opts *SearchRepoOptions) (RepositoryList, int64, error) {
+func SearchRepositoryByName(ctx context.Context, opts SearchRepoOptions) (RepositoryList, int64, error) {
opts.IncludeDescription = false
return SearchRepository(ctx, opts)
}
// SearchRepositoryIDs takes keyword and part of repository name to search,
// it returns results in given range and number of total results.
-func SearchRepositoryIDs(ctx context.Context, opts *SearchRepoOptions) ([]int64, int64, error) {
+func SearchRepositoryIDs(ctx context.Context, opts SearchRepoOptions) ([]int64, int64, error) {
opts.IncludeDescription = false
cond := SearchRepositoryCondition(opts)
@@ -745,7 +742,7 @@ func FindUserCodeAccessibleOwnerRepoIDs(ctx context.Context, ownerID int64, user
}
// GetUserRepositories returns a list of repositories of given user.
-func GetUserRepositories(ctx context.Context, opts *SearchRepoOptions) (RepositoryList, int64, error) {
+func GetUserRepositories(ctx context.Context, opts SearchRepoOptions) (RepositoryList, int64, error) {
if len(opts.OrderBy) == 0 {
opts.OrderBy = "updated_unix DESC"
}
@@ -772,5 +769,5 @@ func GetUserRepositories(ctx context.Context, opts *SearchRepoOptions) (Reposito
sess = sess.Where(cond).OrderBy(opts.OrderBy.String())
repos := make(RepositoryList, 0, opts.PageSize)
- return repos, count, db.SetSessionPagination(sess, opts).Find(&repos)
+ return repos, count, db.SetSessionPagination(sess, &opts).Find(&repos)
}
diff --git a/models/repo/repo_list_test.go b/models/repo/repo_list_test.go
index ca6007f6c7..7eb76416c2 100644
--- a/models/repo/repo_list_test.go
+++ b/models/repo/repo_list_test.go
@@ -17,162 +17,162 @@ import (
func getTestCases() []struct {
name string
- opts *repo_model.SearchRepoOptions
+ opts repo_model.SearchRepoOptions
count int
} {
testCases := []struct {
name string
- opts *repo_model.SearchRepoOptions
+ opts repo_model.SearchRepoOptions
count int
}{
{
name: "PublicRepositoriesByName",
- opts: &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{PageSize: 10}, Collaborate: optional.Some(false)},
+ opts: repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{PageSize: 10}, Collaborate: optional.Some(false)},
count: 7,
},
{
name: "PublicAndPrivateRepositoriesByName",
- opts: &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 1, PageSize: 10}, Private: true, Collaborate: optional.Some(false)},
+ opts: repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 1, PageSize: 10}, Private: true, Collaborate: optional.Some(false)},
count: 14,
},
{
name: "PublicAndPrivateRepositoriesByNameWithPagesizeLimitFirstPage",
- opts: &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 1, PageSize: 5}, Private: true, Collaborate: optional.Some(false)},
+ opts: repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 1, PageSize: 5}, Private: true, Collaborate: optional.Some(false)},
count: 14,
},
{
name: "PublicAndPrivateRepositoriesByNameWithPagesizeLimitSecondPage",
- opts: &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 2, PageSize: 5}, Private: true, Collaborate: optional.Some(false)},
+ opts: repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 2, PageSize: 5}, Private: true, Collaborate: optional.Some(false)},
count: 14,
},
{
name: "PublicAndPrivateRepositoriesByNameWithPagesizeLimitThirdPage",
- opts: &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 3, PageSize: 5}, Private: true, Collaborate: optional.Some(false)},
+ opts: repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 3, PageSize: 5}, Private: true, Collaborate: optional.Some(false)},
count: 14,
},
{
name: "PublicAndPrivateRepositoriesByNameWithPagesizeLimitFourthPage",
- opts: &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 3, PageSize: 5}, Private: true, Collaborate: optional.Some(false)},
+ opts: repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 3, PageSize: 5}, Private: true, Collaborate: optional.Some(false)},
count: 14,
},
{
name: "PublicRepositoriesOfUser",
- opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, Collaborate: optional.Some(false)},
+ opts: repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, Collaborate: optional.Some(false)},
count: 2,
},
{
name: "PublicRepositoriesOfUser2",
- opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 18, Collaborate: optional.Some(false)},
+ opts: repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 18, Collaborate: optional.Some(false)},
count: 0,
},
{
name: "PublicRepositoriesOfOrg3",
- opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 20, Collaborate: optional.Some(false)},
+ opts: repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 20, Collaborate: optional.Some(false)},
count: 2,
},
{
name: "PublicAndPrivateRepositoriesOfUser",
- opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, Private: true, Collaborate: optional.Some(false)},
+ opts: repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, Private: true, Collaborate: optional.Some(false)},
count: 4,
},
{
name: "PublicAndPrivateRepositoriesOfUser2",
- opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 18, Private: true, Collaborate: optional.Some(false)},
+ opts: repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 18, Private: true, Collaborate: optional.Some(false)},
count: 0,
},
{
name: "PublicAndPrivateRepositoriesOfOrg3",
- opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 20, Private: true, Collaborate: optional.Some(false)},
+ opts: repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 20, Private: true, Collaborate: optional.Some(false)},
count: 4,
},
{
name: "PublicRepositoriesOfUserIncludingCollaborative",
- opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15},
+ 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},
+ opts: repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 18},
count: 1,
},
{
name: "PublicRepositoriesOfOrg3IncludingCollaborative",
- opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 20},
+ 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},
+ 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},
+ opts: repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 18, Private: true},
count: 4,
},
{
name: "PublicAndPrivateRepositoriesOfOrg3IncludingCollaborative",
- opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 20, Private: true},
+ 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: optional.Some(false)},
+ opts: repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 17, Collaborate: optional.Some(false)},
count: 1,
},
{
name: "PublicAndPrivateRepositoriesOfOrganization",
- opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 17, Private: true, Collaborate: optional.Some(false)},
+ opts: repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 17, Private: true, Collaborate: optional.Some(false)},
count: 2,
},
{
name: "AllPublic/PublicRepositoriesByName",
- opts: &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{PageSize: 10}, AllPublic: true, Collaborate: optional.Some(false)},
+ opts: repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{PageSize: 10}, AllPublic: true, Collaborate: optional.Some(false)},
count: 7,
},
{
name: "AllPublic/PublicAndPrivateRepositoriesByName",
- opts: &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 1, PageSize: 10}, Private: true, AllPublic: true, Collaborate: optional.Some(false)},
+ opts: repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 1, PageSize: 10}, Private: true, AllPublic: true, Collaborate: optional.Some(false)},
count: 14,
},
{
name: "AllPublic/PublicRepositoriesOfUserIncludingCollaborative",
- opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, AllPublic: true, Template: optional.Some(false)},
+ opts: repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, AllPublic: true, Template: optional.Some(false)},
count: 34,
},
{
name: "AllPublic/PublicAndPrivateRepositoriesOfUserIncludingCollaborative",
- opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, Private: true, AllPublic: true, AllLimited: true, Template: optional.Some(false)},
+ opts: repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, Private: true, AllPublic: true, AllLimited: true, Template: optional.Some(false)},
count: 39,
},
{
name: "AllPublic/PublicAndPrivateRepositoriesOfUserIncludingCollaborativeByName",
- opts: &repo_model.SearchRepoOptions{Keyword: "test", ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, Private: true, AllPublic: true},
+ 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},
+ 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: optional.Some(false), Template: optional.Some(false)},
+ opts: repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 17, AllPublic: true, Collaborate: optional.Some(false), Template: optional.Some(false)},
count: 34,
},
{
name: "AllTemplates",
- opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, Template: optional.Some(true)},
+ opts: repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, Template: optional.Some(true)},
count: 2,
},
{
name: "OwnerSlashRepoSearch",
- opts: &repo_model.SearchRepoOptions{Keyword: "user/repo2", ListOptions: db.ListOptions{Page: 1, PageSize: 10}, Private: true, OwnerID: 0},
+ opts: repo_model.SearchRepoOptions{Keyword: "user/repo2", ListOptions: db.ListOptions{Page: 1, PageSize: 10}, Private: true, OwnerID: 0},
count: 2,
},
{
name: "OwnerSlashSearch",
- opts: &repo_model.SearchRepoOptions{Keyword: "user20/", ListOptions: db.ListOptions{Page: 1, PageSize: 10}, Private: true, OwnerID: 0},
+ opts: repo_model.SearchRepoOptions{Keyword: "user20/", ListOptions: db.ListOptions{Page: 1, PageSize: 10}, Private: true, OwnerID: 0},
count: 4,
},
}
@@ -184,7 +184,7 @@ func TestSearchRepository(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
// test search public repository on explore page
- repos, count, err := repo_model.SearchRepositoryByName(db.DefaultContext, &repo_model.SearchRepoOptions{
+ repos, count, err := repo_model.SearchRepositoryByName(db.DefaultContext, repo_model.SearchRepoOptions{
ListOptions: db.ListOptions{
Page: 1,
PageSize: 10,
@@ -199,7 +199,7 @@ func TestSearchRepository(t *testing.T) {
}
assert.Equal(t, int64(1), count)
- repos, count, err = repo_model.SearchRepositoryByName(db.DefaultContext, &repo_model.SearchRepoOptions{
+ repos, count, err = repo_model.SearchRepositoryByName(db.DefaultContext, repo_model.SearchRepoOptions{
ListOptions: db.ListOptions{
Page: 1,
PageSize: 10,
@@ -213,7 +213,7 @@ func TestSearchRepository(t *testing.T) {
assert.Len(t, repos, 2)
// test search private repository on explore page
- repos, count, err = repo_model.SearchRepositoryByName(db.DefaultContext, &repo_model.SearchRepoOptions{
+ repos, count, err = repo_model.SearchRepositoryByName(db.DefaultContext, repo_model.SearchRepoOptions{
ListOptions: db.ListOptions{
Page: 1,
PageSize: 10,
@@ -229,7 +229,7 @@ func TestSearchRepository(t *testing.T) {
}
assert.Equal(t, int64(1), count)
- repos, count, err = repo_model.SearchRepositoryByName(db.DefaultContext, &repo_model.SearchRepoOptions{
+ repos, count, err = repo_model.SearchRepositoryByName(db.DefaultContext, repo_model.SearchRepoOptions{
ListOptions: db.ListOptions{
Page: 1,
PageSize: 10,
@@ -244,14 +244,14 @@ func TestSearchRepository(t *testing.T) {
assert.Len(t, repos, 3)
// Test non existing owner
- repos, count, err = repo_model.SearchRepositoryByName(db.DefaultContext, &repo_model.SearchRepoOptions{OwnerID: unittest.NonexistentID})
+ repos, count, err = repo_model.SearchRepositoryByName(db.DefaultContext, 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(db.DefaultContext, &repo_model.SearchRepoOptions{
+ repos, count, err = repo_model.SearchRepository(db.DefaultContext, repo_model.SearchRepoOptions{
ListOptions: db.ListOptions{
Page: 1,
PageSize: 10,
@@ -268,7 +268,7 @@ func TestSearchRepository(t *testing.T) {
assert.Equal(t, int64(1), count)
// Test NOT search within description
- repos, count, err = repo_model.SearchRepository(db.DefaultContext, &repo_model.SearchRepoOptions{
+ repos, count, err = repo_model.SearchRepository(db.DefaultContext, repo_model.SearchRepoOptions{
ListOptions: db.ListOptions{
Page: 1,
PageSize: 10,
@@ -374,22 +374,22 @@ func TestSearchRepositoryByTopicName(t *testing.T) {
testCases := []struct {
name string
- opts *repo_model.SearchRepoOptions
+ opts repo_model.SearchRepoOptions
count int
}{
{
name: "AllPublic/SearchPublicRepositoriesFromTopicAndName",
- opts: &repo_model.SearchRepoOptions{OwnerID: 21, AllPublic: true, Keyword: "graphql"},
+ 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},
+ 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},
+ opts: repo_model.SearchRepoOptions{OwnerID: 21, AllPublic: true, Keyword: "graphql,golang", TopicOnly: true},
count: 2,
},
}
diff --git a/models/repo/repo_test.go b/models/repo/repo_test.go
index a9e2cdfb75..66abe864fc 100644
--- a/models/repo/repo_test.go
+++ b/models/repo/repo_test.go
@@ -86,7 +86,7 @@ func TestMetas(t *testing.T) {
repo.Units = nil
- metas := repo.ComposeMetas(db.DefaultContext)
+ metas := repo.ComposeCommentMetas(db.DefaultContext)
assert.Equal(t, "testRepo", metas["repo"])
assert.Equal(t, "testOwner", metas["user"])
@@ -100,7 +100,7 @@ func TestMetas(t *testing.T) {
testSuccess := func(expectedStyle string) {
repo.Units = []*RepoUnit{&externalTracker}
repo.commonRenderingMetas = nil
- metas := repo.ComposeMetas(db.DefaultContext)
+ metas := repo.ComposeCommentMetas(db.DefaultContext)
assert.Equal(t, expectedStyle, metas["style"])
assert.Equal(t, "testRepo", metas["repo"])
assert.Equal(t, "testOwner", metas["user"])
@@ -121,7 +121,7 @@ func TestMetas(t *testing.T) {
repo, err := GetRepositoryByID(db.DefaultContext, 3)
assert.NoError(t, err)
- metas = repo.ComposeMetas(db.DefaultContext)
+ metas = repo.ComposeCommentMetas(db.DefaultContext)
assert.Contains(t, metas, "org")
assert.Contains(t, metas, "teams")
assert.Equal(t, "org3", metas["org"])
@@ -216,7 +216,23 @@ func TestIsUsableRepoName(t *testing.T) {
assert.Error(t, IsUsableRepoName("-"))
assert.Error(t, IsUsableRepoName("🌞"))
+ assert.Error(t, IsUsableRepoName("the/repo"))
assert.Error(t, IsUsableRepoName("the..repo"))
assert.Error(t, IsUsableRepoName("foo.wiki"))
assert.Error(t, IsUsableRepoName("foo.git"))
+ assert.Error(t, IsUsableRepoName("foo.RSS"))
+}
+
+func TestIsValidSSHAccessRepoName(t *testing.T) {
+ assert.True(t, IsValidSSHAccessRepoName("a"))
+ assert.True(t, IsValidSSHAccessRepoName("-1_."))
+ assert.True(t, IsValidSSHAccessRepoName(".profile"))
+ assert.True(t, IsValidSSHAccessRepoName("foo.wiki"))
+
+ assert.False(t, IsValidSSHAccessRepoName("-"))
+ assert.False(t, IsValidSSHAccessRepoName("🌞"))
+ assert.False(t, IsValidSSHAccessRepoName("the/repo"))
+ assert.False(t, IsValidSSHAccessRepoName("the..repo"))
+ assert.False(t, IsValidSSHAccessRepoName("foo.git"))
+ assert.False(t, IsValidSSHAccessRepoName("foo.RSS"))
}
diff --git a/models/repo/repo_unit.go b/models/repo/repo_unit.go
index cb52c2c9e2..a5207bc22a 100644
--- a/models/repo/repo_unit.go
+++ b/models/repo/repo_unit.go
@@ -5,7 +5,6 @@ package repo
import (
"context"
- "fmt"
"slices"
"strings"
@@ -33,7 +32,7 @@ func IsErrUnitTypeNotExist(err error) bool {
}
func (err ErrUnitTypeNotExist) Error() string {
- return fmt.Sprintf("Unit type does not exist: %s", err.UT.LogString())
+ return "Unit type does not exist: " + err.UT.LogString()
}
func (err ErrUnitTypeNotExist) Unwrap() error {
@@ -42,12 +41,13 @@ func (err ErrUnitTypeNotExist) Unwrap() error {
// RepoUnit describes all units of a repository
type RepoUnit struct { //revive:disable-line:exported
- ID int64
- RepoID int64 `xorm:"INDEX(s)"`
- Type unit.Type `xorm:"INDEX(s)"`
- Config convert.Conversion `xorm:"TEXT"`
- CreatedUnix timeutil.TimeStamp `xorm:"INDEX CREATED"`
- EveryoneAccessMode perm.AccessMode `xorm:"NOT NULL DEFAULT 0"`
+ ID int64
+ RepoID int64 `xorm:"INDEX(s)"`
+ Type unit.Type `xorm:"INDEX(s)"`
+ Config convert.Conversion `xorm:"TEXT"`
+ CreatedUnix timeutil.TimeStamp `xorm:"INDEX CREATED"`
+ AnonymousAccessMode perm.AccessMode `xorm:"NOT NULL DEFAULT 0"`
+ EveryoneAccessMode perm.AccessMode `xorm:"NOT NULL DEFAULT 0"`
}
func init() {
@@ -185,10 +185,8 @@ func (cfg *ActionsConfig) IsWorkflowDisabled(file string) bool {
}
func (cfg *ActionsConfig) DisableWorkflow(file string) {
- for _, workflow := range cfg.DisabledWorkflows {
- if file == workflow {
- return
- }
+ if slices.Contains(cfg.DisabledWorkflows, file) {
+ return
}
cfg.DisabledWorkflows = append(cfg.DisabledWorkflows, file)
@@ -341,3 +339,9 @@ func UpdateRepoUnit(ctx context.Context, unit *RepoUnit) error {
_, err := db.GetEngine(ctx).ID(unit.ID).Update(unit)
return err
}
+
+func UpdateRepoUnitPublicAccess(ctx context.Context, unit *RepoUnit) error {
+ _, err := db.GetEngine(ctx).Where("repo_id=? AND `type`=?", unit.RepoID, unit.Type).
+ Cols("anonymous_access_mode", "everyone_access_mode").Update(unit)
+ return err
+}
diff --git a/models/repo/repo_unit_test.go b/models/repo/repo_unit_test.go
index a760594013..56dda5672d 100644
--- a/models/repo/repo_unit_test.go
+++ b/models/repo/repo_unit_test.go
@@ -12,19 +12,19 @@ import (
func TestActionsConfig(t *testing.T) {
cfg := &ActionsConfig{}
cfg.DisableWorkflow("test1.yaml")
- assert.EqualValues(t, []string{"test1.yaml"}, cfg.DisabledWorkflows)
+ assert.Equal(t, []string{"test1.yaml"}, cfg.DisabledWorkflows)
cfg.DisableWorkflow("test1.yaml")
- assert.EqualValues(t, []string{"test1.yaml"}, cfg.DisabledWorkflows)
+ assert.Equal(t, []string{"test1.yaml"}, cfg.DisabledWorkflows)
cfg.EnableWorkflow("test1.yaml")
- assert.EqualValues(t, []string{}, cfg.DisabledWorkflows)
+ assert.Equal(t, []string{}, cfg.DisabledWorkflows)
cfg.EnableWorkflow("test1.yaml")
- assert.EqualValues(t, []string{}, cfg.DisabledWorkflows)
+ assert.Equal(t, []string{}, cfg.DisabledWorkflows)
cfg.DisableWorkflow("test1.yaml")
cfg.DisableWorkflow("test2.yaml")
cfg.DisableWorkflow("test3.yaml")
- assert.EqualValues(t, "test1.yaml,test2.yaml,test3.yaml", cfg.ToString())
+ assert.Equal(t, "test1.yaml,test2.yaml,test3.yaml", cfg.ToString())
}
diff --git a/models/repo/topic_test.go b/models/repo/topic_test.go
index 1600896b6e..b6a7aed7b1 100644
--- a/models/repo/topic_test.go
+++ b/models/repo/topic_test.go
@@ -53,7 +53,7 @@ func TestAddTopic(t *testing.T) {
totalNrOfTopics++
topic, err := repo_model.GetTopicByName(db.DefaultContext, "gitea")
assert.NoError(t, err)
- assert.EqualValues(t, 1, topic.RepoCount)
+ assert.Equal(t, 1, topic.RepoCount)
topics, err = db.Find[repo_model.Topic](db.DefaultContext, &repo_model.FindTopicOptions{})
assert.NoError(t, err)
diff --git a/models/repo/transfer.go b/models/repo/transfer.go
index 43e15b33bc..3fb8cb69ab 100644
--- a/models/repo/transfer.go
+++ b/models/repo/transfer.go
@@ -61,13 +61,14 @@ func (err ErrRepoTransferInProgress) Unwrap() error {
}
// RepoTransfer is used to manage repository transfers
-type RepoTransfer struct { //nolint
+type RepoTransfer struct { //nolint:revive // export stutter
ID int64 `xorm:"pk autoincr"`
DoerID int64
Doer *user_model.User `xorm:"-"`
RecipientID int64
Recipient *user_model.User `xorm:"-"`
RepoID int64
+ Repo *Repository `xorm:"-"`
TeamIDs []int64
Teams []*organization.Team `xorm:"-"`
@@ -79,48 +80,65 @@ func init() {
db.RegisterModel(new(RepoTransfer))
}
-// LoadAttributes fetches the transfer recipient from the database
-func (r *RepoTransfer) LoadAttributes(ctx context.Context) error {
+func (r *RepoTransfer) LoadRecipient(ctx context.Context) error {
if r.Recipient == nil {
u, err := user_model.GetUserByID(ctx, r.RecipientID)
if err != nil {
return err
}
-
r.Recipient = u
}
- if r.Recipient.IsOrganization() && len(r.TeamIDs) != len(r.Teams) {
- for _, v := range r.TeamIDs {
- team, err := organization.GetTeamByID(ctx, v)
- if err != nil {
- return err
- }
+ return nil
+}
- if team.OrgID != r.Recipient.ID {
- return fmt.Errorf("team %d belongs not to org %d", v, r.Recipient.ID)
- }
+func (r *RepoTransfer) LoadRepo(ctx context.Context) error {
+ if r.Repo == nil {
+ repo, err := GetRepositoryByID(ctx, r.RepoID)
+ if err != nil {
+ return err
+ }
+ r.Repo = repo
+ }
+
+ return nil
+}
+
+// LoadAttributes fetches the transfer recipient from the database
+func (r *RepoTransfer) LoadAttributes(ctx context.Context) error {
+ if err := r.LoadRecipient(ctx); err != nil {
+ return err
+ }
+ if r.Recipient.IsOrganization() && r.Teams == nil {
+ teamsMap, err := organization.GetTeamsByIDs(ctx, r.TeamIDs)
+ if err != nil {
+ return err
+ }
+ for _, team := range teamsMap {
r.Teams = append(r.Teams, team)
}
}
+ if err := r.LoadRepo(ctx); err != nil {
+ return err
+ }
+
if r.Doer == nil {
u, err := user_model.GetUserByID(ctx, r.DoerID)
if err != nil {
return err
}
-
r.Doer = u
}
return nil
}
-// CanUserAcceptTransfer checks if the user has the rights to accept/decline a repo transfer.
+// CanUserAcceptOrRejectTransfer checks if the user has the rights to accept/decline a repo transfer.
// For user, it checks if it's himself
// For organizations, it checks if the user is able to create repos
-func (r *RepoTransfer) CanUserAcceptTransfer(ctx context.Context, u *user_model.User) bool {
+func (r *RepoTransfer) CanUserAcceptOrRejectTransfer(ctx context.Context, u *user_model.User) bool {
if err := r.LoadAttributes(ctx); err != nil {
log.Error("LoadAttributes: %v", err)
return false
@@ -166,6 +184,10 @@ func GetPendingRepositoryTransfers(ctx context.Context, opts *PendingRepositoryT
Find(&transfers)
}
+func IsRepositoryTransferExist(ctx context.Context, repoID int64) (bool, error) {
+ return db.GetEngine(ctx).Where("repo_id = ?", repoID).Exist(new(RepoTransfer))
+}
+
// GetPendingRepositoryTransfer fetches the most recent and ongoing transfer
// process for the repository
func GetPendingRepositoryTransfer(ctx context.Context, repo *Repository) (*RepoTransfer, error) {
@@ -206,13 +228,28 @@ func CreatePendingRepositoryTransfer(ctx context.Context, doer, newOwner *user_m
return err
}
+ if _, err := user_model.GetUserByID(ctx, newOwner.ID); err != nil {
+ return err
+ }
+
// Make sure repo is ready to transfer
if err := TestRepositoryReadyForTransfer(repo.Status); err != nil {
return err
}
+ exist, err := IsRepositoryTransferExist(ctx, repo.ID)
+ if err != nil {
+ return err
+ }
+ if exist {
+ return ErrRepoTransferInProgress{
+ Uname: repo.Owner.LowerName,
+ Name: repo.Name,
+ }
+ }
+
repo.Status = RepositoryPendingTransfer
- if err := UpdateRepositoryCols(ctx, repo, "status"); err != nil {
+ if err := UpdateRepositoryColsNoAutoTime(ctx, repo, "status"); err != nil {
return err
}
diff --git a/models/repo/update.go b/models/repo/update.go
index fce357a1ac..64065f11c4 100644
--- a/models/repo/update.go
+++ b/models/repo/update.go
@@ -25,7 +25,7 @@ func UpdateRepositoryOwnerNames(ctx context.Context, ownerID int64, ownerName st
}
defer committer.Close()
- if _, err := db.GetEngine(ctx).Where("owner_id = ?", ownerID).Cols("owner_name").Update(&Repository{
+ if _, err := db.GetEngine(ctx).Where("owner_id = ?", ownerID).Cols("owner_name").NoAutoTime().Update(&Repository{
OwnerName: ownerName,
}); err != nil {
return err
@@ -40,15 +40,15 @@ func UpdateRepositoryUpdatedTime(ctx context.Context, repoID int64, updateTime t
return err
}
-// UpdateRepositoryCols updates repository's columns
-func UpdateRepositoryCols(ctx context.Context, repo *Repository, cols ...string) error {
- _, err := db.GetEngine(ctx).ID(repo.ID).Cols(cols...).Update(repo)
+// UpdateRepositoryColsWithAutoTime updates repository's columns and the timestamp fields automatically
+func UpdateRepositoryColsWithAutoTime(ctx context.Context, repo *Repository, colName string, moreColNames ...string) error {
+ _, err := db.GetEngine(ctx).ID(repo.ID).Cols(append([]string{colName}, moreColNames...)...).Update(repo)
return err
}
-// UpdateRepositoryColsNoAutoTime updates repository's columns and but applies time change automatically
-func UpdateRepositoryColsNoAutoTime(ctx context.Context, repo *Repository, cols ...string) error {
- _, err := db.GetEngine(ctx).ID(repo.ID).Cols(cols...).NoAutoTime().Update(repo)
+// UpdateRepositoryColsNoAutoTime updates repository's columns, doesn't change timestamp field automatically
+func UpdateRepositoryColsNoAutoTime(ctx context.Context, repo *Repository, colName string, moreColNames ...string) error {
+ _, err := db.GetEngine(ctx).ID(repo.ID).Cols(append([]string{colName}, moreColNames...)...).NoAutoTime().Update(repo)
return err
}
@@ -111,31 +111,31 @@ func (err ErrRepoFilesAlreadyExist) Unwrap() error {
return util.ErrAlreadyExist
}
-// CheckCreateRepository check if could created a repository
-func CheckCreateRepository(ctx context.Context, doer, u *user_model.User, name string, overwriteOrAdopt bool) error {
- if !doer.CanCreateRepo() {
- return ErrReachLimitOfRepo{u.MaxRepoCreation}
+// CheckCreateRepository check if doer could create a repository in new owner
+func CheckCreateRepository(ctx context.Context, doer, owner *user_model.User, name string, overwriteOrAdopt bool) error {
+ if !doer.CanCreateRepoIn(owner) {
+ return ErrReachLimitOfRepo{owner.MaxRepoCreation}
}
if err := IsUsableRepoName(name); err != nil {
return err
}
- has, err := IsRepositoryModelOrDirExist(ctx, u, name)
+ has, err := IsRepositoryModelOrDirExist(ctx, owner, name)
if err != nil {
return fmt.Errorf("IsRepositoryExist: %w", err)
} else if has {
- return ErrRepoAlreadyExist{u.Name, name}
+ return ErrRepoAlreadyExist{owner.Name, name}
}
- repoPath := RepoPath(u.Name, name)
+ repoPath := RepoPath(owner.Name, name)
isExist, err := util.IsExist(repoPath)
if err != nil {
log.Error("Unable to check if %s exists. Error: %v", repoPath, err)
return err
}
if !overwriteOrAdopt && isExist {
- return ErrRepoFilesAlreadyExist{u.Name, name}
+ return ErrRepoFilesAlreadyExist{owner.Name, name}
}
return nil
}
diff --git a/models/repo/upload.go b/models/repo/upload.go
index 18834f6b83..20a8fa26fe 100644
--- a/models/repo/upload.go
+++ b/models/repo/upload.go
@@ -10,7 +10,7 @@ import (
"io"
"mime/multipart"
"os"
- "path"
+ "path/filepath"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/log"
@@ -51,14 +51,10 @@ func init() {
db.RegisterModel(new(Upload))
}
-// UploadLocalPath returns where uploads is stored in local file system based on given UUID.
-func UploadLocalPath(uuid string) string {
- return path.Join(setting.Repository.Upload.TempPath, uuid[0:1], uuid[1:2], uuid)
-}
-
-// LocalPath returns where uploads are temporarily stored in local file system.
+// LocalPath returns where uploads are temporarily stored in local file system based on given UUID.
func (upload *Upload) LocalPath() string {
- return UploadLocalPath(upload.UUID)
+ uuid := upload.UUID
+ return setting.AppDataTempDir("repo-uploads").JoinPath(uuid[0:1], uuid[1:2], uuid)
}
// NewUpload creates a new upload object.
@@ -69,7 +65,7 @@ func NewUpload(ctx context.Context, name string, buf []byte, file multipart.File
}
localPath := upload.LocalPath()
- if err = os.MkdirAll(path.Dir(localPath), os.ModePerm); err != nil {
+ if err = os.MkdirAll(filepath.Dir(localPath), os.ModePerm); err != nil {
return nil, fmt.Errorf("MkdirAll: %w", err)
}
@@ -128,7 +124,7 @@ func DeleteUploads(ctx context.Context, uploads ...*Upload) (err error) {
defer committer.Close()
ids := make([]int64, len(uploads))
- for i := 0; i < len(uploads); i++ {
+ for i := range uploads {
ids[i] = uploads[i].ID
}
if err = db.DeleteByIDs[Upload](ctx, ids...); err != nil {
diff --git a/models/repo/user_repo.go b/models/repo/user_repo.go
index a9b1360df1..232087d865 100644
--- a/models/repo/user_repo.go
+++ b/models/repo/user_repo.go
@@ -5,6 +5,7 @@ package repo
import (
"context"
+ "strings"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/perm"
@@ -149,9 +150,9 @@ func GetRepoAssignees(ctx context.Context, repo *Repository) (_ []*user_model.Us
// If isShowFullName is set to true, also include full name prefix search
func GetIssuePostersWithSearch(ctx context.Context, repo *Repository, isPull bool, search string, isShowFullName bool) ([]*user_model.User, error) {
users := make([]*user_model.User, 0, 30)
- var prefixCond builder.Cond = builder.Like{"name", search + "%"}
+ var prefixCond builder.Cond = builder.Like{"lower_name", strings.ToLower(search) + "%"}
if isShowFullName {
- prefixCond = prefixCond.Or(builder.Like{"full_name", "%" + search + "%"})
+ prefixCond = prefixCond.Or(db.BuildCaseInsensitiveLike("full_name", "%"+search+"%"))
}
cond := builder.In("`user`.id",
diff --git a/models/repo/user_repo_test.go b/models/repo/user_repo_test.go
index 44ebe5f214..50c970344c 100644
--- a/models/repo/user_repo_test.go
+++ b/models/repo/user_repo_test.go
@@ -12,6 +12,7 @@ import (
user_model "code.gitea.io/gitea/models/user"
"github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
)
func TestRepoAssignees(t *testing.T) {
@@ -38,3 +39,19 @@ func TestRepoAssignees(t *testing.T) {
assert.NotContains(t, []int64{users[0].ID, users[1].ID, users[2].ID}, 15)
}
}
+
+func TestGetIssuePostersWithSearch(t *testing.T) {
+ assert.NoError(t, unittest.PrepareTestDatabase())
+
+ repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2})
+
+ users, err := repo_model.GetIssuePostersWithSearch(db.DefaultContext, repo2, false, "USER", false /* full name */)
+ require.NoError(t, err)
+ require.Len(t, users, 1)
+ assert.Equal(t, "user2", users[0].Name)
+
+ users, err = repo_model.GetIssuePostersWithSearch(db.DefaultContext, repo2, false, "TW%O", true /* full name */)
+ require.NoError(t, err)
+ require.Len(t, users, 1)
+ assert.Equal(t, "user2", users[0].Name)
+}
diff --git a/models/repo/watch_test.go b/models/repo/watch_test.go
index c39ef607e8..7ed72386c9 100644
--- a/models/repo/watch_test.go
+++ b/models/repo/watch_test.go
@@ -36,7 +36,7 @@ func TestGetWatchers(t *testing.T) {
// One watchers are inactive, thus minus 1
assert.Len(t, watches, repo.NumWatches-1)
for _, watch := range watches {
- assert.EqualValues(t, repo.ID, watch.RepoID)
+ assert.Equal(t, repo.ID, watch.RepoID)
}
watches, err = repo_model.GetWatchers(db.DefaultContext, unittest.NonexistentID)
diff --git a/models/repo/wiki.go b/models/repo/wiki.go
index 4239a815b2..832e15ae0d 100644
--- a/models/repo/wiki.go
+++ b/models/repo/wiki.go
@@ -46,7 +46,7 @@ func IsErrWikiReservedName(err error) bool {
}
func (err ErrWikiReservedName) Error() string {
- return fmt.Sprintf("wiki title is reserved: %s", err.Title)
+ return "wiki title is reserved: " + err.Title
}
func (err ErrWikiReservedName) Unwrap() error {
@@ -65,7 +65,7 @@ func IsErrWikiInvalidFileName(err error) bool {
}
func (err ErrWikiInvalidFileName) Error() string {
- return fmt.Sprintf("Invalid wiki filename: %s", err.FileName)
+ return "Invalid wiki filename: " + err.FileName
}
func (err ErrWikiInvalidFileName) Unwrap() error {
diff --git a/models/repo/wiki_test.go b/models/repo/wiki_test.go
index 0157b7735d..103420a392 100644
--- a/models/repo/wiki_test.go
+++ b/models/repo/wiki_test.go
@@ -4,7 +4,6 @@
package repo_test
import (
- "context"
"path/filepath"
"testing"
@@ -19,7 +18,7 @@ func TestRepository_WikiCloneLink(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
- cloneLink := repo.WikiCloneLink(context.Background(), nil)
+ cloneLink := repo.WikiCloneLink(t.Context(), nil)
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)
}