Skip to content

Commit f5fc847

Browse files
authored
Merge branch 'main' into ava-cleanup
2 parents a7892c8 + bed6885 commit f5fc847

File tree

19 files changed

+246
-68
lines changed

19 files changed

+246
-68
lines changed

.github/workflows/pull-db-tests.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,13 @@ jobs:
102102
--health-retries 10
103103
ports:
104104
- 6379:6379
105+
minio:
106+
image: bitnami/minio:2021.3.17
107+
env:
108+
MINIO_ACCESS_KEY: 123456
109+
MINIO_SECRET_KEY: 12345678
110+
ports:
111+
- "9000:9000"
105112
steps:
106113
- uses: actions/checkout@v3
107114
- uses: actions/setup-go@v4

Dockerfile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#Build stage
2-
FROM docker.io/library/golang:1.20-alpine3.17 AS build-env
2+
FROM docker.io/library/golang:1.20-alpine3.18 AS build-env
33

44
ARG GOPROXY
55
ENV GOPROXY ${GOPROXY:-direct}
@@ -23,7 +23,7 @@ RUN if [ -n "${GITEA_VERSION}" ]; then git checkout "${GITEA_VERSION}"; fi \
2323
# Begin env-to-ini build
2424
RUN go build contrib/environment-to-ini/environment-to-ini.go
2525

26-
FROM docker.io/library/alpine:3.17
26+
FROM docker.io/library/alpine:3.18
2727
LABEL maintainer="[email protected]"
2828

2929
EXPOSE 22 3000

Dockerfile.rootless

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#Build stage
2-
FROM docker.io/library/golang:1.20-alpine3.17 AS build-env
2+
FROM docker.io/library/golang:1.20-alpine3.18 AS build-env
33

44
ARG GOPROXY
55
ENV GOPROXY ${GOPROXY:-direct}
@@ -23,7 +23,7 @@ RUN if [ -n "${GITEA_VERSION}" ]; then git checkout "${GITEA_VERSION}"; fi \
2323
# Begin env-to-ini build
2424
RUN go build contrib/environment-to-ini/environment-to-ini.go
2525

26-
FROM docker.io/library/alpine:3.17
26+
FROM docker.io/library/alpine:3.18
2727
LABEL maintainer="[email protected]"
2828

2929
EXPOSE 2222 3000

models/git/commit_status.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
api "code.gitea.io/gitea/modules/structs"
2424
"code.gitea.io/gitea/modules/timeutil"
2525

26+
"xorm.io/builder"
2627
"xorm.io/xorm"
2728
)
2829

@@ -240,6 +241,55 @@ func GetLatestCommitStatus(ctx context.Context, repoID int64, sha string, listOp
240241
return statuses, count, db.GetEngine(ctx).In("id", ids).Find(&statuses)
241242
}
242243

