diff --git a/.github/workflows/pull-db-tests.yml b/.github/workflows/pull-db-tests.yml index 66f48d5af8..d168c2ecc5 100644 --- a/.github/workflows/pull-db-tests.yml +++ b/.github/workflows/pull-db-tests.yml @@ -63,7 +63,6 @@ jobs: RACE_ENABLED: true TEST_TAGS: gogit TEST_LDAP: 1 - USE_REPO_TEST_DIR: 1 test-sqlite: if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true' @@ -90,7 +89,6 @@ jobs: TAGS: bindata gogit sqlite sqlite_unlock_notify RACE_ENABLED: true TEST_TAGS: gogit sqlite sqlite_unlock_notify - USE_REPO_TEST_DIR: 1 test-unit: if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true' @@ -206,7 +204,6 @@ jobs: env: TAGS: bindata RACE_ENABLED: true - USE_REPO_TEST_DIR: 1 TEST_INDEXER_CODE_ES_URL: "http://elastic:changeme@elasticsearch:9200" test-mssql: @@ -246,4 +243,3 @@ jobs: timeout-minutes: 50 env: TAGS: bindata - USE_REPO_TEST_DIR: 1 diff --git a/Makefile b/Makefile index 6b16780eb1..3c7582dd57 100644 --- a/Makefile +++ b/Makefile @@ -1,22 +1,5 @@ -ifeq ($(USE_REPO_TEST_DIR),1) - -# This rule replaces the whole Makefile when we're trying to use /tmp repository temporary files -location = $(CURDIR)/$(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST)) -self := $(location) - -%: - @tmpdir=`mktemp --tmpdir -d` ; \ - echo Using temporary directory $$tmpdir for test repositories ; \ - USE_REPO_TEST_DIR= $(MAKE) -f $(self) --no-print-directory REPO_TEST_DIR=$$tmpdir/ $@ ; \ - STATUS=$$? ; rm -r "$$tmpdir" ; exit $$STATUS - -else - -# This is the "normal" part of the Makefile - DIST := dist DIST_DIRS := $(DIST)/binaries $(DIST)/release -IMPORT := code.gitea.io/gitea # By default use go's 1.25 experimental json v2 library when building # TODO: remove when no longer experimental @@ -83,7 +66,6 @@ endif EXTRA_GOFLAGS ?= -MAKE_VERSION := $(shell "$(MAKE)" -v | cat | head -n 1) MAKE_EVIDENCE_DIR := .make_evidence GOTESTFLAGS ?= @@ -129,7 +111,7 @@ ifeq ($(VERSION),main) VERSION := main-nightly endif -LDFLAGS := $(LDFLAGS) -X "main.MakeVersion=$(MAKE_VERSION)" -X "main.Version=$(GITEA_VERSION)" -X "main.Tags=$(TAGS)" +LDFLAGS := $(LDFLAGS) -X "main.Version=$(GITEA_VERSION)" -X "main.Tags=$(TAGS)" LINUX_ARCHS ?= linux/amd64,linux/386,linux/arm-5,linux/arm-6,linux/arm64,linux/riscv64 @@ -227,7 +209,7 @@ clean: ## delete backend and integration files e2e*.test \ tests/integration/gitea-integration-* \ tests/integration/indexers-* \ - tests/mysql.ini tests/pgsql.ini tests/mssql.ini man/ \ + tests/sqlite.ini tests/mysql.ini tests/pgsql.ini tests/mssql.ini man/ \ tests/e2e/gitea-e2e-*/ \ tests/e2e/indexers-*/ \ tests/e2e/reports/ tests/e2e/test-artifacts/ tests/e2e/test-snapshots/ @@ -474,9 +456,8 @@ $(GO_LICENSE_FILE): go.mod go.sum GO=$(GO) $(GO) run build/generate-go-licenses.go $(GO_LICENSE_FILE) generate-ini-sqlite: - sed -e 's|{{REPO_TEST_DIR}}|${REPO_TEST_DIR}|g' \ + sed -e 's|{{WORK_PATH}}|$(CURDIR)/tests/$(or $(TEST_TYPE),integration)/gitea-$(or $(TEST_TYPE),integration)-sqlite|g' \ -e 's|{{TEST_LOGGER}}|$(or $(TEST_LOGGER),test$(COMMA)file)|g' \ - -e 's|{{TEST_TYPE}}|$(or $(TEST_TYPE),integration)|g' \ tests/sqlite.ini.tmpl > tests/sqlite.ini .PHONY: test-sqlite @@ -495,9 +476,8 @@ generate-ini-mysql: -e 's|{{TEST_MYSQL_DBNAME}}|${TEST_MYSQL_DBNAME}|g' \ -e 's|{{TEST_MYSQL_USERNAME}}|${TEST_MYSQL_USERNAME}|g' \ -e 's|{{TEST_MYSQL_PASSWORD}}|${TEST_MYSQL_PASSWORD}|g' \ - -e 's|{{REPO_TEST_DIR}}|${REPO_TEST_DIR}|g' \ + -e 's|{{WORK_PATH}}|$(CURDIR)/tests/$(or $(TEST_TYPE),integration)/gitea-$(or $(TEST_TYPE),integration)-mysql|g' \ -e 's|{{TEST_LOGGER}}|$(or $(TEST_LOGGER),test$(COMMA)file)|g' \ - -e 's|{{TEST_TYPE}}|$(or $(TEST_TYPE),integration)|g' \ tests/mysql.ini.tmpl > tests/mysql.ini .PHONY: test-mysql @@ -518,9 +498,8 @@ generate-ini-pgsql: -e 's|{{TEST_PGSQL_PASSWORD}}|${TEST_PGSQL_PASSWORD}|g' \ -e 's|{{TEST_PGSQL_SCHEMA}}|${TEST_PGSQL_SCHEMA}|g' \ -e 's|{{TEST_MINIO_ENDPOINT}}|${TEST_MINIO_ENDPOINT}|g' \ - -e 's|{{REPO_TEST_DIR}}|${REPO_TEST_DIR}|g' \ + -e 's|{{WORK_PATH}}|$(CURDIR)/tests/$(or $(TEST_TYPE),integration)/gitea-$(or $(TEST_TYPE),integration)-pgsql|g' \ -e 's|{{TEST_LOGGER}}|$(or $(TEST_LOGGER),test$(COMMA)file)|g' \ - -e 's|{{TEST_TYPE}}|$(or $(TEST_TYPE),integration)|g' \ tests/pgsql.ini.tmpl > tests/pgsql.ini .PHONY: test-pgsql @@ -539,9 +518,8 @@ generate-ini-mssql: -e 's|{{TEST_MSSQL_DBNAME}}|${TEST_MSSQL_DBNAME}|g' \ -e 's|{{TEST_MSSQL_USERNAME}}|${TEST_MSSQL_USERNAME}|g' \ -e 's|{{TEST_MSSQL_PASSWORD}}|${TEST_MSSQL_PASSWORD}|g' \ - -e 's|{{REPO_TEST_DIR}}|${REPO_TEST_DIR}|g' \ + -e 's|{{WORK_PATH}}|$(CURDIR)/tests/$(or $(TEST_TYPE),integration)/gitea-$(or $(TEST_TYPE),integration)-mssql|g' \ -e 's|{{TEST_LOGGER}}|$(or $(TEST_LOGGER),test$(COMMA)file)|g' \ - -e 's|{{TEST_TYPE}}|$(or $(TEST_TYPE),integration)|g' \ tests/mssql.ini.tmpl > tests/mssql.ini .PHONY: test-mssql @@ -662,7 +640,7 @@ migrations.sqlite.test: $(GO_SOURCES) generate-ini-sqlite GITEA_TEST_CONF=tests/sqlite.ini ./migrations.sqlite.test .PHONY: migrations.individual.mysql.test -migrations.individual.mysql.test: $(GO_SOURCES) +migrations.individual.mysql.test: $(GO_SOURCES) generate-ini-mysql GITEA_TEST_CONF=tests/mysql.ini $(GO) test $(GOTESTFLAGS) -tags='$(TEST_TAGS)' -p 1 $(MIGRATE_TEST_PACKAGES) .PHONY: migrations.individual.sqlite.test\#% @@ -670,7 +648,7 @@ migrations.individual.sqlite.test\#%: $(GO_SOURCES) generate-ini-sqlite 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) +migrations.individual.pgsql.test: $(GO_SOURCES) generate-ini-pgsql GITEA_TEST_CONF=tests/pgsql.ini $(GO) test $(GOTESTFLAGS) -tags='$(TEST_TAGS)' -p 1 $(MIGRATE_TEST_PACKAGES) .PHONY: migrations.individual.pgsql.test\#% @@ -735,7 +713,7 @@ generate-go: $(TAGS_PREREQ) .PHONY: security-check security-check: - GOEXPERIMENT= go run $(GOVULNCHECK_PACKAGE) -show color ./... + GOEXPERIMENT= go run $(GOVULNCHECK_PACKAGE) -show color ./... || true $(EXECUTABLE): $(GO_SOURCES) $(TAGS_PREREQ) ifneq ($(and $(STATIC),$(findstring pam,$(TAGS))),) @@ -901,9 +879,6 @@ docker: docker build --disable-content-trust=false -t $(DOCKER_REF) . # support also build args docker build --build-arg GITEA_VERSION=v1.2.3 --build-arg TAGS="bindata sqlite sqlite_unlock_notify" . -# This endif closes the if at the top of the file -endif - # Disable parallel execution because it would break some targets that don't # specify exact dependencies like 'backend' which does currently not depend # on 'frontend' to enable Node.js-less builds from source tarballs. diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 084c66aab0..c7f8401cd9 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -2858,6 +2858,9 @@ LEVEL = Info ;ABANDONED_JOB_TIMEOUT = 24h ;; Strings committers can place inside a commit message or PR title to skip executing the corresponding actions workflow ;SKIP_WORKFLOW_STRINGS = [skip ci],[ci skip],[no ci],[skip actions],[actions skip] +;; Comma-separated list of workflow directories, the first one to exist +;; in a repo is used to find Actions workflow files +;WORKFLOW_DIRS = .gitea/workflows,.github/workflows ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/flake.lock b/flake.lock index 4cbc85b87a..a608aa3b89 100644 --- a/flake.lock +++ b/flake.lock @@ -2,11 +2,11 @@ "nodes": { "nixpkgs": { "locked": { - "lastModified": 1760038930, - "narHash": "sha256-Oncbh0UmHjSlxO7ErQDM3KM0A5/Znfofj2BSzlHLeVw=", + "lastModified": 1771369470, + "narHash": "sha256-0NBlEBKkN3lufyvFegY4TYv5mCNHbi5OmBDrzihbBMQ=", "owner": "nixos", "repo": "nixpkgs", - "rev": "0b4defa2584313f3b781240b29d61f6f9f7e0df3", + "rev": "0182a361324364ae3f436a63005877674cf45efb", "type": "github" }, "original": { diff --git a/go.mod b/go.mod index f784ac2581..b7a3af6a3f 100644 --- a/go.mod +++ b/go.mod @@ -53,7 +53,7 @@ require ( github.com/go-co-op/gocron v1.37.0 github.com/go-enry/go-enry/v2 v2.9.4 github.com/go-git/go-billy/v5 v5.7.0 - github.com/go-git/go-git/v5 v5.16.4 + github.com/go-git/go-git/v5 v5.16.5 github.com/go-ldap/ldap/v3 v3.4.12 github.com/go-redsync/redsync/v4 v4.15.0 github.com/go-sql-driver/mysql v1.9.3 diff --git a/go.sum b/go.sum index b10e259c91..1a6decc18b 100644 --- a/go.sum +++ b/go.sum @@ -332,8 +332,8 @@ github.com/go-git/go-billy/v5 v5.7.0 h1:83lBUJhGWhYp0ngzCMSgllhUSuoHP1iEWYjsPl9n github.com/go-git/go-billy/v5 v5.7.0/go.mod h1:/1IUejTKH8xipsAcdfcSAlUlo2J7lkYV8GTKxAT/L3E= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII= -github.com/go-git/go-git/v5 v5.16.4 h1:7ajIEZHZJULcyJebDLo99bGgS0jRrOxzZG4uCk2Yb2Y= -github.com/go-git/go-git/v5 v5.16.4/go.mod h1:4Ge4alE/5gPs30F2H1esi2gPd69R0C39lolkucHBOp8= +github.com/go-git/go-git/v5 v5.16.5 h1:mdkuqblwr57kVfXri5TTH+nMFLNUxIj9Z7F5ykFbw5s= +github.com/go-git/go-git/v5 v5.16.5/go.mod h1:QOMLpNf1qxuSY4StA/ArOdfFR2TrKEjJiye2kel2m+M= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A= diff --git a/main.go b/main.go index bc2121b1e7..fcfbb73371 100644 --- a/main.go +++ b/main.go @@ -26,9 +26,8 @@ import ( // these flags will be set by the build flags var ( - Version = "development" // program version for this build - Tags = "" // the Golang build tags - MakeVersion = "" // "make" program version if built with make + Version = "development" // program version for this build + Tags = "" // the Golang build tags ) func init() { @@ -50,9 +49,6 @@ func main() { func formatBuiltWith() string { version := runtime.Version() - if len(MakeVersion) > 0 { - version = MakeVersion + ", " + runtime.Version() - } if len(Tags) == 0 { return " built with " + version } diff --git a/models/actions/run.go b/models/actions/run.go index be332d6857..99e6267071 100644 --- a/models/actions/run.go +++ b/models/actions/run.go @@ -168,7 +168,7 @@ func (run *ActionRun) GetPushEventPayload() (*api.PushPayload, error) { } func (run *ActionRun) GetPullRequestEventPayload() (*api.PullRequestPayload, error) { - if run.Event.IsPullRequest() { + if run.Event.IsPullRequest() || run.Event.IsPullRequestReview() { var payload api.PullRequestPayload if err := json.Unmarshal([]byte(run.EventPayload), &payload); err != nil { return nil, err diff --git a/models/migrations/base/tests.go b/models/migrations/base/tests.go index 36afd35dd4..17ea951b5a 100644 --- a/models/migrations/base/tests.go +++ b/models/migrations/base/tests.go @@ -10,7 +10,6 @@ import ( "path" "path/filepath" "testing" - "time" "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/unittest" @@ -27,18 +26,6 @@ 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 @@ -213,13 +200,12 @@ func LoadTableSchemasMap(t *testing.T, x *xorm.Engine) map[string]*schemas.Table return tableMap } -func MainTest(m *testing.M) { +func mainTest(m *testing.M) int { testlogger.Init() - setting.SetupGiteaTestEnv() tmpDataPath, cleanup, err := tempdir.OsTempDir("gitea-test").MkdirTempRandom("data") if err != nil { - testlogger.Fatalf("Unable to create temporary data path %v\n", err) + testlogger.Panicf("Unable to create temporary data path %v\n", err) } defer cleanup() @@ -227,15 +213,13 @@ func MainTest(m *testing.M) { unittest.InitSettingsForTesting() if err = git.InitFull(); err != nil { - testlogger.Fatalf("Unable to InitFull: %v\n", err) + testlogger.Panicf("Unable to InitFull: %v\n", err) } setting.LoadDBSetting() setting.InitLoggersForTest() - - exitStatus := m.Run() - - if err := removeAllWithRetry(setting.RepoRootPath); err != nil { - _, _ = fmt.Fprintf(os.Stderr, "os.RemoveAll: %v\n", err) - } - os.Exit(exitStatus) + return m.Run() +} + +func MainTest(m *testing.M) { + os.Exit(mainTest(m)) } diff --git a/models/unittest/fixtures_test.go b/models/unittest/fixtures_test.go index 879277c9b1..72944ec0db 100644 --- a/models/unittest/fixtures_test.go +++ b/models/unittest/fixtures_test.go @@ -4,6 +4,7 @@ package unittest_test import ( + "os" "path/filepath" "testing" @@ -58,9 +59,14 @@ func NewFixturesLoaderVendorGoTestfixtures(e *xorm.Engine, opts unittest.Fixture } */ +func TestMain(m *testing.M) { + setting.SetupGiteaTestEnv() + os.Exit(m.Run()) +} + func prepareTestFixturesLoaders(t testing.TB) unittest.FixturesOptions { _ = user_model.User{} - giteaRoot := setting.SetupGiteaTestEnv() + giteaRoot := setting.GetGiteaTestSourceRoot() opts := unittest.FixturesOptions{Dir: filepath.Join(giteaRoot, "models", "fixtures"), Files: []string{ "user.yml", }} diff --git a/models/unittest/fscopy.go b/models/unittest/fscopy.go index 98b01815bd..cddb7a3f77 100644 --- a/models/unittest/fscopy.go +++ b/models/unittest/fscopy.go @@ -4,10 +4,12 @@ package unittest import ( + "errors" "os" "path/filepath" "strings" + "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" ) @@ -39,7 +41,20 @@ func SyncFile(srcPath, destPath string) error { // SyncDirs synchronizes files recursively from source to target directory. // It returns error when error occurs in underlying functions. func SyncDirs(srcPath, destPath string) error { - err := os.MkdirAll(destPath, os.ModePerm) + destPath = filepath.Clean(destPath) + destPathAbs, err := filepath.Abs(destPath) + if err != nil { + return err + } + devDataPathAbs, err := filepath.Abs(filepath.Join(setting.GetGiteaTestSourceRoot(), "data")) + if err != nil { + return err + } + if strings.HasPrefix(destPathAbs+string(filepath.Separator), devDataPathAbs+string(filepath.Separator)) { + return errors.New("destination path should not be inside Gitea data directory, otherwise your data for dev mode will be removed") + } + + err = os.MkdirAll(destPath, os.ModePerm) if err != nil { return err } diff --git a/models/unittest/testdb.go b/models/unittest/testdb.go index 398090760e..63c9a3a999 100644 --- a/models/unittest/testdb.go +++ b/models/unittest/testdb.go @@ -21,6 +21,7 @@ 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/testlogger" "code.gitea.io/gitea/modules/util" "github.com/stretchr/testify/assert" @@ -28,16 +29,10 @@ import ( "xorm.io/xorm/names" ) -var giteaRoot string - -func fatalTestError(fmtStr string, args ...any) { - _, _ = fmt.Fprintf(os.Stderr, fmtStr, args...) - os.Exit(1) -} - // InitSettingsForTesting initializes config provider and load common settings for tests func InitSettingsForTesting() { - setting.IsInTesting = true + setting.SetupGiteaTestEnv() + log.OsExiter = func(code int) { if code != 0 { // non-zero exit code (log.Fatal) shouldn't occur during testing, if it happens, show a full stacktrace for more details @@ -49,8 +44,12 @@ func InitSettingsForTesting() { setting.CustomConf = filepath.Join(setting.CustomPath, "conf/app-unittest-tmp.ini") _ = os.Remove(setting.CustomConf) } - setting.InitCfgProvider(setting.CustomConf) - setting.LoadCommonSettings() + + // init paths and config system for testing + getTestEnv := func(key string) string { + return "" + } + setting.InitWorkPathAndCommonConfig(getTestEnv, setting.ArgWorkPathAndCustomConf{CustomConf: setting.CustomConf}) if err := setting.PrepareAppDataPath(); err != nil { log.Fatal("Can not prepare APP_DATA_PATH: %v", err) @@ -71,16 +70,18 @@ type TestOptions struct { // MainTest a reusable TestMain(..) function for unit tests that need to use a // test database. Creates the test database, and sets necessary settings. func MainTest(m *testing.M, testOptsArg ...*TestOptions) { - testOpts := util.OptionalArg(testOptsArg, &TestOptions{}) - giteaRoot = setting.SetupGiteaTestEnv() - InitSettingsForTesting() + os.Exit(mainTest(m, testOptsArg...)) +} +func mainTest(m *testing.M, testOptsArg ...*TestOptions) int { + testOpts := util.OptionalArg(testOptsArg, &TestOptions{}) + InitSettingsForTesting() + giteaRoot := setting.GetGiteaTestSourceRoot() fixturesOpts := FixturesOptions{Dir: filepath.Join(giteaRoot, "models", "fixtures"), Files: testOpts.FixtureFiles} if err := CreateTestEngine(fixturesOpts); err != nil { - fatalTestError("Error creating test engine: %v\n", err) + testlogger.Panicf("Error creating test engine: %v\n", err) } - setting.IsInTesting = true setting.AppURL = "https://try.gitea.io/" setting.Domain = "try.gitea.io" setting.RunUser = "runuser" @@ -92,20 +93,18 @@ func MainTest(m *testing.M, testOptsArg ...*TestOptions) { setting.Repository.DefaultBranch = "master" // many test code still assume that default branch is called "master" repoRootPath, cleanup1, err := tempdir.OsTempDir("gitea-test").MkdirTempRandom("repos") if err != nil { - fatalTestError("TempDir: %v\n", err) + testlogger.Panicf("TempDir: %v\n", err) } defer cleanup1() setting.RepoRootPath = repoRootPath appDataPath, cleanup2, err := tempdir.OsTempDir("gitea-test").MkdirTempRandom("appdata") if err != nil { - fatalTestError("TempDir: %v\n", err) + testlogger.Panicf("TempDir: %v\n", err) } defer cleanup2() setting.AppDataPath = appDataPath - setting.AppWorkPath = giteaRoot - setting.StaticRootPath = giteaRoot setting.GravatarSource = "https://secure.gravatar.com/avatar/" setting.Attachment.Storage.Path = filepath.Join(setting.AppDataPath, "attachments") @@ -129,22 +128,22 @@ func MainTest(m *testing.M, testOptsArg ...*TestOptions) { config.SetDynGetter(system.NewDatabaseDynKeyGetter()) if err = cache.Init(); err != nil { - fatalTestError("cache.Init: %v\n", err) + testlogger.Panicf("cache.Init: %v\n", err) } if err = storage.Init(); err != nil { - fatalTestError("storage.Init: %v\n", err) + testlogger.Panicf("storage.Init: %v\n", err) } if err = SyncDirs(filepath.Join(giteaRoot, "tests", "gitea-repositories-meta"), setting.RepoRootPath); err != nil { - fatalTestError("util.SyncDirs: %v\n", err) + testlogger.Panicf("util.SyncDirs: %v\n", err) } if err = git.InitFull(); err != nil { - fatalTestError("git.Init: %v\n", err) + testlogger.Panicf("git.Init: %v\n", err) } if testOpts.SetUp != nil { if err := testOpts.SetUp(); err != nil { - fatalTestError("set up failed: %v\n", err) + testlogger.Panicf("set up failed: %v\n", err) } } @@ -152,10 +151,10 @@ func MainTest(m *testing.M, testOptsArg ...*TestOptions) { if testOpts.TearDown != nil { if err := testOpts.TearDown(); err != nil { - fatalTestError("tear down failed: %v\n", err) + testlogger.Panicf("tear down failed: %v\n", err) } } - os.Exit(exitStatus) + return exitStatus } // FixturesOptions fixtures needs to be loaded options @@ -196,7 +195,6 @@ func PrepareTestDatabase() error { // by tests that use the above MainTest(..) function. func PrepareTestEnv(t testing.TB) { assert.NoError(t, PrepareTestDatabase()) - metaPath := filepath.Join(giteaRoot, "tests", "gitea-repositories-meta") + metaPath := filepath.Join(setting.GetGiteaTestSourceRoot(), "tests", "gitea-repositories-meta") assert.NoError(t, SyncDirs(metaPath, setting.RepoRootPath)) - setting.SetupGiteaTestEnv() } diff --git a/modules/actions/workflows.go b/modules/actions/workflows.go index 26a6ebc370..72892f4124 100644 --- a/modules/actions/workflows.go +++ b/modules/actions/workflows.go @@ -11,6 +11,7 @@ import ( "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/glob" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" webhook_module "code.gitea.io/gitea/modules/webhook" @@ -41,22 +42,30 @@ func IsWorkflow(path string) bool { return false } - return strings.HasPrefix(path, ".gitea/workflows") || strings.HasPrefix(path, ".github/workflows") + for _, workflowDir := range setting.Actions.WorkflowDirs { + if strings.HasPrefix(path, workflowDir+"/") { + return true + } + } + return false } func ListWorkflows(commit *git.Commit) (string, git.Entries, error) { - rpath := ".gitea/workflows" - tree, err := commit.SubTree(rpath) - if _, ok := err.(git.ErrNotExist); ok { - rpath = ".github/workflows" - tree, err = commit.SubTree(rpath) + var tree *git.Tree + var err error + var workflowDir string + for _, workflowDir = range setting.Actions.WorkflowDirs { + tree, err = commit.SubTree(workflowDir) + if err == nil { + break + } + if !git.IsErrNotExist(err) { + return "", nil, err + } } - if _, ok := err.(git.ErrNotExist); ok { + if tree == nil { return "", nil, nil } - if err != nil { - return "", nil, err - } entries, err := tree.ListEntriesRecursiveFast() if err != nil { @@ -69,7 +78,7 @@ func ListWorkflows(commit *git.Commit) (string, git.Entries, error) { ret = append(ret, entry) } } - return rpath, ret, nil + return workflowDir, ret, nil } func GetContentFromEntry(entry *git.TreeEntry) ([]byte, error) { diff --git a/modules/actions/workflows_test.go b/modules/actions/workflows_test.go index 89620fb698..77a65aae49 100644 --- a/modules/actions/workflows_test.go +++ b/modules/actions/workflows_test.go @@ -7,12 +7,83 @@ import ( "testing" "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" webhook_module "code.gitea.io/gitea/modules/webhook" "github.com/stretchr/testify/assert" ) +func TestIsWorkflow(t *testing.T) { + oldDirs := setting.Actions.WorkflowDirs + defer func() { + setting.Actions.WorkflowDirs = oldDirs + }() + + tests := []struct { + name string + dirs []string + path string + expected bool + }{ + { + name: "default with yml extension", + dirs: []string{".gitea/workflows", ".github/workflows"}, + path: ".gitea/workflows/test.yml", + expected: true, + }, + { + name: "default with yaml extension", + dirs: []string{".gitea/workflows", ".github/workflows"}, + path: ".github/workflows/test.yaml", + expected: true, + }, + { + name: "only gitea configured, github path rejected", + dirs: []string{".gitea/workflows"}, + path: ".github/workflows/test.yml", + expected: false, + }, + { + name: "only github configured, gitea path rejected", + dirs: []string{".github/workflows"}, + path: ".gitea/workflows/test.yml", + expected: false, + }, + { + name: "custom workflow dir", + dirs: []string{".custom/workflows"}, + path: ".custom/workflows/deploy.yml", + expected: true, + }, + { + name: "non-workflow file", + dirs: []string{".gitea/workflows", ".github/workflows"}, + path: ".gitea/workflows/readme.md", + expected: false, + }, + { + name: "directory boundary", + dirs: []string{".gitea/workflows"}, + path: ".gitea/workflows2/test.yml", + expected: false, + }, + { + name: "unrelated path", + dirs: []string{".gitea/workflows", ".github/workflows"}, + path: "src/main.go", + expected: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + setting.Actions.WorkflowDirs = tt.dirs + assert.Equal(t, tt.expected, IsWorkflow(tt.path)) + }) + } +} + func TestDetectMatched(t *testing.T) { testCases := []struct { desc string diff --git a/modules/git/git.go b/modules/git/git.go index 932da1989b..2df83f9843 100644 --- a/modules/git/git.go +++ b/modules/git/git.go @@ -17,6 +17,7 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/tempdir" + "code.gitea.io/gitea/modules/testlogger" "github.com/hashicorp/go-version" ) @@ -185,21 +186,19 @@ func InitFull() (err error) { // RunGitTests helps to init the git module and run tests. // FIXME: GIT-PACKAGE-DEPENDENCY: the dependency is not right, setting.Git.HomePath is initialized in this package but used in gitcmd package func RunGitTests(m interface{ Run() int }) { - fatalf := func(exitCode int, format string, args ...any) { - _, _ = fmt.Fprintf(os.Stderr, format, args...) - os.Exit(exitCode) - } + os.Exit(runGitTests(m)) +} + +func runGitTests(m interface{ Run() int }) int { gitHomePath, cleanup, err := tempdir.OsTempDir("gitea-test").MkdirTempRandom("git-home") if err != nil { - fatalf(1, "unable to create temp dir: %s", err.Error()) + testlogger.Panicf("unable to create temp dir: %s", err.Error()) } defer cleanup() setting.Git.HomePath = gitHomePath if err = InitFull(); err != nil { - fatalf(1, "failed to call Init: %s", err.Error()) - } - if exitCode := m.Run(); exitCode != 0 { - fatalf(exitCode, "run test failed, ExitCode=%d", exitCode) + testlogger.Panicf("failed to call Init: %s", err.Error()) } + return m.Run() } diff --git a/modules/git/gitcmd/command_test.go b/modules/git/gitcmd/command_test.go index 86771f499f..662356bc3f 100644 --- a/modules/git/gitcmd/command_test.go +++ b/modules/git/gitcmd/command_test.go @@ -12,23 +12,27 @@ import ( "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/tempdir" + "code.gitea.io/gitea/modules/testlogger" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) -func TestMain(m *testing.M) { +func testMain(m *testing.M) int { // FIXME: GIT-PACKAGE-DEPENDENCY: the dependency is not right. // "setting.Git.HomePath" is initialized in "git" package but really used in "gitcmd" package gitHomePath, cleanup, err := tempdir.OsTempDir("gitea-test").MkdirTempRandom("git-home") if err != nil { - _, _ = fmt.Fprintf(os.Stderr, "unable to create temp dir: %v", err) - os.Exit(1) + testlogger.Panicf("failed to create temp dir: %v", err) } defer cleanup() setting.Git.HomePath = gitHomePath - os.Exit(m.Run()) + return m.Run() +} + +func TestMain(m *testing.M) { + os.Exit(testMain(m)) } func TestRunWithContextStd(t *testing.T) { diff --git a/modules/gitrepo/main_test.go b/modules/gitrepo/main_test.go index e47eda7bc9..08afdffcc6 100644 --- a/modules/gitrepo/main_test.go +++ b/modules/gitrepo/main_test.go @@ -13,12 +13,13 @@ import ( func TestMain(m *testing.M) { // resolve repository path relative to the test directory - testRootDir := setting.SetupGiteaTestEnv() + setting.SetupGiteaTestEnv() + giteaRoot := setting.GetGiteaTestSourceRoot() repoPath = func(repo Repository) string { if filepath.IsAbs(repo.RelativePath()) { return repo.RelativePath() // for testing purpose only } - return filepath.Join(testRootDir, "modules/git/tests/repos", repo.RelativePath()) + return filepath.Join(giteaRoot, "modules/git/tests/repos", repo.RelativePath()) } git.RunGitTests(m) } diff --git a/modules/hcaptcha/hcaptcha_test.go b/modules/hcaptcha/hcaptcha_test.go index 5906faf17c..6b207bfb77 100644 --- a/modules/hcaptcha/hcaptcha_test.go +++ b/modules/hcaptcha/hcaptcha_test.go @@ -8,7 +8,6 @@ import ( "io" "net/http" "net/url" - "os" "strings" "testing" "time" @@ -20,10 +19,6 @@ const ( dummyToken = "10000000-aaaa-bbbb-cccc-000000000001" ) -func TestMain(m *testing.M) { - os.Exit(m.Run()) -} - type mockTransport struct{} func (mockTransport) RoundTrip(req *http.Request) (*http.Response, error) { diff --git a/modules/session/virtual.go b/modules/session/virtual.go index 35a995d2d0..597b9e55c1 100644 --- a/modules/session/virtual.go +++ b/modules/session/virtual.go @@ -65,7 +65,6 @@ func (o *VirtualSessionProvider) Read(sid string) (session.RawStore, error) { return nil, fmt.Errorf("check if '%s' exist failed: %w", sid, err) } kv := make(map[any]any) - kv["_old_uid"] = "0" return NewVirtualStore(o, sid, kv), nil } @@ -160,7 +159,7 @@ func (s *VirtualStore) Release() error { // Now need to lock the provider s.p.lock.Lock() defer s.p.lock.Unlock() - if oldUID, ok := s.data["_old_uid"]; (ok && (oldUID != "0" || len(s.data) > 1)) || (!ok && len(s.data) > 0) { + if len(s.data) > 0 { // Now ensure that we don't exist! realProvider := s.p.provider diff --git a/modules/setting/actions.go b/modules/setting/actions.go index 34346b62cf..7a91ecb593 100644 --- a/modules/setting/actions.go +++ b/modules/setting/actions.go @@ -4,6 +4,7 @@ package setting import ( + "errors" "fmt" "strings" "time" @@ -25,10 +26,12 @@ var ( EndlessTaskTimeout time.Duration `ini:"ENDLESS_TASK_TIMEOUT"` AbandonedJobTimeout time.Duration `ini:"ABANDONED_JOB_TIMEOUT"` SkipWorkflowStrings []string `ini:"SKIP_WORKFLOW_STRINGS"` + WorkflowDirs []string `ini:"WORKFLOW_DIRS"` }{ Enabled: true, DefaultActionsURL: defaultActionsURLGitHub, SkipWorkflowStrings: []string{"[skip ci]", "[ci skip]", "[no ci]", "[skip actions]", "[actions skip]"}, + WorkflowDirs: []string{".gitea/workflows", ".github/workflows"}, } ) @@ -119,5 +122,20 @@ func loadActionsFrom(rootCfg ConfigProvider) error { return fmt.Errorf("invalid [actions] LOG_COMPRESSION: %q", Actions.LogCompression) } + workflowDirs := make([]string, 0, len(Actions.WorkflowDirs)) + for _, dir := range Actions.WorkflowDirs { + dir = strings.TrimSpace(dir) + if dir == "" { + continue + } + dir = strings.ReplaceAll(dir, `\`, `/`) + dir = strings.TrimRight(dir, "/") + workflowDirs = append(workflowDirs, dir) + } + if len(workflowDirs) == 0 { + return errors.New("[actions] WORKFLOW_DIRS must contain at least one entry") + } + Actions.WorkflowDirs = workflowDirs + return nil } diff --git a/modules/setting/actions_test.go b/modules/setting/actions_test.go index 353cc657fa..5c7ab268c1 100644 --- a/modules/setting/actions_test.go +++ b/modules/setting/actions_test.go @@ -97,6 +97,65 @@ STORAGE_TYPE = minio assert.Equal(t, "actions_artifacts", filepath.Base(Actions.ArtifactStorage.Path)) } +func Test_WorkflowDirs(t *testing.T) { + oldActions := Actions + defer func() { + Actions = oldActions + }() + + tests := []struct { + name string + iniStr string + wantDirs []string + wantErr bool + }{ + { + name: "default", + iniStr: `[actions]`, + wantDirs: []string{".gitea/workflows", ".github/workflows"}, + }, + { + name: "single dir", + iniStr: "[actions]\nWORKFLOW_DIRS = .github/workflows", + wantDirs: []string{".github/workflows"}, + }, + { + name: "custom order", + iniStr: "[actions]\nWORKFLOW_DIRS = .github/workflows,.gitea/workflows", + wantDirs: []string{".github/workflows", ".gitea/workflows"}, + }, + { + name: "whitespace trimming", + iniStr: "[actions]\nWORKFLOW_DIRS = .gitea/workflows , .github/workflows ", + wantDirs: []string{".gitea/workflows", ".github/workflows"}, + }, + { + name: "trailing slash normalization", + iniStr: "[actions]\nWORKFLOW_DIRS = .gitea/workflows/,.github/workflows/", + wantDirs: []string{".gitea/workflows", ".github/workflows"}, + }, + { + name: "only commas and whitespace", + iniStr: "[actions]\nWORKFLOW_DIRS = , , ,", + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + cfg, err := NewConfigProviderFromData(tt.iniStr) + require.NoError(t, err) + err = loadActionsFrom(cfg) + if tt.wantErr { + require.Error(t, err) + return + } + require.NoError(t, err) + assert.Equal(t, tt.wantDirs, Actions.WorkflowDirs) + }) + } +} + func Test_getDefaultActionsURLForActions(t *testing.T) { oldActions := Actions oldAppURL := AppURL diff --git a/modules/setting/testenv.go b/modules/setting/testenv.go index 52e8912af0..853521c328 100644 --- a/modules/setting/testenv.go +++ b/modules/setting/testenv.go @@ -13,7 +13,18 @@ import ( "code.gitea.io/gitea/modules/util" ) -func SetupGiteaTestEnv() string { +var giteaTestSourceRoot *string + +func GetGiteaTestSourceRoot() string { + return *giteaTestSourceRoot +} + +func SetupGiteaTestEnv() { + if giteaTestSourceRoot != nil { + return // already initialized + } + + IsInTesting = true giteaRoot := os.Getenv("GITEA_TEST_ROOT") if giteaRoot == "" { _, filename, _, _ := runtime.Caller(0) @@ -27,6 +38,7 @@ func SetupGiteaTestEnv() string { appWorkPathBuiltin = giteaRoot AppWorkPath = giteaRoot AppPath = filepath.Join(giteaRoot, "gitea") + util.Iif(IsWindows, ".exe", "") + StaticRootPath = giteaRoot // need to load assets (options, public) from the source code directory for testing // 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") @@ -56,6 +68,5 @@ func SetupGiteaTestEnv() string { // 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 + giteaTestSourceRoot = &giteaRoot } diff --git a/modules/testlogger/testlogger.go b/modules/testlogger/testlogger.go index bf08e1d6d5..39232a3eed 100644 --- a/modules/testlogger/testlogger.go +++ b/modules/testlogger/testlogger.go @@ -173,7 +173,7 @@ func Init() { log.RegisterEventWriter("test", newTestLoggerWriter) } -func Fatalf(format string, args ...any) { - Printf(format+"\n", args...) - os.Exit(1) +func Panicf(format string, args ...any) { + // don't call os.Exit, otherwise the "defer" functions won't be executed + panic(fmt.Sprintf(format, args...)) } diff --git a/modules/timeutil/since_test.go b/modules/timeutil/since_test.go index 40fefe8700..bf848bd05a 100644 --- a/modules/timeutil/since_test.go +++ b/modules/timeutil/since_test.go @@ -32,11 +32,7 @@ func TestMain(m *testing.M) { // setup translation.InitLocales(context.Background()) BaseDate = time.Date(2000, time.January, 1, 0, 0, 0, 0, time.UTC) - - // run the tests - retVal := m.Run() - - os.Exit(retVal) + os.Exit(m.Run()) } func TestTimeSincePro(t *testing.T) { diff --git a/modules/webhook/type.go b/modules/webhook/type.go index 89c6a4bfe5..18a4086710 100644 --- a/modules/webhook/type.go +++ b/modules/webhook/type.go @@ -98,6 +98,20 @@ func (h HookEventType) IsPullRequest() bool { return h.Event() == "pull_request" } +// IsPullRequestReview returns true for pull request review events +// (approved, rejected, comment). These events use the same PullRequestPayload +// as regular pull_request events. +func (h HookEventType) IsPullRequestReview() bool { + switch h { + case HookEventPullRequestReviewApproved, + HookEventPullRequestReviewRejected, + HookEventPullRequestReviewComment: + return true + default: + return false + } +} + // HookType is the type of a webhook type HookType = string diff --git a/package.json b/package.json index e8f1c55816..a7792c5fee 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,7 @@ "swagger-ui-dist": "5.31.1", "tailwindcss": "3.4.17", "throttle-debounce": "5.0.2", - "tinycolor2": "1.6.0", + "colord": "2.9.3", "tippy.js": "6.3.7", "toastify-js": "1.12.0", "tributejs": "5.1.3", @@ -77,11 +77,11 @@ "@types/jquery": "3.5.33", "@types/js-yaml": "4.0.9", "@types/katex": "0.16.8", + "@types/node": "25.2.3", "@types/pdfobject": "2.2.5", "@types/sortablejs": "1.15.9", "@types/swagger-ui-dist": "3.30.6", "@types/throttle-debounce": "5.0.2", - "@types/tinycolor2": "1.4.6", "@types/toastify-js": "1.12.4", "@typescript-eslint/parser": "8.56.0", "@vitejs/plugin-vue": "6.0.4", @@ -119,9 +119,6 @@ "vitest": "4.0.18", "vue-tsc": "3.2.4" }, - "browserslist": [ - "defaults" - ], "pnpm": { "overrides": { "array-includes": "npm:@nolyfill/array-includes@^1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f273662cad..e67da15ad3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -89,6 +89,9 @@ importers: clippie: specifier: 4.1.10 version: 4.1.10 + colord: + specifier: 2.9.3 + version: 2.9.3 compare-versions: specifier: 6.1.1 version: 6.1.1 @@ -164,9 +167,6 @@ importers: throttle-debounce: specifier: 5.0.2 version: 5.0.2 - tinycolor2: - specifier: 1.6.0 - version: 1.6.0 tippy.js: specifier: 6.3.7 version: 6.3.7 @@ -234,6 +234,9 @@ importers: '@types/katex': specifier: 0.16.8 version: 0.16.8 + '@types/node': + specifier: 25.2.3 + version: 25.2.3 '@types/pdfobject': specifier: 2.2.5 version: 2.2.5 @@ -246,9 +249,6 @@ importers: '@types/throttle-debounce': specifier: 5.0.2 version: 5.0.2 - '@types/tinycolor2': - specifier: 1.4.6 - version: 1.4.6 '@types/toastify-js': specifier: 1.12.4 version: 1.12.4 @@ -1294,9 +1294,6 @@ packages: '@types/throttle-debounce@5.0.2': resolution: {integrity: sha512-pDzSNulqooSKvSNcksnV72nk8p7gRqN8As71Sp28nov1IgmPKWbOEIwAWvBME5pPTtaXJAvG3O4oc76HlQ4kqQ==} - '@types/tinycolor2@1.4.6': - resolution: {integrity: sha512-iEN8J0BoMnsWBqjVbWH/c0G0Hh7O21lpR2/+PrvAVgWdzL7eexIFm4JN/Wn10PTcmNdtS6U67r499mlWMXOxNw==} - '@types/toastify-js@1.12.4': resolution: {integrity: sha512-zfZHU4tKffPCnZRe7pjv/eFKzTVHozKewFCKaCjZ4gFinKgJRz/t0bkZiMCXJxPhv/ZoeDGNOeRD09R0kQZ/nw==} @@ -4053,9 +4050,6 @@ packages: tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} - tinycolor2@1.6.0: - resolution: {integrity: sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==} - tinyexec@1.0.2: resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==} engines: {node: '>=18'} @@ -5238,8 +5232,6 @@ snapshots: '@types/throttle-debounce@5.0.2': {} - '@types/tinycolor2@1.4.6': {} - '@types/toastify-js@1.12.4': {} '@types/trusted-types@2.0.7': @@ -8212,8 +8204,6 @@ snapshots: tinybench@2.9.0: {} - tinycolor2@1.6.0: {} - tinyexec@1.0.2: {} tinyglobby@0.2.15: diff --git a/services/actions/commit_status.go b/services/actions/commit_status.go index 7271f58091..884b98e966 100644 --- a/services/actions/commit_status.go +++ b/services/actions/commit_status.go @@ -115,6 +115,21 @@ func getCommitStatusEventNameAndCommitID(run *actions_model.ActionRun) (event, c return "", "", errors.New("head of pull request is missing in event payload") } commitID = payload.PullRequest.Head.Sha + case // pull_request_review events share the same PullRequestPayload as pull_request + webhook_module.HookEventPullRequestReviewApproved, + webhook_module.HookEventPullRequestReviewRejected, + webhook_module.HookEventPullRequestReviewComment: + event = run.TriggerEvent + payload, err := run.GetPullRequestEventPayload() + if err != nil { + return "", "", fmt.Errorf("GetPullRequestEventPayload: %w", err) + } + if payload.PullRequest == nil { + return "", "", errors.New("pull request is missing in event payload") + } else if payload.PullRequest.Head == nil { + return "", "", errors.New("head of pull request is missing in event payload") + } + commitID = payload.PullRequest.Head.Sha case webhook_module.HookEventRelease: event = string(run.Event) commitID = run.CommitSHA diff --git a/services/actions/init_test.go b/services/actions/init_test.go index 2d33a4e5cc..e61b3759e1 100644 --- a/services/actions/init_test.go +++ b/services/actions/init_test.go @@ -18,7 +18,6 @@ import ( func TestMain(m *testing.M) { unittest.MainTest(m) - os.Exit(m.Run()) } func TestInitToken(t *testing.T) { diff --git a/tests/e2e/e2e_test.go b/tests/e2e/e2e_test.go index 95093ffd29..6e7890105c 100644 --- a/tests/e2e/e2e_test.go +++ b/tests/e2e/e2e_test.go @@ -37,7 +37,7 @@ func TestMain(m *testing.M) { graceful.InitManager(managerCtx) defer cancel() - tests.InitTest(false) + tests.InitTest() testE2eWebRoutes = routers.NormalRoutes() err := unittest.InitFixtures( diff --git a/tests/integration/actions_trigger_test.go b/tests/integration/actions_trigger_test.go index b0eabdd432..7fff796af6 100644 --- a/tests/integration/actions_trigger_test.go +++ b/tests/integration/actions_trigger_test.go @@ -691,6 +691,144 @@ func insertFakeStatus(t *testing.T, repo *repo_model.Repository, sha, targetURL, assert.NoError(t, err) } +func TestPullRequestReviewCommitStatusEvent(t *testing.T) { + onGiteaRun(t, func(t *testing.T, u *url.URL) { + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // owner of the repo + user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) // reviewer + + // create a repo + repo, err := repo_service.CreateRepository(t.Context(), user2, user2, repo_service.CreateRepoOptions{ + Name: "repo-pull-request-review", + Description: "test pull-request-review commit status", + AutoInit: true, + Gitignores: "Go", + License: "MIT", + Readme: "Default", + DefaultBranch: "main", + IsPrivate: false, + }) + assert.NoError(t, err) + assert.NotEmpty(t, repo) + + // add user4 as collaborator so they can review + ctx := NewAPITestContext(t, repo.OwnerName, repo.Name, auth_model.AccessTokenScopeWriteRepository) + t.Run("AddUser4AsCollaboratorWithWriteAccess", doAPIAddCollaborator(ctx, "user4", perm.AccessModeWrite)) + + // add workflow file that triggers on pull_request_review + addWorkflow, err := files_service.ChangeRepoFiles(t.Context(), repo, user2, &files_service.ChangeRepoFilesOptions{ + Files: []*files_service.ChangeRepoFile{ + { + Operation: "create", + TreePath: ".gitea/workflows/pr-review.yml", + ContentReader: strings.NewReader(`name: test +on: + pull_request_review: + types: [submitted] +jobs: + test: + runs-on: ubuntu-latest + steps: + - run: echo helloworld +`), + }, + }, + Message: "add workflow", + OldBranch: "main", + NewBranch: "main", + Author: &files_service.IdentityOptions{ + GitUserName: user2.Name, + GitUserEmail: user2.Email, + }, + Committer: &files_service.IdentityOptions{ + GitUserName: user2.Name, + GitUserEmail: user2.Email, + }, + Dates: &files_service.CommitDateOptions{ + Author: time.Now(), + Committer: time.Now(), + }, + }) + assert.NoError(t, err) + assert.NotEmpty(t, addWorkflow) + + // create a branch and a PR + testBranch := "test-review-branch" + err = repo_service.CreateNewBranch(t.Context(), user2, repo, "main", testBranch) + assert.NoError(t, err) + + // add a file on the test branch so the PR has changes + addFileResp, err := files_service.ChangeRepoFiles(t.Context(), repo, user2, &files_service.ChangeRepoFilesOptions{ + Files: []*files_service.ChangeRepoFile{ + { + Operation: "create", + TreePath: "test.txt", + ContentReader: strings.NewReader("test content"), + }, + }, + Message: "add test file", + OldBranch: testBranch, + NewBranch: testBranch, + Author: &files_service.IdentityOptions{ + GitUserName: user2.Name, + GitUserEmail: user2.Email, + }, + Committer: &files_service.IdentityOptions{ + GitUserName: user2.Name, + GitUserEmail: user2.Email, + }, + Dates: &files_service.CommitDateOptions{ + Author: time.Now(), + Committer: time.Now(), + }, + }) + assert.NoError(t, err) + assert.NotEmpty(t, addFileResp) + sha := addFileResp.Commit.SHA + + pullIssue := &issues_model.Issue{ + RepoID: repo.ID, + Title: "A test PR for review", + PosterID: user2.ID, + Poster: user2, + IsPull: true, + } + pullRequest := &issues_model.PullRequest{ + HeadRepoID: repo.ID, + BaseRepoID: repo.ID, + HeadBranch: testBranch, + BaseBranch: "main", + HeadRepo: repo, + BaseRepo: repo, + Type: issues_model.PullRequestGitea, + } + prOpts := &pull_service.NewPullRequestOptions{Repo: repo, Issue: pullIssue, PullRequest: pullRequest} + err = pull_service.NewPullRequest(t.Context(), prOpts) + assert.NoError(t, err) + + // submit an approval review as user4 + gitRepo, err := gitrepo.OpenRepository(t.Context(), repo) + assert.NoError(t, err) + defer gitRepo.Close() + + _, _, err = pull_service.SubmitReview(t.Context(), user4, gitRepo, pullIssue, issues_model.ReviewTypeApprove, "lgtm", sha, nil) + assert.NoError(t, err) + + // verify that a commit status was created for the review event + assert.Eventually(t, func() bool { + latestCommitStatuses, err := git_model.GetLatestCommitStatus(t.Context(), repo.ID, sha, db.ListOptionsAll) + assert.NoError(t, err) + if len(latestCommitStatuses) == 0 { + return false + } + if latestCommitStatuses[0].State == commitstatus.CommitStatusPending { + insertFakeStatus(t, repo, sha, latestCommitStatuses[0].TargetURL, latestCommitStatuses[0].Context) + return true + } + return false + }, 1*time.Second, 100*time.Millisecond) + }) +} + func TestWorkflowDispatchPublicApi(t *testing.T) { onGiteaRun(t, func(t *testing.T, u *url.URL) { user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) diff --git a/tests/integration/integration_test.go b/tests/integration/integration_test.go index 3803f331c4..ca1e094ac2 100644 --- a/tests/integration/integration_test.go +++ b/tests/integration/integration_test.go @@ -1,7 +1,6 @@ // Copyright 2017 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -//nolint:forbidigo // use of print functions is allowed in tests package integration import ( @@ -27,6 +26,7 @@ import ( "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/testlogger" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/modules/web/middleware" @@ -79,14 +79,14 @@ func NewNilResponseHashSumRecorder() *NilResponseHashSumRecorder { } } -func TestMain(m *testing.M) { +func testMain(m *testing.M) int { defer log.GetManager().Close() managerCtx, cancel := context.WithCancel(context.Background()) graceful.InitManager(managerCtx) defer cancel() - tests.InitTest(true) + tests.InitTest() testWebRoutes = routers.NormalRoutes() err := unittest.InitFixtures( @@ -95,8 +95,7 @@ func TestMain(m *testing.M) { }, ) if err != nil { - fmt.Printf("Error initializing test database: %v\n", err) - os.Exit(1) + testlogger.Panicf("InitFixtures: %v", err) } // FIXME: the console logger is deleted by mistake, so if there is any `log.Fatal`, developers won't see any error message. @@ -104,15 +103,16 @@ func TestMain(m *testing.M) { exitCode := m.Run() if err = util.RemoveAll(setting.Indexer.IssuePath); err != nil { - fmt.Printf("util.RemoveAll: %v\n", err) - os.Exit(1) + log.Error("Failed to remove indexer path: %v", err) } if err = util.RemoveAll(setting.Indexer.RepoPath); err != nil { - fmt.Printf("Unable to remove repo indexer: %v\n", err) - os.Exit(1) + log.Error("Failed to remove indexer path: %v", err) } + return exitCode +} - os.Exit(exitCode) +func TestMain(m *testing.M) { + os.Exit(testMain(m)) } type TestSession struct { diff --git a/tests/integration/migration-test/migration_test.go b/tests/integration/migration-test/migration_test.go index ee49829127..2e25afb43c 100644 --- a/tests/integration/migration-test/migration_test.go +++ b/tests/integration/migration-test/migration_test.go @@ -36,8 +36,6 @@ var currentEngine *xorm.Engine func initMigrationTest(t *testing.T) func() { testlogger.Init() - setting.SetupGiteaTestEnv() - unittest.InitSettingsForTesting() assert.NotEmpty(t, setting.RepoRootPath) diff --git a/tests/integration/pull_create_test.go b/tests/integration/pull_create_test.go index 3db335fc3f..2c17557eb0 100644 --- a/tests/integration/pull_create_test.go +++ b/tests/integration/pull_create_test.go @@ -176,41 +176,6 @@ func TestPullCreate(t *testing.T) { }) } -func TestPullCreate_TitleEscape(t *testing.T) { - onGiteaRun(t, func(t *testing.T, u *url.URL) { - session := loginUser(t, "user1") - testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "") - testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n") - resp := testPullCreate(t, session, "user1", "repo1", false, "master", "master", "XSS PR") - - // check the redirected URL - url := test.RedirectURL(resp) - assert.Regexp(t, "^/user2/repo1/pulls/[0-9]*$", url) - - // Edit title - req := NewRequest(t, "GET", url) - resp = session.MakeRequest(t, req, http.StatusOK) - htmlDoc := NewHTMLParser(t, resp.Body) - editTestTitleURL, exists := htmlDoc.doc.Find(".issue-title-buttons button[data-update-url]").First().Attr("data-update-url") - assert.True(t, exists, "The template has changed") - - req = NewRequestWithValues(t, "POST", editTestTitleURL, map[string]string{ - "title": "XSS PR", - }) - session.MakeRequest(t, req, http.StatusOK) - - req = NewRequest(t, "GET", url) - resp = session.MakeRequest(t, req, http.StatusOK) - htmlDoc = NewHTMLParser(t, resp.Body) - titleHTML, err := htmlDoc.doc.Find(".comment-list .timeline-item.event .comment-text-line b").First().Html() - assert.NoError(t, err) - assert.Equal(t, "<i>XSS PR</i>", titleHTML) - titleHTML, err = htmlDoc.doc.Find(".comment-list .timeline-item.event .comment-text-line b").Next().Html() - assert.NoError(t, err) - assert.Equal(t, "<u>XSS PR</u>", titleHTML) - }) -} - func testUIDeleteBranch(t *testing.T, session *TestSession, ownerName, repoName, branchName string) { relURL := "/" + path.Join(ownerName, repoName, "branches") req := NewRequestWithValues(t, "POST", relURL+"/delete", map[string]string{ diff --git a/tests/integration/xss_test.go b/tests/integration/xss_test.go deleted file mode 100644 index 62d2e27bcd..0000000000 --- a/tests/integration/xss_test.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2017 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package integration - -import ( - "net/http" - "testing" - - "code.gitea.io/gitea/models/unittest" - user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/tests" - - "github.com/stretchr/testify/assert" -) - -func TestXSSUserFullName(t *testing.T) { - defer tests.PrepareTestEnv(t)() - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) - const fullName = `name & ` - - session := loginUser(t, user.Name) - req := NewRequestWithValues(t, "POST", "/user/settings", map[string]string{ - "name": user.Name, - "full_name": fullName, - "email": user.Email, - "language": "en-US", - }) - session.MakeRequest(t, req, http.StatusSeeOther) - - req = NewRequestf(t, "GET", "/%s", user.Name) - resp := session.MakeRequest(t, req, http.StatusOK) - htmlDoc := NewHTMLParser(t, resp.Body) - assert.Equal(t, 0, htmlDoc.doc.Find("script.evil").Length()) - assert.Equal(t, fullName, - htmlDoc.doc.Find("div.content").Find(".header.text.center").Text(), - ) -} diff --git a/tests/mssql.ini.tmpl b/tests/mssql.ini.tmpl index 42bf683a07..0d16905033 100644 --- a/tests/mssql.ini.tmpl +++ b/tests/mssql.ini.tmpl @@ -1,3 +1,4 @@ +WORK_PATH = {{WORK_PATH}} APP_NAME = Gitea: Git with a cup of tea RUN_MODE = prod @@ -11,11 +12,9 @@ SSL_MODE = disable [indexer] REPO_INDEXER_ENABLED = true -REPO_INDEXER_PATH = tests/{{TEST_TYPE}}/gitea-{{TEST_TYPE}}-mssql/indexers/repos.bleve [queue.issue_indexer] TYPE = level -DATADIR = tests/{{TEST_TYPE}}/gitea-{{TEST_TYPE}}-mssql/indexers/issues.queue [queue] TYPE = immediate @@ -29,15 +28,6 @@ TYPE = immediate [queue.webhook_sender] TYPE = immediate -[repository] -ROOT = {{REPO_TEST_DIR}}tests/{{TEST_TYPE}}/gitea-{{TEST_TYPE}}-mssql/gitea-repositories - -[repository.local] -LOCAL_COPY_PATH = tests/{{TEST_TYPE}}/gitea-{{TEST_TYPE}}-mssql/tmp/local-repo - -[repository.upload] -TEMP_PATH = tests/{{TEST_TYPE}}/gitea-{{TEST_TYPE}}-mssql/tmp/uploads - [repository.signing] SIGNING_KEY = none @@ -53,14 +43,13 @@ START_SSH_SERVER = true LFS_START_SERVER = true OFFLINE_MODE = false LFS_JWT_SECRET = Tv_MjmZuHqpIY6GFl12ebgkRAMt4RlWt0v4EHKSXO0w -APP_DATA_PATH = tests/{{TEST_TYPE}}/gitea-{{TEST_TYPE}}-mssql/data BUILTIN_SSH_SERVER_USER = git SSH_TRUSTED_USER_CA_KEYS = ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCb4DC1dMFnJ6pXWo7GMxTchtzmJHYzfN6sZ9FAPFR4ijMLfGki+olvOMO5Fql1/yGnGfbELQa1S6y4shSvj/5K+zUFScmEXYf3Gcr87RqilLkyk16RS+cHNB1u87xTHbETaa3nyCJeGQRpd4IQ4NKob745mwDZ7jQBH8AZEng50Oh8y8fi8skBBBzaYp1ilgvzG740L7uex6fHV62myq0SXeCa+oJUjq326FU8y+Vsa32H8A3e7tOgXZPdt2TVNltx2S9H2WO8RMi7LfaSwARNfy1zu+bfR50r6ef8Yx5YKCMz4wWb1SHU1GS800mjOjlInLQORYRNMlSwR1+vLlVDciOqFapDSbj+YOVOawR0R1aqlSKpZkt33DuOBPx9qe6CVnIi7Z+Px/KqM+OLCzlLY/RS+LbxQpDWcfTVRiP+S5qRTcE3M3UioN/e0BE/1+MpX90IGpvVkA63ILYbKEa4bM3ASL7ChTCr6xN5XT+GpVJveFKK1cfNx9ExHI4rzYE= [mailer] ENABLED = true PROTOCOL = dummy -FROM = mssql-{{TEST_TYPE}}-test@gitea.io +FROM = mssql-integration-test@gitea.io [service] REGISTER_EMAIL_CONFIRM = false @@ -76,16 +65,12 @@ ENABLE_NOTIFY_MAIL = true [picture] DISABLE_GRAVATAR = false ENABLE_FEDERATED_AVATAR = false -AVATAR_UPLOAD_PATH = tests/{{TEST_TYPE}}/gitea-{{TEST_TYPE}}-mssql/data/avatars -REPOSITORY_AVATAR_UPLOAD_PATH = tests/{{TEST_TYPE}}/gitea-{{TEST_TYPE}}-mssql/data/repo-avatars [session] PROVIDER = file -PROVIDER_CONFIG = tests/{{TEST_TYPE}}/gitea-{{TEST_TYPE}}-mssql/data/sessions [log] MODE = {{TEST_LOGGER}} -ROOT_PATH = {{REPO_TEST_DIR}}mssql-log ENABLE_SSH_LOG = true logger.xorm.MODE = file diff --git a/tests/mysql.ini.tmpl b/tests/mysql.ini.tmpl index 7cef540d1d..bf59efde4c 100644 --- a/tests/mysql.ini.tmpl +++ b/tests/mysql.ini.tmpl @@ -1,3 +1,4 @@ +WORK_PATH = {{WORK_PATH}} APP_NAME = Gitea: Git with a cup of tea RUN_MODE = prod @@ -11,13 +12,11 @@ SSL_MODE = disable [indexer] REPO_INDEXER_ENABLED = true -REPO_INDEXER_PATH = tests/{{TEST_TYPE}}/gitea-{{TEST_TYPE}}-mysql/indexers/repos.bleve ISSUE_INDEXER_TYPE = elasticsearch ISSUE_INDEXER_CONN_STR = http://elastic:changeme@elasticsearch:9200 [queue.issue_indexer] TYPE = level -DATADIR = tests/{{TEST_TYPE}}/gitea-{{TEST_TYPE}}-mysql/indexers/issues.queue [queue] TYPE = immediate @@ -31,15 +30,6 @@ TYPE = immediate [queue.webhook_sender] TYPE = immediate -[repository] -ROOT = {{REPO_TEST_DIR}}tests/{{TEST_TYPE}}/gitea-{{TEST_TYPE}}-mysql/gitea-repositories - -[repository.local] -LOCAL_COPY_PATH = tests/{{TEST_TYPE}}/gitea-{{TEST_TYPE}}-mysql/tmp/local-repo - -[repository.upload] -TEMP_PATH = tests/{{TEST_TYPE}}/gitea-{{TEST_TYPE}}-mysql/tmp/uploads - [repository.signing] SIGNING_KEY = none @@ -51,7 +41,6 @@ LOCAL_ROOT_URL = http://127.0.0.1:3001/ DISABLE_SSH = false SSH_LISTEN_HOST = localhost SSH_PORT = 2201 -APP_DATA_PATH = tests/{{TEST_TYPE}}/gitea-{{TEST_TYPE}}-mysql/data BUILTIN_SSH_SERVER_USER = git START_SSH_SERVER = true OFFLINE_MODE = false @@ -63,7 +52,7 @@ SSH_TRUSTED_USER_CA_KEYS = ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCb4DC1dMFnJ6pXW [mailer] ENABLED = true PROTOCOL = dummy -FROM = mysql-{{TEST_TYPE}}-test@gitea.io +FROM = mysql-integration-test@gitea.io [service] REGISTER_EMAIL_CONFIRM = false @@ -82,11 +71,9 @@ ENABLE_FEDERATED_AVATAR = false [session] PROVIDER = file -PROVIDER_CONFIG = tests/{{TEST_TYPE}}/gitea-{{TEST_TYPE}}-mysql/data/sessions [log] MODE = {{TEST_LOGGER}} -ROOT_PATH = {{REPO_TEST_DIR}}mysql-log ENABLE_SSH_LOG = true logger.xorm.MODE = file @@ -103,9 +90,6 @@ SECRET_KEY = 9pCviYTWSb INTERNAL_TOKEN = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE0OTU1NTE2MTh9.hhSVGOANkaKk3vfCd2jDOIww4pUk0xtg9JRde5UogyQ DISABLE_QUERY_AUTH_TOKEN = true -[lfs] -PATH = tests/{{TEST_TYPE}}/gitea-{{TEST_TYPE}}-mysql/data/lfs - [packages] ENABLED = true diff --git a/tests/pgsql.ini.tmpl b/tests/pgsql.ini.tmpl index 13a5932608..b6fcd33f70 100644 --- a/tests/pgsql.ini.tmpl +++ b/tests/pgsql.ini.tmpl @@ -1,3 +1,4 @@ +WORK_PATH = {{WORK_PATH}} APP_NAME = Gitea: Git with a cup of tea RUN_MODE = prod @@ -12,11 +13,9 @@ SSL_MODE = disable [indexer] REPO_INDEXER_ENABLED = true -REPO_INDEXER_PATH = tests/{{TEST_TYPE}}/gitea-{{TEST_TYPE}}-pgsql/indexers/repos.bleve [queue.issue_indexer] TYPE = level -DATADIR = tests/{{TEST_TYPE}}/gitea-{{TEST_TYPE}}-pgsql/indexers/issues.queue [queue] TYPE = immediate @@ -30,15 +29,6 @@ TYPE = immediate [queue.webhook_sender] TYPE = immediate -[repository] -ROOT = {{REPO_TEST_DIR}}tests/{{TEST_TYPE}}/gitea-{{TEST_TYPE}}-pgsql/gitea-repositories - -[repository.local] -LOCAL_COPY_PATH = tests/{{TEST_TYPE}}/gitea-{{TEST_TYPE}}-pgsql/tmp/local-repo - -[repository.upload] -TEMP_PATH = tests/{{TEST_TYPE}}/gitea-{{TEST_TYPE}}-pgsql/tmp/uploads - [repository.signing] SIGNING_KEY = none @@ -54,14 +44,13 @@ START_SSH_SERVER = true LFS_START_SERVER = true OFFLINE_MODE = false LFS_JWT_SECRET = Tv_MjmZuHqpIY6GFl12ebgkRAMt4RlWt0v4EHKSXO0w -APP_DATA_PATH = tests/{{TEST_TYPE}}/gitea-{{TEST_TYPE}}-pgsql/data BUILTIN_SSH_SERVER_USER = git SSH_TRUSTED_USER_CA_KEYS = ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCb4DC1dMFnJ6pXWo7GMxTchtzmJHYzfN6sZ9FAPFR4ijMLfGki+olvOMO5Fql1/yGnGfbELQa1S6y4shSvj/5K+zUFScmEXYf3Gcr87RqilLkyk16RS+cHNB1u87xTHbETaa3nyCJeGQRpd4IQ4NKob745mwDZ7jQBH8AZEng50Oh8y8fi8skBBBzaYp1ilgvzG740L7uex6fHV62myq0SXeCa+oJUjq326FU8y+Vsa32H8A3e7tOgXZPdt2TVNltx2S9H2WO8RMi7LfaSwARNfy1zu+bfR50r6ef8Yx5YKCMz4wWb1SHU1GS800mjOjlInLQORYRNMlSwR1+vLlVDciOqFapDSbj+YOVOawR0R1aqlSKpZkt33DuOBPx9qe6CVnIi7Z+Px/KqM+OLCzlLY/RS+LbxQpDWcfTVRiP+S5qRTcE3M3UioN/e0BE/1+MpX90IGpvVkA63ILYbKEa4bM3ASL7ChTCr6xN5XT+GpVJveFKK1cfNx9ExHI4rzYE= [mailer] ENABLED = true PROTOCOL = dummy -FROM = pgsql-{{TEST_TYPE}}-test@gitea.io +FROM = pgsql-integration-test@gitea.io [service] REGISTER_EMAIL_CONFIRM = false @@ -77,16 +66,12 @@ ENABLE_NOTIFY_MAIL = true [picture] DISABLE_GRAVATAR = false ENABLE_FEDERATED_AVATAR = false -AVATAR_UPLOAD_PATH = tests/{{TEST_TYPE}}/gitea-{{TEST_TYPE}}-pgsql/data/avatars -REPOSITORY_AVATAR_UPLOAD_PATH = tests/{{TEST_TYPE}}/gitea-{{TEST_TYPE}}-pgsql/data/repo-avatars [session] PROVIDER = file -PROVIDER_CONFIG = tests/{{TEST_TYPE}}/gitea-{{TEST_TYPE}}-pgsql/data/sessions [log] MODE = {{TEST_LOGGER}} -ROOT_PATH = {{REPO_TEST_DIR}}pgsql-log ENABLE_SSH_LOG = true logger.xorm.MODE = file diff --git a/tests/sqlite.ini.tmpl b/tests/sqlite.ini.tmpl index 61f7e2a46d..243bea86f1 100644 --- a/tests/sqlite.ini.tmpl +++ b/tests/sqlite.ini.tmpl @@ -1,17 +1,16 @@ +WORK_PATH = {{WORK_PATH}} APP_NAME = Gitea: Git with a cup of tea RUN_MODE = prod [database] DB_TYPE = sqlite3 -PATH = tests/{{TEST_TYPE}}/gitea-{{TEST_TYPE}}-sqlite/gitea.db +PATH = gitea.db [indexer] REPO_INDEXER_ENABLED = true -REPO_INDEXER_PATH = tests/{{TEST_TYPE}}/gitea-{{TEST_TYPE}}-sqlite/indexers/repos.bleve [queue.issue_indexer] TYPE = level -DATADIR = tests/{{TEST_TYPE}}/gitea-{{TEST_TYPE}}-sqlite/indexers/issues.queue [queue] TYPE = immediate @@ -25,15 +24,6 @@ TYPE = immediate [queue.webhook_sender] TYPE = immediate -[repository] -ROOT = {{REPO_TEST_DIR}}tests/{{TEST_TYPE}}/gitea-{{TEST_TYPE}}-sqlite/gitea-repositories - -[repository.local] -LOCAL_COPY_PATH = tests/{{TEST_TYPE}}/gitea-{{TEST_TYPE}}-sqlite/tmp/local-repo - -[repository.upload] -TEMP_PATH = tests/{{TEST_TYPE}}/gitea-{{TEST_TYPE}}-sqlite/tmp/uploads - [repository.signing] SIGNING_KEY = none @@ -49,18 +39,14 @@ START_SSH_SERVER = true LFS_START_SERVER = true OFFLINE_MODE = false LFS_JWT_SECRET = Tv_MjmZuHqpIY6GFl12ebgkRAMt4RlWt0v4EHKSXO0w -APP_DATA_PATH = tests/{{TEST_TYPE}}/gitea-{{TEST_TYPE}}-sqlite/data ENABLE_GZIP = true BUILTIN_SSH_SERVER_USER = git SSH_TRUSTED_USER_CA_KEYS = ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCb4DC1dMFnJ6pXWo7GMxTchtzmJHYzfN6sZ9FAPFR4ijMLfGki+olvOMO5Fql1/yGnGfbELQa1S6y4shSvj/5K+zUFScmEXYf3Gcr87RqilLkyk16RS+cHNB1u87xTHbETaa3nyCJeGQRpd4IQ4NKob745mwDZ7jQBH8AZEng50Oh8y8fi8skBBBzaYp1ilgvzG740L7uex6fHV62myq0SXeCa+oJUjq326FU8y+Vsa32H8A3e7tOgXZPdt2TVNltx2S9H2WO8RMi7LfaSwARNfy1zu+bfR50r6ef8Yx5YKCMz4wWb1SHU1GS800mjOjlInLQORYRNMlSwR1+vLlVDciOqFapDSbj+YOVOawR0R1aqlSKpZkt33DuOBPx9qe6CVnIi7Z+Px/KqM+OLCzlLY/RS+LbxQpDWcfTVRiP+S5qRTcE3M3UioN/e0BE/1+MpX90IGpvVkA63ILYbKEa4bM3ASL7ChTCr6xN5XT+GpVJveFKK1cfNx9ExHI4rzYE= -[attachment] -PATH = tests/{{TEST_TYPE}}/gitea-{{TEST_TYPE}}-sqlite/data/attachments - [mailer] ENABLED = true PROTOCOL = dummy -FROM = sqlite-{{TEST_TYPE}}-test@gitea.io +FROM = sqlite-integration-test@gitea.io [service] REGISTER_EMAIL_CONFIRM = false @@ -76,16 +62,12 @@ NO_REPLY_ADDRESS = noreply.example.org [picture] DISABLE_GRAVATAR = false ENABLE_FEDERATED_AVATAR = false -AVATAR_UPLOAD_PATH = tests/{{TEST_TYPE}}/gitea-{{TEST_TYPE}}-sqlite/data/avatars -REPOSITORY_AVATAR_UPLOAD_PATH = tests/{{TEST_TYPE}}/gitea-{{TEST_TYPE}}-sqlite/data/repo-avatars [session] PROVIDER = file -PROVIDER_CONFIG = tests/{{TEST_TYPE}}/gitea-{{TEST_TYPE}}-sqlite/data/sessions [log] MODE = {{TEST_LOGGER}} -ROOT_PATH = {{REPO_TEST_DIR}}sqlite-log ENABLE_SSH_LOG = true logger.xorm.MODE = file @@ -105,9 +87,6 @@ DISABLE_QUERY_AUTH_TOKEN = true [oauth2] JWT_SECRET = KZb_QLUd4fYVyxetjxC4eZkrBgWM2SndOOWDNtgUUko -[lfs] -PATH = tests/{{TEST_TYPE}}/gitea-{{TEST_TYPE}}-sqlite/data/lfs - [packages] ENABLED = true diff --git a/tests/test_utils.go b/tests/test_utils.go index 0cb99a1f2c..34645e5370 100644 --- a/tests/test_utils.go +++ b/tests/test_utils.go @@ -24,11 +24,8 @@ import ( "github.com/stretchr/testify/assert" ) -func InitTest(requireGitea bool) { +func InitTest() { testlogger.Init() - - setting.SetupGiteaTestEnv() - unittest.InitSettingsForTesting() setting.Repository.DefaultBranch = "master" // many test code still assume that default branch is called "master" @@ -38,7 +35,7 @@ func InitTest(requireGitea bool) { setting.LoadDBSetting() if err := storage.Init(); err != nil { - testlogger.Fatalf("Init storage failed: %v\n", err) + testlogger.Panicf("Init storage failed: %v\n", err) } switch { diff --git a/tsconfig.json b/tsconfig.json index 7b16df0196..9b978cf54e 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -44,6 +44,7 @@ "stripInternal": true, "verbatimModuleSyntax": true, "types": [ + "node", "webpack/module", "vitest/globals", "./web_src/js/globals.d.ts", diff --git a/web_src/js/features/codeeditor.ts b/web_src/js/features/codeeditor.ts index 47f378c47a..b2aa9ea1c5 100644 --- a/web_src/js/features/codeeditor.ts +++ b/web_src/js/features/codeeditor.ts @@ -1,4 +1,4 @@ -import tinycolor from 'tinycolor2'; +import {colord} from 'colord'; import {basename, extname, isObject, isDarkTheme} from '../utils.ts'; import {onInputDebounce} from '../utils/dom.ts'; import type MonacoNamespace from 'monaco-editor'; @@ -94,7 +94,7 @@ function updateTheme(monaco: Monaco): void { // https://github.com/microsoft/monaco-editor/issues/2427 // also, monaco can only parse 6-digit hex colors, so we convert the colors to that format const styles = window.getComputedStyle(document.documentElement); - const getColor = (name: string) => tinycolor(styles.getPropertyValue(name).trim()).toString('hex6'); + const getColor = (name: string) => colord(styles.getPropertyValue(name).trim()).alpha(1).toHex(); monaco.editor.defineTheme('gitea', { base: isDarkTheme() ? 'vs-dark' : 'vs', diff --git a/web_src/js/utils/color.ts b/web_src/js/utils/color.ts index 57c909b8a0..096356983a 100644 --- a/web_src/js/utils/color.ts +++ b/web_src/js/utils/color.ts @@ -1,22 +1,21 @@ -import tinycolor from 'tinycolor2'; -import type {ColorInput} from 'tinycolor2'; +import {colord} from 'colord'; +import type {AnyColor} from 'colord'; /** Returns relative luminance for a SRGB color - https://en.wikipedia.org/wiki/Relative_luminance */ // Keep this in sync with modules/util/color.go -function getRelativeLuminance(color: ColorInput): number { - const {r, g, b} = tinycolor(color).toRgb(); +function getRelativeLuminance(color: AnyColor): number { + const {r, g, b} = colord(color).toRgb(); return (0.2126729 * r + 0.7151522 * g + 0.072175 * b) / 255; } -function useLightText(backgroundColor: ColorInput): boolean { +function useLightText(backgroundColor: AnyColor): boolean { return getRelativeLuminance(backgroundColor) < 0.453; } -/** Given a background color, returns a black or white foreground color that the highest - * contrast ratio. */ +/** Given a background color, returns a black or white foreground color with the highest contrast ratio. */ // In the future, the APCA contrast function, or CSS `contrast-color` will be better. // https://github.com/color-js/color.js/blob/eb7b53f7a13bb716ec8b28c7a56f052cd599acd9/src/contrast/APCA.js#L42 -export function contrastColor(backgroundColor: ColorInput): string { +export function contrastColor(backgroundColor: AnyColor): string { return useLightText(backgroundColor) ? '#fff' : '#000'; }