mirror of
https://github.com/go-gitea/gitea.git
synced 2026-02-23 04:18:07 +01:00
Merge branch 'main' into feature/workflow-graph
This commit is contained in:
commit
ce16e4fdc3
7
AGENTS.md
Normal file
7
AGENTS.md
Normal file
@ -0,0 +1,7 @@
|
||||
# Instructions for agents
|
||||
|
||||
- Use `make help` to find available development targets
|
||||
- Before committing go code changes, run `make fmt`
|
||||
- Before committing `go.mod` changes, run `make tidy`
|
||||
- Before committing new `.go` files, add the current year into the copyright header
|
||||
- Before committing files, removed any trailing whitespace
|
||||
@ -76,5 +76,6 @@ ENV GITEA_CUSTOM=/data/gitea
|
||||
|
||||
VOLUME ["/data"]
|
||||
|
||||
# HINT: HEALTH-CHECK-ENDPOINT: don't use HEALTHCHECK, search this hint keyword for more information
|
||||
ENTRYPOINT ["/usr/bin/entrypoint"]
|
||||
CMD ["/usr/bin/s6-svscan", "/etc/s6"]
|
||||
|
||||
@ -77,5 +77,6 @@ ENV HOME="/var/lib/gitea/git"
|
||||
VOLUME ["/var/lib/gitea", "/etc/gitea"]
|
||||
WORKDIR /var/lib/gitea
|
||||
|
||||
# HINT: HEALTH-CHECK-ENDPOINT: don't use HEALTHCHECK, search this hint keyword for more information
|
||||
ENTRYPOINT ["/usr/bin/dumb-init", "--", "/usr/local/bin/docker-entrypoint.sh"]
|
||||
CMD []
|
||||
|
||||
70
Makefile
70
Makefile
@ -489,11 +489,11 @@ generate-ini-sqlite:
|
||||
|
||||
.PHONY: test-sqlite
|
||||
test-sqlite: integrations.sqlite.test generate-ini-sqlite
|
||||
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini ./integrations.sqlite.test
|
||||
GITEA_TEST_CONF=tests/sqlite.ini ./integrations.sqlite.test
|
||||
|
||||
.PHONY: test-sqlite\#%
|
||||
test-sqlite\#%: integrations.sqlite.test generate-ini-sqlite
|
||||
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini ./integrations.sqlite.test -test.run $(subst .,/,$*)
|
||||
GITEA_TEST_CONF=tests/sqlite.ini ./integrations.sqlite.test -test.run $(subst .,/,$*)
|
||||
|
||||
.PHONY: test-sqlite-migration
|
||||
test-sqlite-migration: migrations.sqlite.test migrations.individual.sqlite.test
|
||||
@ -510,11 +510,11 @@ generate-ini-mysql:
|
||||
|
||||
.PHONY: test-mysql
|
||||
test-mysql: integrations.mysql.test generate-ini-mysql
|
||||
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql.ini ./integrations.mysql.test
|
||||
GITEA_TEST_CONF=tests/mysql.ini ./integrations.mysql.test
|
||||
|
||||
.PHONY: test-mysql\#%
|
||||
test-mysql\#%: integrations.mysql.test generate-ini-mysql
|
||||
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql.ini ./integrations.mysql.test -test.run $(subst .,/,$*)
|
||||
GITEA_TEST_CONF=tests/mysql.ini ./integrations.mysql.test -test.run $(subst .,/,$*)
|
||||
|
||||
.PHONY: test-mysql-migration
|
||||
test-mysql-migration: migrations.mysql.test migrations.individual.mysql.test
|
||||
@ -533,11 +533,11 @@ generate-ini-pgsql:
|
||||
|
||||
.PHONY: test-pgsql
|
||||
test-pgsql: integrations.pgsql.test generate-ini-pgsql
|
||||
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/pgsql.ini ./integrations.pgsql.test
|
||||
GITEA_TEST_CONF=tests/pgsql.ini ./integrations.pgsql.test
|
||||
|
||||
.PHONY: test-pgsql\#%
|
||||
test-pgsql\#%: integrations.pgsql.test generate-ini-pgsql
|
||||
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/pgsql.ini ./integrations.pgsql.test -test.run $(subst .,/,$*)
|
||||
GITEA_TEST_CONF=tests/pgsql.ini ./integrations.pgsql.test -test.run $(subst .,/,$*)
|
||||
|
||||
.PHONY: test-pgsql-migration
|
||||
test-pgsql-migration: migrations.pgsql.test migrations.individual.pgsql.test
|
||||
@ -554,11 +554,11 @@ generate-ini-mssql:
|
||||
|
||||
.PHONY: test-mssql
|
||||
test-mssql: integrations.mssql.test generate-ini-mssql
|
||||
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mssql.ini ./integrations.mssql.test
|
||||
GITEA_TEST_CONF=tests/mssql.ini ./integrations.mssql.test
|
||||
|
||||
.PHONY: test-mssql\#%
|
||||
test-mssql\#%: integrations.mssql.test generate-ini-mssql
|
||||
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mssql.ini ./integrations.mssql.test -test.run $(subst .,/,$*)
|
||||
GITEA_TEST_CONF=tests/mssql.ini ./integrations.mssql.test -test.run $(subst .,/,$*)
|
||||
|
||||
.PHONY: test-mssql-migration
|
||||
test-mssql-migration: migrations.mssql.test migrations.individual.mssql.test
|
||||
@ -577,59 +577,59 @@ test-e2e: test-e2e-sqlite
|
||||
|
||||
.PHONY: test-e2e-sqlite
|
||||
test-e2e-sqlite: playwright e2e.sqlite.test generate-ini-sqlite
|
||||
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini ./e2e.sqlite.test
|
||||
GITEA_TEST_CONF=tests/sqlite.ini ./e2e.sqlite.test
|
||||
|
||||
.PHONY: test-e2e-sqlite\#%
|
||||
test-e2e-sqlite\#%: playwright e2e.sqlite.test generate-ini-sqlite
|
||||
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini ./e2e.sqlite.test -test.run TestE2e/$*
|
||||
GITEA_TEST_CONF=tests/sqlite.ini ./e2e.sqlite.test -test.run TestE2e/$*
|
||||
|
||||
.PHONY: test-e2e-mysql
|
||||
test-e2e-mysql: playwright e2e.mysql.test generate-ini-mysql
|
||||
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql.ini ./e2e.mysql.test
|
||||
GITEA_TEST_CONF=tests/mysql.ini ./e2e.mysql.test
|
||||
|
||||
.PHONY: test-e2e-mysql\#%
|
||||
test-e2e-mysql\#%: playwright e2e.mysql.test generate-ini-mysql
|
||||
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql.ini ./e2e.mysql.test -test.run TestE2e/$*
|
||||
GITEA_TEST_CONF=tests/mysql.ini ./e2e.mysql.test -test.run TestE2e/$*
|
||||
|
||||
.PHONY: test-e2e-pgsql
|
||||
test-e2e-pgsql: playwright e2e.pgsql.test generate-ini-pgsql
|
||||
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/pgsql.ini ./e2e.pgsql.test
|
||||
GITEA_TEST_CONF=tests/pgsql.ini ./e2e.pgsql.test
|
||||
|
||||
.PHONY: test-e2e-pgsql\#%
|
||||
test-e2e-pgsql\#%: playwright e2e.pgsql.test generate-ini-pgsql
|
||||
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/pgsql.ini ./e2e.pgsql.test -test.run TestE2e/$*
|
||||
GITEA_TEST_CONF=tests/pgsql.ini ./e2e.pgsql.test -test.run TestE2e/$*
|
||||
|
||||
.PHONY: test-e2e-mssql
|
||||
test-e2e-mssql: playwright e2e.mssql.test generate-ini-mssql
|
||||
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mssql.ini ./e2e.mssql.test
|
||||
GITEA_TEST_CONF=tests/mssql.ini ./e2e.mssql.test
|
||||
|
||||
.PHONY: test-e2e-mssql\#%
|
||||
test-e2e-mssql\#%: playwright e2e.mssql.test generate-ini-mssql
|
||||
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mssql.ini ./e2e.mssql.test -test.run TestE2e/$*
|
||||
GITEA_TEST_CONF=tests/mssql.ini ./e2e.mssql.test -test.run TestE2e/$*
|
||||
|
||||
.PHONY: bench-sqlite
|
||||
bench-sqlite: integrations.sqlite.test generate-ini-sqlite
|
||||
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini ./integrations.sqlite.test -test.cpuprofile=cpu.out -test.run DontRunTests -test.bench .
|
||||
GITEA_TEST_CONF=tests/sqlite.ini ./integrations.sqlite.test -test.cpuprofile=cpu.out -test.run DontRunTests -test.bench .
|
||||
|
||||
.PHONY: bench-mysql
|
||||
bench-mysql: integrations.mysql.test generate-ini-mysql
|
||||
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql.ini ./integrations.mysql.test -test.cpuprofile=cpu.out -test.run DontRunTests -test.bench .
|
||||
GITEA_TEST_CONF=tests/mysql.ini ./integrations.mysql.test -test.cpuprofile=cpu.out -test.run DontRunTests -test.bench .
|
||||
|
||||
.PHONY: bench-mssql
|
||||
bench-mssql: integrations.mssql.test generate-ini-mssql
|
||||
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mssql.ini ./integrations.mssql.test -test.cpuprofile=cpu.out -test.run DontRunTests -test.bench .
|
||||
GITEA_TEST_CONF=tests/mssql.ini ./integrations.mssql.test -test.cpuprofile=cpu.out -test.run DontRunTests -test.bench .
|
||||
|
||||
.PHONY: bench-pgsql
|
||||
bench-pgsql: integrations.pgsql.test generate-ini-pgsql
|
||||
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/pgsql.ini ./integrations.pgsql.test -test.cpuprofile=cpu.out -test.run DontRunTests -test.bench .
|
||||
GITEA_TEST_CONF=tests/pgsql.ini ./integrations.pgsql.test -test.cpuprofile=cpu.out -test.run DontRunTests -test.bench .
|
||||
|
||||
.PHONY: integration-test-coverage
|
||||
integration-test-coverage: integrations.cover.test generate-ini-mysql
|
||||
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql.ini ./integrations.cover.test -test.coverprofile=integration.coverage.out
|
||||
GITEA_TEST_CONF=tests/mysql.ini ./integrations.cover.test -test.coverprofile=integration.coverage.out
|
||||
|
||||
.PHONY: integration-test-coverage-sqlite
|
||||
integration-test-coverage-sqlite: integrations.cover.sqlite.test generate-ini-sqlite
|
||||
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini ./integrations.cover.sqlite.test -test.coverprofile=integration.coverage.out
|
||||
GITEA_TEST_CONF=tests/sqlite.ini ./integrations.cover.sqlite.test -test.coverprofile=integration.coverage.out
|
||||
|
||||
integrations.mysql.test: git-check $(GO_SOURCES)
|
||||
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration -o integrations.mysql.test
|
||||
@ -652,54 +652,54 @@ integrations.cover.sqlite.test: git-check $(GO_SOURCES)
|
||||
.PHONY: migrations.mysql.test
|
||||
migrations.mysql.test: $(GO_SOURCES) generate-ini-mysql
|
||||
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration/migration-test -o migrations.mysql.test
|
||||
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql.ini ./migrations.mysql.test
|
||||
GITEA_TEST_CONF=tests/mysql.ini ./migrations.mysql.test
|
||||
|
||||
.PHONY: migrations.pgsql.test
|
||||
migrations.pgsql.test: $(GO_SOURCES) generate-ini-pgsql
|
||||
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration/migration-test -o migrations.pgsql.test
|
||||
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/pgsql.ini ./migrations.pgsql.test
|
||||
GITEA_TEST_CONF=tests/pgsql.ini ./migrations.pgsql.test
|
||||
|
||||
.PHONY: migrations.mssql.test
|
||||
migrations.mssql.test: $(GO_SOURCES) generate-ini-mssql
|
||||
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration/migration-test -o migrations.mssql.test
|
||||
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mssql.ini ./migrations.mssql.test
|
||||
GITEA_TEST_CONF=tests/mssql.ini ./migrations.mssql.test
|
||||
|
||||
.PHONY: migrations.sqlite.test
|
||||
migrations.sqlite.test: $(GO_SOURCES) generate-ini-sqlite
|
||||
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration/migration-test -o migrations.sqlite.test -tags '$(TEST_TAGS)'
|
||||
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini ./migrations.sqlite.test
|
||||
GITEA_TEST_CONF=tests/sqlite.ini ./migrations.sqlite.test
|
||||
|
||||
.PHONY: migrations.individual.mysql.test
|
||||
migrations.individual.mysql.test: $(GO_SOURCES)
|
||||
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql.ini $(GO) test $(GOTESTFLAGS) -tags='$(TEST_TAGS)' -p 1 $(MIGRATE_TEST_PACKAGES)
|
||||
GITEA_TEST_CONF=tests/mysql.ini $(GO) test $(GOTESTFLAGS) -tags='$(TEST_TAGS)' -p 1 $(MIGRATE_TEST_PACKAGES)
|
||||
|
||||
.PHONY: migrations.individual.sqlite.test\#%
|
||||
migrations.individual.sqlite.test\#%: $(GO_SOURCES) generate-ini-sqlite
|
||||
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini $(GO) test $(GOTESTFLAGS) -tags '$(TEST_TAGS)' code.gitea.io/gitea/models/migrations/$*
|
||||
GITEA_TEST_CONF=tests/sqlite.ini $(GO) test $(GOTESTFLAGS) -tags '$(TEST_TAGS)' code.gitea.io/gitea/models/migrations/$*
|
||||
|
||||
.PHONY: migrations.individual.pgsql.test
|
||||
migrations.individual.pgsql.test: $(GO_SOURCES)
|
||||
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/pgsql.ini $(GO) test $(GOTESTFLAGS) -tags='$(TEST_TAGS)' -p 1 $(MIGRATE_TEST_PACKAGES)
|
||||
GITEA_TEST_CONF=tests/pgsql.ini $(GO) test $(GOTESTFLAGS) -tags='$(TEST_TAGS)' -p 1 $(MIGRATE_TEST_PACKAGES)
|
||||
|
||||
.PHONY: migrations.individual.pgsql.test\#%
|
||||
migrations.individual.pgsql.test\#%: $(GO_SOURCES) generate-ini-pgsql
|
||||
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/pgsql.ini $(GO) test $(GOTESTFLAGS) -tags '$(TEST_TAGS)' code.gitea.io/gitea/models/migrations/$*
|
||||
GITEA_TEST_CONF=tests/pgsql.ini $(GO) test $(GOTESTFLAGS) -tags '$(TEST_TAGS)' code.gitea.io/gitea/models/migrations/$*
|
||||
|
||||
.PHONY: migrations.individual.mssql.test
|
||||
migrations.individual.mssql.test: $(GO_SOURCES) generate-ini-mssql
|
||||
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mssql.ini $(GO) test $(GOTESTFLAGS) -tags='$(TEST_TAGS)' -p 1 $(MIGRATE_TEST_PACKAGES)
|
||||
GITEA_TEST_CONF=tests/mssql.ini $(GO) test $(GOTESTFLAGS) -tags='$(TEST_TAGS)' -p 1 $(MIGRATE_TEST_PACKAGES)
|
||||
|
||||
.PHONY: migrations.individual.mssql.test\#%
|
||||
migrations.individual.mssql.test\#%: $(GO_SOURCES) generate-ini-mssql
|
||||
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mssql.ini $(GO) test $(GOTESTFLAGS) -tags '$(TEST_TAGS)' code.gitea.io/gitea/models/migrations/$*
|
||||
GITEA_TEST_CONF=tests/mssql.ini $(GO) test $(GOTESTFLAGS) -tags '$(TEST_TAGS)' code.gitea.io/gitea/models/migrations/$*
|
||||
|
||||
.PHONY: migrations.individual.sqlite.test
|
||||
migrations.individual.sqlite.test: $(GO_SOURCES) generate-ini-sqlite
|
||||
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini $(GO) test $(GOTESTFLAGS) -tags='$(TEST_TAGS)' -p 1 $(MIGRATE_TEST_PACKAGES)
|
||||
GITEA_TEST_CONF=tests/sqlite.ini $(GO) test $(GOTESTFLAGS) -tags='$(TEST_TAGS)' -p 1 $(MIGRATE_TEST_PACKAGES)
|
||||
|
||||
.PHONY: migrations.individual.sqlite.test\#%
|
||||
migrations.individual.sqlite.test\#%: $(GO_SOURCES) generate-ini-sqlite
|
||||
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini $(GO) test $(GOTESTFLAGS) -tags '$(TEST_TAGS)' code.gitea.io/gitea/models/migrations/$*
|
||||
GITEA_TEST_CONF=tests/sqlite.ini $(GO) test $(GOTESTFLAGS) -tags '$(TEST_TAGS)' code.gitea.io/gitea/models/migrations/$*
|
||||
|
||||
e2e.mysql.test: $(GO_SOURCES)
|
||||
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/e2e -o e2e.mysql.test
|
||||
@ -747,7 +747,7 @@ security-check:
|
||||
|
||||
$(EXECUTABLE): $(GO_SOURCES) $(TAGS_PREREQ)
|
||||
ifneq ($(and $(STATIC),$(findstring pam,$(TAGS))),)
|
||||
$(error pam support set via TAGS doesn't support static builds)
|
||||
$(error pam support set via TAGS does not support static builds)
|
||||
endif
|
||||
CGO_ENABLED="$(CGO_ENABLED)" CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) build $(GOFLAGS) $(EXTRA_GOFLAGS) -tags '$(TAGS)' -ldflags '-s -w $(EXTLDFLAGS) $(LDFLAGS)' -o $@
|
||||
|
||||
|
||||
@ -149,7 +149,7 @@ func NewMainApp(appVer AppVersion) *cli.Command {
|
||||
app.Commands = append(app.Commands, subCmdWithConfig...)
|
||||
app.Commands = append(app.Commands, subCmdStandalone...)
|
||||
|
||||
setting.InitGiteaEnvVars()
|
||||
setting.UnsetUnnecessaryEnvVars()
|
||||
return app
|
||||
}
|
||||
|
||||
|
||||
@ -157,6 +157,7 @@ func TestCliCmd(t *testing.T) {
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(c.cmd, func(t *testing.T) {
|
||||
defer test.MockVariableValue(&setting.InstallLock, false)()
|
||||
app := newTestApp(cli.Command{
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
_, _ = fmt.Fprint(cmd.Root().Writer, makePathOutput(setting.AppWorkPath, setting.CustomPath, setting.CustomConf))
|
||||
@ -170,7 +171,10 @@ func TestCliCmd(t *testing.T) {
|
||||
r, err := runTestApp(app, args...)
|
||||
assert.NoError(t, err, c.cmd)
|
||||
assert.NotEmpty(t, c.exp, c.cmd)
|
||||
assert.Contains(t, r.Stdout, c.exp, c.cmd)
|
||||
if !assert.Contains(t, r.Stdout, c.exp, c.cmd) {
|
||||
t.Log("Full output:\n" + r.Stdout)
|
||||
t.Log("Expected:\n" + c.exp)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -1329,9 +1329,12 @@ LEVEL = Info
|
||||
;; Leave it empty to allow users to select any theme from "{CustomPath}/public/assets/css/theme-*.css"
|
||||
;THEMES =
|
||||
;;
|
||||
;; The icons for file list (basic/material), this is a temporary option which will be replaced by a user setting in the future.
|
||||
;; The icon theme for files (basic/material)
|
||||
;FILE_ICON_THEME = material
|
||||
;;
|
||||
;; The icon theme for folders (basic/material)
|
||||
;FOLDER_ICON_THEME = basic
|
||||
;;
|
||||
;; All available reactions users can choose on issues/prs and comments.
|
||||
;; Values can be emoji alias (:smile:) or a unicode emoji.
|
||||
;; For custom reactions, add a tightly cropped square image to public/assets/img/emoji/reaction_name.png
|
||||
|
||||
6
go.mod
6
go.mod
@ -28,7 +28,7 @@ require (
|
||||
github.com/ProtonMail/go-crypto v1.3.0
|
||||
github.com/PuerkitoBio/goquery v1.10.3
|
||||
github.com/SaveTheRbtz/zstd-seekable-format-go/pkg v0.8.0
|
||||
github.com/alecthomas/chroma/v2 v2.23.0
|
||||
github.com/alecthomas/chroma/v2 v2.23.1
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.18.10
|
||||
github.com/aws/aws-sdk-go-v2/service/codecommit v1.32.2
|
||||
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb
|
||||
@ -50,10 +50,10 @@ require (
|
||||
github.com/gliderlabs/ssh v0.3.8
|
||||
github.com/go-ap/activitypub v0.0.0-20250810115208-cb73b20a1742
|
||||
github.com/go-ap/jsonld v0.0.0-20221030091449-f2a191312c73
|
||||
github.com/go-chi/chi/v5 v5.2.3
|
||||
github.com/go-chi/chi/v5 v5.2.4
|
||||
github.com/go-chi/cors v1.2.2
|
||||
github.com/go-co-op/gocron v1.37.0
|
||||
github.com/go-enry/go-enry/v2 v2.9.2
|
||||
github.com/go-enry/go-enry/v2 v2.9.4
|
||||
github.com/go-git/go-billy/v5 v5.6.2
|
||||
github.com/go-git/go-git/v5 v5.16.3
|
||||
github.com/go-ldap/ldap/v3 v3.4.11
|
||||
|
||||
12
go.sum
12
go.sum
@ -98,8 +98,8 @@ github.com/SaveTheRbtz/zstd-seekable-format-go/pkg v0.8.0/go.mod h1:1HmmMEVsr+0R
|
||||
github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0=
|
||||
github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
|
||||
github.com/alecthomas/chroma/v2 v2.2.0/go.mod h1:vf4zrexSH54oEjJ7EdB65tGNHmH3pGZmVkgTP5RHvAs=
|
||||
github.com/alecthomas/chroma/v2 v2.23.0 h1:u/Orux1J0eLuZDeQ44froV8smumheieI0EofhbyKhhk=
|
||||
github.com/alecthomas/chroma/v2 v2.23.0/go.mod h1:NqVhfBR0lte5Ouh3DcthuUCTUpDC9cxBOfyMbMQPs3o=
|
||||
github.com/alecthomas/chroma/v2 v2.23.1 h1:nv2AVZdTyClGbVQkIzlDm/rnhk1E9bU9nXwmZ/Vk/iY=
|
||||
github.com/alecthomas/chroma/v2 v2.23.1/go.mod h1:NqVhfBR0lte5Ouh3DcthuUCTUpDC9cxBOfyMbMQPs3o=
|
||||
github.com/alecthomas/repr v0.0.0-20220113201626-b1b626ac65ae/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8=
|
||||
github.com/alecthomas/repr v0.5.2 h1:SU73FTI9D1P5UNtvseffFSGmdNci/O6RsqzeXJtP0Qs=
|
||||
github.com/alecthomas/repr v0.5.2/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
|
||||
@ -316,14 +316,14 @@ github.com/go-ap/jsonld v0.0.0-20221030091449-f2a191312c73/go.mod h1:jyveZeGw5La
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 h1:BP4M0CvQ4S3TGls2FvczZtj5Re/2ZzkV9VwqPHH/3Bo=
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667/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.2.3 h1:WQIt9uxdsAbgIYgid+BpYc+liqQZGMHRaUwp0JUcvdE=
|
||||
github.com/go-chi/chi/v5 v5.2.3/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops=
|
||||
github.com/go-chi/chi/v5 v5.2.4 h1:WtFKPHwlywe8Srng8j2BhOD9312j9cGUxG1SP4V2cR4=
|
||||
github.com/go-chi/chi/v5 v5.2.4/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0=
|
||||
github.com/go-chi/cors v1.2.2 h1:Jmey33TE+b+rB7fT8MUy1u0I4L+NARQlK6LhzKPSyQE=
|
||||
github.com/go-chi/cors v1.2.2/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/go.mod h1:3L/n6BkO7ABj+TrfSVXLRzsP26zmikL4ISkLQ0O8iNY=
|
||||
github.com/go-enry/go-enry/v2 v2.9.2 h1:giOQAtCgBX08kosrX818DCQJTCNtKwoPBGu0qb6nKTY=
|
||||
github.com/go-enry/go-enry/v2 v2.9.2/go.mod h1:9yrj4ES1YrbNb1Wb7/PWYr2bpaCXUGRt0uafN0ISyG8=
|
||||
github.com/go-enry/go-enry/v2 v2.9.4 h1:DS4l06/NgMzYjsJ2J52wORo6UsfFDjDCwfAn7w3gG44=
|
||||
github.com/go-enry/go-enry/v2 v2.9.4/go.mod h1:9yrj4ES1YrbNb1Wb7/PWYr2bpaCXUGRt0uafN0ISyG8=
|
||||
github.com/go-enry/go-oniguruma v1.2.1 h1:k8aAMuJfMrqm/56SG2lV9Cfti6tC4x8673aHCcBk+eo=
|
||||
github.com/go-enry/go-oniguruma v1.2.1/go.mod h1:bWDhYP+S6xZQgiRL7wlTScFYBe023B6ilRZbCAD5Hf4=
|
||||
github.com/go-fed/httpsig v1.1.1-0.20201223112313-55836744818e h1:oRq/fiirun5HqlEWMLIcDmLpIELlG4iGbd0s8iqgPi8=
|
||||
|
||||
@ -57,7 +57,7 @@ func InitEngine(ctx context.Context) error {
|
||||
xe, err := newXORMEngine()
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "SQLite3 support") {
|
||||
return fmt.Errorf(`sqlite3 requires: -tags sqlite,sqlite_unlock_notify%s%w`, "\n", err)
|
||||
return fmt.Errorf("sqlite3 requires: -tags sqlite,sqlite_unlock_notify\n%w", err)
|
||||
}
|
||||
return fmt.Errorf("failed to connect to database: %w", err)
|
||||
}
|
||||
|
||||
@ -5,21 +5,14 @@ package base
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
|
||||
"xorm.io/xorm"
|
||||
"xorm.io/xorm/schemas"
|
||||
@ -515,114 +508,3 @@ func ModifyColumn(x *xorm.Engine, tableName string, col *schemas.Column) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func removeAllWithRetry(dir string) error {
|
||||
var err error
|
||||
for range 20 {
|
||||
err = os.RemoveAll(dir)
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func newXORMEngine() (*xorm.Engine, error) {
|
||||
if err := db.InitEngine(context.Background()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
x := unittest.GetXORMEngine()
|
||||
return x, nil
|
||||
}
|
||||
|
||||
func deleteDB() error {
|
||||
switch {
|
||||
case setting.Database.Type.IsSQLite3():
|
||||
if err := util.Remove(setting.Database.Path); err != nil {
|
||||
return err
|
||||
}
|
||||
return os.MkdirAll(path.Dir(setting.Database.Path), os.ModePerm)
|
||||
|
||||
case setting.Database.Type.IsMySQL():
|
||||
db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@tcp(%s)/",
|
||||
setting.Database.User, setting.Database.Passwd, setting.Database.Host))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
if _, err = db.Exec("DROP DATABASE IF EXISTS " + setting.Database.Name); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err = db.Exec("CREATE DATABASE IF NOT EXISTS " + setting.Database.Name); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
case setting.Database.Type.IsPostgreSQL():
|
||||
db, err := sql.Open("postgres", fmt.Sprintf("postgres://%s:%s@%s/?sslmode=%s",
|
||||
setting.Database.User, setting.Database.Passwd, setting.Database.Host, setting.Database.SSLMode))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
if _, err = db.Exec("DROP DATABASE IF EXISTS " + setting.Database.Name); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err = db.Exec("CREATE DATABASE " + setting.Database.Name); err != nil {
|
||||
return err
|
||||
}
|
||||
db.Close()
|
||||
|
||||
// Check if we need to setup a specific schema
|
||||
if len(setting.Database.Schema) != 0 {
|
||||
db, err = sql.Open("postgres", fmt.Sprintf("postgres://%s:%s@%s/%s?sslmode=%s",
|
||||
setting.Database.User, setting.Database.Passwd, setting.Database.Host, setting.Database.Name, setting.Database.SSLMode))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
schrows, err := db.Query(fmt.Sprintf("SELECT 1 FROM information_schema.schemata WHERE schema_name = '%s'", setting.Database.Schema))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer schrows.Close()
|
||||
|
||||
if !schrows.Next() {
|
||||
// Create and setup a DB schema
|
||||
_, err = db.Exec("CREATE SCHEMA " + setting.Database.Schema)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Make the user's default search path the created schema; this will affect new connections
|
||||
_, err = db.Exec(fmt.Sprintf(`ALTER USER "%s" SET search_path = %s`, setting.Database.User, setting.Database.Schema))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
case setting.Database.Type.IsMSSQL():
|
||||
host, port := setting.ParseMSSQLHostPort(setting.Database.Host)
|
||||
db, err := sql.Open("mssql", fmt.Sprintf("server=%s; port=%s; database=%s; user id=%s; password=%s;",
|
||||
host, port, "master", setting.Database.User, setting.Database.Passwd))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
if _, err = db.Exec(fmt.Sprintf("DROP DATABASE IF EXISTS [%s]", setting.Database.Name)); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err = db.Exec(fmt.Sprintf("CREATE DATABASE [%s]", setting.Database.Name)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -11,6 +11,10 @@ import (
|
||||
"xorm.io/xorm/names"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
MainTest(m)
|
||||
}
|
||||
|
||||
func Test_DropTableColumns(t *testing.T) {
|
||||
x, deferable := PrepareTestEnv(t, 0)
|
||||
if x == nil || t.Failed() {
|
||||
|
||||
@ -1,12 +0,0 @@
|
||||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package base
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
MainTest(m)
|
||||
}
|
||||
@ -4,18 +4,21 @@
|
||||
package base
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/tempdir"
|
||||
"code.gitea.io/gitea/modules/test"
|
||||
"code.gitea.io/gitea/modules/testlogger"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"xorm.io/xorm"
|
||||
@ -24,6 +27,117 @@ import (
|
||||
|
||||
// FIXME: this file shouldn't be in a normal package, it should only be compiled for tests
|
||||
|
||||
func removeAllWithRetry(dir string) error {
|
||||
var err error
|
||||
for range 20 {
|
||||
err = os.RemoveAll(dir)
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func newXORMEngine(t *testing.T) (*xorm.Engine, error) {
|
||||
if err := db.InitEngine(t.Context()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
x := unittest.GetXORMEngine()
|
||||
return x, nil
|
||||
}
|
||||
|
||||
func deleteDB() error {
|
||||
switch {
|
||||
case setting.Database.Type.IsSQLite3():
|
||||
if err := util.Remove(setting.Database.Path); err != nil {
|
||||
return err
|
||||
}
|
||||
return os.MkdirAll(path.Dir(setting.Database.Path), os.ModePerm)
|
||||
|
||||
case setting.Database.Type.IsMySQL():
|
||||
db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@tcp(%s)/",
|
||||
setting.Database.User, setting.Database.Passwd, setting.Database.Host))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
if _, err = db.Exec("DROP DATABASE IF EXISTS " + setting.Database.Name); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err = db.Exec("CREATE DATABASE IF NOT EXISTS " + setting.Database.Name); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
case setting.Database.Type.IsPostgreSQL():
|
||||
db, err := sql.Open("postgres", fmt.Sprintf("postgres://%s:%s@%s/?sslmode=%s",
|
||||
setting.Database.User, setting.Database.Passwd, setting.Database.Host, setting.Database.SSLMode))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
if _, err = db.Exec("DROP DATABASE IF EXISTS " + setting.Database.Name); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err = db.Exec("CREATE DATABASE " + setting.Database.Name); err != nil {
|
||||
return err
|
||||
}
|
||||
db.Close()
|
||||
|
||||
// Check if we need to setup a specific schema
|
||||
if len(setting.Database.Schema) != 0 {
|
||||
db, err = sql.Open("postgres", fmt.Sprintf("postgres://%s:%s@%s/%s?sslmode=%s",
|
||||
setting.Database.User, setting.Database.Passwd, setting.Database.Host, setting.Database.Name, setting.Database.SSLMode))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
schrows, err := db.Query(fmt.Sprintf("SELECT 1 FROM information_schema.schemata WHERE schema_name = '%s'", setting.Database.Schema))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer schrows.Close()
|
||||
|
||||
if !schrows.Next() {
|
||||
// Create and setup a DB schema
|
||||
_, err = db.Exec("CREATE SCHEMA " + setting.Database.Schema)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Make the user's default search path the created schema; this will affect new connections
|
||||
_, err = db.Exec(fmt.Sprintf(`ALTER USER "%s" SET search_path = %s`, setting.Database.User, setting.Database.Schema))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
case setting.Database.Type.IsMSSQL():
|
||||
host, port := setting.ParseMSSQLHostPort(setting.Database.Host)
|
||||
db, err := sql.Open("mssql", fmt.Sprintf("server=%s; port=%s; database=%s; user id=%s; password=%s;",
|
||||
host, port, "master", setting.Database.User, setting.Database.Passwd))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
if _, err = db.Exec(fmt.Sprintf("DROP DATABASE IF EXISTS [%s]", setting.Database.Name)); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err = db.Exec(fmt.Sprintf("CREATE DATABASE [%s]", setting.Database.Name)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// PrepareTestEnv prepares the test environment and reset the database. The skip parameter should usually be 0.
|
||||
// Provide models to be sync'd with the database - in particular any models you expect fixtures to be loaded from.
|
||||
//
|
||||
@ -40,7 +154,7 @@ func PrepareTestEnv(t *testing.T, skip int, syncModels ...any) (*xorm.Engine, fu
|
||||
return nil, deferFn
|
||||
}
|
||||
|
||||
x, err := newXORMEngine()
|
||||
x, err := newXORMEngine(t)
|
||||
require.NoError(t, err)
|
||||
if x != nil {
|
||||
oldDefer := deferFn
|
||||
@ -101,28 +215,7 @@ func LoadTableSchemasMap(t *testing.T, x *xorm.Engine) map[string]*schemas.Table
|
||||
|
||||
func MainTest(m *testing.M) {
|
||||
testlogger.Init()
|
||||
|
||||
giteaRoot := test.SetupGiteaRoot()
|
||||
giteaBinary := "gitea"
|
||||
if runtime.GOOS == "windows" {
|
||||
giteaBinary += ".exe"
|
||||
}
|
||||
setting.AppPath = filepath.Join(giteaRoot, giteaBinary)
|
||||
if _, err := os.Stat(setting.AppPath); err != nil {
|
||||
testlogger.Fatalf("Could not find gitea binary at %s\n", setting.AppPath)
|
||||
}
|
||||
|
||||
giteaConf := os.Getenv("GITEA_CONF")
|
||||
if giteaConf == "" {
|
||||
giteaConf = filepath.Join(filepath.Dir(setting.AppPath), "tests/sqlite.ini")
|
||||
_, _ = fmt.Fprintf(os.Stderr, "Environment variable $GITEA_CONF not set - defaulting to %s\n", giteaConf)
|
||||
}
|
||||
|
||||
if !filepath.IsAbs(giteaConf) {
|
||||
setting.CustomConf = filepath.Join(giteaRoot, giteaConf)
|
||||
} else {
|
||||
setting.CustomConf = giteaConf
|
||||
}
|
||||
setting.SetupGiteaTestEnv()
|
||||
|
||||
tmpDataPath, cleanup, err := tempdir.OsTempDir("gitea-test").MkdirTempRandom("data")
|
||||
if err != nil {
|
||||
@ -130,7 +223,6 @@ func MainTest(m *testing.M) {
|
||||
}
|
||||
defer cleanup()
|
||||
|
||||
setting.CustomPath = filepath.Join(setting.AppWorkPath, "custom")
|
||||
setting.AppDataPath = tmpDataPath
|
||||
|
||||
unittest.InitSettingsForTesting()
|
||||
|
||||
@ -9,7 +9,7 @@ import (
|
||||
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/test"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"xorm.io/xorm"
|
||||
@ -60,7 +60,8 @@ func NewFixturesLoaderVendorGoTestfixtures(e *xorm.Engine, opts unittest.Fixture
|
||||
|
||||
func prepareTestFixturesLoaders(t testing.TB) unittest.FixturesOptions {
|
||||
_ = user_model.User{}
|
||||
opts := unittest.FixturesOptions{Dir: filepath.Join(test.SetupGiteaRoot(), "models", "fixtures"), Files: []string{
|
||||
giteaRoot := setting.SetupGiteaTestEnv()
|
||||
opts := unittest.FixturesOptions{Dir: filepath.Join(giteaRoot, "models", "fixtures"), Files: []string{
|
||||
"user.yml",
|
||||
}}
|
||||
require.NoError(t, unittest.CreateTestEngine(opts))
|
||||
|
||||
@ -21,7 +21,6 @@ import (
|
||||
"code.gitea.io/gitea/modules/setting/config"
|
||||
"code.gitea.io/gitea/modules/storage"
|
||||
"code.gitea.io/gitea/modules/tempdir"
|
||||
"code.gitea.io/gitea/modules/test"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
@ -60,7 +59,6 @@ func InitSettingsForTesting() {
|
||||
_ = hash.Register("dummy", hash.NewDummyHasher)
|
||||
|
||||
setting.PasswordHashAlgo, _ = hash.SetDefaultPasswordHashAlgorithm("dummy")
|
||||
setting.InitGiteaEnvVarsForTesting()
|
||||
}
|
||||
|
||||
// TestOptions represents test options
|
||||
@ -74,8 +72,7 @@ type TestOptions struct {
|
||||
// test database. Creates the test database, and sets necessary settings.
|
||||
func MainTest(m *testing.M, testOptsArg ...*TestOptions) {
|
||||
testOpts := util.OptionalArg(testOptsArg, &TestOptions{})
|
||||
giteaRoot = test.SetupGiteaRoot()
|
||||
setting.CustomPath = filepath.Join(giteaRoot, "custom")
|
||||
giteaRoot = setting.SetupGiteaTestEnv()
|
||||
InitSettingsForTesting()
|
||||
|
||||
fixturesOpts := FixturesOptions{Dir: filepath.Join(giteaRoot, "models", "fixtures"), Files: testOpts.FixtureFiles}
|
||||
@ -172,7 +169,7 @@ func CreateTestEngine(opts FixturesOptions) error {
|
||||
x, err := xorm.NewEngine("sqlite3", "file::memory:?cache=shared&_txlock=immediate")
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "unknown driver") {
|
||||
return fmt.Errorf(`sqlite3 requires: -tags sqlite,sqlite_unlock_notify%s%w`, "\n", err)
|
||||
return fmt.Errorf("sqlite3 requires: -tags sqlite,sqlite_unlock_notify\n%w", err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
@ -182,7 +179,7 @@ func CreateTestEngine(opts FixturesOptions) error {
|
||||
if err = db.SyncAllTables(); err != nil {
|
||||
return err
|
||||
}
|
||||
switch os.Getenv("GITEA_UNIT_TESTS_LOG_SQL") {
|
||||
switch os.Getenv("GITEA_TEST_LOG_SQL") {
|
||||
case "true", "1":
|
||||
x.ShowSQL(true)
|
||||
}
|
||||
@ -201,5 +198,5 @@ func PrepareTestEnv(t testing.TB) {
|
||||
assert.NoError(t, PrepareTestDatabase())
|
||||
metaPath := filepath.Join(giteaRoot, "tests", "gitea-repositories-meta")
|
||||
assert.NoError(t, SyncDirs(metaPath, setting.RepoRootPath))
|
||||
test.SetupGiteaRoot() // Makes sure GITEA_ROOT is set
|
||||
setting.SetupGiteaTestEnv()
|
||||
}
|
||||
|
||||
@ -34,7 +34,13 @@ func (p *RenderedIconPool) RenderToHTML() template.HTML {
|
||||
}
|
||||
|
||||
func RenderEntryIconHTML(renderedIconPool *RenderedIconPool, entry *EntryInfo) template.HTML {
|
||||
if setting.UI.FileIconTheme == "material" {
|
||||
// Use folder theme for directories and symlinks to directories
|
||||
theme := setting.UI.FileIconTheme
|
||||
if entry.EntryMode.IsDir() || (entry.EntryMode.IsLink() && entry.SymlinkToMode.IsDir()) {
|
||||
theme = setting.UI.FolderIconTheme
|
||||
}
|
||||
|
||||
if theme == "material" {
|
||||
return DefaultMaterialIconProvider().EntryIconHTML(renderedIconPool, entry)
|
||||
}
|
||||
return BasicEntryIconHTML(entry)
|
||||
|
||||
75
modules/fileicon/render_test.go
Normal file
75
modules/fileicon/render_test.go
Normal file
@ -0,0 +1,75 @@
|
||||
// Copyright 2026 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package fileicon_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/modules/fileicon"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/test"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestRenderEntryIconHTML_WithDifferentThemes(t *testing.T) {
|
||||
// Test that folder icons use the folder theme
|
||||
t.Run("FolderUsesBasicTheme", func(t *testing.T) {
|
||||
defer test.MockVariableValue(&setting.UI.FileIconTheme, "material")()
|
||||
defer test.MockVariableValue(&setting.UI.FolderIconTheme, "basic")()
|
||||
|
||||
folderEntry := &fileicon.EntryInfo{
|
||||
BaseName: "testfolder",
|
||||
EntryMode: git.EntryModeTree,
|
||||
}
|
||||
|
||||
html := fileicon.RenderEntryIconHTML(nil, folderEntry)
|
||||
// Basic theme renders octicon classes
|
||||
assert.Contains(t, string(html), "octicon-file-directory-fill")
|
||||
})
|
||||
|
||||
t.Run("FileUsesMaterialTheme", func(t *testing.T) {
|
||||
defer test.MockVariableValue(&setting.UI.FileIconTheme, "material")()
|
||||
defer test.MockVariableValue(&setting.UI.FolderIconTheme, "basic")()
|
||||
|
||||
fileEntry := &fileicon.EntryInfo{
|
||||
BaseName: "test.js",
|
||||
EntryMode: git.EntryModeBlob,
|
||||
}
|
||||
|
||||
html := fileicon.RenderEntryIconHTML(nil, fileEntry)
|
||||
// Material theme for files renders material icons
|
||||
assert.Contains(t, string(html), "svg-mfi-")
|
||||
})
|
||||
|
||||
t.Run("SymlinkToFolderUsesBasicTheme", func(t *testing.T) {
|
||||
defer test.MockVariableValue(&setting.UI.FileIconTheme, "material")()
|
||||
defer test.MockVariableValue(&setting.UI.FolderIconTheme, "basic")()
|
||||
|
||||
symlinkEntry := &fileicon.EntryInfo{
|
||||
BaseName: "link",
|
||||
EntryMode: git.EntryModeSymlink,
|
||||
SymlinkToMode: git.EntryModeTree,
|
||||
}
|
||||
|
||||
html := fileicon.RenderEntryIconHTML(nil, symlinkEntry)
|
||||
// Symlinks to folders should use folder theme
|
||||
assert.Contains(t, string(html), "octicon-file-directory-symlink")
|
||||
})
|
||||
|
||||
t.Run("BothMaterialTheme", func(t *testing.T) {
|
||||
defer test.MockVariableValue(&setting.UI.FileIconTheme, "material")()
|
||||
defer test.MockVariableValue(&setting.UI.FolderIconTheme, "material")()
|
||||
|
||||
folderEntry := &fileicon.EntryInfo{
|
||||
BaseName: "testfolder",
|
||||
EntryMode: git.EntryModeTree,
|
||||
}
|
||||
|
||||
html := fileicon.RenderEntryIconHTML(nil, folderEntry)
|
||||
// Material theme for folders renders material folder icons
|
||||
assert.Contains(t, string(html), "svg-mfi-")
|
||||
})
|
||||
}
|
||||
@ -8,12 +8,12 @@ import (
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/test"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
// resolve repository path relative to the test directory
|
||||
testRootDir := test.SetupGiteaRoot()
|
||||
testRootDir := setting.SetupGiteaTestEnv()
|
||||
repoPath = func(repo Repository) string {
|
||||
if filepath.IsAbs(repo.RelativePath()) {
|
||||
return repo.RelativePath() // for testing purpose only
|
||||
|
||||
@ -167,24 +167,13 @@ func EnvironmentToConfig(cfg ConfigProvider, envs []string) (changed bool) {
|
||||
return changed
|
||||
}
|
||||
|
||||
// InitGiteaEnvVars initializes the environment variables for gitea
|
||||
func InitGiteaEnvVars() {
|
||||
func UnsetUnnecessaryEnvVars() {
|
||||
// Ideally Gitea should only accept the environment variables which it clearly knows instead of unsetting the ones it doesn't want,
|
||||
// but the ideal behavior would be a breaking change, and it seems not bringing enough benefits to end users,
|
||||
// so at the moment we could still keep "unsetting the unnecessary environments"
|
||||
// but the ideal behavior would be a breaking change, and it seems not bringing enough benefits to end users.
|
||||
// So at the moment we just keep "unsetting the unnecessary environment variables".
|
||||
|
||||
// HOME is managed by Gitea, Gitea's git should use "HOME/.gitconfig".
|
||||
// But git would try "XDG_CONFIG_HOME/git/config" first if "HOME/.gitconfig" does not exist,
|
||||
// then our git.InitFull would still write to "XDG_CONFIG_HOME/git/config" if XDG_CONFIG_HOME is set.
|
||||
_ = os.Unsetenv("XDG_CONFIG_HOME")
|
||||
}
|
||||
|
||||
func InitGiteaEnvVarsForTesting() {
|
||||
InitGiteaEnvVars()
|
||||
_ = os.Unsetenv("GIT_AUTHOR_NAME")
|
||||
_ = os.Unsetenv("GIT_AUTHOR_EMAIL")
|
||||
_ = os.Unsetenv("GIT_AUTHOR_DATE")
|
||||
_ = os.Unsetenv("GIT_COMMITTER_NAME")
|
||||
_ = os.Unsetenv("GIT_COMMITTER_EMAIL")
|
||||
_ = os.Unsetenv("GIT_COMMITTER_DATE")
|
||||
}
|
||||
|
||||
@ -11,12 +11,12 @@ import (
|
||||
|
||||
func Test_loadMailerFrom(t *testing.T) {
|
||||
kases := map[string]*Mailer{
|
||||
"smtp.mydomain.com": {
|
||||
SMTPAddr: "smtp.mydomain.com",
|
||||
"smtp.mydomain.test": {
|
||||
SMTPAddr: "smtp.mydomain.test",
|
||||
SMTPPort: "465",
|
||||
},
|
||||
"smtp.mydomain.com:123": {
|
||||
SMTPAddr: "smtp.mydomain.com",
|
||||
"smtp.mydomain.test:123": {
|
||||
SMTPAddr: "smtp.mydomain.test",
|
||||
SMTPPort: "123",
|
||||
},
|
||||
":123": {
|
||||
|
||||
61
modules/setting/testenv.go
Normal file
61
modules/setting/testenv.go
Normal file
@ -0,0 +1,61 @@
|
||||
// Copyright 2026 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package setting
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
)
|
||||
|
||||
func SetupGiteaTestEnv() string {
|
||||
giteaRoot := os.Getenv("GITEA_TEST_ROOT")
|
||||
if giteaRoot == "" {
|
||||
_, filename, _, _ := runtime.Caller(0)
|
||||
giteaRoot = filepath.Dir(filepath.Dir(filepath.Dir(filename)))
|
||||
fixturesDir := filepath.Join(giteaRoot, "models", "fixtures")
|
||||
if _, err := os.Stat(fixturesDir); err != nil {
|
||||
panic("in gitea source code directory, fixtures directory not found: " + fixturesDir)
|
||||
}
|
||||
}
|
||||
|
||||
appWorkPathBuiltin = giteaRoot
|
||||
AppWorkPath = giteaRoot
|
||||
AppPath = filepath.Join(giteaRoot, "gitea") + util.Iif(IsWindows, ".exe", "")
|
||||
|
||||
// giteaConf (GITEA_CONF) must be relative because it is used in the git hooks as "$GITEA_ROOT/$GITEA_CONF"
|
||||
giteaConf := os.Getenv("GITEA_TEST_CONF")
|
||||
if giteaConf == "" {
|
||||
// By default, use sqlite.ini for testing, then IDE like GoLand can start the test process with debugger.
|
||||
// It's easier for developers to debug bugs step by step with a debugger.
|
||||
// Notice: when doing "ssh push", Gitea executes sub processes, debugger won't work for the sub processes.
|
||||
giteaConf = "tests/sqlite.ini"
|
||||
_, _ = fmt.Fprintf(os.Stderr, "Environment variable GITEA_TEST_CONF not set - defaulting to %s\n", giteaConf)
|
||||
if !EnableSQLite3 {
|
||||
_, _ = fmt.Fprintf(os.Stderr, "sqlite3 requires: -tags sqlite,sqlite_unlock_notify\n")
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
// CustomConf must be absolute path to make tests pass,
|
||||
CustomConf = filepath.Join(AppWorkPath, giteaConf)
|
||||
|
||||
// also unset unnecessary env vars for testing (only keep "GITEA_TEST_*" ones)
|
||||
UnsetUnnecessaryEnvVars()
|
||||
for _, env := range os.Environ() {
|
||||
if strings.HasPrefix(env, "GIT_") || (strings.HasPrefix(env, "GITEA_") && !strings.HasPrefix(env, "GITEA_TEST_")) {
|
||||
k, _, _ := strings.Cut(env, "=")
|
||||
_ = os.Unsetenv(k)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: some git repo hooks (test fixtures) still use these env variables, need to be refactored in the future
|
||||
_ = os.Setenv("GITEA_ROOT", giteaRoot)
|
||||
_ = os.Setenv("GITEA_CONF", giteaConf) // test fixture git hooks use "$GITEA_ROOT/$GITEA_CONF" in their scripts
|
||||
|
||||
return giteaRoot
|
||||
}
|
||||
@ -29,6 +29,7 @@ var UI = struct {
|
||||
DefaultTheme string
|
||||
Themes []string
|
||||
FileIconTheme string
|
||||
FolderIconTheme string
|
||||
Reactions []string
|
||||
ReactionsLookup container.Set[string] `ini:"-"`
|
||||
CustomEmojis []string
|
||||
@ -88,6 +89,7 @@ var UI = struct {
|
||||
MaxDisplayFileSize: 8388608,
|
||||
DefaultTheme: `gitea-auto`,
|
||||
FileIconTheme: `material`,
|
||||
FolderIconTheme: `basic`,
|
||||
Reactions: []string{`+1`, `-1`, `laugh`, `hooray`, `confused`, `heart`, `rocket`, `eyes`},
|
||||
CustomEmojis: []string{`git`, `gitea`, `codeberg`, `gitlab`, `github`, `gogs`},
|
||||
CustomEmojisMap: map[string]string{"git": ":git:", "gitea": ":gitea:", "codeberg": ":codeberg:", "gitlab": ":gitlab:", "github": ":github:", "gogs": ":gogs:"},
|
||||
|
||||
@ -9,13 +9,9 @@ import (
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/json"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
)
|
||||
|
||||
// RedirectURL returns the redirect URL of a http response.
|
||||
@ -59,22 +55,6 @@ func MockVariableValue[T any](p *T, v ...T) (reset func()) {
|
||||
return func() { *p = old }
|
||||
}
|
||||
|
||||
// SetupGiteaRoot Sets GITEA_ROOT if it is not already set and returns the value
|
||||
func SetupGiteaRoot() string {
|
||||
giteaRoot := os.Getenv("GITEA_ROOT")
|
||||
if giteaRoot != "" {
|
||||
return giteaRoot
|
||||
}
|
||||
_, filename, _, _ := runtime.Caller(0)
|
||||
giteaRoot = filepath.Dir(filepath.Dir(filepath.Dir(filename)))
|
||||
fixturesDir := filepath.Join(giteaRoot, "models", "fixtures")
|
||||
if exist, _ := util.IsDir(fixturesDir); !exist {
|
||||
panic("fixtures directory not found: " + fixturesDir)
|
||||
}
|
||||
_ = os.Setenv("GITEA_ROOT", giteaRoot)
|
||||
return giteaRoot
|
||||
}
|
||||
|
||||
func ReadAllTarGzContent(r io.Reader) (map[string]string, error) {
|
||||
gzr, err := gzip.NewReader(r)
|
||||
if err != nil {
|
||||
|
||||
@ -1,17 +0,0 @@
|
||||
// Copyright 2024 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestSetupGiteaRoot(t *testing.T) {
|
||||
t.Setenv("GITEA_ROOT", "test")
|
||||
assert.Equal(t, "test", SetupGiteaRoot())
|
||||
t.Setenv("GITEA_ROOT", "")
|
||||
assert.NotEqual(t, "test", SetupGiteaRoot())
|
||||
}
|
||||
@ -118,7 +118,7 @@ func PrintCurrentTest(t testing.TB, skip ...int) func() {
|
||||
deferHasRun := false
|
||||
t.Cleanup(func() {
|
||||
if !deferHasRun {
|
||||
Printf("!!! defer function hasn't been run but Cleanup is called\n%s", getRuntimeStackAll())
|
||||
Printf("!!! %s defer function hasn't been run but Cleanup is called, usually caused by panic", t.Name())
|
||||
}
|
||||
})
|
||||
Printf("=== %s (%s:%d)\n", log.NewColoredValue(t.Name()), strings.TrimPrefix(filename, prefix), line)
|
||||
@ -171,16 +171,6 @@ func Init() {
|
||||
prefix = strings.TrimSuffix(filename, relFilePath)
|
||||
|
||||
log.RegisterEventWriter("test", newTestLoggerWriter)
|
||||
|
||||
duration, err := time.ParseDuration(os.Getenv("GITEA_TEST_SLOW_RUN"))
|
||||
if err == nil && duration > 0 {
|
||||
TestSlowRun = duration
|
||||
}
|
||||
|
||||
duration, err = time.ParseDuration(os.Getenv("GITEA_TEST_SLOW_FLUSH"))
|
||||
if err == nil && duration > 0 {
|
||||
TestSlowFlush = duration
|
||||
}
|
||||
}
|
||||
|
||||
func Fatalf(format string, args ...any) {
|
||||
|
||||
@ -271,7 +271,7 @@
|
||||
"install.smtp_port": "SMTP 端口",
|
||||
"install.smtp_from": "邮件发件人",
|
||||
"install.smtp_from_invalid": "「邮件发件人」地址无效",
|
||||
"install.smtp_from_helper": "请输入一个用于 Gitea 的邮箱地址,或者使用完整格式:「名称」<email@example.com>。",
|
||||
"install.smtp_from_helper": "请输入一个用于 Gitea 的邮箱地址,或者使用完整格式:\"名称\" <email@example.com>。",
|
||||
"install.mailer_user": "SMTP 用户名",
|
||||
"install.mailer_password": "SMTP 密码",
|
||||
"install.register_confirm": "需要邮件确认注册",
|
||||
@ -1796,6 +1796,7 @@
|
||||
"repo.pulls.remove_prefix": "删除 <strong>%s</strong> 前缀",
|
||||
"repo.pulls.data_broken": "此合并请求因为派生仓库信息缺失而中断。",
|
||||
"repo.pulls.files_conflicted": "此合并请求有变更与目标分支冲突。",
|
||||
"repo.pulls.files_conflicted_no_listed_files": "(未列出冲突文件)",
|
||||
"repo.pulls.is_checking": "正在进行合并冲突检查…",
|
||||
"repo.pulls.is_ancestor": "此分支已经包含在目标分支中,没有什么可以合并。",
|
||||
"repo.pulls.is_empty": "此分支上的更改已经在目标分支上。这将是一个空提交。",
|
||||
@ -2932,7 +2933,7 @@
|
||||
"admin.dashboard.delete_old_actions.started": "已开始从数据库中删除所有旧工作流记录。",
|
||||
"admin.dashboard.update_checker": "更新检查器",
|
||||
"admin.dashboard.delete_old_system_notices": "从数据库中删除所有旧系统通知",
|
||||
"admin.dashboard.gc_lfs": "垃圾回收 LFS 元数据",
|
||||
"admin.dashboard.gc_lfs": "对 LFS 元数据进行垃圾回收",
|
||||
"admin.dashboard.stop_zombie_tasks": "停止僵尸工作流任务",
|
||||
"admin.dashboard.stop_endless_tasks": "停止无限循环的工作流任务",
|
||||
"admin.dashboard.cancel_abandoned_jobs": "取消已放弃的工作流任务",
|
||||
@ -3324,7 +3325,7 @@
|
||||
"admin.monitor.queue.numberinqueue": "队列中的数量",
|
||||
"admin.monitor.queue.review_add": "查看 / 添加工作者",
|
||||
"admin.monitor.queue.settings.title": "池设置",
|
||||
"admin.monitor.queue.settings.desc": "因为工作者队列阻塞,池正在动态扩展。",
|
||||
"admin.monitor.queue.settings.desc": "工作池会根据其工作队列阻塞情况动态增长。",
|
||||
"admin.monitor.queue.settings.maxnumberworkers": "最大工作者数量",
|
||||
"admin.monitor.queue.settings.maxnumberworkers.placeholder": "当前 %[1]d",
|
||||
"admin.monitor.queue.settings.maxnumberworkers.error": "最大工作者数必须是数字",
|
||||
|
||||
@ -2,7 +2,7 @@ import {devices} from '@playwright/test';
|
||||
import {env} from 'node:process';
|
||||
import type {PlaywrightTestConfig} from '@playwright/test';
|
||||
|
||||
const BASE_URL = env.GITEA_URL?.replace?.(/\/$/g, '') || 'http://localhost:3000';
|
||||
const BASE_URL = env.GITEA_TEST_SERVER_URL?.replace?.(/\/$/g, '') || 'http://localhost:3000';
|
||||
|
||||
export default {
|
||||
testDir: './tests/e2e/',
|
||||
|
||||
@ -64,6 +64,15 @@ type componentStatus struct {
|
||||
}
|
||||
|
||||
// Check is the health check API handler
|
||||
//
|
||||
// HINT: HEALTH-CHECK-ENDPOINT: there is no clear definition about what "health" means.
|
||||
// In most cases, end users don't need to check such endpoint, because even if database is down,
|
||||
// Gitea will reover after database is up again. Sysop should monitor database and cache status directly.
|
||||
//
|
||||
// And keep in mind: this health check should NEVER be used as a "restart" trigger, for example: Docker's "HEALTHCHECK".
|
||||
// * If Gitea is upgrading and migrating database, there will be a long time before this endpoint starts to return "pass" status.
|
||||
// In this case, if the checker restarts Gitea just because it doesn't get "pass" status in short time,
|
||||
// the instance will just be restarted again and again before the migation finishes and the sitution just goes worse.
|
||||
func Check(w http.ResponseWriter, r *http.Request) {
|
||||
rsp := response{
|
||||
Status: pass,
|
||||
|
||||
@ -1530,7 +1530,7 @@ func registerWebRoutes(m *web.Router) {
|
||||
m.Group("/{username}/{reponame}", func() {
|
||||
m.Get("/{type:pulls}", repo.Issues)
|
||||
m.Group("/{type:pulls}/{index}", func() {
|
||||
m.Get("", repo.SetWhitespaceBehavior, repo.GetPullDiffStats, repo.ViewIssue)
|
||||
m.Get("", repo.SetEditorconfigIfExists, repo.SetWhitespaceBehavior, repo.GetPullDiffStats, repo.ViewIssue)
|
||||
m.Get(".diff", repo.DownloadPullDiff)
|
||||
m.Get(".patch", repo.DownloadPullPatch)
|
||||
m.Get("/merge_box", repo.ViewPullMergeBox)
|
||||
|
||||
@ -84,7 +84,11 @@ func GetCompareInfo(ctx context.Context, baseRepo, headRepo *repo_model.Reposito
|
||||
|
||||
// We have a common base - therefore we know that ... should work
|
||||
if !fileOnly {
|
||||
compareInfo.Commits, err = headGitRepo.ShowPrettyFormatLogToList(ctx, compareInfo.BaseCommitID+compareInfo.CompareSeparator+compareInfo.HeadCommitID)
|
||||
// In git log/rev-list, the "..." syntax represents the symmetric difference between two references,
|
||||
// which is different from the meaning of "..." in git diff (where it implies diffing from the merge base).
|
||||
// For listing PR commits, we must use merge-base..head to include only the commits introduced by the head branch.
|
||||
// Otherwise, commits newly pushed to the base branch would also be included, which is incorrect.
|
||||
compareInfo.Commits, err = headGitRepo.ShowPrettyFormatLogToList(ctx, compareInfo.MergeBase+".."+compareInfo.HeadCommitID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("ShowPrettyFormatLogToList: %w", err)
|
||||
}
|
||||
|
||||
@ -89,6 +89,24 @@ func issueAddTime(ctx context.Context, issue *issues_model.Issue, doer *user_mod
|
||||
return err
|
||||
}
|
||||
|
||||
// isSelfReference checks if a commit is the merge commit of the PR it references.
|
||||
// This prevents creating self-referencing timeline entries when a PR merge commit
|
||||
// contains a reference to its own PR number in the commit message.
|
||||
func isSelfReference(ctx context.Context, issue *issues_model.Issue, commitSHA string) bool {
|
||||
if !issue.IsPull {
|
||||
return false
|
||||
}
|
||||
|
||||
if err := issue.LoadPullRequest(ctx); err != nil {
|
||||
if !issues_model.IsErrPullRequestNotExist(err) {
|
||||
log.Error("LoadPullRequest: %v", err)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
return issue.PullRequest.MergedCommitID == commitSHA
|
||||
}
|
||||
|
||||
// getIssueFromRef returns the issue referenced by a ref. Returns a nil *Issue
|
||||
// if the provided ref references a non-existent issue.
|
||||
func getIssueFromRef(ctx context.Context, repo *repo_model.Repository, index int64) (*issues_model.Issue, error) {
|
||||
@ -158,6 +176,11 @@ func UpdateIssuesCommit(ctx context.Context, doer *user_model.User, repo *repo_m
|
||||
continue
|
||||
}
|
||||
|
||||
// Skip self-references: if this commit is the merge commit of the PR it references
|
||||
if isSelfReference(ctx, refIssue, c.Sha1) {
|
||||
continue
|
||||
}
|
||||
|
||||
message := fmt.Sprintf(`<a href="%s/commit/%s">%s</a>`, html.EscapeString(repo.Link()), html.EscapeString(url.PathEscape(c.Sha1)), html.EscapeString(strings.SplitN(c.Message, "\n", 2)[0]))
|
||||
if err = CreateRefComment(ctx, doer, refRepo, refIssue, message, c.Sha1); err != nil {
|
||||
if errors.Is(err, user_model.ErrBlockedUser) {
|
||||
|
||||
@ -298,3 +298,59 @@ func TestUpdateIssuesCommit_AnotherRepoNoPermission(t *testing.T) {
|
||||
unittest.AssertNotExistsBean(t, issueBean, "is_closed=1")
|
||||
unittest.CheckConsistencyFor(t, &activities_model.Action{})
|
||||
}
|
||||
|
||||
func TestUpdateIssuesCommit_SelfReference(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
|
||||
// Test that a PR merge commit that references its own PR does not create a self-reference comment
|
||||
// PR #2 (issue_id=2) has merged_commit_id: 1a8823cd1a9549fde083f992f6b9b87a7ab74fb3
|
||||
pushCommits := []*repository.PushCommit{
|
||||
{
|
||||
Sha1: "1a8823cd1a9549fde083f992f6b9b87a7ab74fb3",
|
||||
CommitterEmail: "user2@example.com",
|
||||
CommitterName: "User Two",
|
||||
AuthorEmail: "user2@example.com",
|
||||
AuthorName: "User Two",
|
||||
Message: "Merge pull request 'issue2' (#2) from branch1 into master",
|
||||
},
|
||||
}
|
||||
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
|
||||
selfRefCommentBean := &issues_model.Comment{
|
||||
Type: issues_model.CommentTypeCommitRef,
|
||||
CommitSHA: "1a8823cd1a9549fde083f992f6b9b87a7ab74fb3",
|
||||
PosterID: user.ID,
|
||||
IssueID: 2,
|
||||
}
|
||||
|
||||
unittest.AssertNotExistsBean(t, selfRefCommentBean)
|
||||
assert.NoError(t, UpdateIssuesCommit(t.Context(), user, repo, pushCommits, repo.DefaultBranch))
|
||||
unittest.AssertNotExistsBean(t, selfRefCommentBean)
|
||||
unittest.CheckConsistencyFor(t, &activities_model.Action{})
|
||||
|
||||
// Test that normal commit references are still created
|
||||
pushCommits2 := []*repository.PushCommit{
|
||||
{
|
||||
Sha1: "abcdef9876543210",
|
||||
CommitterEmail: "user2@example.com",
|
||||
CommitterName: "User Two",
|
||||
AuthorEmail: "user2@example.com",
|
||||
AuthorName: "User Two",
|
||||
Message: "Fix bug, refs #1",
|
||||
},
|
||||
}
|
||||
|
||||
otherRefCommentBean := &issues_model.Comment{
|
||||
Type: issues_model.CommentTypeCommitRef,
|
||||
CommitSHA: "abcdef9876543210",
|
||||
PosterID: user.ID,
|
||||
IssueID: 1,
|
||||
}
|
||||
|
||||
unittest.AssertNotExistsBean(t, otherRefCommentBean)
|
||||
assert.NoError(t, UpdateIssuesCommit(t.Context(), user, repo, pushCommits2, repo.DefaultBranch))
|
||||
unittest.AssertExistsAndLoadBean(t, otherRefCommentBean)
|
||||
unittest.CheckConsistencyFor(t, &activities_model.Action{})
|
||||
}
|
||||
|
||||
@ -17,10 +17,10 @@ import (
|
||||
)
|
||||
|
||||
func TestGiteaDownloadRepo(t *testing.T) {
|
||||
// Skip tests if Gitea token is not found
|
||||
giteaToken := os.Getenv("GITEA_TOKEN")
|
||||
// Skip tests if Gitea token is not found (TODO: this test seems stopped for long time because there is no token in CI secrets)
|
||||
giteaToken := os.Getenv("GITEA_TEST_OFFICIAL_SITE_TOKEN")
|
||||
if giteaToken == "" {
|
||||
t.Skip("skipped test because GITEA_TOKEN was not in the environment")
|
||||
t.Skip("skipped test because GITEA_TEST_OFFICIAL_SITE_TOKEN was not in the environment")
|
||||
}
|
||||
|
||||
resp, err := http.Get("https://gitea.com/gitea")
|
||||
|
||||
@ -56,6 +56,7 @@ func TestGetTreeBySHA(t *testing.T) {
|
||||
|
||||
func TestGetTreeViewNodes(t *testing.T) {
|
||||
unittest.PrepareTestEnv(t)
|
||||
|
||||
ctx, _ := contexttest.MockContext(t, "user2/repo1")
|
||||
ctx.Repo.RefFullName = git.RefNameFromBranch("sub-home-md-img-check")
|
||||
contexttest.LoadRepo(t, ctx, 1)
|
||||
@ -69,11 +70,13 @@ func TestGetTreeViewNodes(t *testing.T) {
|
||||
mockIconForFile := func(id string) template.HTML {
|
||||
return template.HTML(`<svg class="svg git-entry-icon octicon-file" width="16" height="16" aria-hidden="true"><use href="#` + id + `"></use></svg>`)
|
||||
}
|
||||
mockIconForFolder := func(id string) template.HTML {
|
||||
return template.HTML(`<svg class="svg git-entry-icon octicon-file-directory-fill" width="16" height="16" aria-hidden="true"><use href="#` + id + `"></use></svg>`)
|
||||
mockIconForFolder := func() template.HTML {
|
||||
// With basic theme (default for folders), we get octicon icons without IDs
|
||||
return template.HTML(`<span>octicon-file-directory-fill(16/)</span>`)
|
||||
}
|
||||
mockOpenIconForFolder := func(id string) template.HTML {
|
||||
return template.HTML(`<svg class="svg git-entry-icon octicon-file-directory-open-fill" width="16" height="16" aria-hidden="true"><use href="#` + id + `"></use></svg>`)
|
||||
mockOpenIconForFolder := func() template.HTML {
|
||||
// With basic theme (default for folders), we get octicon icons without IDs
|
||||
return template.HTML(`<span>octicon-file-directory-open-fill(16/)</span>`)
|
||||
}
|
||||
treeNodes, err := GetTreeViewNodes(ctx, curRepoLink, renderedIconPool, ctx.Repo.Commit, "", "")
|
||||
assert.NoError(t, err)
|
||||
@ -82,8 +85,8 @@ func TestGetTreeViewNodes(t *testing.T) {
|
||||
EntryName: "docs",
|
||||
EntryMode: "tree",
|
||||
FullPath: "docs",
|
||||
EntryIcon: mockIconForFolder(`svg-mfi-folder-docs`),
|
||||
EntryIconOpen: mockOpenIconForFolder(`svg-mfi-folder-docs`),
|
||||
EntryIcon: mockIconForFolder(),
|
||||
EntryIconOpen: mockOpenIconForFolder(),
|
||||
},
|
||||
}, treeNodes)
|
||||
|
||||
@ -94,8 +97,8 @@ func TestGetTreeViewNodes(t *testing.T) {
|
||||
EntryName: "docs",
|
||||
EntryMode: "tree",
|
||||
FullPath: "docs",
|
||||
EntryIcon: mockIconForFolder(`svg-mfi-folder-docs`),
|
||||
EntryIconOpen: mockOpenIconForFolder(`svg-mfi-folder-docs`),
|
||||
EntryIcon: mockIconForFolder(),
|
||||
EntryIconOpen: mockOpenIconForFolder(),
|
||||
Children: []*TreeViewNode{
|
||||
{
|
||||
EntryName: "README.md",
|
||||
|
||||
@ -94,7 +94,7 @@ func TestE2e(t *testing.T) {
|
||||
onGiteaRun(t, func(*testing.T, *url.URL) {
|
||||
cmd := exec.Command(runArgs[0], runArgs...)
|
||||
cmd.Env = os.Environ()
|
||||
cmd.Env = append(cmd.Env, "GITEA_URL="+setting.AppURL)
|
||||
cmd.Env = append(cmd.Env, "GITEA_TEST_SERVER_URL="+setting.AppURL)
|
||||
|
||||
var stdout, stderr bytes.Buffer
|
||||
cmd.Stdout = &stdout
|
||||
|
||||
@ -25,7 +25,6 @@ import (
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/test"
|
||||
"code.gitea.io/gitea/modules/testlogger"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"github.com/stretchr/testify/assert"
|
||||
@ -37,20 +36,7 @@ var currentEngine *xorm.Engine
|
||||
|
||||
func initMigrationTest(t *testing.T) func() {
|
||||
testlogger.Init()
|
||||
giteaRoot := test.SetupGiteaRoot()
|
||||
setting.AppPath = filepath.Join(giteaRoot, "gitea")
|
||||
if _, err := os.Stat(setting.AppPath); err != nil {
|
||||
testlogger.Fatalf(fmt.Sprintf("Could not find gitea binary at %s\n", setting.AppPath))
|
||||
}
|
||||
|
||||
giteaConf := os.Getenv("GITEA_CONF")
|
||||
if giteaConf == "" {
|
||||
testlogger.Fatalf("Environment variable $GITEA_CONF not set\n")
|
||||
} else if !path.IsAbs(giteaConf) {
|
||||
setting.CustomConf = filepath.Join(giteaRoot, giteaConf)
|
||||
} else {
|
||||
setting.CustomConf = giteaConf
|
||||
}
|
||||
setting.SetupGiteaTestEnv()
|
||||
|
||||
unittest.InitSettingsForTesting()
|
||||
|
||||
|
||||
@ -6,7 +6,6 @@ package tests
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
@ -18,7 +17,6 @@ import (
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/storage"
|
||||
"code.gitea.io/gitea/modules/test"
|
||||
"code.gitea.io/gitea/modules/testlogger"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/routers"
|
||||
@ -29,40 +27,7 @@ import (
|
||||
func InitTest(requireGitea bool) {
|
||||
testlogger.Init()
|
||||
|
||||
giteaRoot := test.SetupGiteaRoot()
|
||||
|
||||
// TODO: Speedup tests that rely on the event source ticker, confirm whether there is any bug or failure.
|
||||
// setting.UI.Notification.EventSourceUpdateTime = time.Second
|
||||
|
||||
setting.AppWorkPath = giteaRoot
|
||||
setting.CustomPath = filepath.Join(setting.AppWorkPath, "custom")
|
||||
if requireGitea {
|
||||
giteaBinary := "gitea"
|
||||
if setting.IsWindows {
|
||||
giteaBinary += ".exe"
|
||||
}
|
||||
setting.AppPath = filepath.Join(giteaRoot, giteaBinary)
|
||||
if _, err := os.Stat(setting.AppPath); err != nil {
|
||||
testlogger.Fatalf("Could not find gitea binary at %s\n", setting.AppPath)
|
||||
}
|
||||
}
|
||||
giteaConf := os.Getenv("GITEA_CONF")
|
||||
if giteaConf == "" {
|
||||
// By default, use sqlite.ini for testing, then IDE like GoLand can start the test process with debugger.
|
||||
// It's easier for developers to debug bugs step by step with a debugger.
|
||||
// Notice: when doing "ssh push", Gitea executes sub processes, debugger won't work for the sub processes.
|
||||
giteaConf = "tests/sqlite.ini"
|
||||
_ = os.Setenv("GITEA_CONF", giteaConf)
|
||||
_, _ = fmt.Fprintf(os.Stderr, "Environment variable $GITEA_CONF not set - defaulting to %s\n", giteaConf)
|
||||
if !setting.EnableSQLite3 {
|
||||
testlogger.Fatalf(`sqlite3 requires: -tags sqlite,sqlite_unlock_notify` + "\n")
|
||||
}
|
||||
}
|
||||
if !filepath.IsAbs(giteaConf) {
|
||||
setting.CustomConf = filepath.Join(giteaRoot, giteaConf)
|
||||
} else {
|
||||
setting.CustomConf = giteaConf
|
||||
}
|
||||
setting.SetupGiteaTestEnv()
|
||||
|
||||
unittest.InitSettingsForTesting()
|
||||
setting.Repository.DefaultBranch = "master" // many test code still assume that default branch is called "master"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user