Skip to content

Commit 99f3b1f

Browse files
committed
services/repository: fix ListUnadoptedRepositories incorrect total count
The total count returned by ListUnadoptedRepositories is incorrectly calculated. The code snippet within ListUnadoptedRepositories used to verify unadopted repositories is repeated three times in the function. It is moved in the checkUnadoptedRepositories function and a unit test is added to verify it works as expected. A unit test is added to verify the total count returned by ListUnadoptedRepositories is as expected. Signed-off-by: singuliere <[email protected]>
1 parent c99b8ef commit 99f3b1f

File tree

2 files changed

+156
-110
lines changed

2 files changed

+156
-110
lines changed

services/repository/adopt.go

+70-110
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,57 @@ func DeleteUnadoptedRepository(doer, u *user_model.User, repoName string) error
217217
return util.RemoveAll(repoPath)
218218
}
219219

220+
type unadoptedRrepositories struct {
221+
repositories []string
222+
index int
223+
start int
224+
end int
225+
}
226+
227+
func (unadopted *unadoptedRrepositories) add(repository string) {
228+
if unadopted.index >= unadopted.start && unadopted.index < unadopted.end {
229+
unadopted.repositories = append(unadopted.repositories, repository)
230+
}
231+
unadopted.index++
232+
}
233+
234+
func checkUnadoptedRepositories(userName string, repoNamesToCheck []string, unadopted *unadoptedRrepositories) error {
235+
if len(repoNamesToCheck) == 0 {
236+
return nil
237+
}
238+
ctxUser, err := user_model.GetUserByName(userName)
239+
if err != nil {
240+
if user_model.IsErrUserNotExist(err) {
241+
log.Debug("Missing user: %s", userName)
242+
return nil
243+
}
244+
return err
245+
}
246+
repos, _, err := models.GetUserRepositories(&models.SearchRepoOptions{
247+
Actor: ctxUser,
248+
Private: true,
249+
ListOptions: db.ListOptions{
250+
Page: 1,
251+
PageSize: len(repoNamesToCheck),
252+
}, LowerNames: repoNamesToCheck})
253+
if err != nil {
254+
return err
255+
}
256+
if len(repos) == len(repoNamesToCheck) {
257+
return nil
258+
}
259+
repoNames := make(map[string]bool, len(repos))
260+
for _, repo := range repos {
261+
repoNames[repo.LowerName] = true
262+
}
263+
for _, repoName := range repoNamesToCheck {
264+
if _, ok := repoNames[repoName]; !ok {
265+
unadopted.add(filepath.Join(userName, repoName))
266+
}
267+
}
268+
return nil
269+
}
270+
220271
// ListUnadoptedRepositories lists all the unadopted repositories that match the provided query
221272
func ListUnadoptedRepositories(query string, opts *db.ListOptions) ([]string, int, error) {
222273
globUser, _ := glob.Compile("*")
@@ -236,15 +287,17 @@ func ListUnadoptedRepositories(query string, opts *db.ListOptions) ([]string, in
236287
}
237288
}
238289
}
239-
start := (opts.Page - 1) * opts.PageSize
240-
end := start + opts.PageSize
241-
242-
repoNamesToCheck := make([]string, 0, opts.PageSize)
290+
var repoNamesToCheck []string
243291

244-
repoNames := make([]string, 0, opts.PageSize)
245-
var ctxUser *user_model.User
292+
start := (opts.Page - 1) * opts.PageSize
293+
unadopted := &unadoptedRrepositories{
294+
repositories: make([]string, 0, opts.PageSize),
295+
start: start,
296+
end: start + opts.PageSize,
297+
index: 0,
298+
}
246299

247-
count := 0
300+
var userName string
248301

