Skip to content

Commit e17b6ce

Browse files
Merge branch 'master' into bucket
2 parents 22eead1 + e0f95d1 commit e17b6ce

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

85 files changed

+2671
-1630
lines changed

custom/conf/app.ini.sample

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,8 @@ DEFAULT_THEME = gitea
116116
THEMES = gitea,arc-green
117117
; Whether the full name of the users should be shown where possible. If the full name isn't set, the username will be used.
118118
DEFAULT_SHOW_FULL_NAME = false
119+
; Whether to search within description at repository search on explore page.
120+
SEARCH_REPO_DESCRIPTION = true
119121

120122
[ui.admin]
121123
; Number of users that are displayed on one page

docs/content/doc/advanced/config-cheat-sheet.en-us.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`.
9696
- `THEMES`: **gitea,arc-green**: All available themes. Allow users select personalized themes
9797
regardless of the value of `DEFAULT_THEME`.
9898
- `DEFAULT_SHOW_FULL_NAME`: false: Whether the full name of the users should be shown where possible. If the full name isn't set, the username will be used.
99+
- `SEARCH_REPO_DESCRIPTION`: true: Whether to search within description at repository search on explore page.
99100

100101
### UI - Admin (`ui.admin`)
101102

go.mod

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ require (
4545
github.com/glycerine/goconvey v0.0.0-20190315024820-982ee783a72e // indirect
4646
github.com/go-redis/redis v6.15.2+incompatible
4747
github.com/go-sql-driver/mysql v1.4.1
48-
github.com/go-xorm/xorm v0.7.4
48+
github.com/go-xorm/xorm v0.7.7-0.20190822154023-17592d96b35b
4949
github.com/gogits/chardet v0.0.0-20150115103509-2404f7772561
5050
github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14
5151
github.com/google/go-github/v24 v24.0.1
@@ -116,5 +116,5 @@ require (
116116
mvdan.cc/xurls/v2 v2.0.0
117117
strk.kbt.io/projects/go/libravatar v0.0.0-20160628055650-5eed7bff870a
118118
xorm.io/builder v0.3.5
119-
xorm.io/core v0.6.3
119+
xorm.io/core v0.7.0
120120
)

go.sum

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,8 @@ github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:9wScpmSP5A3Bk
177177
github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:56xuuqnHyryaerycW3BfssRdxQstACi0Epw/yC5E2xM=
178178
github.com/go-xorm/xorm v0.7.4 h1:g/NgC590SzqV5VKmdRDNe/K3Holw3YJUCXX28r+rFGw=
179179
github.com/go-xorm/xorm v0.7.4/go.mod h1:vpza5fydeRgt+stvo9qgMhSNohYqmNt0I1/D6hkCekA=
180+
github.com/go-xorm/xorm v0.7.7-0.20190822154023-17592d96b35b h1:Y0hWUheXDHpIs7BWtJcykO4d1VOsVDKg1PsP5YJwxxM=
181+
github.com/go-xorm/xorm v0.7.7-0.20190822154023-17592d96b35b/go.mod h1:nqz2TAsuOHWH2yk4FYWtacCGgdbrcdZ5mF1XadqEHls=
180182
github.com/gogits/chardet v0.0.0-20150115103509-2404f7772561 h1:deE7ritpK04PgtpyVOS2TYcQEld9qLCD5b5EbVNOuLA=
181183
github.com/gogits/chardet v0.0.0-20150115103509-2404f7772561/go.mod h1:YgYOrVn3Nj9Tq0EvjmFbphRytDj7JNRoWSStJZWDJTQ=
182184
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
@@ -508,6 +510,7 @@ golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5h
508510
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
509511
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
510512
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
513+
golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
511514
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
512515
golang.org/x/sys v0.0.0-20190620070143-6f217b454f45/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
513516
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -528,6 +531,7 @@ golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3
528531
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
529532
golang.org/x/tools v0.0.0-20190422233926-fe54fb35175b/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
530533
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
534+
golang.org/x/tools v0.0.0-20190606050223-4d9ae51c2468/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
531535
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
532536
golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a h1:mEQZbbaBjWyLNy0tmZmgEuQAR8XOQ3hL8GYi3J/NG64=
533537
golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
@@ -542,6 +546,7 @@ google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9Ywl
542546
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
543547
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
544548
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
549+
google.golang.org/appengine v1.6.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
545550
google.golang.org/appengine v1.6.1 h1:QzqyMA1tlu6CgqCDUtU9V+ZKhLFT2dkJuANu5QaxI3I=
546551
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
547552
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
@@ -613,3 +618,5 @@ xorm.io/builder v0.3.5 h1:EilU39fvWDxjb1cDaELpYhsF+zziRBhew8xk4pngO+A=
613618
xorm.io/builder v0.3.5/go.mod h1:ZFbByS/KxZI1FKRjL05PyJ4YrK2bcxlUaAxdum5aTR8=
614619
xorm.io/core v0.6.3 h1:n1NhVZt1s2oLw1BZfX2ocIJsHyso259uPgg63BGr37M=
615620
xorm.io/core v0.6.3/go.mod h1:8kz/C6arVW/O9vk3PgCiMJO2hIAm1UcuOL3dSPyZ2qo=
621+
xorm.io/core v0.7.0 h1:hKxuOKWZNeiFQsSuGet/KV8HZ788hclvAl+7azx3tkM=
622+
xorm.io/core v0.7.0/go.mod h1:TuOJjIVa7e3w/rN8tDcAvuLBMtwzdHPbyOzE6Gk1EUI=

integrations/api_repo_git_commits_test.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ import (
99
"testing"
1010

1111
"code.gitea.io/gitea/models"
12+
api "code.gitea.io/gitea/modules/structs"
13+
14+
"github.com/stretchr/testify/assert"
1215
)
1316

1417
func TestAPIReposGitCommits(t *testing.T) {
@@ -30,3 +33,58 @@ func TestAPIReposGitCommits(t *testing.T) {
3033
req := NewRequestf(t, "GET", "/api/v1/repos/%s/repo1/git/commits/unknown?token="+token, user.Name)
3134
session.MakeRequest(t, req, http.StatusNotFound)
3235
}
36+
37+
func TestAPIReposGitCommitList(t *testing.T) {
38+
prepareTestEnv(t)
39+
user := models.AssertExistsAndLoadBean(t, &models.User{ID: 2}).(*models.User)
40+
// Login as User2.
41+
session := loginUser(t, user.Name)
42+
token := getTokenForLoggedInUser(t, session)
43+
44+
// Test getting commits (Page 1)
45+
req := NewRequestf(t, "GET", "/api/v1/repos/%s/repo16/commits?token="+token, user.Name)
46+
resp := session.MakeRequest(t, req, http.StatusOK)
47+
48+
var apiData []api.Commit
49+
DecodeJSON(t, resp, &apiData)
50+
51+
assert.Equal(t, 3, len(apiData))
52+
assert.Equal(t, "69554a64c1e6030f051e5c3f94bfbd773cd6a324", apiData[0].CommitMeta.SHA)
53+
assert.Equal(t, "27566bd5738fc8b4e3fef3c5e72cce608537bd95", apiData[1].CommitMeta.SHA)
54+
assert.Equal(t, "5099b81332712fe655e34e8dd63574f503f61811", apiData[2].CommitMeta.SHA)
55+
}
56+
57+
func TestAPIReposGitCommitListPage2Empty(t *testing.T) {
58+
prepareTestEnv(t)
59+
user := models.AssertExistsAndLoadBean(t, &models.User{ID: 2}).(*models.User)
60+
// Login as User2.
61+
session := loginUser(t, user.Name)
62+
token := getTokenForLoggedInUser(t, session)
63+
64+
// Test getting commits (Page=2)
65+
req := NewRequestf(t, "GET", "/api/v1/repos/%s/repo16/commits?token="+token+"&page=2", user.Name)
66+
resp := session.MakeRequest(t, req, http.StatusOK)
67+
68+
var apiData []api.Commit
69+
DecodeJSON(t, resp, &apiData)
70+
71+
assert.Equal(t, 0, len(apiData))
72+
}
73+
74+
func TestAPIReposGitCommitListDifferentBranch(t *testing.T) {
75+
prepareTestEnv(t)
76+
user := models.AssertExistsAndLoadBean(t, &models.User{ID: 2}).(*models.User)
77+
// Login as User2.
78+
session := loginUser(t, user.Name)
79+
token := getTokenForLoggedInUser(t, session)
80+
81+
// Test getting commits (Page=1, Branch=good-sign)
82+
req := NewRequestf(t, "GET", "/api/v1/repos/%s/repo16/commits?token="+token+"&sha=good-sign", user.Name)
83+
resp := session.MakeRequest(t, req, http.StatusOK)
84+
85+
var apiData []api.Commit
86+
DecodeJSON(t, resp, &apiData)
87+
88+
assert.Equal(t, 1, len(apiData))
89+
assert.Equal(t, "f27c2b2b03dcab38beaf89b0ab4ff61f6de63441", apiData[0].CommitMeta.SHA)
90+
}

models/fixtures/repository.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@
165165
owner_id: 14
166166
lower_name: test_repo_14
167167
name: test_repo_14
168+
description: test_description_14
168169
is_private: false
169170
num_issues: 0
170171
num_closed_issues: 0

models/issue.go

Lines changed: 23 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
package models
66

77
import (
8-
"errors"
98
"fmt"
109
"path"
1110
"regexp"
@@ -74,6 +73,7 @@ var (
7473

7574
const issueTasksRegexpStr = `(^\s*[-*]\s\[[\sx]\]\s.)|(\n\s*[-*]\s\[[\sx]\]\s.)`
7675
const issueTasksDoneRegexpStr = `(^\s*[-*]\s\[[x]\]\s.)|(\n\s*[-*]\s\[[x]\]\s.)`
76+
const issueMaxDupIndexAttempts = 3
7777

7878
func init() {
7979
issueTasksPat = regexp.MustCompile(issueTasksRegexpStr)
@@ -1031,36 +1031,9 @@ type NewIssueOptions struct {
10311031
IsPull bool
10321032
}
10331033

1034-
// GetMaxIndexOfIssue returns the max index on issue
1035-
func GetMaxIndexOfIssue(repoID int64) (int64, error) {
1036-
return getMaxIndexOfIssue(x, repoID)
1037-
}
1038-
1039-
func getMaxIndexOfIssue(e Engine, repoID int64) (int64, error) {
1040-
var (
1041-
maxIndex int64
1042-
has bool
1043-
err error
1044-
)
1045-
1046-
has, err = e.SQL("SELECT COALESCE((SELECT MAX(`index`) FROM issue WHERE repo_id = ?),0)", repoID).Get(&maxIndex)
1047-
if err != nil {
1048-
return 0, err
1049-
} else if !has {
1050-
return 0, errors.New("Retrieve Max index from issue failed")
1051-
}
1052-
return maxIndex, nil
1053-
}
1054-
10551034
func newIssue(e *xorm.Session, doer *User, opts NewIssueOptions) (err error) {
10561035
opts.Issue.Title = strings.TrimSpace(opts.Issue.Title)
10571036

1058-
maxIndex, err := getMaxIndexOfIssue(e, opts.Issue.RepoID)
1059-
if err != nil {
1060-
return err
1061-
}
1062-
opts.Issue.Index = maxIndex + 1
1063-
10641037
if opts.Issue.MilestoneID > 0 {
10651038
milestone, err := getMilestoneByRepoID(e, opts.Issue.RepoID, opts.Issue.MilestoneID)
10661039
if err != nil && !IsErrMilestoneNotExist(err) {
@@ -1109,10 +1082,31 @@ func newIssue(e *xorm.Session, doer *User, opts NewIssueOptions) (err error) {
11091082
}
11101083

11111084
// Milestone and assignee validation should happen before insert actual object.
1112-
if _, err = e.Insert(opts.Issue); err != nil {
1085+
1086+
// There's no good way to identify a duplicate key error in database/sql; brute force some retries
1087+
dupIndexAttempts := issueMaxDupIndexAttempts
1088+
for {
1089+
_, err := e.SetExpr("`index`", "coalesce(MAX(`index`),0)+1").
1090+
Where("repo_id=?", opts.Issue.RepoID).
1091+
Insert(opts.Issue)
1092+
if err == nil {
1093+
break
1094+
}
1095+
1096+
dupIndexAttempts--
1097+
if dupIndexAttempts <= 0 {
1098+
return err
1099+
}
1100+
}
1101+
1102+
inserted, err := getIssueByID(e, opts.Issue.ID)
1103+
if err != nil {
11131104
return err
11141105
}
11151106

1107+
// Patch Index with the value calculated by the database
1108+
opts.Issue.Index = inserted.Index
1109+
11161110
if opts.Issue.MilestoneID > 0 {
11171111
if err = changeMilestoneAssign(e, doer, opts.Issue, -1); err != nil {
11181112
return err

models/repo_list.go

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,8 @@ type SearchRepoOptions struct {
136136
Mirror util.OptionalBool
137137
// only search topic name
138138
TopicOnly bool
139+
// include description in keyword search
140+
IncludeDescription bool
139141
}
140142

141143
//SearchOrderBy is used to sort the result
@@ -163,9 +165,9 @@ const (
163165
SearchOrderByForksReverse SearchOrderBy = "num_forks DESC"
164166
)
165167

166-
// SearchRepositoryByName takes keyword and part of repository name to search,
168+
// SearchRepository returns repositories based on search options,
167169
// it returns results in given range and number of total results.
168-
func SearchRepositoryByName(opts *SearchRepoOptions) (RepositoryList, int64, error) {
170+
func SearchRepository(opts *SearchRepoOptions) (RepositoryList, int64, error) {
169171
if opts.Page <= 0 {
170172
opts.Page = 1
171173
}
@@ -264,6 +266,9 @@ func SearchRepositoryByName(opts *SearchRepoOptions) (RepositoryList, int64, err
264266
var likes = builder.NewCond()
265267
for _, v := range strings.Split(opts.Keyword, ",") {
266268
likes = likes.Or(builder.Like{"lower_name", strings.ToLower(v)})
269+
if opts.IncludeDescription {
270+
likes = likes.Or(builder.Like{"LOWER(description)", strings.ToLower(v)})
271+
}
267272
}
268273
keywordCond = keywordCond.Or(likes)
269274
}
@@ -311,6 +316,13 @@ func SearchRepositoryByName(opts *SearchRepoOptions) (RepositoryList, int64, err
311316
return repos, count, nil
312317
}
313318

319+
// SearchRepositoryByName takes keyword and part of repository name to search,
320+
// it returns results in given range and number of total results.
321+
func SearchRepositoryByName(opts *SearchRepoOptions) (RepositoryList, int64, error) {
322+
opts.IncludeDescription = false
323+
return SearchRepository(opts)
324+
}
325+
314326
// FindUserAccessibleRepoIDs find all accessible repositories' ID by user's id
315327
func FindUserAccessibleRepoIDs(userID int64) ([]int64, error) {
316328
var accessCond builder.Cond = builder.Eq{"is_private": false}

models/repo_list_test.go

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import (
1212
"github.com/stretchr/testify/assert"
1313
)
1414

15-
func TestSearchRepositoryByName(t *testing.T) {
15+
func TestSearchRepository(t *testing.T) {
1616
assert.NoError(t, PrepareTestDatabase())
1717

1818
// test search public repository on explore page
@@ -74,6 +74,34 @@ func TestSearchRepositoryByName(t *testing.T) {
7474
assert.Empty(t, repos)
7575
assert.Equal(t, int64(0), count)
7676

77+
// Test search within description
78+
repos, count, err = SearchRepository(&SearchRepoOptions{
79+
Keyword: "description_14",
80+
Page: 1,
81+
PageSize: 10,
82+
Collaborate: util.OptionalBoolFalse,
83+
IncludeDescription: true,
84+
})
85+
86+
assert.NoError(t, err)
87+
if assert.Len(t, repos, 1) {
88+
assert.Equal(t, "test_repo_14", repos[0].Name)
89+
}
90+
assert.Equal(t, int64(1), count)
91+
92+
// Test NOT search within description
93+
repos, count, err = SearchRepository(&SearchRepoOptions{
94+
Keyword: "description_14",
95+
Page: 1,
96+
PageSize: 10,
97+
Collaborate: util.OptionalBoolFalse,
98+
IncludeDescription: false,
99+
})
100+
101+
assert.NoError(t, err)
102+
assert.Empty(t, repos)
103+
assert.Equal(t, int64(0), count)
104+
77105
testCases := []struct {
78106
name string
79107
opts *SearchRepoOptions

models/user.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1692,7 +1692,12 @@ func SyncExternalUsers() {
16921692
return
16931693
}
16941694

1695-
sr := s.LDAP().SearchEntries()
1695+
sr, err := s.LDAP().SearchEntries()
1696+
if err != nil {
1697+
log.Error("SyncExternalUsers LDAP source failure [%s], skipped", s.Name)
1698+
continue
1699+
}
1700+
16961701
for _, su := range sr {
16971702
if len(su.Username) == 0 {
16981703
continue

modules/auth/ldap/ldap.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -308,20 +308,20 @@ func (ls *Source) UsePagedSearch() bool {
308308
}
309309

310310
// SearchEntries : search an LDAP source for all users matching userFilter
311-
func (ls *Source) SearchEntries() []*SearchResult {
311+
func (ls *Source) SearchEntries() ([]*SearchResult, error) {
312312
l, err := dial(ls)
313313
if err != nil {
314314
log.Error("LDAP Connect error, %s:%v", ls.Host, err)
315315
ls.Enabled = false
316-
return nil
316+
return nil, err
317317
}
318318
defer l.Close()
319319

320320
if ls.BindDN != "" && ls.BindPassword != "" {
321321
err := l.Bind(ls.BindDN, ls.BindPassword)
322322
if err != nil {
323323
log.Debug("Failed to bind as BindDN[%s]: %v", ls.BindDN, err)
324-
return nil
324+
return nil, err
325325
}
326326
log.Trace("Bound as BindDN %s", ls.BindDN)
327327
} else {
@@ -350,7 +350,7 @@ func (ls *Source) SearchEntries() []*SearchResult {
350350
}
351351
if err != nil {
352352
log.Error("LDAP Search failed unexpectedly! (%v)", err)
353-
return nil
353+
return nil, err
354354
}
355355

356356
result := make([]*SearchResult, len(sr.Entries))
@@ -368,5 +368,5 @@ func (ls *Source) SearchEntries() []*SearchResult {
368368
}
369369
}
370370

371-
return result
371+
return result, nil
372372
}

modules/git/repo_tag.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ func (repo *Repository) GetTagNameBySHA(sha string) (string, error) {
153153

154154
// GetTagID returns the object ID for a tag (annotated tags have both an object SHA AND a commit SHA)
155155
func (repo *Repository) GetTagID(name string) (string, error) {
156-
stdout, err := NewCommand("show-ref", "--", name).RunInDir(repo.Path)
156+
stdout, err := NewCommand("show-ref", "--tags", "--", name).RunInDir(repo.Path)
157157
if err != nil {
158158
return "", err
159159
}

0 commit comments

Comments
 (0)