mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2024-12-01 13:44:06 +01:00
Merge branch 'forgejo' into bugfix-arch
This commit is contained in:
commit
bc4849a904
71 changed files with 1044 additions and 365 deletions
|
@ -10,7 +10,7 @@ labels:
|
||||||
|
|
||||||
## Checklist
|
## 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
|
### 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
|
# https://codeberg.org/forgejo-integration/forgejo
|
||||||
#
|
#
|
||||||
|
|
|
@ -22,7 +22,7 @@ jobs:
|
||||||
go-version-file: "go.mod"
|
go-version-file: "go.mod"
|
||||||
- run: |
|
- run: |
|
||||||
apt-get -qq update
|
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
|
sed -i -e 's/%sudo.*/%sudo ALL=(ALL:ALL) NOPASSWD:ALL/' /etc/sudoers
|
||||||
git config --add safe.directory '*'
|
git config --add safe.directory '*'
|
||||||
adduser --quiet --comment forgejo --disabled-password forgejo
|
adduser --quiet --comment forgejo --disabled-password forgejo
|
||||||
|
@ -30,6 +30,8 @@ jobs:
|
||||||
chown -R forgejo:forgejo .
|
chown -R forgejo:forgejo .
|
||||||
- run: |
|
- run: |
|
||||||
su forgejo -c 'make deps-frontend frontend deps-backend'
|
su forgejo -c 'make deps-frontend frontend deps-backend'
|
||||||
|
- run: |
|
||||||
|
su forgejo -c 'make backend'
|
||||||
- run: |
|
- run: |
|
||||||
su forgejo -c 'make generate test-e2e-sqlite'
|
su forgejo -c 'make generate test-e2e-sqlite'
|
||||||
timeout-minutes: 40
|
timeout-minutes: 40
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# SPDX-License-Identifier: MIT
|
# 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
|
# https://codeberg.org/forgejo-experimental/forgejo
|
||||||
#
|
#
|
||||||
|
|
|
@ -23,7 +23,7 @@ jobs:
|
||||||
|
|
||||||
runs-on: docker
|
runs-on: docker
|
||||||
container:
|
container:
|
||||||
image: code.forgejo.org/forgejo-contrib/renovate:38.39.6
|
image: code.forgejo.org/forgejo-contrib/renovate:38.52.3
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Load renovate repo cache
|
- 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).
|
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
|
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
|
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
|
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)
|
ifeq ($(HAS_GO), yes)
|
||||||
CGO_EXTRA_CFLAGS := -DSQLITE_MAX_VARIABLE_NUMBER=32766
|
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/storage"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
|
|
||||||
"gitea.com/go-chi/session"
|
"code.forgejo.org/go-chi/session"
|
||||||
"github.com/mholt/archiver/v3"
|
"github.com/mholt/archiver/v3"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
17
go.mod
17
go.mod
|
@ -5,6 +5,7 @@ go 1.23.0
|
||||||
require (
|
require (
|
||||||
code.forgejo.org/f3/gof3/v3 v3.7.0
|
code.forgejo.org/f3/gof3/v3 v3.7.0
|
||||||
code.forgejo.org/forgejo/reply v1.0.2
|
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/actions-proto-go v0.4.0
|
||||||
code.gitea.io/gitea-vet v0.2.3
|
code.gitea.io/gitea-vet v0.2.3
|
||||||
code.gitea.io/sdk/gitea v0.17.1
|
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/binding v0.0.0-20240430071103-39a851e106ed
|
||||||
gitea.com/go-chi/cache v0.2.0
|
gitea.com/go-chi/cache v0.2.0
|
||||||
gitea.com/go-chi/captcha v0.0.0-20240315150714-fb487f629098
|
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
|
gitea.com/lunny/levelqueue v0.4.2-0.20230414023320-3c0159fe0fe4
|
||||||
github.com/42wim/sshsig v0.0.0-20211121163825-841cf5bbc121
|
github.com/42wim/sshsig v0.0.0-20211121163825-841cf5bbc121
|
||||||
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358
|
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358
|
||||||
|
@ -37,7 +37,7 @@ require (
|
||||||
github.com/gliderlabs/ssh v0.3.7
|
github.com/gliderlabs/ssh v0.3.7
|
||||||
github.com/go-ap/activitypub v0.0.0-20231114162308-e219254dc5c9
|
github.com/go-ap/activitypub v0.0.0-20231114162308-e219254dc5c9
|
||||||
github.com/go-ap/jsonld v0.0.0-20221030091449-f2a191312c73
|
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-chi/cors v1.2.1
|
||||||
github.com/go-co-op/gocron v1.37.0
|
github.com/go-co-op/gocron v1.37.0
|
||||||
github.com/go-enry/go-enry/v2 v2.8.9
|
github.com/go-enry/go-enry/v2 v2.8.9
|
||||||
|
@ -84,7 +84,7 @@ require (
|
||||||
github.com/pquerna/otp v1.4.0
|
github.com/pquerna/otp v1.4.0
|
||||||
github.com/prometheus/client_golang v1.18.0
|
github.com/prometheus/client_golang v1.18.0
|
||||||
github.com/quasoft/websspi v1.1.2
|
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/robfig/cron/v3 v3.0.1
|
||||||
github.com/santhosh-tekuri/jsonschema/v6 v6.0.1
|
github.com/santhosh-tekuri/jsonschema/v6 v6.0.1
|
||||||
github.com/sassoftware/go-rpmutils v0.4.0
|
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/cention-sany/utf7 v0.0.0-20170124080048-26cad61bd60a // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||||
github.com/cloudflare/circl v1.3.8 // 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/cpuguy83/go-md2man/v2 v2.0.4 // indirect
|
||||||
github.com/cyphar/filepath-securejoin v0.2.4 // indirect
|
github.com/cyphar/filepath-securejoin v0.2.4 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // 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
|
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
|
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/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 h1:dMhQCHV6/O3L5CLWNTol+dNzDAuyCK88z4J/lCdgFuQ=
|
||||||
code.forgejo.org/forgejo/reply v1.0.2/go.mod h1:RyZUfzQLc+fuLIGjTSQWDAJWPiL4WtKXB/FifT5fM7U=
|
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 h1:OsPBPhodXuQnsspG1sQ4eRE1PeoZyofd7+i73zCwnsU=
|
||||||
code.gitea.io/actions-proto-go v0.4.0/go.mod h1:mn7Wkqz6JbnTOHQpot3yDeHx+O5C9EGhMEE+htvHBas=
|
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=
|
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/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 h1:p2ki+WK0cIeNQuqjR98IP2KZQKRzJJiV7aTeMAFwaWo=
|
||||||
gitea.com/go-chi/captcha v0.0.0-20240315150714-fb487f629098/go.mod h1:LjzIOHlRemuUyO7WR12fmm18VZIlCAaOt9L3yKw40pk=
|
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 h1:IFT+hup2xejHqdhS7keYWioqfmxdnfblFDTGoOwcZ+o=
|
||||||
gitea.com/lunny/levelqueue v0.4.2-0.20230414023320-3c0159fe0fe4/go.mod h1:HBqmLbz56JWpfEGG0prskAV97ATNRoj5LDmPicD22hU=
|
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=
|
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.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
|
||||||
github.com/cloudflare/circl v1.3.8 h1:j+V8jJt09PoeMFIu2uh5JUyEaIHTXVOHslFoLNAKqwI=
|
github.com/cloudflare/circl v1.3.8 h1:j+V8jJt09PoeMFIu2uh5JUyEaIHTXVOHslFoLNAKqwI=
|
||||||
github.com/cloudflare/circl v1.3.8/go.mod h1:PDRU+oXvdD7KCtgKxW95M5Z8BpSCJXQORiZFnBQS5QU=
|
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 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
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=
|
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 h1:MNHlNMBDgEKD4TcKr36vQN68BA00aDfjIt3/bD50WnA=
|
||||||
github.com/go-asn1-ber/asn1-ber v1.5.5/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
|
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.1/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
||||||
github.com/go-chi/chi/v5 v5.0.14 h1:PyEwo2Vudraa0x/Wl6eDRRW2NXBvekgfxyydcM0WGE0=
|
github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw=
|
||||||
github.com/go-chi/chi/v5 v5.0.14/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
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 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4=
|
||||||
github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
|
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=
|
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/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 h1:/mA4w0LxWlE3novvsoEL6BBA1WnjJATbjkh1kFrTidw=
|
||||||
github.com/quasoft/websspi v1.1.2/go.mod h1:HmVdl939dQ0WIXZhyik+ARdI03M6bQzaSEKcgpFmewk=
|
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.6.1 h1:HHDteefn6ZkTtY5fGUE8tj8uy85AHk6zP7CpzIAM0y4=
|
||||||
github.com/redis/go-redis/v9 v9.5.2/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M=
|
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 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||||
github.com/rhysd/actionlint v1.6.27 h1:xxwe8YmveBcC8lydW6GoHMGmB6H/MTqUU60F2p10wjw=
|
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 {
|
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 {
|
if gl == nil || len(*gl) == 0 {
|
||||||
return true
|
return EvaluateDefault(used, forSubject)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, group := range *gl {
|
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
|
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.
|
// Run before opening git cat-file.
|
||||||
// This is needed otherwise the git cat-file will hang for invalid repositories.
|
// 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{}
|
stderr := strings.Builder{}
|
||||||
err := NewCommand(ctx, "rev-parse").
|
err := NewCommand(ctx, "rev-parse").
|
||||||
SetDescription(fmt.Sprintf("%s rev-parse [repo_path: %s]", GitExecutable, repoPath)).
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CatFileBatchCheck opens git cat-file --batch-check in the provided repo and returns a stdin pipe, a stdout reader and cancel function
|
// 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()) {
|
func catFileBatchCheck(ctx context.Context, repoPath string) (WriteCloserError, *bufio.Reader, func()) {
|
||||||
batchStdinReader, batchStdinWriter := io.Pipe()
|
batchStdinReader, batchStdinWriter := io.Pipe()
|
||||||
batchStdoutReader, batchStdoutWriter := io.Pipe()
|
batchStdoutReader, batchStdoutWriter := io.Pipe()
|
||||||
ctx, ctxCancel := context.WithCancel(ctx)
|
ctx, ctxCancel := context.WithCancel(ctx)
|
||||||
|
@ -93,8 +93,8 @@ func CatFileBatchCheck(ctx context.Context, repoPath string) (WriteCloserError,
|
||||||
return batchStdinWriter, batchReader, cancel
|
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
|
// 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()) {
|
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.
|
// 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
|
// so let's create a batch stdin and stdout
|
||||||
batchStdinReader, batchStdinWriter := io.Pipe()
|
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.
|
// 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.
|
// Calling the Close function on the result will discard all unread output.
|
||||||
func (b *Blob) DataAsync() (io.ReadCloser, error) {
|
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 {
|
if err != nil {
|
||||||
cancel()
|
cancel()
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -66,9 +69,13 @@ func (b *Blob) Size() int64 {
|
||||||
return b.size
|
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()
|
defer cancel()
|
||||||
_, err := wr.Write([]byte(b.ID.String() + "\n"))
|
_, err = wr.Write([]byte(b.ID.String() + "\n"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("error whilst reading size for %s in %s. Error: %v", b.ID.String(), b.repo.Path, err)
|
log.Debug("error whilst reading size for %s in %s. Error: %v", b.ID.String(), b.repo.Path, err)
|
||||||
return 0
|
return 0
|
||||||
|
|
|
@ -129,7 +129,10 @@ func GetLastCommitForPaths(ctx context.Context, commit *Commit, treePath string,
|
||||||
return nil, err
|
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()
|
defer cancel()
|
||||||
|
|
||||||
commitsMap := map[string]*Commit{}
|
commitsMap := map[string]*Commit{}
|
||||||
|
|
|
@ -38,6 +38,8 @@ var (
|
||||||
InvertedGitFlushEnv bool // 2.43.1
|
InvertedGitFlushEnv bool // 2.43.1
|
||||||
SupportCheckAttrOnBare bool // >= 2.40
|
SupportCheckAttrOnBare bool // >= 2.40
|
||||||
|
|
||||||
|
HasSSHExecutable bool
|
||||||
|
|
||||||
gitVersion *version.Version
|
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=")
|
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()
|
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.
|
// 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
|
// 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()
|
defer cancel()
|
||||||
|
|
||||||
// We'll use a scanner for the revList because it's simpler than a bufio.Reader
|
// We'll use a scanner for the revList because it's simpler than a bufio.Reader
|
||||||
|
|
|
@ -22,14 +22,10 @@ type Repository struct {
|
||||||
gpgSettings *GPGSettings
|
gpgSettings *GPGSettings
|
||||||
|
|
||||||
batchInUse bool
|
batchInUse bool
|
||||||
batchCancel context.CancelFunc
|
batch *Batch
|
||||||
batchReader *bufio.Reader
|
|
||||||
batchWriter WriteCloserError
|
|
||||||
|
|
||||||
checkInUse bool
|
checkInUse bool
|
||||||
checkCancel context.CancelFunc
|
check *Batch
|
||||||
checkReader *bufio.Reader
|
|
||||||
checkWriter WriteCloserError
|
|
||||||
|
|
||||||
Ctx context.Context
|
Ctx context.Context
|
||||||
LastCommitCache *LastCommitCache
|
LastCommitCache *LastCommitCache
|
||||||
|
@ -51,63 +47,75 @@ func OpenRepository(ctx context.Context, repoPath string) (*Repository, error) {
|
||||||
return nil, errors.New("no such file or directory")
|
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!
|
return &Repository{
|
||||||
if err := EnsureValidGitRepository(ctx, repoPath); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
repo := &Repository{
|
|
||||||
Path: repoPath,
|
Path: repoPath,
|
||||||
tagCache: newObjectCache(),
|
tagCache: newObjectCache(),
|
||||||
Ctx: ctx,
|
Ctx: ctx,
|
||||||
}
|
}, nil
|
||||||
|
|
||||||
repo.batchWriter, repo.batchReader, repo.batchCancel = CatFileBatch(ctx, repoPath)
|
|
||||||
repo.checkWriter, repo.checkReader, repo.checkCancel = CatFileBatchCheck(ctx, repoPath)
|
|
||||||
|
|
||||||
return repo, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CatFileBatch obtains a CatFileBatch for this repository
|
// CatFileBatch obtains a CatFileBatch for this repository
|
||||||
func (repo *Repository) CatFileBatch(ctx context.Context) (WriteCloserError, *bufio.Reader, func()) {
|
func (repo *Repository) CatFileBatch(ctx context.Context) (WriteCloserError, *bufio.Reader, func(), error) {
|
||||||
if repo.batchCancel == nil || repo.batchInUse {
|
if repo.batch == nil {
|
||||||
log.Debug("Opening temporary cat file batch for: %s", repo.Path)
|
var err error
|
||||||
return CatFileBatch(ctx, repo.Path)
|
repo.batch, err = repo.NewBatch(ctx)
|
||||||
}
|
if err != nil {
|
||||||
repo.batchInUse = true
|
return nil, nil, nil, err
|
||||||
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
|
// CatFileBatchCheck obtains a CatFileBatchCheck for this repository
|
||||||
func (repo *Repository) CatFileBatchCheck(ctx context.Context) (WriteCloserError, *bufio.Reader, func()) {
|
func (repo *Repository) CatFileBatchCheck(ctx context.Context) (WriteCloserError, *bufio.Reader, func(), error) {
|
||||||
if repo.checkCancel == nil || repo.checkInUse {
|
if repo.check == nil {
|
||||||
log.Debug("Opening temporary cat file batch-check for: %s", repo.Path)
|
var err error
|
||||||
return CatFileBatchCheck(ctx, repo.Path)
|
repo.check, err = repo.NewBatchCheck(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, nil, err
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !repo.checkInUse {
|
||||||
repo.checkInUse = true
|
repo.checkInUse = true
|
||||||
return repo.checkWriter, repo.checkReader, func() {
|
return repo.check.Writer, repo.check.Reader, func() {
|
||||||
repo.checkInUse = false
|
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 {
|
func (repo *Repository) Close() error {
|
||||||
if repo == nil {
|
if repo == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if repo.batchCancel != nil {
|
if repo.batch != nil {
|
||||||
repo.batchCancel()
|
repo.batch.Close()
|
||||||
repo.batchReader = nil
|
repo.batch = nil
|
||||||
repo.batchWriter = nil
|
|
||||||
repo.batchCancel = nil
|
|
||||||
repo.batchInUse = false
|
repo.batchInUse = false
|
||||||
}
|
}
|
||||||
if repo.checkCancel != nil {
|
if repo.check != nil {
|
||||||
repo.checkCancel()
|
repo.check.Close()
|
||||||
repo.checkCancel = nil
|
repo.check = nil
|
||||||
repo.checkReader = nil
|
|
||||||
repo.checkWriter = nil
|
|
||||||
repo.checkInUse = false
|
repo.checkInUse = false
|
||||||
}
|
}
|
||||||
repo.LastCommitCache = nil
|
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
|
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()
|
defer cancel()
|
||||||
_, err := wr.Write([]byte(name + "\n"))
|
_, err = wr.Write([]byte(name + "\n"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Error writing to CatFileBatchCheck %v", err)
|
log.Debug("Error writing to CatFileBatchCheck %v", err)
|
||||||
return false
|
return false
|
||||||
|
@ -186,9 +190,13 @@ func (repo *Repository) IsReferenceExist(name string) bool {
|
||||||
return false
|
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()
|
defer cancel()
|
||||||
_, err := wr.Write([]byte(name + "\n"))
|
_, err = wr.Write([]byte(name + "\n"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Error writing to CatFileBatchCheck %v", err)
|
log.Debug("Error writing to CatFileBatchCheck %v", err)
|
||||||
return false
|
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).
|
// GetRefCommitID returns the last commit ID string of given reference (branch or tag).
|
||||||
func (repo *Repository) GetRefCommitID(name string) (string, error) {
|
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()
|
defer cancel()
|
||||||
_, err := wr.Write([]byte(name + "\n"))
|
_, err = wr.Write([]byte(name + "\n"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
@ -564,12 +567,19 @@ func (repo *Repository) RemoveReference(name string) error {
|
||||||
|
|
||||||
// IsCommitExist returns true if given commit exists in current repository.
|
// IsCommitExist returns true if given commit exists in current repository.
|
||||||
func (repo *Repository) IsCommitExist(name string) bool {
|
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})
|
_, _, err := NewCommand(repo.Ctx, "cat-file", "-e").AddDynamicArguments(name).RunStdString(&RunOpts{Dir: repo.Path})
|
||||||
return err == nil
|
return err == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *Repository) getCommit(id ObjectID) (*Commit, error) {
|
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()
|
defer cancel()
|
||||||
|
|
||||||
_, _ = wr.Write([]byte(id.String() + "\n"))
|
_, _ = 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()
|
defer cancel()
|
||||||
_, err = wr.Write([]byte(commitID + "\n"))
|
_, err = wr.Write([]byte(commitID + "\n"))
|
||||||
if err != nil {
|
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) {
|
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.
|
// 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
|
// 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()
|
defer cancel()
|
||||||
|
|
||||||
writeID := func(id string) error {
|
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)
|
// GetTagType gets the type of the tag, either commit (simple) or tag (annotated)
|
||||||
func (repo *Repository) GetTagType(id ObjectID) (string, error) {
|
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()
|
defer cancel()
|
||||||
_, err := wr.Write([]byte(id.String() + "\n"))
|
_, err = wr.Write([]byte(id.String() + "\n"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
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.
|
// 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()
|
defer cancel()
|
||||||
|
|
||||||
if _, err := wr.Write([]byte(tagID.String() + "\n")); err != nil {
|
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) {
|
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()
|
defer cancel()
|
||||||
|
|
||||||
_, _ = wr.Write([]byte(id.String() + "\n"))
|
_, _ = wr.Write([]byte(id.String() + "\n"))
|
||||||
|
|
|
@ -41,7 +41,10 @@ func (t *Tree) ListEntries() (Entries, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if t.repo != nil {
|
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()
|
defer cancel()
|
||||||
|
|
||||||
_, _ = wr.Write([]byte(t.ID.String() + "\n"))
|
_, _ = wr.Write([]byte(t.ID.String() + "\n"))
|
||||||
|
|
|
@ -47,9 +47,13 @@ func (te *TreeEntry) Size() int64 {
|
||||||
return te.size
|
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()
|
defer cancel()
|
||||||
_, err := wr.Write([]byte(te.ID.String() + "\n"))
|
_, err = wr.Write([]byte(te.ID.String() + "\n"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("error whilst reading size for %s in %s. Error: %v", te.ID.String(), te.ptree.repo.Path, err)
|
log.Debug("error whilst reading size for %s in %s. Error: %v", te.ID.String(), te.ptree.repo.Path, err)
|
||||||
return 0
|
return 0
|
||||||
|
|
|
@ -16,10 +16,10 @@ import (
|
||||||
"code.gitea.io/gitea/modules/analyze"
|
"code.gitea.io/gitea/modules/analyze"
|
||||||
"code.gitea.io/gitea/modules/charset"
|
"code.gitea.io/gitea/modules/charset"
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
|
"code.gitea.io/gitea/modules/gitrepo"
|
||||||
"code.gitea.io/gitea/modules/indexer/code/internal"
|
"code.gitea.io/gitea/modules/indexer/code/internal"
|
||||||
indexer_internal "code.gitea.io/gitea/modules/indexer/internal"
|
indexer_internal "code.gitea.io/gitea/modules/indexer/internal"
|
||||||
inner_bleve "code.gitea.io/gitea/modules/indexer/internal/bleve"
|
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/setting"
|
||||||
"code.gitea.io/gitea/modules/timeutil"
|
"code.gitea.io/gitea/modules/timeutil"
|
||||||
"code.gitea.io/gitea/modules/typesniffer"
|
"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 {
|
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)
|
batch := inner_bleve.NewFlushingBatch(b.inner.Indexer, maxBatchSize)
|
||||||
if len(changes.Updates) > 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!
|
r, err := gitrepo.OpenRepository(ctx, repo)
|
||||||
if err := git.EnsureValidGitRepository(ctx, repo.RepoPath()); err != nil {
|
if err != nil {
|
||||||
log.Error("Unable to open git repo: %s for %-v: %v", repo.RepoPath(), repo, err)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
defer r.Close()
|
||||||
batchWriter, batchReader, cancel := git.CatFileBatch(ctx, repo.RepoPath())
|
gitBatch, err := r.NewBatch(ctx)
|
||||||
defer cancel()
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer gitBatch.Close()
|
||||||
|
|
||||||
for _, update := range changes.Updates {
|
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
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cancel()
|
gitBatch.Close()
|
||||||
}
|
}
|
||||||
for _, filename := range changes.RemovedFilenames {
|
for _, filename := range changes.RemovedFilenames {
|
||||||
if err := b.addDelete(filename, repo, batch); err != nil {
|
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/analyze"
|
||||||
"code.gitea.io/gitea/modules/charset"
|
"code.gitea.io/gitea/modules/charset"
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
|
"code.gitea.io/gitea/modules/gitrepo"
|
||||||
"code.gitea.io/gitea/modules/indexer/code/internal"
|
"code.gitea.io/gitea/modules/indexer/code/internal"
|
||||||
indexer_internal "code.gitea.io/gitea/modules/indexer/internal"
|
indexer_internal "code.gitea.io/gitea/modules/indexer/internal"
|
||||||
inner_elasticsearch "code.gitea.io/gitea/modules/indexer/internal/elasticsearch"
|
inner_elasticsearch "code.gitea.io/gitea/modules/indexer/internal/elasticsearch"
|
||||||
"code.gitea.io/gitea/modules/json"
|
"code.gitea.io/gitea/modules/json"
|
||||||
"code.gitea.io/gitea/modules/log"
|
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/modules/timeutil"
|
"code.gitea.io/gitea/modules/timeutil"
|
||||||
"code.gitea.io/gitea/modules/typesniffer"
|
"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 {
|
func (b *Indexer) Index(ctx context.Context, repo *repo_model.Repository, sha string, changes *internal.RepoChanges) error {
|
||||||
reqs := make([]elastic.BulkableRequest, 0)
|
reqs := make([]elastic.BulkableRequest, 0)
|
||||||
if len(changes.Updates) > 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!
|
r, err := gitrepo.OpenRepository(ctx, repo)
|
||||||
if err := git.EnsureValidGitRepository(ctx, repo.RepoPath()); err != nil {
|
if err != nil {
|
||||||
log.Error("Unable to open git repo: %s for %-v: %v", repo.RepoPath(), repo, err)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
defer r.Close()
|
||||||
batchWriter, batchReader, cancel := git.CatFileBatch(ctx, repo.RepoPath())
|
batch, err := r.NewBatch(ctx)
|
||||||
defer cancel()
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer batch.Close()
|
||||||
|
|
||||||
for _, update := range changes.Updates {
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -172,7 +174,7 @@ func (b *Indexer) Index(ctx context.Context, repo *repo_model.Repository, sha st
|
||||||
reqs = append(reqs, updateReqs...)
|
reqs = append(reqs, updateReqs...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cancel()
|
batch.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, filename := range changes.RemovedFilenames {
|
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)
|
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.
|
// HGet mocks base method.
|
||||||
func (m *MockUniversalClient) HGet(arg0 context.Context, arg1, arg2 string) *redis.StringCmd {
|
func (m *MockUniversalClient) HGet(arg0 context.Context, arg1, arg2 string) *redis.StringCmd {
|
||||||
m.ctrl.T.Helper()
|
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...)
|
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.
|
// HRandField mocks base method.
|
||||||
func (m *MockUniversalClient) HRandField(arg0 context.Context, arg1 string, arg2 int) *redis.StringSliceCmd {
|
func (m *MockUniversalClient) HRandField(arg0 context.Context, arg1 string, arg2 int) *redis.StringSliceCmd {
|
||||||
m.ctrl.T.Helper()
|
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)
|
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.
|
// HSet mocks base method.
|
||||||
func (m *MockUniversalClient) HSet(arg0 context.Context, arg1 string, arg2 ...any) *redis.IntCmd {
|
func (m *MockUniversalClient) HSet(arg0 context.Context, arg1 string, arg2 ...any) *redis.IntCmd {
|
||||||
m.ctrl.T.Helper()
|
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)
|
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.
|
// HVals mocks base method.
|
||||||
func (m *MockUniversalClient) HVals(arg0 context.Context, arg1 string) *redis.StringSliceCmd {
|
func (m *MockUniversalClient) HVals(arg0 context.Context, arg1 string) *redis.StringSliceCmd {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
|
|
|
@ -11,7 +11,7 @@ import (
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
"code.gitea.io/gitea/modules/timeutil"
|
"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.
|
// 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/graceful"
|
||||||
"code.gitea.io/gitea/modules/nosql"
|
"code.gitea.io/gitea/modules/nosql"
|
||||||
|
|
||||||
"gitea.com/go-chi/session"
|
"code.forgejo.org/go-chi/session"
|
||||||
"github.com/redis/go-redis/v9"
|
"github.com/redis/go-redis/v9"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ package session
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"gitea.com/go-chi/session"
|
"code.forgejo.org/go-chi/session"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Store represents a session store
|
// Store represents a session store
|
||||||
|
|
|
@ -8,12 +8,12 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/json"
|
"code.gitea.io/gitea/modules/json"
|
||||||
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
|
||||||
"gitea.com/go-chi/session"
|
"code.forgejo.org/go-chi/session"
|
||||||
couchbase "gitea.com/go-chi/session/couchbase"
|
memcache "code.forgejo.org/go-chi/session/memcache"
|
||||||
memcache "gitea.com/go-chi/session/memcache"
|
mysql "code.forgejo.org/go-chi/session/mysql"
|
||||||
mysql "gitea.com/go-chi/session/mysql"
|
postgres "code.forgejo.org/go-chi/session/postgres"
|
||||||
postgres "gitea.com/go-chi/session/postgres"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// VirtualSessionProvider represents a shadowed session provider implementation.
|
// VirtualSessionProvider represents a shadowed session provider implementation.
|
||||||
|
@ -35,6 +35,9 @@ func (o *VirtualSessionProvider) Init(gclifetime int64, config string) error {
|
||||||
switch opts.Provider {
|
switch opts.Provider {
|
||||||
case "memory":
|
case "memory":
|
||||||
o.provider = &session.MemProvider{}
|
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":
|
case "file":
|
||||||
o.provider = &session.FileProvider{}
|
o.provider = &session.FileProvider{}
|
||||||
case "redis":
|
case "redis":
|
||||||
|
@ -45,8 +48,6 @@ func (o *VirtualSessionProvider) Init(gclifetime int64, config string) error {
|
||||||
o.provider = &mysql.MysqlProvider{}
|
o.provider = &mysql.MysqlProvider{}
|
||||||
case "postgres":
|
case "postgres":
|
||||||
o.provider = &postgres.PostgresProvider{}
|
o.provider = &postgres.PostgresProvider{}
|
||||||
case "couchbase":
|
|
||||||
o.provider = &couchbase.CouchbaseProvider{}
|
|
||||||
case "memcache":
|
case "memcache":
|
||||||
o.provider = &memcache.MemcacheProvider{}
|
o.provider = &memcache.MemcacheProvider{}
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -7,9 +7,18 @@ package setting
|
||||||
var Quota = struct {
|
var Quota = struct {
|
||||||
Enabled bool `ini:"ENABLED"`
|
Enabled bool `ini:"ENABLED"`
|
||||||
DefaultGroups []string `ini:"DEFAULT_GROUPS"`
|
DefaultGroups []string `ini:"DEFAULT_GROUPS"`
|
||||||
|
|
||||||
|
Default struct {
|
||||||
|
Total int64
|
||||||
|
} `ini:"quota.default"`
|
||||||
}{
|
}{
|
||||||
Enabled: false,
|
Enabled: false,
|
||||||
DefaultGroups: []string{},
|
DefaultGroups: []string{},
|
||||||
|
Default: struct {
|
||||||
|
Total int64
|
||||||
|
}{
|
||||||
|
Total: -1,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadQuotaFrom(rootCfg ConfigProvider) {
|
func loadQuotaFrom(rootCfg ConfigProvider) {
|
||||||
|
|
|
@ -1105,6 +1105,7 @@ mirror_interval_invalid = The mirror interval is not valid.
|
||||||
mirror_public_key = Public SSH key
|
mirror_public_key = Public SSH key
|
||||||
mirror_use_ssh.text = Use SSH authentication
|
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.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_denied_combination = Cannot use public key and password based authentication in combination.
|
||||||
mirror_sync = synced
|
mirror_sync = synced
|
||||||
mirror_sync_on_commit = Sync when commits are pushed
|
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, _ := contexttest.MockAPIContext(t, "user2/repo1/wiki/_pages")
|
||||||
ctx.SetParams(":id", "1")
|
ctx.SetParams(":id", "1")
|
||||||
contexttest.LoadRepo(t, ctx, 1)
|
|
||||||
contexttest.LoadRepoCommit(t, ctx)
|
|
||||||
contexttest.LoadUser(t, ctx, 2)
|
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)
|
TestHook(ctx)
|
||||||
assert.EqualValues(t, http.StatusNoContent, ctx.Resp.Status())
|
assert.EqualValues(t, http.StatusNoContent, ctx.Resp.Status())
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ import (
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
"code.gitea.io/gitea/models/unit"
|
"code.gitea.io/gitea/models/unit"
|
||||||
|
"code.gitea.io/gitea/modules/git"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
|
@ -350,6 +351,11 @@ func CreatePushMirror(ctx *context.APIContext, mirrorOption *api.CreatePushMirro
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if mirrorOption.UseSSH && !git.HasSSHExecutable {
|
||||||
|
ctx.Error(http.StatusBadRequest, "CreatePushMirror", "SSH authentication not available.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if mirrorOption.UseSSH && (mirrorOption.RemoteUsername != "" || mirrorOption.RemotePassword != "") {
|
if mirrorOption.UseSSH && (mirrorOption.RemoteUsername != "" || mirrorOption.RemotePassword != "") {
|
||||||
ctx.Error(http.StatusBadRequest, "CreatePushMirror", "'use_ssh' is mutually exclusive with 'remote_username' and 'remote_passoword'")
|
ctx.Error(http.StatusBadRequest, "CreatePushMirror", "'use_ssh' is mutually exclusive with 'remote_username' and 'remote_passoword'")
|
||||||
return
|
return
|
||||||
|
|
|
@ -15,7 +15,7 @@ import (
|
||||||
"code.gitea.io/gitea/modules/web/routing"
|
"code.gitea.io/gitea/modules/web/routing"
|
||||||
"code.gitea.io/gitea/services/context"
|
"code.gitea.io/gitea/services/context"
|
||||||
|
|
||||||
"gitea.com/go-chi/session"
|
"code.forgejo.org/go-chi/session"
|
||||||
"github.com/chi-middleware/proxy"
|
"github.com/chi-middleware/proxy"
|
||||||
chi "github.com/go-chi/chi/v5"
|
chi "github.com/go-chi/chi/v5"
|
||||||
)
|
)
|
||||||
|
|
|
@ -36,7 +36,7 @@ import (
|
||||||
"code.gitea.io/gitea/services/context"
|
"code.gitea.io/gitea/services/context"
|
||||||
"code.gitea.io/gitea/services/forms"
|
"code.gitea.io/gitea/services/forms"
|
||||||
|
|
||||||
"gitea.com/go-chi/session"
|
"code.forgejo.org/go-chi/session"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
|
@ -22,7 +22,7 @@ import (
|
||||||
"code.gitea.io/gitea/services/context"
|
"code.gitea.io/gitea/services/context"
|
||||||
"code.gitea.io/gitea/services/mailer"
|
"code.gitea.io/gitea/services/mailer"
|
||||||
|
|
||||||
"gitea.com/go-chi/session"
|
"code.forgejo.org/go-chi/session"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
|
@ -6,6 +6,7 @@ package repo
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
"code.gitea.io/gitea/modules/gitrepo"
|
"code.gitea.io/gitea/modules/gitrepo"
|
||||||
|
@ -45,7 +46,6 @@ func TestGetUniquePatchBranchName(t *testing.T) {
|
||||||
ctx, _ := contexttest.MockContext(t, "user2/repo1")
|
ctx, _ := contexttest.MockContext(t, "user2/repo1")
|
||||||
ctx.SetParams(":id", "1")
|
ctx.SetParams(":id", "1")
|
||||||
contexttest.LoadRepo(t, ctx, 1)
|
contexttest.LoadRepo(t, ctx, 1)
|
||||||
contexttest.LoadRepoCommit(t, ctx)
|
|
||||||
contexttest.LoadUser(t, ctx, 2)
|
contexttest.LoadUser(t, ctx, 2)
|
||||||
contexttest.LoadGitRepo(t, ctx)
|
contexttest.LoadGitRepo(t, ctx)
|
||||||
defer ctx.Repo.GitRepo.Close()
|
defer ctx.Repo.GitRepo.Close()
|
||||||
|
@ -57,15 +57,7 @@ func TestGetUniquePatchBranchName(t *testing.T) {
|
||||||
|
|
||||||
func TestGetClosestParentWithFiles(t *testing.T) {
|
func TestGetClosestParentWithFiles(t *testing.T) {
|
||||||
unittest.PrepareTestEnv(t)
|
unittest.PrepareTestEnv(t)
|
||||||
ctx, _ := contexttest.MockContext(t, "user2/repo1")
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||||
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
|
|
||||||
branch := repo.DefaultBranch
|
branch := repo.DefaultBranch
|
||||||
gitRepo, _ := gitrepo.OpenRepository(git.DefaultContext, repo)
|
gitRepo, _ := gitrepo.OpenRepository(git.DefaultContext, repo)
|
||||||
defer gitRepo.Close()
|
defer gitRepo.Close()
|
||||||
|
|
|
@ -154,6 +154,7 @@ func GetContentHistoryDetail(ctx *context.Context) {
|
||||||
dmp := diffmatchpatch.New()
|
dmp := diffmatchpatch.New()
|
||||||
// `checklines=false` makes better diff result
|
// `checklines=false` makes better diff result
|
||||||
diff := dmp.DiffMain(prevHistoryContentText, history.ContentText, false)
|
diff := dmp.DiffMain(prevHistoryContentText, history.ContentText, false)
|
||||||
|
diff = dmp.DiffCleanupSemantic(diff)
|
||||||
diff = dmp.DiffCleanupEfficiency(diff)
|
diff = dmp.DiffCleanupEfficiency(diff)
|
||||||
|
|
||||||
// use chroma to render the diff html
|
// use chroma to render the diff html
|
||||||
|
|
|
@ -92,6 +92,7 @@ func SettingsCtxData(ctx *context.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ctx.Data["PushMirrors"] = pushMirrors
|
ctx.Data["PushMirrors"] = pushMirrors
|
||||||
|
ctx.Data["CanUseSSHMirroring"] = git.HasSSHExecutable
|
||||||
}
|
}
|
||||||
|
|
||||||
// Units show a repositorys unit settings page
|
// Units show a repositorys unit settings page
|
||||||
|
@ -643,6 +644,11 @@ func SettingsPost(ctx *context.Context) {
|
||||||
return
|
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)
|
address, err := forms.ParseRemoteAddr(form.PushMirrorAddress, form.PushMirrorUsername, form.PushMirrorPassword)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
err = migrations.IsMigrateURLAllowed(address, ctx.Doer)
|
err = migrations.IsMigrateURLAllowed(address, ctx.Doer)
|
||||||
|
|
|
@ -11,7 +11,7 @@ import (
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
session_module "code.gitea.io/gitea/modules/session"
|
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"
|
"github.com/gorilla/sessions"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -27,8 +27,8 @@ import (
|
||||||
"code.gitea.io/gitea/modules/web/middleware"
|
"code.gitea.io/gitea/modules/web/middleware"
|
||||||
web_types "code.gitea.io/gitea/modules/web/types"
|
web_types "code.gitea.io/gitea/modules/web/types"
|
||||||
|
|
||||||
|
"code.forgejo.org/go-chi/session"
|
||||||
"gitea.com/go-chi/cache"
|
"gitea.com/go-chi/cache"
|
||||||
"gitea.com/go-chi/session"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Render represents a template render
|
// 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")
|
assert.FailNow(t, "context is not *context.Context or *context.APIContext")
|
||||||
}
|
}
|
||||||
|
|
||||||
gitRepo, err := gitrepo.OpenRepository(ctx, repo.Repository)
|
if repo.GitRepo == nil {
|
||||||
require.NoError(t, err)
|
assert.FailNow(t, "must call LoadGitRepo")
|
||||||
defer gitRepo.Close()
|
}
|
||||||
branch, err := gitRepo.GetHEADBranch()
|
|
||||||
|
branch, err := repo.GitRepo.GetHEADBranch()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.NotNil(t, branch)
|
assert.NotNil(t, branch)
|
||||||
if branch != nil {
|
if branch != nil {
|
||||||
repo.Commit, err = gitRepo.GetBranchCommit(branch.Name)
|
repo.Commit, err = repo.GitRepo.GetBranchCommit(branch.Name)
|
||||||
require.NoError(t, err)
|
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
|
// LoadGitRepo load a git repo into a test context. Requires that ctx.Repo has
|
||||||
// already been populated.
|
// already been populated.
|
||||||
func LoadGitRepo(t *testing.T, ctx *context.Context) {
|
func LoadGitRepo(t *testing.T, ctx gocontext.Context) {
|
||||||
require.NoError(t, ctx.Repo.Repository.LoadOwner(ctx))
|
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
|
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)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -75,9 +75,9 @@ func checkAuthorizedKeys(ctx context.Context, logger log.Logger, autofix bool) e
|
||||||
logger.Critical(
|
logger.Critical(
|
||||||
"authorized_keys file %q is out of date.\nRegenerate it with:\n\t\"%s\"\nor\n\t\"%s\"",
|
"authorized_keys file %q is out of date.\nRegenerate it with:\n\t\"%s\"\nor\n\t\"%s\"",
|
||||||
fPath,
|
fPath,
|
||||||
"gitea admin regenerate keys",
|
"forgejo admin regenerate keys",
|
||||||
"gitea doctor --run authorized-keys --fix")
|
"forgejo doctor check --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"`)
|
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...")
|
logger.Warn("authorized_keys is out of date. Attempting rewrite...")
|
||||||
err = asymkey_model.RewriteAllPublicKeys(ctx)
|
err = asymkey_model.RewriteAllPublicKeys(ctx)
|
||||||
|
|
|
@ -97,6 +97,7 @@ func (hcd *HighlightCodeDiff) diffWithHighlight(filename, language, codeA, codeB
|
||||||
convertedCodeB := hcd.ConvertToPlaceholders(string(highlightCodeB))
|
convertedCodeB := hcd.ConvertToPlaceholders(string(highlightCodeB))
|
||||||
|
|
||||||
diffs := diffMatchPatch.DiffMain(convertedCodeA, convertedCodeB, true)
|
diffs := diffMatchPatch.DiffMain(convertedCodeA, convertedCodeB, true)
|
||||||
|
diffs = diffMatchPatch.DiffCleanupSemantic(diffs)
|
||||||
diffs = diffMatchPatch.DiffCleanupEfficiency(diffs)
|
diffs = diffMatchPatch.DiffCleanupEfficiency(diffs)
|
||||||
|
|
||||||
for i := range diffs {
|
for i := range diffs {
|
||||||
|
|
|
@ -6,10 +6,11 @@ package files
|
||||||
import (
|
import (
|
||||||
"testing"
|
"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/models/unittest"
|
||||||
"code.gitea.io/gitea/modules/gitrepo"
|
"code.gitea.io/gitea/modules/gitrepo"
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
"code.gitea.io/gitea/services/contexttest"
|
|
||||||
|
|
||||||
_ "code.gitea.io/gitea/models/actions"
|
_ "code.gitea.io/gitea/models/actions"
|
||||||
|
|
||||||
|
@ -53,27 +54,21 @@ func getExpectedReadmeContentsResponse() *api.ContentsResponse {
|
||||||
|
|
||||||
func TestGetContents(t *testing.T) {
|
func TestGetContents(t *testing.T) {
|
||||||
unittest.PrepareTestEnv(t)
|
unittest.PrepareTestEnv(t)
|
||||||
ctx, _ := contexttest.MockContext(t, "user2/repo1")
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||||
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()
|
|
||||||
|
|
||||||
treePath := "README.md"
|
treePath := "README.md"
|
||||||
ref := ctx.Repo.Repository.DefaultBranch
|
ref := repo.DefaultBranch
|
||||||
|
|
||||||
expectedContentsResponse := getExpectedReadmeContentsResponse()
|
expectedContentsResponse := getExpectedReadmeContentsResponse()
|
||||||
|
|
||||||
t.Run("Get README.md contents with GetContents(ctx, )", func(t *testing.T) {
|
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)
|
assert.EqualValues(t, expectedContentsResponse, fileContentResponse)
|
||||||
require.NoError(t, err)
|
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) {
|
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)
|
assert.EqualValues(t, expectedContentsResponse, fileContentResponse)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
})
|
})
|
||||||
|
@ -81,16 +76,10 @@ func TestGetContents(t *testing.T) {
|
||||||
|
|
||||||
func TestGetContentsOrListForDir(t *testing.T) {
|
func TestGetContentsOrListForDir(t *testing.T) {
|
||||||
unittest.PrepareTestEnv(t)
|
unittest.PrepareTestEnv(t)
|
||||||
ctx, _ := contexttest.MockContext(t, "user2/repo1")
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||||
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()
|
|
||||||
|
|
||||||
treePath := "" // root dir
|
treePath := "" // root dir
|
||||||
ref := ctx.Repo.Repository.DefaultBranch
|
ref := repo.DefaultBranch
|
||||||
|
|
||||||
readmeContentsResponse := getExpectedReadmeContentsResponse()
|
readmeContentsResponse := getExpectedReadmeContentsResponse()
|
||||||
// because will be in a list, doesn't have encoding and content
|
// 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) {
|
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)
|
assert.EqualValues(t, expectedContentsListResponse, fileContentResponse)
|
||||||
require.NoError(t, err)
|
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) {
|
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)
|
assert.EqualValues(t, expectedContentsListResponse, fileContentResponse)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
})
|
})
|
||||||
|
@ -116,27 +105,21 @@ func TestGetContentsOrListForDir(t *testing.T) {
|
||||||
|
|
||||||
func TestGetContentsOrListForFile(t *testing.T) {
|
func TestGetContentsOrListForFile(t *testing.T) {
|
||||||
unittest.PrepareTestEnv(t)
|
unittest.PrepareTestEnv(t)
|
||||||
ctx, _ := contexttest.MockContext(t, "user2/repo1")
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||||
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()
|
|
||||||
|
|
||||||
treePath := "README.md"
|
treePath := "README.md"
|
||||||
ref := ctx.Repo.Repository.DefaultBranch
|
ref := repo.DefaultBranch
|
||||||
|
|
||||||
expectedContentsResponse := getExpectedReadmeContentsResponse()
|
expectedContentsResponse := getExpectedReadmeContentsResponse()
|
||||||
|
|
||||||
t.Run("Get README.md contents with GetContentsOrList(ctx, )", func(t *testing.T) {
|
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)
|
assert.EqualValues(t, expectedContentsResponse, fileContentResponse)
|
||||||
require.NoError(t, err)
|
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) {
|
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)
|
assert.EqualValues(t, expectedContentsResponse, fileContentResponse)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
})
|
})
|
||||||
|
@ -144,28 +127,21 @@ func TestGetContentsOrListForFile(t *testing.T) {
|
||||||
|
|
||||||
func TestGetContentsErrors(t *testing.T) {
|
func TestGetContentsErrors(t *testing.T) {
|
||||||
unittest.PrepareTestEnv(t)
|
unittest.PrepareTestEnv(t)
|
||||||
ctx, _ := contexttest.MockContext(t, "user2/repo1")
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||||
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
|
|
||||||
treePath := "README.md"
|
treePath := "README.md"
|
||||||
ref := repo.DefaultBranch
|
ref := repo.DefaultBranch
|
||||||
|
|
||||||
t.Run("bad treePath", func(t *testing.T) {
|
t.Run("bad treePath", func(t *testing.T) {
|
||||||
badTreePath := "bad/tree.md"
|
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]")
|
require.EqualError(t, err, "object does not exist [id: , rel_path: bad]")
|
||||||
assert.Nil(t, fileContentResponse)
|
assert.Nil(t, fileContentResponse)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("bad ref", func(t *testing.T) {
|
t.Run("bad ref", func(t *testing.T) {
|
||||||
badRef := "bad_ref"
|
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: ]")
|
require.EqualError(t, err, "object does not exist [id: "+badRef+", rel_path: ]")
|
||||||
assert.Nil(t, fileContentResponse)
|
assert.Nil(t, fileContentResponse)
|
||||||
})
|
})
|
||||||
|
@ -173,28 +149,21 @@ func TestGetContentsErrors(t *testing.T) {
|
||||||
|
|
||||||
func TestGetContentsOrListErrors(t *testing.T) {
|
func TestGetContentsOrListErrors(t *testing.T) {
|
||||||
unittest.PrepareTestEnv(t)
|
unittest.PrepareTestEnv(t)
|
||||||
ctx, _ := contexttest.MockContext(t, "user2/repo1")
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||||
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
|
|
||||||
treePath := "README.md"
|
treePath := "README.md"
|
||||||
ref := repo.DefaultBranch
|
ref := repo.DefaultBranch
|
||||||
|
|
||||||
t.Run("bad treePath", func(t *testing.T) {
|
t.Run("bad treePath", func(t *testing.T) {
|
||||||
badTreePath := "bad/tree.md"
|
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]")
|
require.EqualError(t, err, "object does not exist [id: , rel_path: bad]")
|
||||||
assert.Nil(t, fileContentResponse)
|
assert.Nil(t, fileContentResponse)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("bad ref", func(t *testing.T) {
|
t.Run("bad ref", func(t *testing.T) {
|
||||||
badRef := "bad_ref"
|
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: ]")
|
require.EqualError(t, err, "object does not exist [id: "+badRef+", rel_path: ]")
|
||||||
assert.Nil(t, fileContentResponse)
|
assert.Nil(t, fileContentResponse)
|
||||||
})
|
})
|
||||||
|
@ -202,17 +171,10 @@ func TestGetContentsOrListErrors(t *testing.T) {
|
||||||
|
|
||||||
func TestGetContentsOrListOfEmptyRepos(t *testing.T) {
|
func TestGetContentsOrListOfEmptyRepos(t *testing.T) {
|
||||||
unittest.PrepareTestEnv(t)
|
unittest.PrepareTestEnv(t)
|
||||||
ctx, _ := contexttest.MockContext(t, "user30/empty")
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 52})
|
||||||
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
|
|
||||||
|
|
||||||
t.Run("empty repo", func(t *testing.T) {
|
t.Run("empty repo", func(t *testing.T) {
|
||||||
contents, err := GetContentsOrList(ctx, repo, "", "")
|
contents, err := GetContentsOrList(db.DefaultContext, repo, "", "")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Empty(t, contents)
|
assert.Empty(t, contents)
|
||||||
})
|
})
|
||||||
|
@ -220,23 +182,13 @@ func TestGetContentsOrListOfEmptyRepos(t *testing.T) {
|
||||||
|
|
||||||
func TestGetBlobBySHA(t *testing.T) {
|
func TestGetBlobBySHA(t *testing.T) {
|
||||||
unittest.PrepareTestEnv(t)
|
unittest.PrepareTestEnv(t)
|
||||||
ctx, _ := contexttest.MockContext(t, "user2/repo1")
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{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()
|
|
||||||
|
|
||||||
sha := "65f1bf27bc3bf70f64657658635e66094edbcb4d"
|
gitRepo, err := gitrepo.OpenRepository(db.DefaultContext, repo)
|
||||||
ctx.SetParams(":id", "1")
|
require.NoError(t, err)
|
||||||
ctx.SetParams(":sha", sha)
|
defer gitRepo.Close()
|
||||||
|
|
||||||
gitRepo, err := gitrepo.OpenRepository(ctx, ctx.Repo.Repository)
|
gbr, err := GetBlobBySHA(db.DefaultContext, repo, gitRepo, "65f1bf27bc3bf70f64657658635e66094edbcb4d")
|
||||||
if err != nil {
|
|
||||||
t.Fail()
|
|
||||||
}
|
|
||||||
|
|
||||||
gbr, err := GetBlobBySHA(ctx, ctx.Repo.Repository, gitRepo, ctx.Params(":sha"))
|
|
||||||
expectedGBR := &api.GitBlobResponse{
|
expectedGBR := &api.GitBlobResponse{
|
||||||
Content: "dHJlZSAyYTJmMWQ0NjcwNzI4YTJlMTAwNDllMzQ1YmQ3YTI3NjQ2OGJlYWI2CmF1dGhvciB1c2VyMSA8YWRkcmVzczFAZXhhbXBsZS5jb20+IDE0ODk5NTY0NzkgLTA0MDAKY29tbWl0dGVyIEV0aGFuIEtvZW5pZyA8ZXRoYW50a29lbmlnQGdtYWlsLmNvbT4gMTQ4OTk1NjQ3OSAtMDQwMAoKSW5pdGlhbCBjb21taXQK",
|
Content: "dHJlZSAyYTJmMWQ0NjcwNzI4YTJlMTAwNDllMzQ1YmQ3YTI3NjQ2OGJlYWI2CmF1dGhvciB1c2VyMSA8YWRkcmVzczFAZXhhbXBsZS5jb20+IDE0ODk5NTY0NzkgLTA0MDAKY29tbWl0dGVyIEV0aGFuIEtvZW5pZyA8ZXRoYW50a29lbmlnQGdtYWlsLmNvbT4gMTQ4OTk1NjQ3OSAtMDQwMAoKSW5pdGlhbCBjb21taXQK",
|
||||||
Encoding: "base64",
|
Encoding: "base64",
|
||||||
|
|
|
@ -6,6 +6,7 @@ package files
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/models/db"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
"code.gitea.io/gitea/modules/json"
|
"code.gitea.io/gitea/modules/json"
|
||||||
|
@ -21,7 +22,6 @@ func TestGetDiffPreview(t *testing.T) {
|
||||||
ctx, _ := contexttest.MockContext(t, "user2/repo1")
|
ctx, _ := contexttest.MockContext(t, "user2/repo1")
|
||||||
ctx.SetParams(":id", "1")
|
ctx.SetParams(":id", "1")
|
||||||
contexttest.LoadRepo(t, ctx, 1)
|
contexttest.LoadRepo(t, ctx, 1)
|
||||||
contexttest.LoadRepoCommit(t, ctx)
|
|
||||||
contexttest.LoadUser(t, ctx, 2)
|
contexttest.LoadUser(t, ctx, 2)
|
||||||
contexttest.LoadGitRepo(t, ctx)
|
contexttest.LoadGitRepo(t, ctx)
|
||||||
defer ctx.Repo.GitRepo.Close()
|
defer ctx.Repo.GitRepo.Close()
|
||||||
|
@ -140,33 +140,26 @@ func TestGetDiffPreview(t *testing.T) {
|
||||||
|
|
||||||
func TestGetDiffPreviewErrors(t *testing.T) {
|
func TestGetDiffPreviewErrors(t *testing.T) {
|
||||||
unittest.PrepareTestEnv(t)
|
unittest.PrepareTestEnv(t)
|
||||||
ctx, _ := contexttest.MockContext(t, "user2/repo1")
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||||
ctx.SetParams(":id", "1")
|
branch := repo.DefaultBranch
|
||||||
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
|
|
||||||
treePath := "README.md"
|
treePath := "README.md"
|
||||||
content := "# repo1\n\nDescription for repo1\nthis is a new line"
|
content := "# repo1\n\nDescription for repo1\nthis is a new line"
|
||||||
|
|
||||||
t.Run("empty repo", func(t *testing.T) {
|
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.Nil(t, diff)
|
||||||
assert.EqualError(t, err, "repository does not exist [id: 0, uid: 0, owner_name: , name: ]")
|
assert.EqualError(t, err, "repository does not exist [id: 0, uid: 0, owner_name: , name: ]")
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("bad branch", func(t *testing.T) {
|
t.Run("bad branch", func(t *testing.T) {
|
||||||
badBranch := "bad_branch"
|
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.Nil(t, diff)
|
||||||
assert.EqualError(t, err, "branch does not exist [name: "+badBranch+"]")
|
assert.EqualError(t, err, "branch does not exist [name: "+badBranch+"]")
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("empty treePath", func(t *testing.T) {
|
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.Nil(t, diff)
|
||||||
assert.EqualError(t, err, "path is invalid [path: ]")
|
assert.EqualError(t, err, "path is invalid [path: ]")
|
||||||
})
|
})
|
||||||
|
|
|
@ -6,11 +6,12 @@ package files
|
||||||
import (
|
import (
|
||||||
"testing"
|
"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/models/unittest"
|
||||||
"code.gitea.io/gitea/modules/gitrepo"
|
"code.gitea.io/gitea/modules/gitrepo"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
"code.gitea.io/gitea/services/contexttest"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
@ -99,23 +100,16 @@ func getExpectedFileResponse() *api.FileResponse {
|
||||||
|
|
||||||
func TestGetFileResponseFromCommit(t *testing.T) {
|
func TestGetFileResponseFromCommit(t *testing.T) {
|
||||||
unittest.PrepareTestEnv(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
|
branch := repo.DefaultBranch
|
||||||
treePath := "README.md"
|
treePath := "README.md"
|
||||||
gitRepo, _ := gitrepo.OpenRepository(ctx, repo)
|
gitRepo, _ := gitrepo.OpenRepository(db.DefaultContext, repo)
|
||||||
defer gitRepo.Close()
|
defer gitRepo.Close()
|
||||||
commit, _ := gitRepo.GetBranchCommit(branch)
|
commit, _ := gitRepo.GetBranchCommit(branch)
|
||||||
expectedFileResponse := getExpectedFileResponse()
|
expectedFileResponse := getExpectedFileResponse()
|
||||||
|
|
||||||
fileResponse, err := GetFileResponseFromCommit(ctx, repo, commit, branch, treePath)
|
fileResponse, err := GetFileResponseFromCommit(db.DefaultContext, repo, commit, branch, treePath)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.EqualValues(t, expectedFileResponse, fileResponse)
|
assert.EqualValues(t, expectedFileResponse, fileResponse)
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,6 @@ func TestGetTreeBySHA(t *testing.T) {
|
||||||
unittest.PrepareTestEnv(t)
|
unittest.PrepareTestEnv(t)
|
||||||
ctx, _ := contexttest.MockContext(t, "user2/repo1")
|
ctx, _ := contexttest.MockContext(t, "user2/repo1")
|
||||||
contexttest.LoadRepo(t, ctx, 1)
|
contexttest.LoadRepo(t, ctx, 1)
|
||||||
contexttest.LoadRepoCommit(t, ctx)
|
|
||||||
contexttest.LoadUser(t, ctx, 2)
|
contexttest.LoadUser(t, ctx, 2)
|
||||||
contexttest.LoadGitRepo(t, ctx)
|
contexttest.LoadGitRepo(t, ctx)
|
||||||
defer ctx.Repo.GitRepo.Close()
|
defer ctx.Repo.GitRepo.Close()
|
||||||
|
|
|
@ -300,6 +300,7 @@
|
||||||
<label for="push_mirror_password">{{ctx.Locale.Tr "password"}}</label>
|
<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">
|
<input id="push_mirror_password" name="push_mirror_password" type="password" value="{{.push_mirror_password}}" autocomplete="off">
|
||||||
</div>
|
</div>
|
||||||
|
{{if .CanUseSSHMirroring}}
|
||||||
<div class="inline field {{if .Err_PushMirrorUseSSH}}error{{end}}">
|
<div class="inline field {{if .Err_PushMirrorUseSSH}}error{{end}}">
|
||||||
<div class="ui checkbox df ac">
|
<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}}>
|
<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"}}
|
<span class="help tw-block">{{ctx.Locale.Tr "repo.mirror_use_ssh.helper"}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
</details>
|
</details>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
|
|
|
@ -64,7 +64,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="tw-mb-4">
|
<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>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<button class="ui primary button">{{ctx.Locale.Tr "settings.update_language"}}</button>
|
<button class="ui primary button">{{ctx.Locale.Tr "settings.update_language"}}</button>
|
||||||
|
|
|
@ -14,6 +14,7 @@ env:
|
||||||
|
|
||||||
rules:
|
rules:
|
||||||
playwright/no-conditional-in-test: [0]
|
playwright/no-conditional-in-test: [0]
|
||||||
|
playwright/no-conditional-expect: [0]
|
||||||
playwright/no-networkidle: [0]
|
playwright/no-networkidle: [0]
|
||||||
playwright/no-skipped-test: [2, {allowConditional: true}]
|
playwright/no-skipped-test: [2, {allowConditional: true}]
|
||||||
playwright/prefer-comparison-matcher: [2]
|
playwright/prefer-comparison-matcher: [2]
|
||||||
|
|
|
@ -24,7 +24,8 @@ func TestDebugserver(t *testing.T) {
|
||||||
done := make(chan os.Signal, 1)
|
done := make(chan os.Signal, 1)
|
||||||
signal.Notify(done, syscall.SIGINT, syscall.SIGTERM)
|
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)
|
fmt.Println(setting.AppURL)
|
||||||
<-done
|
<-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)
|
graceful.InitManager(managerCtx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
tests.InitTest(false)
|
tests.InitTest(true)
|
||||||
testE2eWebRoutes = routers.NormalRoutes()
|
testE2eWebRoutes = routers.NormalRoutes()
|
||||||
|
|
||||||
os.Unsetenv("GIT_AUTHOR_NAME")
|
os.Unsetenv("GIT_AUTHOR_NAME")
|
||||||
|
@ -102,7 +102,8 @@ func TestE2e(t *testing.T) {
|
||||||
|
|
||||||
t.Run(testname, func(t *testing.T) {
|
t.Run(testname, func(t *testing.T) {
|
||||||
// Default 2 minute timeout
|
// Default 2 minute timeout
|
||||||
onGiteaRun(t, func(*testing.T, *url.URL) {
|
onForgejoRun(t, func(*testing.T, *url.URL) {
|
||||||
|
defer DeclareGitRepos(t)()
|
||||||
thisTest := runArgs
|
thisTest := runArgs
|
||||||
thisTest = append(thisTest, path)
|
thisTest = append(thisTest, path)
|
||||||
cmd := exec.Command(runArgs[0], thisTest...)
|
cmd := exec.Command(runArgs[0], thisTest...)
|
||||||
|
|
|
@ -51,3 +51,29 @@ test('Line Range Selection', async ({browser}, workerInfo) => {
|
||||||
await page.goto(`${filePath}#L1-L100`);
|
await page.goto(`${filePath}#L1-L100`);
|
||||||
await assertSelectedLines(page, ['1', '2', '3']);
|
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"
|
"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] {
|
if len(prepare) == 0 || prepare[0] {
|
||||||
defer tests.PrepareTestEnv(t, 1)()
|
defer tests.PrepareTestEnv(t, 1)()
|
||||||
}
|
}
|
||||||
|
@ -49,8 +49,8 @@ func onGiteaRunTB(t testing.TB, callback func(testing.TB, *url.URL), prepare ...
|
||||||
callback(t, u)
|
callback(t, u)
|
||||||
}
|
}
|
||||||
|
|
||||||
func onGiteaRun(t *testing.T, callback func(*testing.T, *url.URL), prepare ...bool) {
|
func onForgejoRun(t *testing.T, callback func(*testing.T, *url.URL), prepare ...bool) {
|
||||||
onGiteaRunTB(t, func(t testing.TB, u *url.URL) {
|
onForgejoRunTB(t, func(t testing.TB, u *url.URL) {
|
||||||
callback(t.(*testing.T), u)
|
callback(t.(*testing.T), u)
|
||||||
}, prepare...)
|
}, prepare...)
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -23,6 +24,7 @@ import (
|
||||||
"code.gitea.io/gitea/models/unit"
|
"code.gitea.io/gitea/models/unit"
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
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/optional"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
|
@ -141,6 +143,11 @@ func testAPIPushMirror(t *testing.T, u *url.URL) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAPIPushMirrorSSH(t *testing.T) {
|
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) {
|
onGiteaRun(t, func(t *testing.T, _ *url.URL) {
|
||||||
defer test.MockVariableValue(&setting.Migrations.AllowLocalNetworks, true)()
|
defer test.MockVariableValue(&setting.Migrations.AllowLocalNetworks, true)()
|
||||||
defer test.MockVariableValue(&setting.Mirror.Enabled, 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)
|
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) {
|
t.Run("Normal", func(t *testing.T) {
|
||||||
var pushMirror *repo_model.PushMirror
|
var pushMirror *repo_model.PushMirror
|
||||||
t.Run("Adding", func(t *testing.T) {
|
t.Run("Adding", func(t *testing.T) {
|
||||||
|
|
|
@ -15,7 +15,7 @@ import (
|
||||||
"code.gitea.io/gitea/routers"
|
"code.gitea.io/gitea/routers"
|
||||||
"code.gitea.io/gitea/tests"
|
"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/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -157,6 +158,11 @@ func doRemovePushMirror(ctx APITestContext, address, username, password string,
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSSHPushMirror(t *testing.T) {
|
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) {
|
onGiteaRun(t, func(t *testing.T, _ *url.URL) {
|
||||||
defer test.MockVariableValue(&setting.Migrations.AllowLocalNetworks, true)()
|
defer test.MockVariableValue(&setting.Migrations.AllowLocalNetworks, true)()
|
||||||
defer test.MockVariableValue(&setting.Mirror.Enabled, 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.")
|
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) {
|
t.Run("Normal", func(t *testing.T) {
|
||||||
var pushMirror *repo_model.PushMirror
|
var pushMirror *repo_model.PushMirror
|
||||||
t.Run("Adding", func(t *testing.T) {
|
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! *
|
* Here be dragons! *
|
||||||
* *
|
* *
|
||||||
|
@ -568,6 +604,7 @@ type quotaWebEnv struct {
|
||||||
type quotaWebEnvUsers struct {
|
type quotaWebEnvUsers struct {
|
||||||
Limited quotaWebEnvUser
|
Limited quotaWebEnvUser
|
||||||
Contributor quotaWebEnvUser
|
Contributor quotaWebEnvUser
|
||||||
|
Ungrouped quotaWebEnvUser
|
||||||
}
|
}
|
||||||
|
|
||||||
type quotaWebEnvOrgs struct {
|
type quotaWebEnvOrgs struct {
|
||||||
|
@ -1005,8 +1042,7 @@ func createQuotaWebEnv(t *testing.T) *quotaWebEnv {
|
||||||
|
|
||||||
// *** helpers ***
|
// *** helpers ***
|
||||||
|
|
||||||
// Create a user, its quota group & rule
|
makeUngroupedUser := func(t *testing.T) quotaWebEnvUser {
|
||||||
makeUser := func(t *testing.T, limit int64) quotaWebEnvUser {
|
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
user := quotaWebEnvUser{}
|
user := quotaWebEnvUser{}
|
||||||
|
@ -1021,6 +1057,16 @@ func createQuotaWebEnv(t *testing.T) *quotaWebEnv {
|
||||||
repo, _, _ := tests.CreateDeclarativeRepoWithOptions(t, user.User, tests.DeclarativeRepoOptions{})
|
repo, _, _ := tests.CreateDeclarativeRepoWithOptions(t, user.User, tests.DeclarativeRepoOptions{})
|
||||||
user.Repo = repo
|
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
|
// Create a quota group for them
|
||||||
group, err := quota_model.CreateGroup(db.DefaultContext, userName)
|
group, err := quota_model.CreateGroup(db.DefaultContext, userName)
|
||||||
require.NoError(t, err)
|
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.Limited = makeOrg(t, env.Users.Limited.User, int64(0))
|
||||||
env.Orgs.Unlimited = makeOrg(t, env.Users.Limited.User, int64(-1))
|
env.Orgs.Unlimited = makeOrg(t, env.Users.Limited.User, int64(-1))
|
||||||
|
|
||||||
|
env.Users.Ungrouped = makeUngroupedUser(t)
|
||||||
|
|
||||||
return &env
|
return &env
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,8 +52,13 @@ func createRepoAndGetContext(t *testing.T, files []string, deleteMdReadme bool)
|
||||||
ctx, _ := contexttest.MockContext(t, "user1/readmetest")
|
ctx, _ := contexttest.MockContext(t, "user1/readmetest")
|
||||||
ctx.SetParams(":id", fmt.Sprint(repo.ID))
|
ctx.SetParams(":id", fmt.Sprint(repo.ID))
|
||||||
contexttest.LoadRepo(t, ctx, repo.ID)
|
contexttest.LoadRepo(t, ctx, repo.ID)
|
||||||
|
contexttest.LoadGitRepo(t, ctx)
|
||||||
contexttest.LoadRepoCommit(t, ctx)
|
contexttest.LoadRepoCommit(t, ctx)
|
||||||
return ctx, f
|
|
||||||
|
return ctx, func() {
|
||||||
|
f()
|
||||||
|
ctx.Repo.GitRepo.Close()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRepoView_FindReadme(t *testing.T) {
|
func TestRepoView_FindReadme(t *testing.T) {
|
||||||
|
|
|
@ -12,11 +12,11 @@ import (
|
||||||
|
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"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/git"
|
||||||
"code.gitea.io/gitea/modules/gitrepo"
|
"code.gitea.io/gitea/modules/gitrepo"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
"code.gitea.io/gitea/services/contexttest"
|
|
||||||
files_service "code.gitea.io/gitea/services/repository/files"
|
files_service "code.gitea.io/gitea/services/repository/files"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
@ -247,16 +247,8 @@ func getExpectedFileResponseForRepofilesUpdate(commitID, filename, lastCommitSHA
|
||||||
func TestChangeRepoFilesForCreate(t *testing.T) {
|
func TestChangeRepoFilesForCreate(t *testing.T) {
|
||||||
// setup
|
// setup
|
||||||
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
||||||
ctx, _ := contexttest.MockContext(t, "user2/repo1")
|
doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||||
ctx.SetParams(":id", "1")
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{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
|
|
||||||
opts := getCreateRepoFilesOptions(repo)
|
opts := getCreateRepoFilesOptions(repo)
|
||||||
|
|
||||||
// test
|
// test
|
||||||
|
@ -284,16 +276,8 @@ func TestChangeRepoFilesForCreate(t *testing.T) {
|
||||||
func TestChangeRepoFilesForUpdate(t *testing.T) {
|
func TestChangeRepoFilesForUpdate(t *testing.T) {
|
||||||
// setup
|
// setup
|
||||||
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
||||||
ctx, _ := contexttest.MockContext(t, "user2/repo1")
|
doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||||
ctx.SetParams(":id", "1")
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{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
|
|
||||||
opts := getUpdateRepoFilesOptions(repo)
|
opts := getUpdateRepoFilesOptions(repo)
|
||||||
|
|
||||||
// test
|
// test
|
||||||
|
@ -318,16 +302,8 @@ func TestChangeRepoFilesForUpdate(t *testing.T) {
|
||||||
func TestChangeRepoFilesForUpdateWithFileMove(t *testing.T) {
|
func TestChangeRepoFilesForUpdateWithFileMove(t *testing.T) {
|
||||||
// setup
|
// setup
|
||||||
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
||||||
ctx, _ := contexttest.MockContext(t, "user2/repo1")
|
doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||||
ctx.SetParams(":id", "1")
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{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
|
|
||||||
opts := getUpdateRepoFilesOptions(repo)
|
opts := getUpdateRepoFilesOptions(repo)
|
||||||
opts.Files[0].FromTreePath = "README.md"
|
opts.Files[0].FromTreePath = "README.md"
|
||||||
opts.Files[0].TreePath = "README_new.md" // new file name, README_new.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) {
|
func TestChangeRepoFilesWithoutBranchNames(t *testing.T) {
|
||||||
// setup
|
// setup
|
||||||
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
||||||
ctx, _ := contexttest.MockContext(t, "user2/repo1")
|
doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||||
ctx.SetParams(":id", "1")
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{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
|
|
||||||
opts := getUpdateRepoFilesOptions(repo)
|
opts := getUpdateRepoFilesOptions(repo)
|
||||||
opts.OldBranch = ""
|
opts.OldBranch = ""
|
||||||
opts.NewBranch = ""
|
opts.NewBranch = ""
|
||||||
|
@ -405,15 +373,8 @@ func TestChangeRepoFilesForDelete(t *testing.T) {
|
||||||
func testDeleteRepoFiles(t *testing.T, u *url.URL) {
|
func testDeleteRepoFiles(t *testing.T, u *url.URL) {
|
||||||
// setup
|
// setup
|
||||||
unittest.PrepareTestEnv(t)
|
unittest.PrepareTestEnv(t)
|
||||||
ctx, _ := contexttest.MockContext(t, "user2/repo1")
|
doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||||
ctx.SetParams(":id", "1")
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{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
|
|
||||||
opts := getDeleteRepoFilesOptions(repo)
|
opts := getDeleteRepoFilesOptions(repo)
|
||||||
|
|
||||||
t.Run("Delete README.md file", func(t *testing.T) {
|
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) {
|
func testDeleteRepoFilesWithoutBranchNames(t *testing.T, u *url.URL) {
|
||||||
// setup
|
// setup
|
||||||
unittest.PrepareTestEnv(t)
|
unittest.PrepareTestEnv(t)
|
||||||
ctx, _ := contexttest.MockContext(t, "user2/repo1")
|
doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||||
ctx.SetParams(":id", "1")
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{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
|
|
||||||
opts := getDeleteRepoFilesOptions(repo)
|
opts := getDeleteRepoFilesOptions(repo)
|
||||||
opts.OldBranch = ""
|
opts.OldBranch = ""
|
||||||
opts.NewBranch = ""
|
opts.NewBranch = ""
|
||||||
|
@ -474,16 +428,8 @@ func testDeleteRepoFilesWithoutBranchNames(t *testing.T, u *url.URL) {
|
||||||
func TestChangeRepoFilesErrors(t *testing.T) {
|
func TestChangeRepoFilesErrors(t *testing.T) {
|
||||||
// setup
|
// setup
|
||||||
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
||||||
ctx, _ := contexttest.MockContext(t, "user2/repo1")
|
doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||||
ctx.SetParams(":id", "1")
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{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
|
|
||||||
|
|
||||||
t.Run("bad branch", func(t *testing.T) {
|
t.Run("bad branch", func(t *testing.T) {
|
||||||
opts := getUpdateRepoFilesOptions(repo)
|
opts := getUpdateRepoFilesOptions(repo)
|
||||||
|
|
|
@ -389,7 +389,7 @@ func TestUserHints(t *testing.T) {
|
||||||
assert.Equal(t, enabled, hintChecked)
|
assert.Equal(t, enabled, hintChecked)
|
||||||
|
|
||||||
link, _ := htmlDoc.Find("form[action='/user/settings/appearance/language'] a").Attr("href")
|
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) {
|
t.Run("view", func(t *testing.T) {
|
||||||
|
|
Loading…
Reference in a new issue