244+
// GetLatestCommitStatusForPairs returns all statuses with a unique context for a given list of repo-sha pairs
245+
func GetLatestCommitStatusForPairs(ctx context.Context, repoIDsToLatestCommitSHAs map[int64]string, listOptions db.ListOptions) (map[int64][]*CommitStatus, error) {
246+
type result struct {
247+
ID int64
248+
RepoID int64
249+
}
250+
251+
results := make([]result, 0, len(repoIDsToLatestCommitSHAs))
252+
253+
sess := db.GetEngine(ctx).Table(&CommitStatus{})
254+
255+
// Create a disjunction of conditions for each repoID and SHA pair
256+
conds := make([]builder.Cond, 0, len(repoIDsToLatestCommitSHAs))
257+
for repoID, sha := range repoIDsToLatestCommitSHAs {
258+
conds = append(conds, builder.Eq{"repo_id": repoID, "sha": sha})
259+
}
260+
sess = sess.Where(builder.Or(conds...)).
261+
Select("max( id ) as id, repo_id").
262+
GroupBy("context_hash, repo_id").OrderBy("max( id ) desc")
263+
264+
sess = db.SetSessionPagination(sess, &listOptions)
265+
266+
err := sess.Find(&results)
267+
if err != nil {
268+
return nil, err
269+
}
270+
271+
ids := make([]int64, 0, len(results))
272+
repoStatuses := make(map[int64][]*CommitStatus)
273+
for _, result := range results {
274+
ids = append(ids, result.ID)
275+
}
276+
277+
statuses := make([]*CommitStatus, 0, len(ids))
278+
if len(ids) > 0 {
279+
err = db.GetEngine(ctx).In("id", ids).Find(&statuses)
280+
if err != nil {
281+
return nil, err
282+
}
283+
284+
// Group the statuses by repo ID
285+
for _, status := range statuses {
286+
repoStatuses[status.RepoID] = append(repoStatuses[status.RepoID], status)
287+
}
288+
}
289+
290+
return repoStatuses, nil
291+
}
292+
243293
// FindRepoRecentCommitStatusContexts returns repository's recent commit status contexts
244294
func FindRepoRecentCommitStatusContexts(ctx context.Context, repoID int64, before time.Duration) ([]string, error) {
245295
start := timeutil.TimeStampNow().AddDuration(-before)

modules/git/repo_branch.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,17 @@ func GetBranchesByPath(ctx context.Context, path string, skip, limit int) ([]*Br
106106
return gitRepo.GetBranches(skip, limit)
107107
}
108108

109+
// GetBranchCommitID returns a branch commit ID by its name
110+
func GetBranchCommitID(ctx context.Context, path, branch string) (string, error) {
111+
gitRepo, err := OpenRepository(ctx, path)
112+
if err != nil {
113+
return "", err
114+
}
115+
defer gitRepo.Close()
116+
117+
return gitRepo.GetBranchCommitID(branch)
118+
}
119+
109120
// GetBranches returns a slice of *git.Branch
110121
func (repo *Repository) GetBranches(skip, limit int) ([]*Branch, int, error) {
111122
brs, countAll, err := repo.GetBranchNames(skip, limit)

modules/storage/local.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,8 @@ func (l *LocalStorage) URL(path, name string) (*url.URL, error) {
133133
}
134134

135135
// IterateObjects iterates across the objects in the local storage
136-
func (l *LocalStorage) IterateObjects(prefix string, fn func(path string, obj Object) error) error {
137-
dir := l.buildLocalPath(prefix)
136+
func (l *LocalStorage) IterateObjects(dirName string, fn func(path string, obj Object) error) error {
137+
dir := l.buildLocalPath(dirName)
138138
return filepath.WalkDir(dir, func(path string, d os.DirEntry, err error) error {
139139
if err != nil {
140140
return err

modules/storage/local_test.go

Lines changed: 1 addition & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44
package storage
55

66
import (
7-
"bytes"
8-
"context"
97
"os"
108
"path/filepath"
119
"testing"
@@ -57,38 +55,5 @@ func TestBuildLocalPath(t *testing.T) {
5755

5856
func TestLocalStorageIterator(t *testing.T) {
5957
dir := filepath.Join(os.TempDir(), "TestLocalStorageIteratorTestDir")
60-
l, err := NewLocalStorage(context.Background(), LocalStorageConfig{Path: dir})
61-
assert.NoError(t, err)
62-
63-
testFiles := [][]string{
64-
{"a/1.txt", "a1"},
65-
{"/a/1.txt", "aa1"}, // same as above, but with leading slash that will be trim
66-
{"b/1.txt", "b1"},
67-
{"b/2.txt", "b2"},
68-
{"b/3.txt", "b3"},
69-
{"b/x 4.txt", "bx4"},
70-
}
71-
for _, f := range testFiles {
72-
_, err = l.Save(f[0], bytes.NewBufferString(f[1]), -1)
73-
assert.NoError(t, err)
74-
}
75-
76-
expectedList := map[string][]string{
77-
"a": {"a/1.txt"},
78-
"b": {"b/1.txt", "b/2.txt", "b/3.txt", "b/x 4.txt"},
79-
"": {"a/1.txt", "b/1.txt", "b/2.txt", "b/3.txt", "b/x 4.txt"},
80-
"/": {"a/1.txt", "b/1.txt", "b/2.txt", "b/3.txt", "b/x 4.txt"},
81-
"a/b/../../a": {"a/1.txt"},
82-
}
83-
for dir, expected := range expectedList {
84-
count := 0
85-
err = l.IterateObjects(dir, func(path string, f Object) error {
86-
defer f.Close()
87-
assert.Contains(t, expected, path)
88-
count++
89-
return nil
90-
})
91-
assert.NoError(t, err)
92-
assert.Len(t, expected, count)
93-
}
58+
testStorageIterator(t, string(LocalStorageType), LocalStorageConfig{Path: dir})
9459
}

modules/storage/minio.go

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,11 @@ func NewMinioStorage(ctx context.Context, cfg interface{}) (ObjectStorage, error
129129
}
130130

131131
func (m *MinioStorage) buildMinioPath(p string) string {
132-
return util.PathJoinRelX(m.basePath, p)
132+
p = util.PathJoinRelX(m.basePath, p)
133+
if p == "." {
134+
p = "" // minio doesn't use dot as relative path
135+
}
136+
return p
133137
}
134138

135139
// Open opens a file
@@ -224,14 +228,15 @@ func (m *MinioStorage) URL(path, name string) (*url.URL, error) {
224228
}
225229

226230
// IterateObjects iterates across the objects in the miniostorage
227-
func (m *MinioStorage) IterateObjects(prefix string, fn func(path string, obj Object) error) error {
231+
func (m *MinioStorage) IterateObjects(dirName string, fn func(path string, obj Object) error) error {
228232
opts := minio.GetObjectOptions{}
229233
lobjectCtx, cancel := context.WithCancel(m.ctx)
230234
defer cancel()
231235

232236
basePath := m.basePath
233-
if prefix != "" {
234-
basePath = m.buildMinioPath(prefix)
237+
if dirName != "" {
238+
// ending slash is required for avoiding matching like "foo/" and "foobar/" with prefix "foo"
239+
basePath = m.buildMinioPath(dirName) + "/"
235240
}
236241

237242
for mObjInfo := range m.client.ListObjects(lobjectCtx, m.bucket, minio.ListObjectsOptions{
@@ -244,7 +249,7 @@ func (m *MinioStorage) IterateObjects(prefix string, fn func(path string, obj Ob
244249
}
245250
if err := func(object *minio.Object, fn func(path string, obj Object) error) error {
246251
defer object.Close()
247-
return fn(strings.TrimPrefix(mObjInfo.Key, basePath), &minioObject{object})
252+
return fn(strings.TrimPrefix(mObjInfo.Key, m.basePath), &minioObject{object})
248253
}(object, fn); err != nil {
249254
return convertMinioErr(err)
250255
}

modules/storage/minio_test.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Copyright 2023 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package storage
5+
6+
import (
7+
"testing"
8+
)
9+
10+
func TestMinioStorageIterator(t *testing.T) {
11+
testStorageIterator(t, string(MinioStorageType), MinioStorageConfig{
12+
Endpoint: "127.0.0.1:9000",
13+
AccessKeyID: "123456",
14+
SecretAccessKey: "12345678",
15+
Bucket: "gitea",
16+
Location: "us-east-1",
17+
})
18+
}

modules/storage/storage_test.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// Copyright 2023 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package storage
5+
6+
import (
7+
"bytes"
8+
"testing"
9+
10+
"github.com/stretchr/testify/assert"
11+
)
12+
13+
func testStorageIterator(t *testing.T, typStr string, cfg interface{}) {
14+
l, err := NewStorage(typStr, cfg)
15+
assert.NoError(t, err)
16+
17+
testFiles := [][]string{
18+
{"a/1.txt", "a1"},
19+
{"/a/1.txt", "aa1"}, // same as above, but with leading slash that will be trim
20+
{"ab/1.txt", "ab1"},
21+
{"b/1.txt", "b1"},
22+
{"b/2.txt", "b2"},
23+
{"b/3.txt", "b3"},
24+
{"b/x 4.txt", "bx4"},
25+
}
26+
for _, f := range testFiles {
27+
_, err = l.Save(f[0], bytes.NewBufferString(f[1]), -1)
28+
assert.NoError(t, err)
29+
}
30+
31+
expectedList := map[string][]string{
32+
"a": {"a/1.txt"},
33+
"b": {"b/1.txt", "b/2.txt", "b/3.txt", "b/x 4.txt"},
34+
"": {"a/1.txt", "b/1.txt", "b/2.txt", "b/3.txt", "b/x 4.txt", "ab/1.txt"},
35+
"/": {"a/1.txt", "b/1.txt", "b/2.txt", "b/3.txt", "b/x 4.txt", "ab/1.txt"},
36+
"a/b/../../a": {"a/1.txt"},
37+
}
38+
for dir, expected := range expectedList {
39+
count := 0
40+
err = l.IterateObjects(dir, func(path string, f Object) error {
41+
defer f.Close()
42+
assert.Contains(t, expected, path)
43+
count++
44+
return nil
45+
})
46+
assert.NoError(t, err)
47+
assert.Len(t, expected, count)
48+
}
49+
}

routers/web/repo/repo.go

Lines changed: 41 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,11 @@ import (
99
"fmt"
1010
"net/http"
1111
"strings"
12+
"sync"
1213

1314
"code.gitea.io/gitea/models"
1415
"code.gitea.io/gitea/models/db"
16+
git_model "code.gitea.io/gitea/models/git"
1517
"code.gitea.io/gitea/models/organization"
1618
access_model "code.gitea.io/gitea/models/perm/access"
1719
repo_model "code.gitea.io/gitea/models/repo"
@@ -576,23 +578,49 @@ func SearchRepo(ctx *context.Context) {
576578
return
577579
}
578580

579-
results := make([]*api.Repository, len(repos))
581+
// collect the latest commit of each repo
582+
repoIDsToLatestCommitSHAs := make(map[int64]string)
583+
wg := sync.WaitGroup{}
584+
wg.Add(len(repos))
585+
for _, repo := range repos {
586+
go func(repo *repo_model.Repository) {
587+
defer wg.Done()
588+
commitID, err := repo_service.GetBranchCommitID(ctx, repo, repo.DefaultBranch)
589+
if err != nil {
590+
return
591+
}
592+
repoIDsToLatestCommitSHAs[repo.ID] = commitID
593+
}(repo)
594+
}
595+
wg.Wait()
596+
597+
// call the database O(1) times to get the commit statuses for all repos
598+
repoToItsLatestCommitStatuses, err := git_model.GetLatestCommitStatusForPairs(ctx, repoIDsToLatestCommitSHAs, db.ListOptions{})
599+
if err != nil {
600+
log.Error("GetLatestCommitStatusForPairs: %v", err)
601+
return
602+
}
603+
604+
results := make([]*repo_service.WebSearchRepository, len(repos))
580605
for i, repo := range repos {
581-
results[i] = &api.Repository{
582-
ID: repo.ID,
583-
FullName: repo.FullName(),
584-
Fork: repo.IsFork,
585-
Private: repo.IsPrivate,
586-
Template: repo.IsTemplate,
587-
Mirror: repo.IsMirror,
588-
Stars: repo.NumStars,
589-
HTMLURL: repo.HTMLURL(),
590-
Link: repo.Link(),
591-
Internal: !repo.IsPrivate && repo.Owner.Visibility == api.VisibleTypePrivate,
606+
results[i] = &repo_service.WebSearchRepository{
607+
Repository: &api.Repository{
608+
ID: repo.ID,
609+
FullName: repo.FullName(),
610+
Fork: repo.IsFork,
611+
Private: repo.IsPrivate,
612+
Template: repo.IsTemplate,
613+
Mirror: repo.IsMirror,
614+
Stars: repo.NumStars,
615+
HTMLURL: repo.HTMLURL(),
616+
Link: repo.Link(),
617+
Internal: !repo.IsPrivate && repo.Owner.Visibility == api.VisibleTypePrivate,
618+
},
619+
LatestCommitStatus: git_model.CalcCommitStatus(repoToItsLatestCommitStatuses[repo.ID]),
592620
}
593621
}
594622

595-
ctx.JSON(http.StatusOK, api.SearchResults{
623+
ctx.JSON(http.StatusOK, repo_service.WebSearchResults{
596624
OK: true,
597625
Data: results,
598626
})

services/repository/branch.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ func GetBranches(ctx context.Context, repo *repo_model.Repository, skip, limit i
5353
return git.GetBranchesByPath(ctx, repo.RepoPath(), skip, limit)
5454
}
5555

56+
func GetBranchCommitID(ctx context.Context, repo *repo_model.Repository, branch string) (string, error) {
57+
return git.GetBranchCommitID(ctx, repo.RepoPath(), branch)
58+
}
59+
5660
// checkBranchName validates branch name with existing repository branches
5761
func checkBranchName(ctx context.Context, repo *repo_model.Repository, name string) error {
5862
_, err := git.WalkReferences(ctx, repo.RepoPath(), func(_, refName string) error {

0 commit comments

Comments
 (0)