249302
// We're going to iterate by pagesize.
250303
root := filepath.Clean(setting.RepoRootPath)
@@ -258,51 +311,16 @@ func ListUnadoptedRepositories(query string, opts *db.ListOptions) ([]string, in
258311

259312
if !strings.ContainsRune(path[len(root)+1:], filepath.Separator) {
260313
// Got a new user
261-
262-
// Clean up old repoNamesToCheck
263-
if len(repoNamesToCheck) > 0 {
264-
repos, _, err := models.GetUserRepositories(&models.SearchRepoOptions{
265-
Actor: ctxUser,
266-
Private: true,
267-
ListOptions: db.ListOptions{
268-
Page: 1,
269-
PageSize: opts.PageSize,
270-
}, LowerNames: repoNamesToCheck})
271-
if err != nil {
272-
return err
273-
}
274-
for _, name := range repoNamesToCheck {
275-
found := false
276-
repoLoopCatchup:
277-
for i, repo := range repos {
278-
if repo.LowerName == name {
279-
found = true
280-
repos = append(repos[:i], repos[i+1:]...)
281-
break repoLoopCatchup
282-
}
283-
}
284-
if !found {
285-
if count >= start && count < end {
286-
repoNames = append(repoNames, fmt.Sprintf("%s/%s", ctxUser.Name, name))
287-
}
288-
count++
289-
}
290-
}
291-
repoNamesToCheck = repoNamesToCheck[:0]
314+
if err = checkUnadoptedRepositories(userName, repoNamesToCheck, unadopted); err != nil {
315+
return err
292316
}
317+
repoNamesToCheck = repoNamesToCheck[:0]
293318

294319
if !globUser.Match(info.Name()) {
295320
return filepath.SkipDir
296321
}
297322

298-
ctxUser, err = user_model.GetUserByName(info.Name())
299-
if err != nil {
300-
if user_model.IsErrUserNotExist(err) {
301-
log.Debug("Missing user: %s", info.Name())
302-
return filepath.SkipDir
303-
}
304-
return err
305-
}
323+
userName = info.Name()
306324
return nil
307325
}
308326

@@ -315,74 +333,16 @@ func ListUnadoptedRepositories(query string, opts *db.ListOptions) ([]string, in
315333
if repo_model.IsUsableRepoName(name) != nil || strings.ToLower(name) != name || !globRepo.Match(name) {
316334
return filepath.SkipDir
317335
}
318-
if count < end {
319-
repoNamesToCheck = append(repoNamesToCheck, name)
320-
if len(repoNamesToCheck) >= opts.PageSize {
321-
repos, _, err := models.GetUserRepositories(&models.SearchRepoOptions{
322-
Actor: ctxUser,
323-
Private: true,
324-
ListOptions: db.ListOptions{
325-
Page: 1,
326-
PageSize: opts.PageSize,
327-
}, LowerNames: repoNamesToCheck})
328-
if err != nil {
329-
return err
330-
}
331-
for _, name := range repoNamesToCheck {
332-
found := false
333-
repoLoop:
334-
for i, repo := range repos {
335-
if repo.LowerName == name {
336-
found = true
337-
repos = append(repos[:i], repos[i+1:]...)
338-
break repoLoop
339-
}
340-
}
341-
if !found {
342-
if count >= start && count < end {
343-
repoNames = append(repoNames, fmt.Sprintf("%s/%s", ctxUser.Name, name))
344-
}
345-
count++
346-
}
347-
}
348-
repoNamesToCheck = repoNamesToCheck[:0]
349-
}
350-
return filepath.SkipDir
351-
}
352-
count++
336+
337+
repoNamesToCheck = append(repoNamesToCheck, name)
353338
return filepath.SkipDir
354339
}); err != nil {
355340
return nil, 0, err
356341
}
357342

358-
if len(repoNamesToCheck) > 0 {
359-
repos, _, err := models.GetUserRepositories(&models.SearchRepoOptions{
360-
Actor: ctxUser,
361-
Private: true,
362-
ListOptions: db.ListOptions{
363-
Page: 1,
364-
PageSize: opts.PageSize,
365-
}, LowerNames: repoNamesToCheck})
366-
if err != nil {
367-
return nil, 0, err
368-
}
369-
for _, name := range repoNamesToCheck {
370-
found := false
371-
repoLoop:
372-
for i, repo := range repos {
373-
if repo.LowerName == name {
374-
found = true
375-
repos = append(repos[:i], repos[i+1:]...)
376-
break repoLoop
377-
}
378-
}
379-
if !found {
380-
if count >= start && count < end {
381-
repoNames = append(repoNames, fmt.Sprintf("%s/%s", ctxUser.Name, name))
382-
}
383-
count++
384-
}
385-
}
343+
if err := checkUnadoptedRepositories(userName, repoNamesToCheck, unadopted); err != nil {
344+
return nil, 0, err
386345
}
387-
return repoNames, count, nil
346+
347+
return unadopted.repositories, unadopted.index, nil
388348
}

services/repository/adopt_test.go

+86
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
// Copyright 2021 The Gitea Authors. All rights reserved.
2+
// Use of this source code is governed by a MIT-style
3+
// license that can be found in the LICENSE file.
4+
5+
package repository
6+
7+
import (
8+
"os"
9+
"path"
10+
"testing"
11+
12+
"code.gitea.io/gitea/models/db"
13+
"code.gitea.io/gitea/models/unittest"
14+
"code.gitea.io/gitea/modules/setting"
15+
16+
"github.com/stretchr/testify/assert"
17+
)
18+
19+
func TestCheckUnadoptedRepositories_Add(t *testing.T) {
20+
start := 10
21+
end := 20
22+
unadopted := &unadoptedRrepositories{
23+
start: start,
24+
end: end,
25+
index: 0,
26+
}
27+
28+
total := 30
29+
for i := 0; i < total; i++ {
30+
unadopted.add("something")
31+
}
32+
33+
assert.Equal(t, total, unadopted.index)
34+
assert.Equal(t, end-start, len(unadopted.repositories))
35+
}
36+
37+
func TestCheckUnadoptedRepositories(t *testing.T) {
38+
assert.NoError(t, unittest.PrepareTestDatabase())
39+
//
40+
// Non existent user
41+
//
42+
unadopted := &unadoptedRrepositories{start: 0, end: 100}
43+
err := checkUnadoptedRepositories("notauser", []string{"repo"}, unadopted)
44+
assert.NoError(t, err)
45+
assert.Equal(t, 0, len(unadopted.repositories))
46+
//
47+
// Unadopted repository is returned
48+
// Existing (adopted) repository is not returned
49+
//
50+
userName := "user2"
51+
repoName := "repo2"
52+
unadoptedRepoName := "unadopted"
53+
unadopted = &unadoptedRrepositories{start: 0, end: 100}
54+
err = checkUnadoptedRepositories(userName, []string{repoName, unadoptedRepoName}, unadopted)
55+
assert.NoError(t, err)
56+
assert.Equal(t, []string{path.Join(userName, unadoptedRepoName)}, unadopted.repositories)
57+
//
58+
// Existing (adopted) repository is not returned
59+
//
60+
unadopted = &unadoptedRrepositories{start: 0, end: 100}
61+
err = checkUnadoptedRepositories(userName, []string{repoName}, unadopted)
62+
assert.NoError(t, err)
63+
assert.Equal(t, 0, len(unadopted.repositories))
64+
assert.Equal(t, 0, unadopted.index)
65+
}
66+
67+
func TestListUnadoptedRepositories_ListOptions(t *testing.T) {
68+
assert.NoError(t, unittest.PrepareTestDatabase())
69+
username := "user2"
70+
unadoptedList := []string{path.Join(username, "unadopted1"), path.Join(username, "unadopted2")}
71+
for _, unadopted := range unadoptedList {
72+
_ = os.Mkdir(path.Join(setting.RepoRootPath, unadopted+".git"), 0755)
73+
}
74+
75+
opts := db.ListOptions{Page: 1, PageSize: 1}
76+
repoNames, count, err := ListUnadoptedRepositories("", &opts)
77+
assert.NoError(t, err)
78+
assert.Equal(t, 2, count)
79+
assert.Equal(t, unadoptedList[0], repoNames[0])
80+
81+
opts = db.ListOptions{Page: 2, PageSize: 1}
82+
repoNames, count, err = ListUnadoptedRepositories("", &opts)
83+
assert.NoError(t, err)
84+
assert.Equal(t, 2, count)
85+
assert.Equal(t, unadoptedList[1], repoNames[0])
86+
}

0 commit comments

Comments
 (0)