mirror of
https://codeberg.org/forgejo/forgejo
synced 2024-11-25 11:16:11 +01:00
Merge branch 'forgejo' into bugfix-arch
This commit is contained in:
commit
bc4849a904
|
@ -10,7 +10,7 @@ labels:
|
|||
|
||||
## Checklist
|
||||
|
||||
The [developer guide](https://forgejo.org/docs/next/developer/) contains information that will be helpful to first time contributors. There also are a few [conditions for merging Pull Requests in Forgejo repositories](https://codeberg.org/forgejo/governance/src/branch/main/PullRequestsAgreement.md). You are also welcome to join the [Forgejo development chatroom](https://matrix.to/#/#forgejo-development:matrix.org).
|
||||
The [contributor guide](https://forgejo.org/docs/next/contributor/) contains information that will be helpful to first time contributors. There also are a few [conditions for merging Pull Requests in Forgejo repositories](https://codeberg.org/forgejo/governance/src/branch/main/PullRequestsAgreement.md). You are also welcome to join the [Forgejo development chatroom](https://matrix.to/#/#forgejo-development:matrix.org).
|
||||
|
||||
### Tests
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# See also https://forgejo.org/docs/next/developer/RELEASE/#release-process
|
||||
# See also https://forgejo.org/docs/next/contributor/release/#stable-release-process
|
||||
#
|
||||
# https://codeberg.org/forgejo-integration/forgejo
|
||||
#
|
||||
|
|
|
@ -22,7 +22,7 @@ jobs:
|
|||
go-version-file: "go.mod"
|
||||
- run: |
|
||||
apt-get -qq update
|
||||
apt-get -qq install -q sudo
|
||||
apt-get -qq install -q sudo git git-lfs
|
||||
sed -i -e 's/%sudo.*/%sudo ALL=(ALL:ALL) NOPASSWD:ALL/' /etc/sudoers
|
||||
git config --add safe.directory '*'
|
||||
adduser --quiet --comment forgejo --disabled-password forgejo
|
||||
|
@ -30,6 +30,8 @@ jobs:
|
|||
chown -R forgejo:forgejo .
|
||||
- run: |
|
||||
su forgejo -c 'make deps-frontend frontend deps-backend'
|
||||
- run: |
|
||||
su forgejo -c 'make backend'
|
||||
- run: |
|
||||
su forgejo -c 'make generate test-e2e-sqlite'
|
||||
timeout-minutes: 40
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# SPDX-License-Identifier: MIT
|
||||
#
|
||||
# See also https://forgejo.org/docs/next/developer/RELEASE/#release-process
|
||||
# See also https://forgejo.org/docs/next/contributor/release/#stable-release-process
|
||||
#
|
||||
# https://codeberg.org/forgejo-experimental/forgejo
|
||||
#
|
||||
|
|
|
@ -23,7 +23,7 @@ jobs:
|
|||
|
||||
runs-on: docker
|
||||
container:
|
||||
image: code.forgejo.org/forgejo-contrib/renovate:38.39.6
|
||||
image: code.forgejo.org/forgejo-contrib/renovate:38.52.3
|
||||
|
||||
steps:
|
||||
- name: Load renovate repo cache
|
||||
|
|
|
@ -4,4 +4,4 @@ The Forgejo project is run by a community of people who are expected to follow t
|
|||
|
||||
Sensitive security-related issues should be reported to [security@forgejo.org](mailto:security@forgejo.org) using [encryption](https://keyoxide.org/security@forgejo.org).
|
||||
|
||||
You can find links to the different aspects of Developer documentation on this page: [Forgejo developer guide](https://forgejo.org/docs/next/developer/).
|
||||
You can find links to the different aspects of Developer documentation on this page: [Forgejo Contributor Guide](https://forgejo.org/docs/next/contributor/).
|
||||
|
|
2
Makefile
2
Makefile
|
@ -39,7 +39,7 @@ GOVULNCHECK_PACKAGE ?= golang.org/x/vuln/cmd/govulncheck@v1 # renovate: datasour
|
|||
DEADCODE_PACKAGE ?= golang.org/x/tools/cmd/deadcode@v0.24.0 # renovate: datasource=go
|
||||
GOMOCK_PACKAGE ?= go.uber.org/mock/mockgen@v0.4.0 # renovate: datasource=go
|
||||
GOPLS_PACKAGE ?= golang.org/x/tools/gopls@v0.16.1 # renovate: datasource=go
|
||||
RENOVATE_NPM_PACKAGE ?= renovate@38.39.6 # renovate: datasource=docker packageName=code.forgejo.org/forgejo-contrib/renovate
|
||||
RENOVATE_NPM_PACKAGE ?= renovate@38.52.3 # renovate: datasource=docker packageName=code.forgejo.org/forgejo-contrib/renovate
|
||||
|
||||
ifeq ($(HAS_GO), yes)
|
||||
CGO_EXTRA_CFLAGS := -DSQLITE_MAX_VARIABLE_NUMBER=32766
|
||||
|
|
25
assets/go-licenses.json
generated
25
assets/go-licenses.json
generated
File diff suppressed because one or more lines are too long
|
@ -20,7 +20,7 @@ import (
|
|||
"code.gitea.io/gitea/modules/storage"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
|
||||
"gitea.com/go-chi/session"
|
||||
"code.forgejo.org/go-chi/session"
|
||||
"github.com/mholt/archiver/v3"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
|
17
go.mod
17
go.mod
|
@ -5,6 +5,7 @@ go 1.23.0
|
|||
require (
|
||||
code.forgejo.org/f3/gof3/v3 v3.7.0
|
||||
code.forgejo.org/forgejo/reply v1.0.2
|
||||
code.forgejo.org/go-chi/session v0.0.0-20240825010209-bd25d509c8bf
|
||||
code.gitea.io/actions-proto-go v0.4.0
|
||||
code.gitea.io/gitea-vet v0.2.3
|
||||
code.gitea.io/sdk/gitea v0.17.1
|
||||
|
@ -13,7 +14,6 @@ require (
|
|||
gitea.com/go-chi/binding v0.0.0-20240430071103-39a851e106ed
|
||||
gitea.com/go-chi/cache v0.2.0
|
||||
gitea.com/go-chi/captcha v0.0.0-20240315150714-fb487f629098
|
||||
gitea.com/go-chi/session v0.0.0-20240316035857-16768d98ec96
|
||||
gitea.com/lunny/levelqueue v0.4.2-0.20230414023320-3c0159fe0fe4
|
||||
github.com/42wim/sshsig v0.0.0-20211121163825-841cf5bbc121
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358
|
||||
|
@ -37,7 +37,7 @@ require (
|
|||
github.com/gliderlabs/ssh v0.3.7
|
||||
github.com/go-ap/activitypub v0.0.0-20231114162308-e219254dc5c9
|
||||
github.com/go-ap/jsonld v0.0.0-20221030091449-f2a191312c73
|
||||
github.com/go-chi/chi/v5 v5.0.14
|
||||
github.com/go-chi/chi/v5 v5.1.0
|
||||
github.com/go-chi/cors v1.2.1
|
||||
github.com/go-co-op/gocron v1.37.0
|
||||
github.com/go-enry/go-enry/v2 v2.8.9
|
||||
|
@ -84,7 +84,7 @@ require (
|
|||
github.com/pquerna/otp v1.4.0
|
||||
github.com/prometheus/client_golang v1.18.0
|
||||
github.com/quasoft/websspi v1.1.2
|
||||
github.com/redis/go-redis/v9 v9.5.2
|
||||
github.com/redis/go-redis/v9 v9.6.1
|
||||
github.com/robfig/cron/v3 v3.0.1
|
||||
github.com/santhosh-tekuri/jsonschema/v6 v6.0.1
|
||||
github.com/sassoftware/go-rpmutils v0.4.0
|
||||
|
@ -161,9 +161,6 @@ require (
|
|||
github.com/cention-sany/utf7 v0.0.0-20170124080048-26cad61bd60a // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/cloudflare/circl v1.3.8 // indirect
|
||||
github.com/couchbase/go-couchbase v0.1.1 // indirect
|
||||
github.com/couchbase/gomemcached v0.3.0 // indirect
|
||||
github.com/couchbase/goutils v0.1.2 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect
|
||||
github.com/cyphar/filepath-securejoin v0.2.4 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
|
@ -300,12 +297,4 @@ replace github.com/shurcooL/vfsgen => github.com/lunny/vfsgen v0.0.0-20220105142
|
|||
|
||||
replace github.com/nektos/act => code.forgejo.org/forgejo/act v1.21.2
|
||||
|
||||
exclude github.com/gofrs/uuid v3.2.0+incompatible
|
||||
|
||||
exclude github.com/gofrs/uuid v4.0.0+incompatible
|
||||
|
||||
exclude github.com/goccy/go-json v0.4.11
|
||||
|
||||
exclude github.com/satori/go.uuid v1.2.0
|
||||
|
||||
replace github.com/mholt/archiver/v3 => code.forgejo.org/forgejo/archiver/v3 v3.5.1
|
||||
|
|
18
go.sum
18
go.sum
|
@ -8,6 +8,8 @@ code.forgejo.org/forgejo/archiver/v3 v3.5.1 h1:UmmbA7D5550uf71SQjarmrn6yKwOGxtEj
|
|||
code.forgejo.org/forgejo/archiver/v3 v3.5.1/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnonssnDhppzS1L4=
|
||||
code.forgejo.org/forgejo/reply v1.0.2 h1:dMhQCHV6/O3L5CLWNTol+dNzDAuyCK88z4J/lCdgFuQ=
|
||||
code.forgejo.org/forgejo/reply v1.0.2/go.mod h1:RyZUfzQLc+fuLIGjTSQWDAJWPiL4WtKXB/FifT5fM7U=
|
||||
code.forgejo.org/go-chi/session v0.0.0-20240825010209-bd25d509c8bf h1:gJRuqEPd3/U0/1YM+uSgbC/fpR8qrcMdvT6E7eSetyM=
|
||||
code.forgejo.org/go-chi/session v0.0.0-20240825010209-bd25d509c8bf/go.mod h1:PcnIg89MAhO1yExkw1QXXNDiPssVdCsMmwUo67g7GD4=
|
||||
code.gitea.io/actions-proto-go v0.4.0 h1:OsPBPhodXuQnsspG1sQ4eRE1PeoZyofd7+i73zCwnsU=
|
||||
code.gitea.io/actions-proto-go v0.4.0/go.mod h1:mn7Wkqz6JbnTOHQpot3yDeHx+O5C9EGhMEE+htvHBas=
|
||||
code.gitea.io/gitea-vet v0.2.3 h1:gdFmm6WOTM65rE8FUBTRzeQZYzXePKSSB1+r574hWwI=
|
||||
|
@ -30,8 +32,6 @@ gitea.com/go-chi/cache v0.2.0 h1:E0npuTfDW6CT1yD8NMDVc1SK6IeRjfmRL2zlEsCEd7w=
|
|||
gitea.com/go-chi/cache v0.2.0/go.mod h1:iQlVK2aKTZ/rE9UcHyz9pQWGvdP9i1eI2spOpzgCrtE=
|
||||
gitea.com/go-chi/captcha v0.0.0-20240315150714-fb487f629098 h1:p2ki+WK0cIeNQuqjR98IP2KZQKRzJJiV7aTeMAFwaWo=
|
||||
gitea.com/go-chi/captcha v0.0.0-20240315150714-fb487f629098/go.mod h1:LjzIOHlRemuUyO7WR12fmm18VZIlCAaOt9L3yKw40pk=
|
||||
gitea.com/go-chi/session v0.0.0-20240316035857-16768d98ec96 h1:IFDiMBObsP6CZIRaDLd54SR6zPYAffPXiXck5Xslu0Q=
|
||||
gitea.com/go-chi/session v0.0.0-20240316035857-16768d98ec96/go.mod h1:0iEpFKnwO5dG0aF98O4eq6FMsAiXkNBaDIlUOlq4BtM=
|
||||
gitea.com/lunny/levelqueue v0.4.2-0.20230414023320-3c0159fe0fe4 h1:IFT+hup2xejHqdhS7keYWioqfmxdnfblFDTGoOwcZ+o=
|
||||
gitea.com/lunny/levelqueue v0.4.2-0.20230414023320-3c0159fe0fe4/go.mod h1:HBqmLbz56JWpfEGG0prskAV97ATNRoj5LDmPicD22hU=
|
||||
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:lSA0F4e9A2NcQSqGqTOXqu2aRi/XEQxDCBwM8yJtE6s=
|
||||
|
@ -165,12 +165,6 @@ github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38
|
|||
github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
|
||||
github.com/cloudflare/circl v1.3.8 h1:j+V8jJt09PoeMFIu2uh5JUyEaIHTXVOHslFoLNAKqwI=
|
||||
github.com/cloudflare/circl v1.3.8/go.mod h1:PDRU+oXvdD7KCtgKxW95M5Z8BpSCJXQORiZFnBQS5QU=
|
||||
github.com/couchbase/go-couchbase v0.1.1 h1:ClFXELcKj/ojyoTYbsY34QUrrYCBi/1G749sXSCkdhk=
|
||||
github.com/couchbase/go-couchbase v0.1.1/go.mod h1:+/bddYDxXsf9qt0xpDUtRR47A2GjaXmGGAqQ/k3GJ8A=
|
||||
github.com/couchbase/gomemcached v0.3.0 h1:XkMDdP6w7rtvLijDE0/RhcccX+XvAk5cboyBv1YcI0U=
|
||||
github.com/couchbase/gomemcached v0.3.0/go.mod h1:mxliKQxOv84gQ0bJWbI+w9Wxdpt9HjDvgW9MjCym5Vo=
|
||||
github.com/couchbase/goutils v0.1.2 h1:gWr8B6XNWPIhfalHNog3qQKfGiYyh4K4VhO3P2o9BCs=
|
||||
github.com/couchbase/goutils v0.1.2/go.mod h1:h89Ek/tiOxxqjz30nPPlwZdQbdB8BwgnuBxeoUe/ViE=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
|
@ -244,8 +238,8 @@ github.com/go-ap/jsonld v0.0.0-20221030091449-f2a191312c73/go.mod h1:jyveZeGw5La
|
|||
github.com/go-asn1-ber/asn1-ber v1.5.5 h1:MNHlNMBDgEKD4TcKr36vQN68BA00aDfjIt3/bD50WnA=
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.5/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
|
||||
github.com/go-chi/chi/v5 v5.0.1/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
||||
github.com/go-chi/chi/v5 v5.0.14 h1:PyEwo2Vudraa0x/Wl6eDRRW2NXBvekgfxyydcM0WGE0=
|
||||
github.com/go-chi/chi/v5 v5.0.14/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
||||
github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw=
|
||||
github.com/go-chi/chi/v5 v5.1.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
||||
github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4=
|
||||
github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
|
||||
github.com/go-co-op/gocron v1.37.0 h1:ZYDJGtQ4OMhTLKOKMIch+/CY70Brbb1dGdooLEhh7b0=
|
||||
|
@ -608,8 +602,8 @@ github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k
|
|||
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
|
||||
github.com/quasoft/websspi v1.1.2 h1:/mA4w0LxWlE3novvsoEL6BBA1WnjJATbjkh1kFrTidw=
|
||||
github.com/quasoft/websspi v1.1.2/go.mod h1:HmVdl939dQ0WIXZhyik+ARdI03M6bQzaSEKcgpFmewk=
|
||||
github.com/redis/go-redis/v9 v9.5.2 h1:L0L3fcSNReTRGyZ6AqAEN0K56wYeYAwapBIhkvh0f3E=
|
||||
github.com/redis/go-redis/v9 v9.5.2/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M=
|
||||
github.com/redis/go-redis/v9 v9.6.1 h1:HHDteefn6ZkTtY5fGUE8tj8uy85AHk6zP7CpzIAM0y4=
|
||||
github.com/redis/go-redis/v9 v9.6.1/go.mod h1:0C0c6ycQsdpVNQpxb1njEQIqkx5UcsM8FJCQLgE9+RA=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
github.com/rhysd/actionlint v1.6.27 h1:xxwe8YmveBcC8lydW6GoHMGmB6H/MTqUU60F2p10wjw=
|
||||
|
|
25
models/quota/default.go
Normal file
25
models/quota/default.go
Normal file
|
@ -0,0 +1,25 @@
|
|||
// Copyright 2024 The Forgejo Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package quota
|
||||
|
||||
import (
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
)
|
||||
|
||||
func EvaluateDefault(used Used, forSubject LimitSubject) bool {
|
||||
groups := GroupList{
|
||||
&Group{
|
||||
Name: "builtin-default-group",
|
||||
Rules: []Rule{
|
||||
{
|
||||
Name: "builtin-default-rule",
|
||||
Limit: setting.Quota.Default.Total,
|
||||
Subjects: LimitSubjects{LimitSubjectSizeAll},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
return groups.Evaluate(used, forSubject)
|
||||
}
|
|
@ -230,9 +230,9 @@ func (g *Group) Evaluate(used Used, forSubject LimitSubject) (bool, bool) {
|
|||
}
|
||||
|
||||
func (gl *GroupList) Evaluate(used Used, forSubject LimitSubject) bool {
|
||||
// If there are no groups, default to success:
|
||||
// If there are no groups, use the configured defaults:
|
||||
if gl == nil || len(*gl) == 0 {
|
||||
return true
|
||||
return EvaluateDefault(used, forSubject)
|
||||
}
|
||||
|
||||
for _, group := range *gl {
|
||||
|
|
46
modules/git/batch.go
Normal file
46
modules/git/batch.go
Normal file
|
@ -0,0 +1,46 @@
|
|||
// Copyright 2024 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package git
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
)
|
||||
|
||||
type Batch struct {
|
||||
cancel context.CancelFunc
|
||||
Reader *bufio.Reader
|
||||
Writer WriteCloserError
|
||||
}
|
||||
|
||||
func (repo *Repository) NewBatch(ctx context.Context) (*Batch, error) {
|
||||
// Now because of some insanity with git cat-file not immediately failing if not run in a valid git directory we need to run git rev-parse first!
|
||||
if err := ensureValidGitRepository(ctx, repo.Path); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var batch Batch
|
||||
batch.Writer, batch.Reader, batch.cancel = catFileBatch(ctx, repo.Path)
|
||||
return &batch, nil
|
||||
}
|
||||
|
||||
func (repo *Repository) NewBatchCheck(ctx context.Context) (*Batch, error) {
|
||||
// Now because of some insanity with git cat-file not immediately failing if not run in a valid git directory we need to run git rev-parse first!
|
||||
if err := ensureValidGitRepository(ctx, repo.Path); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var check Batch
|
||||
check.Writer, check.Reader, check.cancel = catFileBatchCheck(ctx, repo.Path)
|
||||
return &check, nil
|
||||
}
|
||||
|
||||
func (b *Batch) Close() {
|
||||
if b.cancel != nil {
|
||||
b.cancel()
|
||||
b.Reader = nil
|
||||
b.Writer = nil
|
||||
b.cancel = nil
|
||||
}
|
||||
}
|
|
@ -26,10 +26,10 @@ type WriteCloserError interface {
|
|||
CloseWithError(err error) error
|
||||
}
|
||||
|
||||
// EnsureValidGitRepository runs git rev-parse in the repository path - thus ensuring that the repository is a valid repository.
|
||||
// ensureValidGitRepository runs git rev-parse in the repository path - thus ensuring that the repository is a valid repository.
|
||||
// Run before opening git cat-file.
|
||||
// This is needed otherwise the git cat-file will hang for invalid repositories.
|
||||
func EnsureValidGitRepository(ctx context.Context, repoPath string) error {
|
||||
func ensureValidGitRepository(ctx context.Context, repoPath string) error {
|
||||
stderr := strings.Builder{}
|
||||
err := NewCommand(ctx, "rev-parse").
|
||||
SetDescription(fmt.Sprintf("%s rev-parse [repo_path: %s]", GitExecutable, repoPath)).
|
||||
|
@ -43,8 +43,8 @@ func EnsureValidGitRepository(ctx context.Context, repoPath string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// CatFileBatchCheck opens git cat-file --batch-check in the provided repo and returns a stdin pipe, a stdout reader and cancel function
|
||||
func CatFileBatchCheck(ctx context.Context, repoPath string) (WriteCloserError, *bufio.Reader, func()) {
|
||||
// catFileBatchCheck opens git cat-file --batch-check in the provided repo and returns a stdin pipe, a stdout reader and cancel function
|
||||
func catFileBatchCheck(ctx context.Context, repoPath string) (WriteCloserError, *bufio.Reader, func()) {
|
||||
batchStdinReader, batchStdinWriter := io.Pipe()
|
||||
batchStdoutReader, batchStdoutWriter := io.Pipe()
|
||||
ctx, ctxCancel := context.WithCancel(ctx)
|
||||
|
@ -93,8 +93,8 @@ func CatFileBatchCheck(ctx context.Context, repoPath string) (WriteCloserError,
|
|||
return batchStdinWriter, batchReader, cancel
|
||||
}
|
||||
|
||||
// CatFileBatch opens git cat-file --batch in the provided repo and returns a stdin pipe, a stdout reader and cancel function
|
||||
func CatFileBatch(ctx context.Context, repoPath string) (WriteCloserError, *bufio.Reader, func()) {
|
||||
// catFileBatch opens git cat-file --batch in the provided repo and returns a stdin pipe, a stdout reader and cancel function
|
||||
func catFileBatch(ctx context.Context, repoPath string) (WriteCloserError, *bufio.Reader, func()) {
|
||||
// We often want to feed the commits in order into cat-file --batch, followed by their trees and sub trees as necessary.
|
||||
// so let's create a batch stdin and stdout
|
||||
batchStdinReader, batchStdinWriter := io.Pipe()
|
||||
|
|
|
@ -28,9 +28,12 @@ type Blob struct {
|
|||
// DataAsync gets a ReadCloser for the contents of a blob without reading it all.
|
||||
// Calling the Close function on the result will discard all unread output.
|
||||
func (b *Blob) DataAsync() (io.ReadCloser, error) {
|
||||
wr, rd, cancel := b.repo.CatFileBatch(b.repo.Ctx)
|
||||
wr, rd, cancel, err := b.repo.CatFileBatch(b.repo.Ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, err := wr.Write([]byte(b.ID.String() + "\n"))
|
||||
_, err = wr.Write([]byte(b.ID.String() + "\n"))
|
||||
if err != nil {
|
||||
cancel()
|
||||
return nil, err
|
||||
|
@ -66,9 +69,13 @@ func (b *Blob) Size() int64 {
|
|||
return b.size
|
||||
}
|
||||
|
||||
wr, rd, cancel := b.repo.CatFileBatchCheck(b.repo.Ctx)
|
||||
wr, rd, cancel, err := b.repo.CatFileBatchCheck(b.repo.Ctx)
|
||||
if err != nil {
|
||||
log.Debug("error whilst reading size for %s in %s. Error: %v", b.ID.String(), b.repo.Path, err)
|
||||
return 0
|
||||
}
|
||||
defer cancel()
|
||||
_, err := wr.Write([]byte(b.ID.String() + "\n"))
|
||||
_, err = wr.Write([]byte(b.ID.String() + "\n"))
|
||||
if err != nil {
|
||||
log.Debug("error whilst reading size for %s in %s. Error: %v", b.ID.String(), b.repo.Path, err)
|
||||
return 0
|
||||
|
|
|
@ -129,7 +129,10 @@ func GetLastCommitForPaths(ctx context.Context, commit *Commit, treePath string,
|
|||
return nil, err
|
||||
}
|
||||
|
||||
batchStdinWriter, batchReader, cancel := commit.repo.CatFileBatch(ctx)
|
||||
batchStdinWriter, batchReader, cancel, err := commit.repo.CatFileBatch(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer cancel()
|
||||
|
||||
commitsMap := map[string]*Commit{}
|
||||
|
|
|
@ -38,6 +38,8 @@ var (
|
|||
InvertedGitFlushEnv bool // 2.43.1
|
||||
SupportCheckAttrOnBare bool // >= 2.40
|
||||
|
||||
HasSSHExecutable bool
|
||||
|
||||
gitVersion *version.Version
|
||||
)
|
||||
|
||||
|
@ -203,6 +205,10 @@ func InitFull(ctx context.Context) (err error) {
|
|||
globalCommandArgs = append(globalCommandArgs, "-c", "filter.lfs.required=", "-c", "filter.lfs.smudge=", "-c", "filter.lfs.clean=")
|
||||
}
|
||||
|
||||
// Detect the presence of the ssh executable in $PATH.
|
||||
_, err = exec.LookPath("ssh")
|
||||
HasSSHExecutable = err == nil
|
||||
|
||||
return syncGitConfig()
|
||||
}
|
||||
|
||||
|
|
|
@ -67,7 +67,10 @@ func FindLFSFile(repo *git.Repository, objectID git.ObjectID) ([]*LFSResult, err
|
|||
|
||||
// Next feed the commits in order into cat-file --batch, followed by their trees and sub trees as necessary.
|
||||
// so let's create a batch stdin and stdout
|
||||
batchStdinWriter, batchReader, cancel := repo.CatFileBatch(repo.Ctx)
|
||||
batchStdinWriter, batchReader, cancel, err := repo.CatFileBatch(repo.Ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer cancel()
|
||||
|
||||
// We'll use a scanner for the revList because it's simpler than a bufio.Reader
|
||||
|
|
|
@ -21,15 +21,11 @@ type Repository struct {
|
|||
|
||||
gpgSettings *GPGSettings
|
||||
|
||||
batchInUse bool
|
||||
batchCancel context.CancelFunc
|
||||
batchReader *bufio.Reader
|
||||
batchWriter WriteCloserError
|
||||
batchInUse bool
|
||||
batch *Batch
|
||||
|
||||
checkInUse bool
|
||||
checkCancel context.CancelFunc
|
||||
checkReader *bufio.Reader
|
||||
checkWriter WriteCloserError
|
||||
checkInUse bool
|
||||
check *Batch
|
||||
|
||||
Ctx context.Context
|
||||
LastCommitCache *LastCommitCache
|
||||
|
@ -51,63 +47,75 @@ func OpenRepository(ctx context.Context, repoPath string) (*Repository, error) {
|
|||
return nil, errors.New("no such file or directory")
|
||||
}
|
||||
|
||||
// Now because of some insanity with git cat-file not immediately failing if not run in a valid git directory we need to run git rev-parse first!
|
||||
if err := EnsureValidGitRepository(ctx, repoPath); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
repo := &Repository{
|
||||
return &Repository{
|
||||
Path: repoPath,
|
||||
tagCache: newObjectCache(),
|
||||
Ctx: ctx,
|
||||
}
|
||||
|
||||
repo.batchWriter, repo.batchReader, repo.batchCancel = CatFileBatch(ctx, repoPath)
|
||||
repo.checkWriter, repo.checkReader, repo.checkCancel = CatFileBatchCheck(ctx, repoPath)
|
||||
|
||||
return repo, nil
|
||||
}, nil
|
||||
}
|
||||
|
||||
// CatFileBatch obtains a CatFileBatch for this repository
|
||||
func (repo *Repository) CatFileBatch(ctx context.Context) (WriteCloserError, *bufio.Reader, func()) {
|
||||
if repo.batchCancel == nil || repo.batchInUse {
|
||||
log.Debug("Opening temporary cat file batch for: %s", repo.Path)
|
||||
return CatFileBatch(ctx, repo.Path)
|
||||
func (repo *Repository) CatFileBatch(ctx context.Context) (WriteCloserError, *bufio.Reader, func(), error) {
|
||||
if repo.batch == nil {
|
||||
var err error
|
||||
repo.batch, err = repo.NewBatch(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
}
|
||||
repo.batchInUse = true
|
||||
return repo.batchWriter, repo.batchReader, func() {
|
||||
repo.batchInUse = false
|
||||
|
||||
if !repo.batchInUse {
|
||||
repo.batchInUse = true
|
||||
return repo.batch.Writer, repo.batch.Reader, func() {
|
||||
repo.batchInUse = false
|
||||
}, nil
|
||||
}
|
||||
|
||||
log.Debug("Opening temporary cat file batch for: %s", repo.Path)
|
||||
tempBatch, err := repo.NewBatch(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
return tempBatch.Writer, tempBatch.Reader, tempBatch.Close, nil
|
||||
}
|
||||
|
||||
// CatFileBatchCheck obtains a CatFileBatchCheck for this repository
|
||||
func (repo *Repository) CatFileBatchCheck(ctx context.Context) (WriteCloserError, *bufio.Reader, func()) {
|
||||
if repo.checkCancel == nil || repo.checkInUse {
|
||||
log.Debug("Opening temporary cat file batch-check for: %s", repo.Path)
|
||||
return CatFileBatchCheck(ctx, repo.Path)
|
||||
func (repo *Repository) CatFileBatchCheck(ctx context.Context) (WriteCloserError, *bufio.Reader, func(), error) {
|
||||
if repo.check == nil {
|
||||
var err error
|
||||
repo.check, err = repo.NewBatchCheck(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
}
|
||||
repo.checkInUse = true
|
||||
return repo.checkWriter, repo.checkReader, func() {
|
||||
repo.checkInUse = false
|
||||
|
||||
if !repo.checkInUse {
|
||||
repo.checkInUse = true
|
||||
return repo.check.Writer, repo.check.Reader, func() {
|
||||
repo.checkInUse = false
|
||||
}, nil
|
||||
}
|
||||
|
||||
log.Debug("Opening temporary cat file batch-check for: %s", repo.Path)
|
||||
tempBatchCheck, err := repo.NewBatchCheck(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
return tempBatchCheck.Writer, tempBatchCheck.Reader, tempBatchCheck.Close, nil
|
||||
}
|
||||
|
||||
func (repo *Repository) Close() error {
|
||||
if repo == nil {
|
||||
return nil
|
||||
}
|
||||
if repo.batchCancel != nil {
|
||||
repo.batchCancel()
|
||||
repo.batchReader = nil
|
||||
repo.batchWriter = nil
|
||||
repo.batchCancel = nil
|
||||
if repo.batch != nil {
|
||||
repo.batch.Close()
|
||||
repo.batch = nil
|
||||
repo.batchInUse = false
|
||||
}
|
||||
if repo.checkCancel != nil {
|
||||
repo.checkCancel()
|
||||
repo.checkCancel = nil
|
||||
repo.checkReader = nil
|
||||
repo.checkWriter = nil
|
||||
if repo.check != nil {
|
||||
repo.check.Close()
|
||||
repo.check = nil
|
||||
repo.checkInUse = false
|
||||
}
|
||||
repo.LastCommitCache = nil
|
||||
|
|
163
modules/git/repo_base_test.go
Normal file
163
modules/git/repo_base_test.go
Normal file
|
@ -0,0 +1,163 @@
|
|||
// Copyright 2024 The Forgejo Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package git
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// This unit test relies on the implementation detail of CatFileBatch.
|
||||
func TestCatFileBatch(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
repo, err := OpenRepository(ctx, "./tests/repos/repo1_bare")
|
||||
require.NoError(t, err)
|
||||
defer repo.Close()
|
||||
|
||||
var wr WriteCloserError
|
||||
var r *bufio.Reader
|
||||
var cancel1 func()
|
||||
t.Run("Request cat file batch", func(t *testing.T) {
|
||||
assert.Nil(t, repo.batch)
|
||||
wr, r, cancel1, err = repo.CatFileBatch(ctx)
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, repo.batch)
|
||||
assert.Equal(t, repo.batch.Writer, wr)
|
||||
assert.True(t, repo.batchInUse)
|
||||
})
|
||||
|
||||
t.Run("Request temporary cat file batch", func(t *testing.T) {
|
||||
wr, r, cancel, err := repo.CatFileBatch(ctx)
|
||||
require.NoError(t, err)
|
||||
assert.NotEqual(t, repo.batch.Writer, wr)
|
||||
|
||||
t.Run("Check temporary cat file batch", func(t *testing.T) {
|
||||
_, err = wr.Write([]byte("95bb4d39648ee7e325106df01a621c530863a653" + "\n"))
|
||||
require.NoError(t, err)
|
||||
|
||||
sha, typ, size, err := ReadBatchLine(r)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "commit", typ)
|
||||
assert.EqualValues(t, []byte("95bb4d39648ee7e325106df01a621c530863a653"), sha)
|
||||
assert.EqualValues(t, 144, size)
|
||||
})
|
||||
|
||||
cancel()
|
||||
assert.True(t, repo.batchInUse)
|
||||
})
|
||||
|
||||
t.Run("Check cached cat file batch", func(t *testing.T) {
|
||||
_, err = wr.Write([]byte("95bb4d39648ee7e325106df01a621c530863a653" + "\n"))
|
||||
require.NoError(t, err)
|
||||
|
||||
sha, typ, size, err := ReadBatchLine(r)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "commit", typ)
|
||||
assert.EqualValues(t, []byte("95bb4d39648ee7e325106df01a621c530863a653"), sha)
|
||||
assert.EqualValues(t, 144, size)
|
||||
})
|
||||
|
||||
t.Run("Cancel cached cat file batch", func(t *testing.T) {
|
||||
cancel1()
|
||||
assert.False(t, repo.batchInUse)
|
||||
assert.NotNil(t, repo.batch)
|
||||
})
|
||||
|
||||
t.Run("Request cached cat file batch", func(t *testing.T) {
|
||||
wr, _, _, err := repo.CatFileBatch(ctx)
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, repo.batch)
|
||||
assert.Equal(t, repo.batch.Writer, wr)
|
||||
assert.True(t, repo.batchInUse)
|
||||
|
||||
t.Run("Close git repo", func(t *testing.T) {
|
||||
require.NoError(t, repo.Close())
|
||||
assert.Nil(t, repo.batch)
|
||||
})
|
||||
|
||||
_, err = wr.Write([]byte("95bb4d39648ee7e325106df01a621c530863a653" + "\n"))
|
||||
require.Error(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
// This unit test relies on the implementation detail of CatFileBatchCheck.
|
||||
func TestCatFileBatchCheck(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
repo, err := OpenRepository(ctx, "./tests/repos/repo1_bare")
|
||||
require.NoError(t, err)
|
||||
defer repo.Close()
|
||||
|
||||
var wr WriteCloserError
|
||||
var r *bufio.Reader
|
||||
var cancel1 func()
|
||||
t.Run("Request cat file batch check", func(t *testing.T) {
|
||||
assert.Nil(t, repo.check)
|
||||
wr, r, cancel1, err = repo.CatFileBatchCheck(ctx)
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, repo.check)
|
||||
assert.Equal(t, repo.check.Writer, wr)
|
||||
assert.True(t, repo.checkInUse)
|
||||
})
|
||||
|
||||
t.Run("Request temporary cat file batch check", func(t *testing.T) {
|
||||
wr, r, cancel, err := repo.CatFileBatchCheck(ctx)
|
||||
require.NoError(t, err)
|
||||
assert.NotEqual(t, repo.check.Writer, wr)
|
||||
|
||||
t.Run("Check temporary cat file batch check", func(t *testing.T) {
|
||||
_, err = wr.Write([]byte("test" + "\n"))
|
||||
require.NoError(t, err)
|
||||
|
||||
sha, typ, size, err := ReadBatchLine(r)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "tag", typ)
|
||||
assert.EqualValues(t, []byte("3ad28a9149a2864384548f3d17ed7f38014c9e8a"), sha)
|
||||
assert.EqualValues(t, 807, size)
|
||||
})
|
||||
|
||||
cancel()
|
||||
assert.True(t, repo.checkInUse)
|
||||
})
|
||||
|
||||
t.Run("Check cached cat file batch check", func(t *testing.T) {
|
||||
_, err = wr.Write([]byte("test" + "\n"))
|
||||
require.NoError(t, err)
|
||||
|
||||
sha, typ, size, err := ReadBatchLine(r)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "tag", typ)
|
||||
assert.EqualValues(t, []byte("3ad28a9149a2864384548f3d17ed7f38014c9e8a"), sha)
|
||||
assert.EqualValues(t, 807, size)
|
||||
})
|
||||
|
||||
t.Run("Cancel cached cat file batch check", func(t *testing.T) {
|
||||
cancel1()
|
||||
assert.False(t, repo.checkInUse)
|
||||
assert.NotNil(t, repo.check)
|
||||
})
|
||||
|
||||
t.Run("Request cached cat file batch check", func(t *testing.T) {
|
||||
wr, _, _, err := repo.CatFileBatchCheck(ctx)
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, repo.check)
|
||||
assert.Equal(t, repo.check.Writer, wr)
|
||||
assert.True(t, repo.checkInUse)
|
||||
|
||||
t.Run("Close git repo", func(t *testing.T) {
|
||||
require.NoError(t, repo.Close())
|
||||
assert.Nil(t, repo.check)
|
||||
})
|
||||
|
||||
_, err = wr.Write([]byte("test" + "\n"))
|
||||
require.Error(t, err)
|
||||
})
|
||||
}
|
|
@ -169,9 +169,13 @@ func (repo *Repository) IsObjectExist(name string) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
wr, rd, cancel := repo.CatFileBatchCheck(repo.Ctx)
|
||||
wr, rd, cancel, err := repo.CatFileBatchCheck(repo.Ctx)
|
||||
if err != nil {
|
||||
log.Debug("Error writing to CatFileBatchCheck %v", err)
|
||||
return false
|
||||
}
|
||||
defer cancel()
|
||||
_, err := wr.Write([]byte(name + "\n"))
|
||||
_, err = wr.Write([]byte(name + "\n"))
|
||||
if err != nil {
|
||||
log.Debug("Error writing to CatFileBatchCheck %v", err)
|
||||
return false
|
||||
|
@ -186,9 +190,13 @@ func (repo *Repository) IsReferenceExist(name string) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
wr, rd, cancel := repo.CatFileBatchCheck(repo.Ctx)
|
||||
wr, rd, cancel, err := repo.CatFileBatchCheck(repo.Ctx)
|
||||
if err != nil {
|
||||
log.Debug("Error writing to CatFileBatchCheck %v", err)
|
||||
return false
|
||||
}
|
||||
defer cancel()
|
||||
_, err := wr.Write([]byte(name + "\n"))
|
||||
_, err = wr.Write([]byte(name + "\n"))
|
||||
if err != nil {
|
||||
log.Debug("Error writing to CatFileBatchCheck %v", err)
|
||||
return false
|
||||
|
|
|
@ -536,9 +536,12 @@ func (repo *Repository) ResolveReference(name string) (string, error) {
|
|||
|
||||
// GetRefCommitID returns the last commit ID string of given reference (branch or tag).
|
||||
func (repo *Repository) GetRefCommitID(name string) (string, error) {
|
||||
wr, rd, cancel := repo.CatFileBatchCheck(repo.Ctx)
|
||||
wr, rd, cancel, err := repo.CatFileBatchCheck(repo.Ctx)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer cancel()
|
||||
_, err := wr.Write([]byte(name + "\n"))
|
||||
_, err = wr.Write([]byte(name + "\n"))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -564,12 +567,19 @@ func (repo *Repository) RemoveReference(name string) error {
|
|||
|
||||
// IsCommitExist returns true if given commit exists in current repository.
|
||||
func (repo *Repository) IsCommitExist(name string) bool {
|
||||
if err := ensureValidGitRepository(repo.Ctx, repo.Path); err != nil {
|
||||
log.Error("IsCommitExist: %v", err)
|
||||
return false
|
||||
}
|
||||
_, _, err := NewCommand(repo.Ctx, "cat-file", "-e").AddDynamicArguments(name).RunStdString(&RunOpts{Dir: repo.Path})
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func (repo *Repository) getCommit(id ObjectID) (*Commit, error) {
|
||||
wr, rd, cancel := repo.CatFileBatch(repo.Ctx)
|
||||
wr, rd, cancel, err := repo.CatFileBatch(repo.Ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer cancel()
|
||||
|
||||
_, _ = wr.Write([]byte(id.String() + "\n"))
|
||||
|
@ -646,7 +656,10 @@ func (repo *Repository) ConvertToGitID(commitID string) (ObjectID, error) {
|
|||
}
|
||||
}
|
||||
|
||||
wr, rd, cancel := repo.CatFileBatchCheck(repo.Ctx)
|
||||
wr, rd, cancel, err := repo.CatFileBatchCheck(repo.Ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer cancel()
|
||||
_, err = wr.Write([]byte(commitID + "\n"))
|
||||
if err != nil {
|
||||
|
|
|
@ -60,7 +60,10 @@ func mergeLanguageStats(stats map[string]int64) map[string]int64 {
|
|||
func (repo *Repository) GetLanguageStats(commitID string) (map[string]int64, error) {
|
||||
// We will feed the commit IDs in order into cat-file --batch, followed by blobs as necessary.
|
||||
// so let's create a batch stdin and stdout
|
||||
batchStdinWriter, batchReader, cancel := repo.CatFileBatch(repo.Ctx)
|
||||
batchStdinWriter, batchReader, cancel, err := repo.CatFileBatch(repo.Ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer cancel()
|
||||
|
||||
writeID := func(id string) error {
|
||||
|
|
|
@ -257,9 +257,12 @@ func (repo *Repository) GetTags(skip, limit int) (tags []string, err error) {
|
|||
|
||||
// GetTagType gets the type of the tag, either commit (simple) or tag (annotated)
|
||||
func (repo *Repository) GetTagType(id ObjectID) (string, error) {
|
||||
wr, rd, cancel := repo.CatFileBatchCheck(repo.Ctx)
|
||||
wr, rd, cancel, err := repo.CatFileBatchCheck(repo.Ctx)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer cancel()
|
||||
_, err := wr.Write([]byte(id.String() + "\n"))
|
||||
_, err = wr.Write([]byte(id.String() + "\n"))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -315,7 +318,10 @@ func (repo *Repository) getTag(tagID ObjectID, name string) (*Tag, error) {
|
|||
}
|
||||
|
||||
// The tag is an annotated tag with a message.
|
||||
wr, rd, cancel := repo.CatFileBatch(repo.Ctx)
|
||||
wr, rd, cancel, err := repo.CatFileBatch(repo.Ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer cancel()
|
||||
|
||||
if _, err := wr.Write([]byte(tagID.String() + "\n")); err != nil {
|
||||
|
|
|
@ -68,7 +68,10 @@ func (repo *Repository) CommitTree(author, committer *Signature, tree *Tree, opt
|
|||
}
|
||||
|
||||
func (repo *Repository) getTree(id ObjectID) (*Tree, error) {
|
||||
wr, rd, cancel := repo.CatFileBatch(repo.Ctx)
|
||||
wr, rd, cancel, err := repo.CatFileBatch(repo.Ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer cancel()
|
||||
|
||||
_, _ = wr.Write([]byte(id.String() + "\n"))
|
||||
|
|
|
@ -41,7 +41,10 @@ func (t *Tree) ListEntries() (Entries, error) {
|
|||
}
|
||||
|
||||
if t.repo != nil {
|
||||
wr, rd, cancel := t.repo.CatFileBatch(t.repo.Ctx)
|
||||
wr, rd, cancel, err := t.repo.CatFileBatch(t.repo.Ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer cancel()
|
||||
|
||||
_, _ = wr.Write([]byte(t.ID.String() + "\n"))
|
||||
|
|
|
@ -47,9 +47,13 @@ func (te *TreeEntry) Size() int64 {
|
|||
return te.size
|
||||
}
|
||||
|
||||
wr, rd, cancel := te.ptree.repo.CatFileBatchCheck(te.ptree.repo.Ctx)
|
||||
wr, rd, cancel, err := te.ptree.repo.CatFileBatchCheck(te.ptree.repo.Ctx)
|
||||
if err != nil {
|
||||
log.Debug("error whilst reading size for %s in %s. Error: %v", te.ID.String(), te.ptree.repo.Path, err)
|
||||
return 0
|
||||
}
|
||||
defer cancel()
|
||||
_, err := wr.Write([]byte(te.ID.String() + "\n"))
|
||||
_, err = wr.Write([]byte(te.ID.String() + "\n"))
|
||||
if err != nil {
|
||||
log.Debug("error whilst reading size for %s in %s. Error: %v", te.ID.String(), te.ptree.repo.Path, err)
|
||||
return 0
|
||||
|
|
|
@ -16,10 +16,10 @@ import (
|
|||
"code.gitea.io/gitea/modules/analyze"
|
||||
"code.gitea.io/gitea/modules/charset"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/gitrepo"
|
||||
"code.gitea.io/gitea/modules/indexer/code/internal"
|
||||
indexer_internal "code.gitea.io/gitea/modules/indexer/internal"
|
||||
inner_bleve "code.gitea.io/gitea/modules/indexer/internal/bleve"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
"code.gitea.io/gitea/modules/typesniffer"
|
||||
|
@ -193,21 +193,23 @@ func (b *Indexer) addDelete(filename string, repo *repo_model.Repository, batch
|
|||
func (b *Indexer) Index(ctx context.Context, repo *repo_model.Repository, sha string, changes *internal.RepoChanges) error {
|
||||
batch := inner_bleve.NewFlushingBatch(b.inner.Indexer, maxBatchSize)
|
||||
if len(changes.Updates) > 0 {
|
||||
// Now because of some insanity with git cat-file not immediately failing if not run in a valid git directory we need to run git rev-parse first!
|
||||
if err := git.EnsureValidGitRepository(ctx, repo.RepoPath()); err != nil {
|
||||
log.Error("Unable to open git repo: %s for %-v: %v", repo.RepoPath(), repo, err)
|
||||
r, err := gitrepo.OpenRepository(ctx, repo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
batchWriter, batchReader, cancel := git.CatFileBatch(ctx, repo.RepoPath())
|
||||
defer cancel()
|
||||
defer r.Close()
|
||||
gitBatch, err := r.NewBatch(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer gitBatch.Close()
|
||||
|
||||
for _, update := range changes.Updates {
|
||||
if err := b.addUpdate(ctx, batchWriter, batchReader, sha, update, repo, batch); err != nil {
|
||||
if err := b.addUpdate(ctx, gitBatch.Writer, gitBatch.Reader, sha, update, repo, batch); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
cancel()
|
||||
gitBatch.Close()
|
||||
}
|
||||
for _, filename := range changes.RemovedFilenames {
|
||||
if err := b.addDelete(filename, repo, batch); err != nil {
|
||||
|
|
|
@ -15,11 +15,11 @@ import (
|
|||
"code.gitea.io/gitea/modules/analyze"
|
||||
"code.gitea.io/gitea/modules/charset"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/gitrepo"
|
||||
"code.gitea.io/gitea/modules/indexer/code/internal"
|
||||
indexer_internal "code.gitea.io/gitea/modules/indexer/internal"
|
||||
inner_elasticsearch "code.gitea.io/gitea/modules/indexer/internal/elasticsearch"
|
||||
"code.gitea.io/gitea/modules/json"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
"code.gitea.io/gitea/modules/typesniffer"
|
||||
|
@ -154,17 +154,19 @@ func (b *Indexer) addDelete(filename string, repo *repo_model.Repository) elasti
|
|||
func (b *Indexer) Index(ctx context.Context, repo *repo_model.Repository, sha string, changes *internal.RepoChanges) error {
|
||||
reqs := make([]elastic.BulkableRequest, 0)
|
||||
if len(changes.Updates) > 0 {
|
||||
// Now because of some insanity with git cat-file not immediately failing if not run in a valid git directory we need to run git rev-parse first!
|
||||
if err := git.EnsureValidGitRepository(ctx, repo.RepoPath()); err != nil {
|
||||
log.Error("Unable to open git repo: %s for %-v: %v", repo.RepoPath(), repo, err)
|
||||
r, err := gitrepo.OpenRepository(ctx, repo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
batchWriter, batchReader, cancel := git.CatFileBatch(ctx, repo.RepoPath())
|
||||
defer cancel()
|
||||
defer r.Close()
|
||||
batch, err := r.NewBatch(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer batch.Close()
|
||||
|
||||
for _, update := range changes.Updates {
|
||||
updateReqs, err := b.addUpdate(ctx, batchWriter, batchReader, sha, update, repo)
|
||||
updateReqs, err := b.addUpdate(ctx, batch.Writer, batch.Reader, sha, update, repo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -172,7 +174,7 @@ func (b *Indexer) Index(ctx context.Context, repo *repo_model.Repository, sha st
|
|||
reqs = append(reqs, updateReqs...)
|
||||
}
|
||||
}
|
||||
cancel()
|
||||
batch.Close()
|
||||
}
|
||||
|
||||
for _, filename := range changes.RemovedFilenames {
|
||||
|
|
|
@ -2540,6 +2540,101 @@ func (mr *MockUniversalClientMockRecorder) HExists(arg0, arg1, arg2 any) *gomock
|
|||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HExists", reflect.TypeOf((*MockUniversalClient)(nil).HExists), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// HExpire mocks base method.
|
||||
func (m *MockUniversalClient) HExpire(arg0 context.Context, arg1 string, arg2 time.Duration, arg3 ...string) *redis.IntSliceCmd {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []any{arg0, arg1, arg2}
|
||||
for _, a := range arg3 {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
ret := m.ctrl.Call(m, "HExpire", varargs...)
|
||||
ret0, _ := ret[0].(*redis.IntSliceCmd)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// HExpire indicates an expected call of HExpire.
|
||||
func (mr *MockUniversalClientMockRecorder) HExpire(arg0, arg1, arg2 any, arg3 ...any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
varargs := append([]any{arg0, arg1, arg2}, arg3...)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HExpire", reflect.TypeOf((*MockUniversalClient)(nil).HExpire), varargs...)
|
||||
}
|
||||
|
||||
// HExpireAt mocks base method.
|
||||
func (m *MockUniversalClient) HExpireAt(arg0 context.Context, arg1 string, arg2 time.Time, arg3 ...string) *redis.IntSliceCmd {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []any{arg0, arg1, arg2}
|
||||
for _, a := range arg3 {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
ret := m.ctrl.Call(m, "HExpireAt", varargs...)
|
||||
ret0, _ := ret[0].(*redis.IntSliceCmd)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// HExpireAt indicates an expected call of HExpireAt.
|
||||
func (mr *MockUniversalClientMockRecorder) HExpireAt(arg0, arg1, arg2 any, arg3 ...any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
varargs := append([]any{arg0, arg1, arg2}, arg3...)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HExpireAt", reflect.TypeOf((*MockUniversalClient)(nil).HExpireAt), varargs...)
|
||||
}
|
||||
|
||||
// HExpireAtWithArgs mocks base method.
|
||||
func (m *MockUniversalClient) HExpireAtWithArgs(arg0 context.Context, arg1 string, arg2 time.Time, arg3 redis.HExpireArgs, arg4 ...string) *redis.IntSliceCmd {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []any{arg0, arg1, arg2, arg3}
|
||||
for _, a := range arg4 {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
ret := m.ctrl.Call(m, "HExpireAtWithArgs", varargs...)
|
||||
ret0, _ := ret[0].(*redis.IntSliceCmd)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// HExpireAtWithArgs indicates an expected call of HExpireAtWithArgs.
|
||||
func (mr *MockUniversalClientMockRecorder) HExpireAtWithArgs(arg0, arg1, arg2, arg3 any, arg4 ...any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
varargs := append([]any{arg0, arg1, arg2, arg3}, arg4...)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HExpireAtWithArgs", reflect.TypeOf((*MockUniversalClient)(nil).HExpireAtWithArgs), varargs...)
|
||||
}
|
||||
|
||||
// HExpireTime mocks base method.
|
||||
func (m *MockUniversalClient) HExpireTime(arg0 context.Context, arg1 string, arg2 ...string) *redis.IntSliceCmd {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []any{arg0, arg1}
|
||||
for _, a := range arg2 {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
ret := m.ctrl.Call(m, "HExpireTime", varargs...)
|
||||
ret0, _ := ret[0].(*redis.IntSliceCmd)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// HExpireTime indicates an expected call of HExpireTime.
|
||||
func (mr *MockUniversalClientMockRecorder) HExpireTime(arg0, arg1 any, arg2 ...any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
varargs := append([]any{arg0, arg1}, arg2...)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HExpireTime", reflect.TypeOf((*MockUniversalClient)(nil).HExpireTime), varargs...)
|
||||
}
|
||||
|
||||
// HExpireWithArgs mocks base method.
|
||||
func (m *MockUniversalClient) HExpireWithArgs(arg0 context.Context, arg1 string, arg2 time.Duration, arg3 redis.HExpireArgs, arg4 ...string) *redis.IntSliceCmd {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []any{arg0, arg1, arg2, arg3}
|
||||
for _, a := range arg4 {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
ret := m.ctrl.Call(m, "HExpireWithArgs", varargs...)
|
||||
ret0, _ := ret[0].(*redis.IntSliceCmd)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// HExpireWithArgs indicates an expected call of HExpireWithArgs.
|
||||
func (mr *MockUniversalClientMockRecorder) HExpireWithArgs(arg0, arg1, arg2, arg3 any, arg4 ...any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
varargs := append([]any{arg0, arg1, arg2, arg3}, arg4...)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HExpireWithArgs", reflect.TypeOf((*MockUniversalClient)(nil).HExpireWithArgs), varargs...)
|
||||
}
|
||||
|
||||
// HGet mocks base method.
|
||||
func (m *MockUniversalClient) HGet(arg0 context.Context, arg1, arg2 string) *redis.StringCmd {
|
||||
m.ctrl.T.Helper()
|
||||
|
@ -2662,6 +2757,139 @@ func (mr *MockUniversalClientMockRecorder) HMSet(arg0, arg1 any, arg2 ...any) *g
|
|||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HMSet", reflect.TypeOf((*MockUniversalClient)(nil).HMSet), varargs...)
|
||||
}
|
||||
|
||||
// HPExpire mocks base method.
|
||||
func (m *MockUniversalClient) HPExpire(arg0 context.Context, arg1 string, arg2 time.Duration, arg3 ...string) *redis.IntSliceCmd {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []any{arg0, arg1, arg2}
|
||||
for _, a := range arg3 {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
ret := m.ctrl.Call(m, "HPExpire", varargs...)
|
||||
ret0, _ := ret[0].(*redis.IntSliceCmd)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// HPExpire indicates an expected call of HPExpire.
|
||||
func (mr *MockUniversalClientMockRecorder) HPExpire(arg0, arg1, arg2 any, arg3 ...any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
varargs := append([]any{arg0, arg1, arg2}, arg3...)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HPExpire", reflect.TypeOf((*MockUniversalClient)(nil).HPExpire), varargs...)
|
||||
}
|
||||
|
||||
// HPExpireAt mocks base method.
|
||||
func (m *MockUniversalClient) HPExpireAt(arg0 context.Context, arg1 string, arg2 time.Time, arg3 ...string) *redis.IntSliceCmd {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []any{arg0, arg1, arg2}
|
||||
for _, a := range arg3 {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
ret := m.ctrl.Call(m, "HPExpireAt", varargs...)
|
||||
ret0, _ := ret[0].(*redis.IntSliceCmd)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// HPExpireAt indicates an expected call of HPExpireAt.
|
||||
func (mr *MockUniversalClientMockRecorder) HPExpireAt(arg0, arg1, arg2 any, arg3 ...any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
varargs := append([]any{arg0, arg1, arg2}, arg3...)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HPExpireAt", reflect.TypeOf((*MockUniversalClient)(nil).HPExpireAt), varargs...)
|
||||
}
|
||||
|
||||
// HPExpireAtWithArgs mocks base method.
|
||||
func (m *MockUniversalClient) HPExpireAtWithArgs(arg0 context.Context, arg1 string, arg2 time.Time, arg3 redis.HExpireArgs, arg4 ...string) *redis.IntSliceCmd {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []any{arg0, arg1, arg2, arg3}
|
||||
for _, a := range arg4 {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
ret := m.ctrl.Call(m, "HPExpireAtWithArgs", varargs...)
|
||||
ret0, _ := ret[0].(*redis.IntSliceCmd)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// HPExpireAtWithArgs indicates an expected call of HPExpireAtWithArgs.
|
||||
func (mr *MockUniversalClientMockRecorder) HPExpireAtWithArgs(arg0, arg1, arg2, arg3 any, arg4 ...any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
varargs := append([]any{arg0, arg1, arg2, arg3}, arg4...)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HPExpireAtWithArgs", reflect.TypeOf((*MockUniversalClient)(nil).HPExpireAtWithArgs), varargs...)
|
||||
}
|
||||
|
||||
// HPExpireTime mocks base method.
|
||||
func (m *MockUniversalClient) HPExpireTime(arg0 context.Context, arg1 string, arg2 ...string) *redis.IntSliceCmd {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []any{arg0, arg1}
|
||||
for _, a := range arg2 {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
ret := m.ctrl.Call(m, "HPExpireTime", varargs...)
|
||||
ret0, _ := ret[0].(*redis.IntSliceCmd)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// HPExpireTime indicates an expected call of HPExpireTime.
|
||||
func (mr *MockUniversalClientMockRecorder) HPExpireTime(arg0, arg1 any, arg2 ...any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
varargs := append([]any{arg0, arg1}, arg2...)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HPExpireTime", reflect.TypeOf((*MockUniversalClient)(nil).HPExpireTime), varargs...)
|
||||
}
|
||||
|
||||
// HPExpireWithArgs mocks base method.
|
||||
func (m *MockUniversalClient) HPExpireWithArgs(arg0 context.Context, arg1 string, arg2 time.Duration, arg3 redis.HExpireArgs, arg4 ...string) *redis.IntSliceCmd {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []any{arg0, arg1, arg2, arg3}
|
||||
for _, a := range arg4 {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
ret := m.ctrl.Call(m, "HPExpireWithArgs", varargs...)
|
||||
ret0, _ := ret[0].(*redis.IntSliceCmd)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// HPExpireWithArgs indicates an expected call of HPExpireWithArgs.
|
||||
func (mr *MockUniversalClientMockRecorder) HPExpireWithArgs(arg0, arg1, arg2, arg3 any, arg4 ...any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
varargs := append([]any{arg0, arg1, arg2, arg3}, arg4...)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HPExpireWithArgs", reflect.TypeOf((*MockUniversalClient)(nil).HPExpireWithArgs), varargs...)
|
||||
}
|
||||
|
||||
// HPTTL mocks base method.
|
||||
func (m *MockUniversalClient) HPTTL(arg0 context.Context, arg1 string, arg2 ...string) *redis.IntSliceCmd {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []any{arg0, arg1}
|
||||
for _, a := range arg2 {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
ret := m.ctrl.Call(m, "HPTTL", varargs...)
|
||||
ret0, _ := ret[0].(*redis.IntSliceCmd)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// HPTTL indicates an expected call of HPTTL.
|
||||
func (mr *MockUniversalClientMockRecorder) HPTTL(arg0, arg1 any, arg2 ...any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
varargs := append([]any{arg0, arg1}, arg2...)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HPTTL", reflect.TypeOf((*MockUniversalClient)(nil).HPTTL), varargs...)
|
||||
}
|
||||
|
||||
// HPersist mocks base method.
|
||||
func (m *MockUniversalClient) HPersist(arg0 context.Context, arg1 string, arg2 ...string) *redis.IntSliceCmd {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []any{arg0, arg1}
|
||||
for _, a := range arg2 {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
ret := m.ctrl.Call(m, "HPersist", varargs...)
|
||||
ret0, _ := ret[0].(*redis.IntSliceCmd)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// HPersist indicates an expected call of HPersist.
|
||||
func (mr *MockUniversalClientMockRecorder) HPersist(arg0, arg1 any, arg2 ...any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
varargs := append([]any{arg0, arg1}, arg2...)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HPersist", reflect.TypeOf((*MockUniversalClient)(nil).HPersist), varargs...)
|
||||
}
|
||||
|
||||
// HRandField mocks base method.
|
||||
func (m *MockUniversalClient) HRandField(arg0 context.Context, arg1 string, arg2 int) *redis.StringSliceCmd {
|
||||
m.ctrl.T.Helper()
|
||||
|
@ -2704,6 +2932,20 @@ func (mr *MockUniversalClientMockRecorder) HScan(arg0, arg1, arg2, arg3, arg4 an
|
|||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HScan", reflect.TypeOf((*MockUniversalClient)(nil).HScan), arg0, arg1, arg2, arg3, arg4)
|
||||
}
|
||||
|
||||
// HScanNoValues mocks base method.
|
||||
func (m *MockUniversalClient) HScanNoValues(arg0 context.Context, arg1 string, arg2 uint64, arg3 string, arg4 int64) *redis.ScanCmd {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "HScanNoValues", arg0, arg1, arg2, arg3, arg4)
|
||||
ret0, _ := ret[0].(*redis.ScanCmd)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// HScanNoValues indicates an expected call of HScanNoValues.
|
||||
func (mr *MockUniversalClientMockRecorder) HScanNoValues(arg0, arg1, arg2, arg3, arg4 any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HScanNoValues", reflect.TypeOf((*MockUniversalClient)(nil).HScanNoValues), arg0, arg1, arg2, arg3, arg4)
|
||||
}
|
||||
|
||||
// HSet mocks base method.
|
||||
func (m *MockUniversalClient) HSet(arg0 context.Context, arg1 string, arg2 ...any) *redis.IntCmd {
|
||||
m.ctrl.T.Helper()
|
||||
|
@ -2737,6 +2979,25 @@ func (mr *MockUniversalClientMockRecorder) HSetNX(arg0, arg1, arg2, arg3 any) *g
|
|||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HSetNX", reflect.TypeOf((*MockUniversalClient)(nil).HSetNX), arg0, arg1, arg2, arg3)
|
||||
}
|
||||
|
||||
// HTTL mocks base method.
|
||||
func (m *MockUniversalClient) HTTL(arg0 context.Context, arg1 string, arg2 ...string) *redis.IntSliceCmd {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []any{arg0, arg1}
|
||||
for _, a := range arg2 {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
ret := m.ctrl.Call(m, "HTTL", varargs...)
|
||||
ret0, _ := ret[0].(*redis.IntSliceCmd)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// HTTL indicates an expected call of HTTL.
|
||||
func (mr *MockUniversalClientMockRecorder) HTTL(arg0, arg1 any, arg2 ...any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
varargs := append([]any{arg0, arg1}, arg2...)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HTTL", reflect.TypeOf((*MockUniversalClient)(nil).HTTL), varargs...)
|
||||
}
|
||||
|
||||
// HVals mocks base method.
|
||||
func (m *MockUniversalClient) HVals(arg0 context.Context, arg1 string) *redis.StringSliceCmd {
|
||||
m.ctrl.T.Helper()
|
||||
|
|
|
@ -11,7 +11,7 @@ import (
|
|||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
|
||||
"gitea.com/go-chi/session"
|
||||
"code.forgejo.org/go-chi/session"
|
||||
)
|
||||
|
||||
// DBStore represents a session store implementation based on the DB.
|
||||
|
|
|
@ -25,7 +25,7 @@ import (
|
|||
"code.gitea.io/gitea/modules/graceful"
|
||||
"code.gitea.io/gitea/modules/nosql"
|
||||
|
||||
"gitea.com/go-chi/session"
|
||||
"code.forgejo.org/go-chi/session"
|
||||
"github.com/redis/go-redis/v9"
|
||||
)
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ package session
|
|||
import (
|
||||
"net/http"
|
||||
|
||||
"gitea.com/go-chi/session"
|
||||
"code.forgejo.org/go-chi/session"
|
||||
)
|
||||
|
||||
// Store represents a session store
|
||||
|
|
|
@ -8,12 +8,12 @@ import (
|
|||
"sync"
|
||||
|
||||
"code.gitea.io/gitea/modules/json"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
|
||||
"gitea.com/go-chi/session"
|
||||
couchbase "gitea.com/go-chi/session/couchbase"
|
||||
memcache "gitea.com/go-chi/session/memcache"
|
||||
mysql "gitea.com/go-chi/session/mysql"
|
||||
postgres "gitea.com/go-chi/session/postgres"
|
||||
"code.forgejo.org/go-chi/session"
|
||||
memcache "code.forgejo.org/go-chi/session/memcache"
|
||||
mysql "code.forgejo.org/go-chi/session/mysql"
|
||||
postgres "code.forgejo.org/go-chi/session/postgres"
|
||||
)
|
||||
|
||||
// VirtualSessionProvider represents a shadowed session provider implementation.
|
||||
|
@ -35,6 +35,9 @@ func (o *VirtualSessionProvider) Init(gclifetime int64, config string) error {
|
|||
switch opts.Provider {
|
||||
case "memory":
|
||||
o.provider = &session.MemProvider{}
|
||||
case "couchbase":
|
||||
log.Warn("Couchbase as session provider is no longer supported, falling back to file as session provider")
|
||||
fallthrough
|
||||
case "file":
|
||||
o.provider = &session.FileProvider{}
|
||||
case "redis":
|
||||
|
@ -45,8 +48,6 @@ func (o *VirtualSessionProvider) Init(gclifetime int64, config string) error {
|
|||
o.provider = &mysql.MysqlProvider{}
|
||||
case "postgres":
|
||||
o.provider = &postgres.PostgresProvider{}
|
||||
case "couchbase":
|
||||
o.provider = &couchbase.CouchbaseProvider{}
|
||||
case "memcache":
|
||||
o.provider = &memcache.MemcacheProvider{}
|
||||
default:
|
||||
|
|
|
@ -7,9 +7,18 @@ package setting
|
|||
var Quota = struct {
|
||||
Enabled bool `ini:"ENABLED"`
|
||||
DefaultGroups []string `ini:"DEFAULT_GROUPS"`
|
||||
|
||||
Default struct {
|
||||
Total int64
|
||||
} `ini:"quota.default"`
|
||||
}{
|
||||
Enabled: false,
|
||||
DefaultGroups: []string{},
|
||||
Default: struct {
|
||||
Total int64
|
||||
}{
|
||||
Total: -1,
|
||||
},
|
||||
}
|
||||
|
||||
func loadQuotaFrom(rootCfg ConfigProvider) {
|
||||
|
|
|
@ -1105,6 +1105,7 @@ mirror_interval_invalid = The mirror interval is not valid.
|
|||
mirror_public_key = Public SSH key
|
||||
mirror_use_ssh.text = Use SSH authentication
|
||||
mirror_use_ssh.helper = Forgejo will mirror the repository via Git over SSH and create a keypair for you when you select this option. You must ensure that the generated public key is authorized to push to the destination repository. You cannot use password-based authorization when selecting this.
|
||||
mirror_use_ssh.not_available = SSH authentication isn't available.
|
||||
mirror_denied_combination = Cannot use public key and password based authentication in combination.
|
||||
mirror_sync = synced
|
||||
mirror_sync_on_commit = Sync when commits are pushed
|
||||
|
|
1
release-notes/5090.md
Normal file
1
release-notes/5090.md
Normal file
|
@ -0,0 +1 @@
|
|||
Remove support for Couchbase as a session provider; it instead will now fallback to the file provider. The rationale for removing Couchbase support is that it's not free software, https://www.couchbase.com/blog/couchbase-adopts-bsl-license/, and therefore cannot be tested in Forgejo and neither should be supported.
|
2
release-notes/5120.md
Normal file
2
release-notes/5120.md
Normal file
|
@ -0,0 +1,2 @@
|
|||
feat: Language detection in the repository learned about the following languages: [Luau](https://github.com/github-linguist/linguist/pull/6612), [BQN](https://github.com/github-linguist/linguist/pull/6623), [Cron table](https://github.com/github-linguist/linguist/pull/6759), [NMODL](https://github.com/github-linguist/linguist/pull/6776), [Pkl](https://github.com/github-linguist/linguist/pull/6730), [templ](https://github.com/github-linguist/linguist/pull/6798), [FIRRTL](https://github.com/github-linguist/linguist/pull/6848), [Julia REPL](https://github.com/github-linguist/linguist/pull/6859), [Caddyfile](https://github.com/github-linguist/linguist/pull/6862).
|
||||
feat: The following extensions or filenames in a repository are associated with the matching language: [.sublime-color-scheme](https://github.com/github-linguist/linguist/pull/6758), [MODULE.bazel.lock](https://github.com/github-linguist/linguist/pull/6783), [Cargo.toml.orig](https://github.com/github-linguist/linguist/pull/6787), [tsx](https://github.com/github-linguist/linguist/pull/6788), [justfile](https://github.com/github-linguist/linguist/pull/6795), [.zig.zon](https://github.com/github-linguist/linguist/pull/6820), [.envrc](https://github.com/github-linguist/linguist/pull/6865).
|
|
@ -19,9 +19,11 @@ func TestTestHook(t *testing.T) {
|
|||
|
||||
ctx, _ := contexttest.MockAPIContext(t, "user2/repo1/wiki/_pages")
|
||||
ctx.SetParams(":id", "1")
|
||||
contexttest.LoadRepo(t, ctx, 1)
|
||||
contexttest.LoadRepoCommit(t, ctx)
|
||||
contexttest.LoadUser(t, ctx, 2)
|
||||
contexttest.LoadRepo(t, ctx, 1)
|
||||
contexttest.LoadGitRepo(t, ctx)
|
||||
defer ctx.Repo.GitRepo.Close()
|
||||
contexttest.LoadRepoCommit(t, ctx)
|
||||
TestHook(ctx)
|
||||
assert.EqualValues(t, http.StatusNoContent, ctx.Resp.Status())
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
"code.gitea.io/gitea/models/db"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/models/unit"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
|
@ -350,6 +351,11 @@ func CreatePushMirror(ctx *context.APIContext, mirrorOption *api.CreatePushMirro
|
|||
return
|
||||
}
|
||||
|
||||
if mirrorOption.UseSSH && !git.HasSSHExecutable {
|
||||
ctx.Error(http.StatusBadRequest, "CreatePushMirror", "SSH authentication not available.")
|
||||
return
|
||||
}
|
||||
|
||||
if mirrorOption.UseSSH && (mirrorOption.RemoteUsername != "" || mirrorOption.RemotePassword != "") {
|
||||
ctx.Error(http.StatusBadRequest, "CreatePushMirror", "'use_ssh' is mutually exclusive with 'remote_username' and 'remote_passoword'")
|
||||
return
|
||||
|
|
|
@ -15,7 +15,7 @@ import (
|
|||
"code.gitea.io/gitea/modules/web/routing"
|
||||
"code.gitea.io/gitea/services/context"
|
||||
|
||||
"gitea.com/go-chi/session"
|
||||
"code.forgejo.org/go-chi/session"
|
||||
"github.com/chi-middleware/proxy"
|
||||
chi "github.com/go-chi/chi/v5"
|
||||
)
|
||||
|
|
|
@ -36,7 +36,7 @@ import (
|
|||
"code.gitea.io/gitea/services/context"
|
||||
"code.gitea.io/gitea/services/forms"
|
||||
|
||||
"gitea.com/go-chi/session"
|
||||
"code.forgejo.org/go-chi/session"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
|
@ -22,7 +22,7 @@ import (
|
|||
"code.gitea.io/gitea/services/context"
|
||||
"code.gitea.io/gitea/services/mailer"
|
||||
|
||||
"gitea.com/go-chi/session"
|
||||
"code.forgejo.org/go-chi/session"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
|
@ -6,6 +6,7 @@ package repo
|
|||
import (
|
||||
"testing"
|
||||
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/gitrepo"
|
||||
|
@ -45,7 +46,6 @@ func TestGetUniquePatchBranchName(t *testing.T) {
|
|||
ctx, _ := contexttest.MockContext(t, "user2/repo1")
|
||||
ctx.SetParams(":id", "1")
|
||||
contexttest.LoadRepo(t, ctx, 1)
|
||||
contexttest.LoadRepoCommit(t, ctx)
|
||||
contexttest.LoadUser(t, ctx, 2)
|
||||
contexttest.LoadGitRepo(t, ctx)
|
||||
defer ctx.Repo.GitRepo.Close()
|
||||
|
@ -57,15 +57,7 @@ func TestGetUniquePatchBranchName(t *testing.T) {
|
|||
|
||||
func TestGetClosestParentWithFiles(t *testing.T) {
|
||||
unittest.PrepareTestEnv(t)
|
||||
ctx, _ := contexttest.MockContext(t, "user2/repo1")
|
||||
ctx.SetParams(":id", "1")
|
||||
contexttest.LoadRepo(t, ctx, 1)
|
||||
contexttest.LoadRepoCommit(t, ctx)
|
||||
contexttest.LoadUser(t, ctx, 2)
|
||||
contexttest.LoadGitRepo(t, ctx)
|
||||
defer ctx.Repo.GitRepo.Close()
|
||||
|
||||
repo := ctx.Repo.Repository
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
branch := repo.DefaultBranch
|
||||
gitRepo, _ := gitrepo.OpenRepository(git.DefaultContext, repo)
|
||||
defer gitRepo.Close()
|
||||
|
|
|
@ -154,6 +154,7 @@ func GetContentHistoryDetail(ctx *context.Context) {
|
|||
dmp := diffmatchpatch.New()
|
||||
// `checklines=false` makes better diff result
|
||||
diff := dmp.DiffMain(prevHistoryContentText, history.ContentText, false)
|
||||
diff = dmp.DiffCleanupSemantic(diff)
|
||||
diff = dmp.DiffCleanupEfficiency(diff)
|
||||
|
||||
// use chroma to render the diff html
|
||||
|
|
|
@ -92,6 +92,7 @@ func SettingsCtxData(ctx *context.Context) {
|
|||
return
|
||||
}
|
||||
ctx.Data["PushMirrors"] = pushMirrors
|
||||
ctx.Data["CanUseSSHMirroring"] = git.HasSSHExecutable
|
||||
}
|
||||
|
||||
// Units show a repositorys unit settings page
|
||||
|
@ -643,6 +644,11 @@ func SettingsPost(ctx *context.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
if form.PushMirrorUseSSH && !git.HasSSHExecutable {
|
||||
ctx.RenderWithErr(ctx.Tr("repo.mirror_use_ssh.not_available"), tplSettingsOptions, &form)
|
||||
return
|
||||
}
|
||||
|
||||
address, err := forms.ParseRemoteAddr(form.PushMirrorAddress, form.PushMirrorUsername, form.PushMirrorPassword)
|
||||
if err == nil {
|
||||
err = migrations.IsMigrateURLAllowed(address, ctx.Doer)
|
||||
|
|
|
@ -11,7 +11,7 @@ import (
|
|||
"code.gitea.io/gitea/modules/log"
|
||||
session_module "code.gitea.io/gitea/modules/session"
|
||||
|
||||
chiSession "gitea.com/go-chi/session"
|
||||
chiSession "code.forgejo.org/go-chi/session"
|
||||
"github.com/gorilla/sessions"
|
||||
)
|
||||
|
||||
|
|
|
@ -27,8 +27,8 @@ import (
|
|||
"code.gitea.io/gitea/modules/web/middleware"
|
||||
web_types "code.gitea.io/gitea/modules/web/types"
|
||||
|
||||
"code.forgejo.org/go-chi/session"
|
||||
"gitea.com/go-chi/cache"
|
||||
"gitea.com/go-chi/session"
|
||||
)
|
||||
|
||||
// Render represents a template render
|
||||
|
|
|
@ -136,14 +136,15 @@ func LoadRepoCommit(t *testing.T, ctx gocontext.Context) {
|
|||
assert.FailNow(t, "context is not *context.Context or *context.APIContext")
|
||||
}
|
||||
|
||||
gitRepo, err := gitrepo.OpenRepository(ctx, repo.Repository)
|
||||
require.NoError(t, err)
|
||||
defer gitRepo.Close()
|
||||
branch, err := gitRepo.GetHEADBranch()
|
||||
if repo.GitRepo == nil {
|
||||
assert.FailNow(t, "must call LoadGitRepo")
|
||||
}
|
||||
|
||||
branch, err := repo.GitRepo.GetHEADBranch()
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, branch)
|
||||
if branch != nil {
|
||||
repo.Commit, err = gitRepo.GetBranchCommit(branch.Name)
|
||||
repo.Commit, err = repo.GitRepo.GetBranchCommit(branch.Name)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
}
|
||||
|
@ -176,10 +177,20 @@ func LoadOrganization(t *testing.T, ctx gocontext.Context, orgID int64) {
|
|||
|
||||
// LoadGitRepo load a git repo into a test context. Requires that ctx.Repo has
|
||||
// already been populated.
|
||||
func LoadGitRepo(t *testing.T, ctx *context.Context) {
|
||||
require.NoError(t, ctx.Repo.Repository.LoadOwner(ctx))
|
||||
func LoadGitRepo(t *testing.T, ctx gocontext.Context) {
|
||||
var repo *context.Repository
|
||||
switch ctx := ctx.(type) {
|
||||
case *context.Context:
|
||||
repo = ctx.Repo
|
||||
case *context.APIContext:
|
||||
repo = ctx.Repo
|
||||
default:
|
||||
assert.FailNow(t, "context is not *context.Context or *context.APIContext")
|
||||
}
|
||||
|
||||
require.NoError(t, repo.Repository.LoadOwner(ctx))
|
||||
var err error
|
||||
ctx.Repo.GitRepo, err = gitrepo.OpenRepository(ctx, ctx.Repo.Repository)
|
||||
repo.GitRepo, err = gitrepo.OpenRepository(ctx, repo.Repository)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
|
|
|
@ -75,9 +75,9 @@ func checkAuthorizedKeys(ctx context.Context, logger log.Logger, autofix bool) e
|
|||
logger.Critical(
|
||||
"authorized_keys file %q is out of date.\nRegenerate it with:\n\t\"%s\"\nor\n\t\"%s\"",
|
||||
fPath,
|
||||
"gitea admin regenerate keys",
|
||||
"gitea doctor --run authorized-keys --fix")
|
||||
return fmt.Errorf(`authorized_keys is out of date and should be regenerated with "gitea admin regenerate keys" or "gitea doctor --run authorized-keys --fix"`)
|
||||
"forgejo admin regenerate keys",
|
||||
"forgejo doctor check --run authorized-keys --fix")
|
||||
return fmt.Errorf(`authorized_keys is out of date and should be regenerated with "forgejo admin regenerate keys" or "forgejo doctor check --run authorized-keys --fix"`)
|
||||
}
|
||||
logger.Warn("authorized_keys is out of date. Attempting rewrite...")
|
||||
err = asymkey_model.RewriteAllPublicKeys(ctx)
|
||||
|
|
|
@ -97,6 +97,7 @@ func (hcd *HighlightCodeDiff) diffWithHighlight(filename, language, codeA, codeB
|
|||
convertedCodeB := hcd.ConvertToPlaceholders(string(highlightCodeB))
|
||||
|
||||
diffs := diffMatchPatch.DiffMain(convertedCodeA, convertedCodeB, true)
|
||||
diffs = diffMatchPatch.DiffCleanupSemantic(diffs)
|
||||
diffs = diffMatchPatch.DiffCleanupEfficiency(diffs)
|
||||
|
||||
for i := range diffs {
|
||||
|
|
|
@ -6,10 +6,11 @@ package files
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
"code.gitea.io/gitea/modules/gitrepo"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/services/contexttest"
|
||||
|
||||
_ "code.gitea.io/gitea/models/actions"
|
||||
|
||||
|
@ -53,27 +54,21 @@ func getExpectedReadmeContentsResponse() *api.ContentsResponse {
|
|||
|
||||
func TestGetContents(t *testing.T) {
|
||||
unittest.PrepareTestEnv(t)
|
||||
ctx, _ := contexttest.MockContext(t, "user2/repo1")
|
||||
ctx.SetParams(":id", "1")
|
||||
contexttest.LoadRepo(t, ctx, 1)
|
||||
contexttest.LoadRepoCommit(t, ctx)
|
||||
contexttest.LoadUser(t, ctx, 2)
|
||||
contexttest.LoadGitRepo(t, ctx)
|
||||
defer ctx.Repo.GitRepo.Close()
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
|
||||
treePath := "README.md"
|
||||
ref := ctx.Repo.Repository.DefaultBranch
|
||||
ref := repo.DefaultBranch
|
||||
|
||||
expectedContentsResponse := getExpectedReadmeContentsResponse()
|
||||
|
||||
t.Run("Get README.md contents with GetContents(ctx, )", func(t *testing.T) {
|
||||
fileContentResponse, err := GetContents(ctx, ctx.Repo.Repository, treePath, ref, false)
|
||||
fileContentResponse, err := GetContents(db.DefaultContext, repo, treePath, ref, false)
|
||||
assert.EqualValues(t, expectedContentsResponse, fileContentResponse)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("Get README.md contents with ref as empty string (should then use the repo's default branch) with GetContents(ctx, )", func(t *testing.T) {
|
||||
fileContentResponse, err := GetContents(ctx, ctx.Repo.Repository, treePath, "", false)
|
||||
fileContentResponse, err := GetContents(db.DefaultContext, repo, treePath, "", false)
|
||||
assert.EqualValues(t, expectedContentsResponse, fileContentResponse)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
@ -81,16 +76,10 @@ func TestGetContents(t *testing.T) {
|
|||
|
||||
func TestGetContentsOrListForDir(t *testing.T) {
|
||||
unittest.PrepareTestEnv(t)
|
||||
ctx, _ := contexttest.MockContext(t, "user2/repo1")
|
||||
ctx.SetParams(":id", "1")
|
||||
contexttest.LoadRepo(t, ctx, 1)
|
||||
contexttest.LoadRepoCommit(t, ctx)
|
||||
contexttest.LoadUser(t, ctx, 2)
|
||||
contexttest.LoadGitRepo(t, ctx)
|
||||
defer ctx.Repo.GitRepo.Close()
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
|
||||
treePath := "" // root dir
|
||||
ref := ctx.Repo.Repository.DefaultBranch
|
||||
ref := repo.DefaultBranch
|
||||
|
||||
readmeContentsResponse := getExpectedReadmeContentsResponse()
|
||||
// because will be in a list, doesn't have encoding and content
|
||||
|
@ -102,13 +91,13 @@ func TestGetContentsOrListForDir(t *testing.T) {
|
|||
}
|
||||
|
||||
t.Run("Get root dir contents with GetContentsOrList(ctx, )", func(t *testing.T) {
|
||||
fileContentResponse, err := GetContentsOrList(ctx, ctx.Repo.Repository, treePath, ref)
|
||||
fileContentResponse, err := GetContentsOrList(db.DefaultContext, repo, treePath, ref)
|
||||
assert.EqualValues(t, expectedContentsListResponse, fileContentResponse)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("Get root dir contents with ref as empty string (should then use the repo's default branch) with GetContentsOrList(ctx, )", func(t *testing.T) {
|
||||
fileContentResponse, err := GetContentsOrList(ctx, ctx.Repo.Repository, treePath, "")
|
||||
fileContentResponse, err := GetContentsOrList(db.DefaultContext, repo, treePath, "")
|
||||
assert.EqualValues(t, expectedContentsListResponse, fileContentResponse)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
@ -116,27 +105,21 @@ func TestGetContentsOrListForDir(t *testing.T) {
|
|||
|
||||
func TestGetContentsOrListForFile(t *testing.T) {
|
||||
unittest.PrepareTestEnv(t)
|
||||
ctx, _ := contexttest.MockContext(t, "user2/repo1")
|
||||
ctx.SetParams(":id", "1")
|
||||
contexttest.LoadRepo(t, ctx, 1)
|
||||
contexttest.LoadRepoCommit(t, ctx)
|
||||
contexttest.LoadUser(t, ctx, 2)
|
||||
contexttest.LoadGitRepo(t, ctx)
|
||||
defer ctx.Repo.GitRepo.Close()
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
|
||||
treePath := "README.md"
|
||||
ref := ctx.Repo.Repository.DefaultBranch
|
||||
ref := repo.DefaultBranch
|
||||
|
||||
expectedContentsResponse := getExpectedReadmeContentsResponse()
|
||||
|
||||
t.Run("Get README.md contents with GetContentsOrList(ctx, )", func(t *testing.T) {
|
||||
fileContentResponse, err := GetContentsOrList(ctx, ctx.Repo.Repository, treePath, ref)
|
||||
fileContentResponse, err := GetContentsOrList(db.DefaultContext, repo, treePath, ref)
|
||||
assert.EqualValues(t, expectedContentsResponse, fileContentResponse)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("Get README.md contents with ref as empty string (should then use the repo's default branch) with GetContentsOrList(ctx, )", func(t *testing.T) {
|
||||
fileContentResponse, err := GetContentsOrList(ctx, ctx.Repo.Repository, treePath, "")
|
||||
fileContentResponse, err := GetContentsOrList(db.DefaultContext, repo, treePath, "")
|
||||
assert.EqualValues(t, expectedContentsResponse, fileContentResponse)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
@ -144,28 +127,21 @@ func TestGetContentsOrListForFile(t *testing.T) {
|
|||
|
||||
func TestGetContentsErrors(t *testing.T) {
|
||||
unittest.PrepareTestEnv(t)
|
||||
ctx, _ := contexttest.MockContext(t, "user2/repo1")
|
||||
ctx.SetParams(":id", "1")
|
||||
contexttest.LoadRepo(t, ctx, 1)
|
||||
contexttest.LoadRepoCommit(t, ctx)
|
||||
contexttest.LoadUser(t, ctx, 2)
|
||||
contexttest.LoadGitRepo(t, ctx)
|
||||
defer ctx.Repo.GitRepo.Close()
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
|
||||
repo := ctx.Repo.Repository
|
||||
treePath := "README.md"
|
||||
ref := repo.DefaultBranch
|
||||
|
||||
t.Run("bad treePath", func(t *testing.T) {
|
||||
badTreePath := "bad/tree.md"
|
||||
fileContentResponse, err := GetContents(ctx, repo, badTreePath, ref, false)
|
||||
fileContentResponse, err := GetContents(db.DefaultContext, repo, badTreePath, ref, false)
|
||||
require.EqualError(t, err, "object does not exist [id: , rel_path: bad]")
|
||||
assert.Nil(t, fileContentResponse)
|
||||
})
|
||||
|
||||
t.Run("bad ref", func(t *testing.T) {
|
||||
badRef := "bad_ref"
|
||||
fileContentResponse, err := GetContents(ctx, repo, treePath, badRef, false)
|
||||
fileContentResponse, err := GetContents(db.DefaultContext, repo, treePath, badRef, false)
|
||||
require.EqualError(t, err, "object does not exist [id: "+badRef+", rel_path: ]")
|
||||
assert.Nil(t, fileContentResponse)
|
||||
})
|
||||
|
@ -173,28 +149,21 @@ func TestGetContentsErrors(t *testing.T) {
|
|||
|
||||
func TestGetContentsOrListErrors(t *testing.T) {
|
||||
unittest.PrepareTestEnv(t)
|
||||
ctx, _ := contexttest.MockContext(t, "user2/repo1")
|
||||
ctx.SetParams(":id", "1")
|
||||
contexttest.LoadRepo(t, ctx, 1)
|
||||
contexttest.LoadRepoCommit(t, ctx)
|
||||
contexttest.LoadUser(t, ctx, 2)
|
||||
contexttest.LoadGitRepo(t, ctx)
|
||||
defer ctx.Repo.GitRepo.Close()
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
|
||||
repo := ctx.Repo.Repository
|
||||
treePath := "README.md"
|
||||
ref := repo.DefaultBranch
|
||||
|
||||
t.Run("bad treePath", func(t *testing.T) {
|
||||
badTreePath := "bad/tree.md"
|
||||
fileContentResponse, err := GetContentsOrList(ctx, repo, badTreePath, ref)
|
||||
fileContentResponse, err := GetContentsOrList(db.DefaultContext, repo, badTreePath, ref)
|
||||
require.EqualError(t, err, "object does not exist [id: , rel_path: bad]")
|
||||
assert.Nil(t, fileContentResponse)
|
||||
})
|
||||
|
||||
t.Run("bad ref", func(t *testing.T) {
|
||||
badRef := "bad_ref"
|
||||
fileContentResponse, err := GetContentsOrList(ctx, repo, treePath, badRef)
|
||||
fileContentResponse, err := GetContentsOrList(db.DefaultContext, repo, treePath, badRef)
|
||||
require.EqualError(t, err, "object does not exist [id: "+badRef+", rel_path: ]")
|
||||
assert.Nil(t, fileContentResponse)
|
||||
})
|
||||
|
@ -202,17 +171,10 @@ func TestGetContentsOrListErrors(t *testing.T) {
|
|||
|
||||
func TestGetContentsOrListOfEmptyRepos(t *testing.T) {
|
||||
unittest.PrepareTestEnv(t)
|
||||
ctx, _ := contexttest.MockContext(t, "user30/empty")
|
||||
ctx.SetParams(":id", "52")
|
||||
contexttest.LoadRepo(t, ctx, 52)
|
||||
contexttest.LoadUser(t, ctx, 30)
|
||||
contexttest.LoadGitRepo(t, ctx)
|
||||
defer ctx.Repo.GitRepo.Close()
|
||||
|
||||
repo := ctx.Repo.Repository
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 52})
|
||||
|
||||
t.Run("empty repo", func(t *testing.T) {
|
||||
contents, err := GetContentsOrList(ctx, repo, "", "")
|
||||
contents, err := GetContentsOrList(db.DefaultContext, repo, "", "")
|
||||
require.NoError(t, err)
|
||||
assert.Empty(t, contents)
|
||||
})
|
||||
|
@ -220,23 +182,13 @@ func TestGetContentsOrListOfEmptyRepos(t *testing.T) {
|
|||
|
||||
func TestGetBlobBySHA(t *testing.T) {
|
||||
unittest.PrepareTestEnv(t)
|
||||
ctx, _ := contexttest.MockContext(t, "user2/repo1")
|
||||
contexttest.LoadRepo(t, ctx, 1)
|
||||
contexttest.LoadRepoCommit(t, ctx)
|
||||
contexttest.LoadUser(t, ctx, 2)
|
||||
contexttest.LoadGitRepo(t, ctx)
|
||||
defer ctx.Repo.GitRepo.Close()
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
|
||||
sha := "65f1bf27bc3bf70f64657658635e66094edbcb4d"
|
||||
ctx.SetParams(":id", "1")
|
||||
ctx.SetParams(":sha", sha)
|
||||
gitRepo, err := gitrepo.OpenRepository(db.DefaultContext, repo)
|
||||
require.NoError(t, err)
|
||||
defer gitRepo.Close()
|
||||
|
||||
gitRepo, err := gitrepo.OpenRepository(ctx, ctx.Repo.Repository)
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
gbr, err := GetBlobBySHA(ctx, ctx.Repo.Repository, gitRepo, ctx.Params(":sha"))
|
||||
gbr, err := GetBlobBySHA(db.DefaultContext, repo, gitRepo, "65f1bf27bc3bf70f64657658635e66094edbcb4d")
|
||||
expectedGBR := &api.GitBlobResponse{
|
||||
Content: "dHJlZSAyYTJmMWQ0NjcwNzI4YTJlMTAwNDllMzQ1YmQ3YTI3NjQ2OGJlYWI2CmF1dGhvciB1c2VyMSA8YWRkcmVzczFAZXhhbXBsZS5jb20+IDE0ODk5NTY0NzkgLTA0MDAKY29tbWl0dGVyIEV0aGFuIEtvZW5pZyA8ZXRoYW50a29lbmlnQGdtYWlsLmNvbT4gMTQ4OTk1NjQ3OSAtMDQwMAoKSW5pdGlhbCBjb21taXQK",
|
||||
Encoding: "base64",
|
||||
|
|
|
@ -6,6 +6,7 @@ package files
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
"code.gitea.io/gitea/modules/json"
|
||||
|
@ -21,7 +22,6 @@ func TestGetDiffPreview(t *testing.T) {
|
|||
ctx, _ := contexttest.MockContext(t, "user2/repo1")
|
||||
ctx.SetParams(":id", "1")
|
||||
contexttest.LoadRepo(t, ctx, 1)
|
||||
contexttest.LoadRepoCommit(t, ctx)
|
||||
contexttest.LoadUser(t, ctx, 2)
|
||||
contexttest.LoadGitRepo(t, ctx)
|
||||
defer ctx.Repo.GitRepo.Close()
|
||||
|
@ -140,33 +140,26 @@ func TestGetDiffPreview(t *testing.T) {
|
|||
|
||||
func TestGetDiffPreviewErrors(t *testing.T) {
|
||||
unittest.PrepareTestEnv(t)
|
||||
ctx, _ := contexttest.MockContext(t, "user2/repo1")
|
||||
ctx.SetParams(":id", "1")
|
||||
contexttest.LoadRepo(t, ctx, 1)
|
||||
contexttest.LoadRepoCommit(t, ctx)
|
||||
contexttest.LoadUser(t, ctx, 2)
|
||||
contexttest.LoadGitRepo(t, ctx)
|
||||
defer ctx.Repo.GitRepo.Close()
|
||||
|
||||
branch := ctx.Repo.Repository.DefaultBranch
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
branch := repo.DefaultBranch
|
||||
treePath := "README.md"
|
||||
content := "# repo1\n\nDescription for repo1\nthis is a new line"
|
||||
|
||||
t.Run("empty repo", func(t *testing.T) {
|
||||
diff, err := GetDiffPreview(ctx, &repo_model.Repository{}, branch, treePath, content)
|
||||
diff, err := GetDiffPreview(db.DefaultContext, &repo_model.Repository{}, branch, treePath, content)
|
||||
assert.Nil(t, diff)
|
||||
assert.EqualError(t, err, "repository does not exist [id: 0, uid: 0, owner_name: , name: ]")
|
||||
})
|
||||
|
||||
t.Run("bad branch", func(t *testing.T) {
|
||||
badBranch := "bad_branch"
|
||||
diff, err := GetDiffPreview(ctx, ctx.Repo.Repository, badBranch, treePath, content)
|
||||
diff, err := GetDiffPreview(db.DefaultContext, repo, badBranch, treePath, content)
|
||||
assert.Nil(t, diff)
|
||||
assert.EqualError(t, err, "branch does not exist [name: "+badBranch+"]")
|
||||
})
|
||||
|
||||
t.Run("empty treePath", func(t *testing.T) {
|
||||
diff, err := GetDiffPreview(ctx, ctx.Repo.Repository, branch, "", content)
|
||||
diff, err := GetDiffPreview(db.DefaultContext, repo, branch, "", content)
|
||||
assert.Nil(t, diff)
|
||||
assert.EqualError(t, err, "path is invalid [path: ]")
|
||||
})
|
||||
|
|
|
@ -6,11 +6,12 @@ package files
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
"code.gitea.io/gitea/modules/gitrepo"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/services/contexttest"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
@ -99,23 +100,16 @@ func getExpectedFileResponse() *api.FileResponse {
|
|||
|
||||
func TestGetFileResponseFromCommit(t *testing.T) {
|
||||
unittest.PrepareTestEnv(t)
|
||||
ctx, _ := contexttest.MockContext(t, "user2/repo1")
|
||||
ctx.SetParams(":id", "1")
|
||||
contexttest.LoadRepo(t, ctx, 1)
|
||||
contexttest.LoadRepoCommit(t, ctx)
|
||||
contexttest.LoadUser(t, ctx, 2)
|
||||
contexttest.LoadGitRepo(t, ctx)
|
||||
defer ctx.Repo.GitRepo.Close()
|
||||
|
||||
repo := ctx.Repo.Repository
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
branch := repo.DefaultBranch
|
||||
treePath := "README.md"
|
||||
gitRepo, _ := gitrepo.OpenRepository(ctx, repo)
|
||||
gitRepo, _ := gitrepo.OpenRepository(db.DefaultContext, repo)
|
||||
defer gitRepo.Close()
|
||||
commit, _ := gitRepo.GetBranchCommit(branch)
|
||||
expectedFileResponse := getExpectedFileResponse()
|
||||
|
||||
fileResponse, err := GetFileResponseFromCommit(ctx, repo, commit, branch, treePath)
|
||||
fileResponse, err := GetFileResponseFromCommit(db.DefaultContext, repo, commit, branch, treePath)
|
||||
require.NoError(t, err)
|
||||
assert.EqualValues(t, expectedFileResponse, fileResponse)
|
||||
}
|
||||
|
|
|
@ -18,7 +18,6 @@ func TestGetTreeBySHA(t *testing.T) {
|
|||
unittest.PrepareTestEnv(t)
|
||||
ctx, _ := contexttest.MockContext(t, "user2/repo1")
|
||||
contexttest.LoadRepo(t, ctx, 1)
|
||||
contexttest.LoadRepoCommit(t, ctx)
|
||||
contexttest.LoadUser(t, ctx, 2)
|
||||
contexttest.LoadGitRepo(t, ctx)
|
||||
defer ctx.Repo.GitRepo.Close()
|
||||
|
|
|
@ -300,6 +300,7 @@
|
|||
<label for="push_mirror_password">{{ctx.Locale.Tr "password"}}</label>
|
||||
<input id="push_mirror_password" name="push_mirror_password" type="password" value="{{.push_mirror_password}}" autocomplete="off">
|
||||
</div>
|
||||
{{if .CanUseSSHMirroring}}
|
||||
<div class="inline field {{if .Err_PushMirrorUseSSH}}error{{end}}">
|
||||
<div class="ui checkbox df ac">
|
||||
<input id="push_mirror_use_ssh" name="push_mirror_use_ssh" type="checkbox" {{if .push_mirror_use_ssh}}checked{{end}}>
|
||||
|
@ -307,6 +308,7 @@
|
|||
<span class="help tw-block">{{ctx.Locale.Tr "repo.mirror_use_ssh.helper"}}
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
</details>
|
||||
<div class="field">
|
||||
|
|
|
@ -64,7 +64,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="tw-mb-4">
|
||||
{{ctx.Locale.Tr "settings.language.localization_project" "https://forgejo.org/docs/latest/developer/localization/"}}
|
||||
{{ctx.Locale.Tr "settings.language.localization_project" "https://forgejo.org/docs/next/contributor/localization/"}}
|
||||
</div>
|
||||
<div class="field">
|
||||
<button class="ui primary button">{{ctx.Locale.Tr "settings.update_language"}}</button>
|
||||
|
|
|
@ -14,6 +14,7 @@ env:
|
|||
|
||||
rules:
|
||||
playwright/no-conditional-in-test: [0]
|
||||
playwright/no-conditional-expect: [0]
|
||||
playwright/no-networkidle: [0]
|
||||
playwright/no-skipped-test: [2, {allowConditional: true}]
|
||||
playwright/prefer-comparison-matcher: [2]
|
||||
|
|
|
@ -24,7 +24,8 @@ func TestDebugserver(t *testing.T) {
|
|||
done := make(chan os.Signal, 1)
|
||||
signal.Notify(done, syscall.SIGINT, syscall.SIGTERM)
|
||||
|
||||
onGiteaRun(t, func(*testing.T, *url.URL) {
|
||||
onForgejoRun(t, func(*testing.T, *url.URL) {
|
||||
defer DeclareGitRepos(t)()
|
||||
fmt.Println(setting.AppURL)
|
||||
<-done
|
||||
})
|
||||
|
|
83
tests/e2e/declare_repos_test.go
Normal file
83
tests/e2e/declare_repos_test.go
Normal file
|
@ -0,0 +1,83 @@
|
|||
// Copyright 2024 The Forgejo Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package e2e
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
unit_model "code.gitea.io/gitea/models/unit"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
files_service "code.gitea.io/gitea/services/repository/files"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
type FileChanges [][]string
|
||||
|
||||
// put your Git repo declarations in here
|
||||
// feel free to amend the helper function below or use the raw variant directly
|
||||
func DeclareGitRepos(t *testing.T) func() {
|
||||
var cleanupFunctions []func()
|
||||
cleanupFunctions = append(cleanupFunctions, newRepo(t, 2, "diff-test", FileChanges{
|
||||
{"testfile", "hello", "hallo", "hola", "native", "ubuntu-latest", "- runs-on: ubuntu-latest", "- runs-on: debian-latest"},
|
||||
}))
|
||||
|
||||
return func() {
|
||||
for _, cleanup := range cleanupFunctions {
|
||||
cleanup()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func newRepo(t *testing.T, userID int64, repoName string, fileChanges FileChanges) func() {
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: userID})
|
||||
somerepo, _, cleanupFunc := tests.CreateDeclarativeRepo(t, user, repoName,
|
||||
[]unit_model.Type{unit_model.TypeCode, unit_model.TypeIssues}, nil,
|
||||
nil,
|
||||
)
|
||||
|
||||
for _, file := range fileChanges {
|
||||
changeLen := len(file)
|
||||
for i := 1; i < changeLen; i++ {
|
||||
operation := "create"
|
||||
if i != 1 {
|
||||
operation = "update"
|
||||
}
|
||||
resp, err := files_service.ChangeRepoFiles(git.DefaultContext, somerepo, user, &files_service.ChangeRepoFilesOptions{
|
||||
Files: []*files_service.ChangeRepoFile{{
|
||||
Operation: operation,
|
||||
TreePath: file[0],
|
||||
ContentReader: strings.NewReader(file[i]),
|
||||
}},
|
||||
Message: fmt.Sprintf("Patch: %s-%s", file[0], strconv.Itoa(i)),
|
||||
OldBranch: "main",
|
||||
NewBranch: "main",
|
||||
Author: &files_service.IdentityOptions{
|
||||
Name: user.Name,
|
||||
Email: user.Email,
|
||||
},
|
||||
Committer: &files_service.IdentityOptions{
|
||||
Name: user.Name,
|
||||
Email: user.Email,
|
||||
},
|
||||
Dates: &files_service.CommitDateOptions{
|
||||
Author: time.Now(),
|
||||
Committer: time.Now(),
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.NotEmpty(t, resp)
|
||||
}
|
||||
}
|
||||
|
||||
return cleanupFunc
|
||||
}
|
|
@ -37,7 +37,7 @@ func TestMain(m *testing.M) {
|
|||
graceful.InitManager(managerCtx)
|
||||
defer cancel()
|
||||
|
||||
tests.InitTest(false)
|
||||
tests.InitTest(true)
|
||||
testE2eWebRoutes = routers.NormalRoutes()
|
||||
|
||||
os.Unsetenv("GIT_AUTHOR_NAME")
|
||||
|
@ -102,7 +102,8 @@ func TestE2e(t *testing.T) {
|
|||
|
||||
t.Run(testname, func(t *testing.T) {
|
||||
// Default 2 minute timeout
|
||||
onGiteaRun(t, func(*testing.T, *url.URL) {
|
||||
onForgejoRun(t, func(*testing.T, *url.URL) {
|
||||
defer DeclareGitRepos(t)()
|
||||
thisTest := runArgs
|
||||
thisTest = append(thisTest, path)
|
||||
cmd := exec.Command(runArgs[0], thisTest...)
|
||||
|
|
|
@ -51,3 +51,29 @@ test('Line Range Selection', async ({browser}, workerInfo) => {
|
|||
await page.goto(`${filePath}#L1-L100`);
|
||||
await assertSelectedLines(page, ['1', '2', '3']);
|
||||
});
|
||||
|
||||
test('Readable diff', async ({page}, workerInfo) => {
|
||||
// remove this when the test covers more (e.g. accessibility scans or interactive behaviour)
|
||||
test.skip(workerInfo.project.name !== 'firefox', 'This currently only tests the backend-generated HTML code and it is not necessary to test with multiple browsers.');
|
||||
const expectedDiffs = [
|
||||
{id: 'testfile-2', removed: 'e', added: 'a'},
|
||||
{id: 'testfile-3', removed: 'allo', added: 'ola'},
|
||||
{id: 'testfile-4', removed: 'hola', added: 'native'},
|
||||
{id: 'testfile-5', removed: 'native', added: 'ubuntu-latest'},
|
||||
{id: 'testfile-6', added: '- runs-on: '},
|
||||
{id: 'testfile-7', removed: 'ubuntu', added: 'debian'},
|
||||
];
|
||||
for (const thisDiff of expectedDiffs) {
|
||||
const response = await page.goto('/user2/diff-test/commits/branch/main');
|
||||
await expect(response?.status()).toBe(200); // Status OK
|
||||
await page.getByText(`Patch: ${thisDiff.id}`).click();
|
||||
if (thisDiff.removed) {
|
||||
await expect(page.getByText(thisDiff.removed, {exact: true})).toHaveClass(/removed-code/);
|
||||
await expect(page.getByText(thisDiff.removed, {exact: true})).toHaveCSS('background-color', 'rgb(252, 165, 165)');
|
||||
}
|
||||
if (thisDiff.added) {
|
||||
await expect(page.getByText(thisDiff.added, {exact: true})).toHaveClass(/added-code/);
|
||||
await expect(page.getByText(thisDiff.added, {exact: true})).toHaveCSS('background-color', 'rgb(134, 239, 172)');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -17,7 +17,7 @@ import (
|
|||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func onGiteaRunTB(t testing.TB, callback func(testing.TB, *url.URL), prepare ...bool) {
|
||||
func onForgejoRunTB(t testing.TB, callback func(testing.TB, *url.URL), prepare ...bool) {
|
||||
if len(prepare) == 0 || prepare[0] {
|
||||
defer tests.PrepareTestEnv(t, 1)()
|
||||
}
|
||||
|
@ -49,8 +49,8 @@ func onGiteaRunTB(t testing.TB, callback func(testing.TB, *url.URL), prepare ...
|
|||
callback(t, u)
|
||||
}
|
||||
|
||||
func onGiteaRun(t *testing.T, callback func(*testing.T, *url.URL), prepare ...bool) {
|
||||
onGiteaRunTB(t, func(t testing.TB, u *url.URL) {
|
||||
func onForgejoRun(t *testing.T, callback func(*testing.T, *url.URL), prepare ...bool) {
|
||||
onForgejoRunTB(t, func(t testing.TB, u *url.URL) {
|
||||
callback(t.(*testing.T), u)
|
||||
}, prepare...)
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
@ -23,6 +24,7 @@ import (
|
|||
"code.gitea.io/gitea/models/unit"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/optional"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
|
@ -141,6 +143,11 @@ func testAPIPushMirror(t *testing.T, u *url.URL) {
|
|||
}
|
||||
|
||||
func TestAPIPushMirrorSSH(t *testing.T) {
|
||||
_, err := exec.LookPath("ssh")
|
||||
if err != nil {
|
||||
t.Skip("SSH executable not present")
|
||||
}
|
||||
|
||||
onGiteaRun(t, func(t *testing.T, _ *url.URL) {
|
||||
defer test.MockVariableValue(&setting.Migrations.AllowLocalNetworks, true)()
|
||||
defer test.MockVariableValue(&setting.Mirror.Enabled, true)()
|
||||
|
@ -178,6 +185,22 @@ func TestAPIPushMirrorSSH(t *testing.T) {
|
|||
assert.EqualValues(t, "'use_ssh' is mutually exclusive with 'remote_username' and 'remote_passoword'", apiError.Message)
|
||||
})
|
||||
|
||||
t.Run("SSH not available", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
defer test.MockVariableValue(&git.HasSSHExecutable, false)()
|
||||
|
||||
req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/repos/%s/push_mirrors", srcRepo.FullName()), &api.CreatePushMirrorOption{
|
||||
RemoteAddress: sshURL,
|
||||
Interval: "8h",
|
||||
UseSSH: true,
|
||||
}).AddTokenAuth(token)
|
||||
resp := MakeRequest(t, req, http.StatusBadRequest)
|
||||
|
||||
var apiError api.APIError
|
||||
DecodeJSON(t, resp, &apiError)
|
||||
assert.EqualValues(t, "SSH authentication not available.", apiError.Message)
|
||||
})
|
||||
|
||||
t.Run("Normal", func(t *testing.T) {
|
||||
var pushMirror *repo_model.PushMirror
|
||||
t.Run("Adding", func(t *testing.T) {
|
||||
|
|
|
@ -15,7 +15,7 @@ import (
|
|||
"code.gitea.io/gitea/routers"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"gitea.com/go-chi/session"
|
||||
"code.forgejo.org/go-chi/session"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
@ -157,6 +158,11 @@ func doRemovePushMirror(ctx APITestContext, address, username, password string,
|
|||
}
|
||||
|
||||
func TestSSHPushMirror(t *testing.T) {
|
||||
_, err := exec.LookPath("ssh")
|
||||
if err != nil {
|
||||
t.Skip("SSH executable not present")
|
||||
}
|
||||
|
||||
onGiteaRun(t, func(t *testing.T, _ *url.URL) {
|
||||
defer test.MockVariableValue(&setting.Migrations.AllowLocalNetworks, true)()
|
||||
defer test.MockVariableValue(&setting.Mirror.Enabled, true)()
|
||||
|
@ -194,6 +200,36 @@ func TestSSHPushMirror(t *testing.T) {
|
|||
assert.Contains(t, errMsg, "Cannot use public key and password based authentication in combination.")
|
||||
})
|
||||
|
||||
inputSelector := `input[id="push_mirror_use_ssh"]`
|
||||
|
||||
t.Run("SSH not available", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
defer test.MockVariableValue(&git.HasSSHExecutable, false)()
|
||||
|
||||
req := NewRequestWithValues(t, "POST", fmt.Sprintf("/%s/settings", srcRepo.FullName()), map[string]string{
|
||||
"_csrf": GetCSRF(t, sess, fmt.Sprintf("/%s/settings", srcRepo.FullName())),
|
||||
"action": "push-mirror-add",
|
||||
"push_mirror_address": sshURL,
|
||||
"push_mirror_use_ssh": "true",
|
||||
"push_mirror_interval": "0",
|
||||
})
|
||||
resp := sess.MakeRequest(t, req, http.StatusOK)
|
||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||
|
||||
errMsg := htmlDoc.Find(".ui.negative.message").Text()
|
||||
assert.Contains(t, errMsg, "SSH authentication isn't available.")
|
||||
|
||||
htmlDoc.AssertElement(t, inputSelector, false)
|
||||
})
|
||||
|
||||
t.Run("SSH available", func(t *testing.T) {
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("/%s/settings", srcRepo.FullName()))
|
||||
resp := sess.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||
htmlDoc.AssertElement(t, inputSelector, true)
|
||||
})
|
||||
|
||||
t.Run("Normal", func(t *testing.T) {
|
||||
var pushMirror *repo_model.PushMirror
|
||||
t.Run("Adding", func(t *testing.T) {
|
||||
|
|
|
@ -548,6 +548,42 @@ func TestGitQuotaEnforcement(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestQuotaConfigDefault(t *testing.T) {
|
||||
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
||||
env := createQuotaWebEnv(t)
|
||||
defer env.Cleanup()
|
||||
|
||||
t.Run("with config-based default", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
defer test.MockVariableValue(&setting.Quota.Default.Total, 0)()
|
||||
|
||||
env.As(t, env.Users.Ungrouped).
|
||||
With(Context{
|
||||
Payload: &Payload{
|
||||
"uid": env.Users.Ungrouped.ID().AsString(),
|
||||
"repo_name": "quota-config-default",
|
||||
},
|
||||
}).
|
||||
PostToPage("/repo/create").
|
||||
ExpectStatus(http.StatusRequestEntityTooLarge)
|
||||
})
|
||||
|
||||
t.Run("without config-based default", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
env.As(t, env.Users.Ungrouped).
|
||||
With(Context{
|
||||
Payload: &Payload{
|
||||
"uid": env.Users.Ungrouped.ID().AsString(),
|
||||
"repo_name": "quota-config-default",
|
||||
},
|
||||
}).
|
||||
PostToPage("/repo/create").
|
||||
ExpectStatus(http.StatusSeeOther)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**********************
|
||||
* Here be dragons! *
|
||||
* *
|
||||
|
@ -568,6 +604,7 @@ type quotaWebEnv struct {
|
|||
type quotaWebEnvUsers struct {
|
||||
Limited quotaWebEnvUser
|
||||
Contributor quotaWebEnvUser
|
||||
Ungrouped quotaWebEnvUser
|
||||
}
|
||||
|
||||
type quotaWebEnvOrgs struct {
|
||||
|
@ -1005,8 +1042,7 @@ func createQuotaWebEnv(t *testing.T) *quotaWebEnv {
|
|||
|
||||
// *** helpers ***
|
||||
|
||||
// Create a user, its quota group & rule
|
||||
makeUser := func(t *testing.T, limit int64) quotaWebEnvUser {
|
||||
makeUngroupedUser := func(t *testing.T) quotaWebEnvUser {
|
||||
t.Helper()
|
||||
|
||||
user := quotaWebEnvUser{}
|
||||
|
@ -1021,6 +1057,16 @@ func createQuotaWebEnv(t *testing.T) *quotaWebEnv {
|
|||
repo, _, _ := tests.CreateDeclarativeRepoWithOptions(t, user.User, tests.DeclarativeRepoOptions{})
|
||||
user.Repo = repo
|
||||
|
||||
return user
|
||||
}
|
||||
|
||||
// Create a user, its quota group & rule
|
||||
makeUser := func(t *testing.T, limit int64) quotaWebEnvUser {
|
||||
t.Helper()
|
||||
|
||||
user := makeUngroupedUser(t)
|
||||
userName := user.User.Name
|
||||
|
||||
// Create a quota group for them
|
||||
group, err := quota_model.CreateGroup(db.DefaultContext, userName)
|
||||
require.NoError(t, err)
|
||||
|
@ -1095,5 +1141,7 @@ func createQuotaWebEnv(t *testing.T) *quotaWebEnv {
|
|||
env.Orgs.Limited = makeOrg(t, env.Users.Limited.User, int64(0))
|
||||
env.Orgs.Unlimited = makeOrg(t, env.Users.Limited.User, int64(-1))
|
||||
|
||||
env.Users.Ungrouped = makeUngroupedUser(t)
|
||||
|
||||
return &env
|
||||
}
|
||||
|
|
|
@ -52,8 +52,13 @@ func createRepoAndGetContext(t *testing.T, files []string, deleteMdReadme bool)
|
|||
ctx, _ := contexttest.MockContext(t, "user1/readmetest")
|
||||
ctx.SetParams(":id", fmt.Sprint(repo.ID))
|
||||
contexttest.LoadRepo(t, ctx, repo.ID)
|
||||
contexttest.LoadGitRepo(t, ctx)
|
||||
contexttest.LoadRepoCommit(t, ctx)
|
||||
return ctx, f
|
||||
|
||||
return ctx, func() {
|
||||
f()
|
||||
ctx.Repo.GitRepo.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func TestRepoView_FindReadme(t *testing.T) {
|
||||
|
|
|
@ -12,11 +12,11 @@ import (
|
|||
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/gitrepo"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/services/contexttest"
|
||||
files_service "code.gitea.io/gitea/services/repository/files"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
@ -247,16 +247,8 @@ func getExpectedFileResponseForRepofilesUpdate(commitID, filename, lastCommitSHA
|
|||
func TestChangeRepoFilesForCreate(t *testing.T) {
|
||||
// setup
|
||||
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
||||
ctx, _ := contexttest.MockContext(t, "user2/repo1")
|
||||
ctx.SetParams(":id", "1")
|
||||
contexttest.LoadRepo(t, ctx, 1)
|
||||
contexttest.LoadRepoCommit(t, ctx)
|
||||
contexttest.LoadUser(t, ctx, 2)
|
||||
contexttest.LoadGitRepo(t, ctx)
|
||||
defer ctx.Repo.GitRepo.Close()
|
||||
|
||||
repo := ctx.Repo.Repository
|
||||
doer := ctx.Doer
|
||||
doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
opts := getCreateRepoFilesOptions(repo)
|
||||
|
||||
// test
|
||||
|
@ -284,16 +276,8 @@ func TestChangeRepoFilesForCreate(t *testing.T) {
|
|||
func TestChangeRepoFilesForUpdate(t *testing.T) {
|
||||
// setup
|
||||
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
||||
ctx, _ := contexttest.MockContext(t, "user2/repo1")
|
||||
ctx.SetParams(":id", "1")
|
||||
contexttest.LoadRepo(t, ctx, 1)
|
||||
contexttest.LoadRepoCommit(t, ctx)
|
||||
contexttest.LoadUser(t, ctx, 2)
|
||||
contexttest.LoadGitRepo(t, ctx)
|
||||
defer ctx.Repo.GitRepo.Close()
|
||||
|
||||
repo := ctx.Repo.Repository
|
||||
doer := ctx.Doer
|
||||
doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
opts := getUpdateRepoFilesOptions(repo)
|
||||
|
||||
// test
|
||||
|
@ -318,16 +302,8 @@ func TestChangeRepoFilesForUpdate(t *testing.T) {
|
|||
func TestChangeRepoFilesForUpdateWithFileMove(t *testing.T) {
|
||||
// setup
|
||||
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
||||
ctx, _ := contexttest.MockContext(t, "user2/repo1")
|
||||
ctx.SetParams(":id", "1")
|
||||
contexttest.LoadRepo(t, ctx, 1)
|
||||
contexttest.LoadRepoCommit(t, ctx)
|
||||
contexttest.LoadUser(t, ctx, 2)
|
||||
contexttest.LoadGitRepo(t, ctx)
|
||||
defer ctx.Repo.GitRepo.Close()
|
||||
|
||||
repo := ctx.Repo.Repository
|
||||
doer := ctx.Doer
|
||||
doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
opts := getUpdateRepoFilesOptions(repo)
|
||||
opts.Files[0].FromTreePath = "README.md"
|
||||
opts.Files[0].TreePath = "README_new.md" // new file name, README_new.md
|
||||
|
@ -369,16 +345,8 @@ func TestChangeRepoFilesForUpdateWithFileMove(t *testing.T) {
|
|||
func TestChangeRepoFilesWithoutBranchNames(t *testing.T) {
|
||||
// setup
|
||||
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
||||
ctx, _ := contexttest.MockContext(t, "user2/repo1")
|
||||
ctx.SetParams(":id", "1")
|
||||
contexttest.LoadRepo(t, ctx, 1)
|
||||
contexttest.LoadRepoCommit(t, ctx)
|
||||
contexttest.LoadUser(t, ctx, 2)
|
||||
contexttest.LoadGitRepo(t, ctx)
|
||||
defer ctx.Repo.GitRepo.Close()
|
||||
|
||||
repo := ctx.Repo.Repository
|
||||
doer := ctx.Doer
|
||||
doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
opts := getUpdateRepoFilesOptions(repo)
|
||||
opts.OldBranch = ""
|
||||
opts.NewBranch = ""
|
||||
|
@ -405,15 +373,8 @@ func TestChangeRepoFilesForDelete(t *testing.T) {
|
|||
func testDeleteRepoFiles(t *testing.T, u *url.URL) {
|
||||
// setup
|
||||
unittest.PrepareTestEnv(t)
|
||||
ctx, _ := contexttest.MockContext(t, "user2/repo1")
|
||||
ctx.SetParams(":id", "1")
|
||||
contexttest.LoadRepo(t, ctx, 1)
|
||||
contexttest.LoadRepoCommit(t, ctx)
|
||||
contexttest.LoadUser(t, ctx, 2)
|
||||
contexttest.LoadGitRepo(t, ctx)
|
||||
defer ctx.Repo.GitRepo.Close()
|
||||
repo := ctx.Repo.Repository
|
||||
doer := ctx.Doer
|
||||
doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
opts := getDeleteRepoFilesOptions(repo)
|
||||
|
||||
t.Run("Delete README.md file", func(t *testing.T) {
|
||||
|
@ -444,16 +405,9 @@ func TestChangeRepoFilesForDeleteWithoutBranchNames(t *testing.T) {
|
|||
func testDeleteRepoFilesWithoutBranchNames(t *testing.T, u *url.URL) {
|
||||
// setup
|
||||
unittest.PrepareTestEnv(t)
|
||||
ctx, _ := contexttest.MockContext(t, "user2/repo1")
|
||||
ctx.SetParams(":id", "1")
|
||||
contexttest.LoadRepo(t, ctx, 1)
|
||||
contexttest.LoadRepoCommit(t, ctx)
|
||||
contexttest.LoadUser(t, ctx, 2)
|
||||
contexttest.LoadGitRepo(t, ctx)
|
||||
defer ctx.Repo.GitRepo.Close()
|
||||
doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
|
||||
repo := ctx.Repo.Repository
|
||||
doer := ctx.Doer
|
||||
opts := getDeleteRepoFilesOptions(repo)
|
||||
opts.OldBranch = ""
|
||||
opts.NewBranch = ""
|
||||
|
@ -474,16 +428,8 @@ func testDeleteRepoFilesWithoutBranchNames(t *testing.T, u *url.URL) {
|
|||
func TestChangeRepoFilesErrors(t *testing.T) {
|
||||
// setup
|
||||
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
||||
ctx, _ := contexttest.MockContext(t, "user2/repo1")
|
||||
ctx.SetParams(":id", "1")
|
||||
contexttest.LoadRepo(t, ctx, 1)
|
||||
contexttest.LoadRepoCommit(t, ctx)
|
||||
contexttest.LoadUser(t, ctx, 2)
|
||||
contexttest.LoadGitRepo(t, ctx)
|
||||
defer ctx.Repo.GitRepo.Close()
|
||||
|
||||
repo := ctx.Repo.Repository
|
||||
doer := ctx.Doer
|
||||
doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
|
||||
t.Run("bad branch", func(t *testing.T) {
|
||||
opts := getUpdateRepoFilesOptions(repo)
|
||||
|
|
|
@ -389,7 +389,7 @@ func TestUserHints(t *testing.T) {
|
|||
assert.Equal(t, enabled, hintChecked)
|
||||
|
||||
link, _ := htmlDoc.Find("form[action='/user/settings/appearance/language'] a").Attr("href")
|
||||
assert.EqualValues(t, "https://forgejo.org/docs/latest/developer/localization/", link)
|
||||
assert.EqualValues(t, "https://forgejo.org/docs/next/contributor/localization/", link)
|
||||
}
|
||||
|
||||
t.Run("view", func(t *testing.T) {
|
||||
|
|
Loading…
Reference in a new issue