diff --git a/.forgejo/workflows/cascade-setup-end-to-end.yml b/.forgejo/workflows/cascade-setup-end-to-end.yml index 404bbe8fa6..3d5237cd00 100644 --- a/.forgejo/workflows/cascade-setup-end-to-end.yml +++ b/.forgejo/workflows/cascade-setup-end-to-end.yml @@ -12,8 +12,10 @@ # whatever is in the default branch instead # # - after it is merged, double check it works by setting the -# run-end-to-end-test on a pull request (any pull request will doe +# run-end-to-end-test on a pull request (any pull request will do) # +name: end-to-end + on: push: branches: @@ -33,10 +35,9 @@ jobs: run: | echo github.event.pull_request.head.repo.fork = ${{ github.event.pull_request.head.repo.fork }} echo github.event.action = ${{ github.event.action }} - echo github.event.pull_request.merged = ${{ github.event.pull_request.merged }} - echo github.event.pull_request.labels.*.name + echo github.event.label cat <<'EOF' - ${{ toJSON(github.event.pull_request.labels.*.name) }} + ${{ toJSON(github.event.label) }} EOF cat <<'EOF' ${{ toJSON(github.event) }} @@ -47,7 +48,7 @@ jobs: !startsWith(vars.ROLE, 'forgejo-') && ( github.event_name == 'push' || ( - github.event.action == 'label_updated' && contains(github.event.pull_request.labels.*.name, 'run-end-to-end-tests') + github.event.action == 'label_updated' && github.event.label.name == 'run-end-to-end-tests' ) ) runs-on: docker diff --git a/.forgejo/workflows/merge-requirements.yml b/.forgejo/workflows/merge-requirements.yml new file mode 100644 index 0000000000..d9650b66a7 --- /dev/null +++ b/.forgejo/workflows/merge-requirements.yml @@ -0,0 +1,44 @@ +# Copyright 2024 The Forgejo Authors +# SPDX-License-Identifier: MIT + +name: requirements + +on: + pull_request: + types: + - labeled + - edited + - opened + - synchronize + +jobs: + merge-conditions: + runs-on: docker + container: + image: 'code.forgejo.org/oci/node:20-bookworm' + steps: + - name: Debug output + run: | + cat <<'EOF' + ${{ toJSON(github.event) }} + EOF + - name: Missing test label + if: > + !( + contains(toJSON(github.event.pull_request.labels), 'test/present') + || contains(toJSON(github.event.pull_request.labels), 'test/not-needed') + || contains(toJSON(github.event.pull_request.labels), 'test/manual') + ) + run: | + echo "Test label must be set to either 'present', 'not-needed' or 'manual'." + exit 1 + - name: Missing manual test instructions + if: > + ( + contains(toJSON(github.event.pull_request.labels), 'test/manual') + && !contains(toJSON(github.event.pull_request.body), '# Test') + ) + run: | + echo "Manual test label is set. The PR description needs to contain test steps introduced by a heading like:" + echo "# Testing" + exit 1 diff --git a/.forgejo/workflows/renovate.yml b/.forgejo/workflows/renovate.yml index 1f29156069..0a5c4bdade 100644 --- a/.forgejo/workflows/renovate.yml +++ b/.forgejo/workflows/renovate.yml @@ -8,7 +8,9 @@ name: renovate on: push: branches: - - 'renovate/**' # self-test updates + - renovate/** # self-test updates + paths: + - .forgejo/workflows/renovate.yml schedule: - cron: '0 0/2 * * *' workflow_dispatch: @@ -21,9 +23,9 @@ jobs: renovate: if: ${{ secrets.RENOVATE_TOKEN != '' }} - runs-on: docker + runs-on: docker-runner-one container: - image: code.forgejo.org/forgejo-contrib/renovate:39.5.0 + image: code.forgejo.org/forgejo-contrib/renovate:39.9.1 steps: - name: Load renovate repo cache diff --git a/.forgejo/workflows/testing.yml b/.forgejo/workflows/testing.yml index 30d765ab30..03ebf0e983 100644 --- a/.forgejo/workflows/testing.yml +++ b/.forgejo/workflows/testing.yml @@ -82,7 +82,7 @@ jobs: - uses: ./.forgejo/workflows-composite/build-backend - run: | su forgejo -c 'make test-backend test-check' - timeout-minutes: 50 + timeout-minutes: 120 env: RACE_ENABLED: 'true' TAGS: bindata @@ -116,7 +116,7 @@ jobs: separator: '\n' - run: | su forgejo -c 'make generate test-e2e-sqlite' - timeout-minutes: 40 + timeout-minutes: 120 env: USE_REPO_TEST_DIR: 1 PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1 @@ -156,7 +156,7 @@ jobs: - uses: ./.forgejo/workflows-composite/build-backend - run: | su forgejo -c 'make test-remote-cacher test-check' - timeout-minutes: 50 + timeout-minutes: 120 env: RACE_ENABLED: 'true' TAGS: bindata @@ -187,7 +187,7 @@ jobs: - uses: ./.forgejo/workflows-composite/build-backend - run: | su forgejo -c 'make test-mysql-migration test-mysql' - timeout-minutes: 50 + timeout-minutes: 120 env: USE_REPO_TEST_DIR: 1 test-pgsql: @@ -219,7 +219,7 @@ jobs: - uses: ./.forgejo/workflows-composite/build-backend - run: | su forgejo -c 'make test-pgsql-migration test-pgsql' - timeout-minutes: 50 + timeout-minutes: 120 env: RACE_ENABLED: true USE_REPO_TEST_DIR: 1 @@ -240,7 +240,7 @@ jobs: - uses: ./.forgejo/workflows-composite/build-backend - run: | su forgejo -c 'make test-sqlite-migration test-sqlite' - timeout-minutes: 50 + timeout-minutes: 120 env: TAGS: sqlite sqlite_unlock_notify RACE_ENABLED: true diff --git a/.golangci.yml b/.golangci.yml index 4a20269b0e..0678b90bfc 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -77,6 +77,8 @@ linters-settings: - name: unreachable-code - name: var-declaration - name: var-naming + - name: redefines-builtin-id + disabled: true gofumpt: extra-rules: true depguard: diff --git a/Makefile b/Makefile index a95a951792..ae7ed16846 100644 --- a/Makefile +++ b/Makefile @@ -39,7 +39,7 @@ XGO_VERSION := go-1.21.x AIR_PACKAGE ?= github.com/air-verse/air@v1 # renovate: datasource=go EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/v3/cmd/editorconfig-checker@v3.0.3 # renovate: datasource=go GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.7.0 # renovate: datasource=go -GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.61.0 # renovate: datasource=go +GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.62.0 # renovate: datasource=go GXZ_PACKAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.11 # renovate: datasource=go MISSPELL_PACKAGE ?= github.com/golangci/misspell/cmd/misspell@v0.6.0 # renovate: datasource=go SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@v0.31.0 # renovate: datasource=go @@ -49,7 +49,7 @@ GOVULNCHECK_PACKAGE ?= golang.org/x/vuln/cmd/govulncheck@v1 # renovate: datasour DEADCODE_PACKAGE ?= golang.org/x/tools/cmd/deadcode@v0.26.0 # renovate: datasource=go GOMOCK_PACKAGE ?= go.uber.org/mock/mockgen@v0.4.0 # renovate: datasource=go GOPLS_PACKAGE ?= golang.org/x/tools/gopls@v0.16.2 # renovate: datasource=go -RENOVATE_NPM_PACKAGE ?= renovate@39.5.0 # renovate: datasource=docker packageName=code.forgejo.org/forgejo-contrib/renovate +RENOVATE_NPM_PACKAGE ?= renovate@39.9.1 # renovate: datasource=docker packageName=code.forgejo.org/forgejo-contrib/renovate ifeq ($(HAS_GO), yes) CGO_EXTRA_CFLAGS := -DSQLITE_MAX_VARIABLE_NUMBER=32766 @@ -660,6 +660,7 @@ generate-ini-pgsql: -e 's|{{REPO_TEST_DIR}}|${REPO_TEST_DIR}|g' \ -e 's|{{TEST_LOGGER}}|$(or $(TEST_LOGGER),test$(COMMA)file)|g' \ -e 's|{{TEST_TYPE}}|$(or $(TEST_TYPE),integration)|g' \ + -e 's|{{TEST_STORAGE_TYPE}}|$(or $(TEST_STORAGE_TYPE),minio)|g' \ tests/pgsql.ini.tmpl > tests/pgsql.ini .PHONY: test-pgsql diff --git a/contrib/ide/vscode/settings.json b/contrib/ide/vscode/settings.json index 2ec666f3c1..7f7de43622 100644 --- a/contrib/ide/vscode/settings.json +++ b/contrib/ide/vscode/settings.json @@ -1,4 +1,6 @@ { - "go.buildTags": "sqlite,sqlite_unlock_notify", - "go.testFlags": ["-v"] + "go.buildTags": "sqlite,sqlite_unlock_notify", + "go.testFlags": ["-v"], + "go.lintTool": "golangci-lint", + "go.lintFlags": ["--fast"] } diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index f0fd40da5f..70db76cf7f 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -353,16 +353,25 @@ RUN_USER = ; git ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; -;; Database to use. Either "mysql", "postgres", "mssql" or "sqlite3". +;; Database to use. Either "sqlite3", "mySQL" or "postgres". +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; SQLite Configuration +;; +DB_TYPE = sqlite3 +;PATH= ; defaults to data/forgejo.db +;SQLITE_TIMEOUT = ; Query timeout defaults to: 500 +;SQLITE_JOURNAL_MODE = ; defaults to sqlite database default (often DELETE), can be used to enable WAL mode. https://www.sqlite.org/pragma.html#pragma_journal_mode ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; MySQL Configuration ;; -DB_TYPE = mysql -HOST = 127.0.0.1:3306 ; can use socket e.g. /var/run/mysqld/mysqld.sock -NAME = gitea -USER = root +;DB_TYPE = mysql +;HOST = 127.0.0.1:3306 ; can use socket e.g. /var/run/mysqld/mysqld.sock +;NAME = gitea +;USER = root ;PASSWD = ;Use PASSWD = `your password` for quoting if you use special characters in the password. ;SSL_MODE = false ; either "false" (default), "true", or "skip-verify" ;CHARSET_COLLATION = ; Empty as default, Gitea will try to find a case-sensitive collation. Don't change it unless you clearly know what you need. @@ -381,26 +390,6 @@ USER = root ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; -;; SQLite Configuration -;; -;DB_TYPE = sqlite3 -;PATH= ; defaults to data/forgejo.db -;SQLITE_TIMEOUT = ; Query timeout defaults to: 500 -;SQLITE_JOURNAL_MODE = ; defaults to sqlite database default (often DELETE), can be used to enable WAL mode. https://www.sqlite.org/pragma.html#pragma_journal_mode -;; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; -;; MSSQL Configuration -;; -;DB_TYPE = mssql -;HOST = 172.17.0.2:1433 -;NAME = gitea -;USER = SA -;PASSWD = MwantsaSecurePassword1 -;CHARSET_COLLATION = ; Empty as default, Gitea will try to find a case-sensitive collation. Don't change it unless you clearly know what you need. -;; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; ;; Other settings ;; ;; For iterate buffer, default is 50 diff --git a/go.mod b/go.mod index 513f119014..9537d12204 100644 --- a/go.mod +++ b/go.mod @@ -6,10 +6,10 @@ require ( code.forgejo.org/f3/gof3/v3 v3.7.0 code.forgejo.org/forgejo-contrib/go-libravatar v0.0.0-20191008002943-06d1c002b251 code.forgejo.org/forgejo/reply v1.0.2 - code.forgejo.org/go-chi/binding v0.0.0-20241105210225-1f8bf5136720 - code.forgejo.org/go-chi/cache v0.0.0-20240912103640-dcb08fba860d - code.forgejo.org/go-chi/captcha v0.0.0-20240905153133-df43b9250ed5 - code.forgejo.org/go-chi/session v0.0.0-20241017103059-2a992261fc26 + code.forgejo.org/go-chi/binding v1.0.0 + code.forgejo.org/go-chi/cache v1.0.0 + code.forgejo.org/go-chi/captcha v1.0.0 + code.forgejo.org/go-chi/session v1.0.0 code.gitea.io/actions-proto-go v0.4.0 code.gitea.io/gitea-vet v0.2.3 code.gitea.io/sdk/gitea v0.17.1 @@ -100,12 +100,12 @@ require ( github.com/yuin/goldmark v1.7.8 github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc go.uber.org/mock v0.4.0 - golang.org/x/crypto v0.28.0 + golang.org/x/crypto v0.29.0 golang.org/x/image v0.21.0 - golang.org/x/net v0.30.0 + golang.org/x/net v0.31.0 golang.org/x/oauth2 v0.23.0 - golang.org/x/sys v0.26.0 - golang.org/x/text v0.19.0 + golang.org/x/sys v0.27.0 + golang.org/x/text v0.20.0 golang.org/x/tools v0.26.0 google.golang.org/grpc v1.67.1 google.golang.org/protobuf v1.35.1 @@ -281,7 +281,7 @@ require ( go.uber.org/zap v1.27.0 // indirect golang.org/x/exp v0.0.0-20240119083558-1b970713d09a // indirect golang.org/x/mod v0.21.0 // indirect - golang.org/x/sync v0.8.0 // indirect + golang.org/x/sync v0.9.0 // indirect golang.org/x/time v0.5.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect @@ -296,3 +296,5 @@ replace github.com/shurcooL/vfsgen => github.com/lunny/vfsgen v0.0.0-20220105142 replace github.com/nektos/act => code.forgejo.org/forgejo/act v1.21.5 replace github.com/mholt/archiver/v3 => code.forgejo.org/forgejo/archiver/v3 v3.5.1 + +replace github.com/goccy/go-json => github.com/grafana/go-json v0.0.0-20241106155216-71a03f133f5c diff --git a/go.sum b/go.sum index c2af9b3c36..a1c1056623 100644 --- a/go.sum +++ b/go.sum @@ -10,14 +10,14 @@ code.forgejo.org/forgejo/archiver/v3 v3.5.1 h1:UmmbA7D5550uf71SQjarmrn6yKwOGxtEj code.forgejo.org/forgejo/archiver/v3 v3.5.1/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnonssnDhppzS1L4= code.forgejo.org/forgejo/reply v1.0.2 h1:dMhQCHV6/O3L5CLWNTol+dNzDAuyCK88z4J/lCdgFuQ= code.forgejo.org/forgejo/reply v1.0.2/go.mod h1:RyZUfzQLc+fuLIGjTSQWDAJWPiL4WtKXB/FifT5fM7U= -code.forgejo.org/go-chi/binding v0.0.0-20241105210225-1f8bf5136720 h1:DDdvrdov1a6HK0xiJIUTfGh1RpKP0prkHi2guxhDKIU= -code.forgejo.org/go-chi/binding v0.0.0-20241105210225-1f8bf5136720/go.mod h1:fWwqaHj0H1/KeCpBqdvKunflq8pYfciEHI5v3UUeE2E= -code.forgejo.org/go-chi/cache v0.0.0-20240912103640-dcb08fba860d h1:nOu/2GX571t4intmtfvpctS148OqsBYrGUySVm93ifc= -code.forgejo.org/go-chi/cache v0.0.0-20240912103640-dcb08fba860d/go.mod h1:OVlZ/TqDYJ+RUJ+R+J+OLxtlyjo3pbjBeK7LAWAB+Vk= -code.forgejo.org/go-chi/captcha v0.0.0-20240905153133-df43b9250ed5 h1:A7P1liXCpJBHEJ5KIDsF0ujnQ8FQ/aX1UixTW0vGrDQ= -code.forgejo.org/go-chi/captcha v0.0.0-20240905153133-df43b9250ed5/go.mod h1:YLOsiln/arX3egGtxG4QNp49G2CIqP9pqD2VL56obLc= -code.forgejo.org/go-chi/session v0.0.0-20241017103059-2a992261fc26 h1:6XCLWu8A0nPM862Uh68kQmxsBsaQNfPPFwYjzG8M8QE= -code.forgejo.org/go-chi/session v0.0.0-20241017103059-2a992261fc26/go.mod h1:lS76JFHZqGXYJTBHqwZ910UG046hIXAaYIN6J0Lf8sI= +code.forgejo.org/go-chi/binding v1.0.0 h1:EIDJtk9brK7WsT7rvS/D4cxX8XlnhY3LMy8ex1jeHu0= +code.forgejo.org/go-chi/binding v1.0.0/go.mod h1:fWwqaHj0H1/KeCpBqdvKunflq8pYfciEHI5v3UUeE2E= +code.forgejo.org/go-chi/cache v1.0.0 h1:akLfGxNlHcacmtutovNtYFSTMsbdcp5MGjAEsP4pxnE= +code.forgejo.org/go-chi/cache v1.0.0/go.mod h1:OVlZ/TqDYJ+RUJ+R+J+OLxtlyjo3pbjBeK7LAWAB+Vk= +code.forgejo.org/go-chi/captcha v1.0.0 h1:ZKVznXrPfruc1RMavCFBEINGxB3RAYr4I+WQAK8+eP0= +code.forgejo.org/go-chi/captcha v1.0.0/go.mod h1:YLOsiln/arX3egGtxG4QNp49G2CIqP9pqD2VL56obLc= +code.forgejo.org/go-chi/session v1.0.0 h1:1hjLWHpXkb4vs/g9rk/unhRL4AoKEqVUPJ+opI8UO3Y= +code.forgejo.org/go-chi/session v1.0.0/go.mod h1:lS76JFHZqGXYJTBHqwZ910UG046hIXAaYIN6J0Lf8sI= code.gitea.io/actions-proto-go v0.4.0 h1:OsPBPhodXuQnsspG1sQ4eRE1PeoZyofd7+i73zCwnsU= code.gitea.io/actions-proto-go v0.4.0/go.mod h1:mn7Wkqz6JbnTOHQpot3yDeHx+O5C9EGhMEE+htvHBas= code.gitea.io/gitea-vet v0.2.3 h1:gdFmm6WOTM65rE8FUBTRzeQZYzXePKSSB1+r574hWwI= @@ -307,8 +307,6 @@ github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJA github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/ws v1.2.1/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY= -github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= -github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f h1:3BSP1Tbs2djlpprl7wCLuiqMaUh5SJkkzI2gDs+FgLs= github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f/go.mod h1:Pcatq5tYkCW2Q6yrR2VRHlbHpZ/R4/7qyL1TCF7vl14= @@ -383,6 +381,8 @@ github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kX github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo= github.com/gorilla/sessions v1.4.0 h1:kpIYOp/oi6MG/p5PgxApU8srsSw9tuFbt46Lt7auzqQ= github.com/gorilla/sessions v1.4.0/go.mod h1:FLWm50oby91+hl7p/wRxDth9bWSuk0qVL2emc7lT5ik= +github.com/grafana/go-json v0.0.0-20241106155216-71a03f133f5c h1:yKBKEC347YZpgii1KazRCfxHsTaxMqWZzoivM1OTT50= +github.com/grafana/go-json v0.0.0-20241106155216-71a03f133f5c/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/h2non/gock v1.2.0 h1:K6ol8rfrRkUOefooBC8elXoaNGYkpp7y2qcxGG6BzUE= github.com/h2non/gock v1.2.0/go.mod h1:tNhoxHYW2W42cYkYb1WqzdbYIieALC99kpYr7rH/BQk= github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw= @@ -733,8 +733,8 @@ golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2Uz golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= -golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= -golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= +golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ= +golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg= golang.org/x/exp v0.0.0-20240119083558-1b970713d09a h1:Q8/wZp0KX97QFTc2ywcOE0YRjZPVIx+MXInMzdvQqcA= golang.org/x/exp v0.0.0-20240119083558-1b970713d09a/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08= golang.org/x/image v0.21.0 h1:c5qV36ajHpdj4Qi0GnE0jUc/yuo33OLFaa0d+crTD5s= @@ -760,8 +760,8 @@ golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= -golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= +golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo= +golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM= golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -771,8 +771,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= -golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= +golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -801,8 +801,8 @@ golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= -golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= +golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= @@ -812,8 +812,8 @@ golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= -golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24= -golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M= +golang.org/x/term v0.26.0 h1:WEQa6V3Gja/BhNxg540hBip/kkaYtRg3cxg4oXSw4AU= +golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -825,8 +825,8 @@ golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= -golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= +golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/models/activities/user_heatmap_test.go b/models/activities/user_heatmap_test.go index 316ea7d76e..d62565a27c 100644 --- a/models/activities/user_heatmap_test.go +++ b/models/activities/user_heatmap_test.go @@ -96,6 +96,6 @@ func TestGetUserHeatmapDataByUser(t *testing.T) { // Test JSON rendering jsonData, err := json.Marshal(heatmap) require.NoError(t, err) - assert.Equal(t, tc.JSONResult, string(jsonData)) + assert.JSONEq(t, tc.JSONResult, string(jsonData)) } } diff --git a/models/fixtures/repository.yml b/models/fixtures/repository.yml index 51f526f889..f7aaad1f31 100644 --- a/models/fixtures/repository.yml +++ b/models/fixtures/repository.yml @@ -29,7 +29,8 @@ size: 7597 is_fsck_enabled: true close_issues_via_commit_in_any_branch: false - + created_unix: 1731254961 + updated_unix: 1731254961 - id: 2 owner_id: 2 diff --git a/models/project/column_test.go b/models/project/column_test.go index b02a5b540f..fb6dc77126 100644 --- a/models/project/column_test.go +++ b/models/project/column_test.go @@ -5,7 +5,6 @@ package project import ( "fmt" - "strings" "testing" "code.gitea.io/gitea/models/db" @@ -124,5 +123,5 @@ func Test_NewColumn(t *testing.T) { ProjectID: project1.ID, }) require.Error(t, err) - assert.True(t, strings.Contains(err.Error(), "maximum number of columns reached")) + assert.Contains(t, err.Error(), "maximum number of columns reached") } diff --git a/models/unittest/fscopy.go b/models/unittest/fscopy.go index 74b12d5057..5cd871ced6 100644 --- a/models/unittest/fscopy.go +++ b/models/unittest/fscopy.go @@ -4,99 +4,12 @@ package unittest import ( - "errors" - "io" "os" - "path" - "strings" - - "code.gitea.io/gitea/modules/util" ) -// Copy copies file from source to target path. -func Copy(src, dest string) error { - // Gather file information to set back later. - si, err := os.Lstat(src) - if err != nil { - return err - } - - // Handle symbolic link. - if si.Mode()&os.ModeSymlink != 0 { - target, err := os.Readlink(src) - if err != nil { - return err - } - // NOTE: os.Chmod and os.Chtimes don't recognize symbolic link, - // which will lead "no such file or directory" error. - return os.Symlink(target, dest) - } - - sr, err := os.Open(src) - if err != nil { - return err - } - defer sr.Close() - - dw, err := os.Create(dest) - if err != nil { - return err - } - defer dw.Close() - - if _, err = io.Copy(dw, sr); err != nil { - return err - } - - // Set back file information. - if err = os.Chtimes(dest, si.ModTime(), si.ModTime()); err != nil { - return err - } - return os.Chmod(dest, si.Mode()) -} - // CopyDir copy files recursively from source to target directory. // -// The filter accepts a function that process the path info. -// and should return true for need to filter. -// // It returns error when error occurs in underlying functions. -func CopyDir(srcPath, destPath string, filters ...func(filePath string) bool) error { - // Check if target directory exists. - if _, err := os.Stat(destPath); !errors.Is(err, os.ErrNotExist) { - return util.NewAlreadyExistErrorf("file or directory already exists: %s", destPath) - } - - err := os.MkdirAll(destPath, os.ModePerm) - if err != nil { - return err - } - - // Gather directory info. - infos, err := util.StatDir(srcPath, true) - if err != nil { - return err - } - - var filter func(filePath string) bool - if len(filters) > 0 { - filter = filters[0] - } - - for _, info := range infos { - if filter != nil && filter(info) { - continue - } - - curPath := path.Join(destPath, info) - if strings.HasSuffix(info, "/") { - err = os.MkdirAll(curPath, os.ModePerm) - } else { - err = Copy(path.Join(srcPath, info), curPath) - } - if err != nil { - return err - } - } - return nil +func CopyDir(srcPath, destPath string) error { + return os.CopyFS(destPath, os.DirFS(srcPath)) } diff --git a/modules/activitypub/client_test.go b/modules/activitypub/client_test.go index 647a0a59d0..6a771b5a7b 100644 --- a/modules/activitypub/client_test.go +++ b/modules/activitypub/client_test.go @@ -9,7 +9,6 @@ import ( "io" "net/http" "net/http/httptest" - "regexp" "testing" "time" @@ -119,7 +118,7 @@ func TestActivityPubSignedPost(t *testing.T) { expected := "BODY" srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Regexp(t, regexp.MustCompile("^"+setting.Federation.DigestAlgorithm), r.Header.Get("Digest")) + assert.Regexp(t, "^"+setting.Federation.DigestAlgorithm, r.Header.Get("Digest")) assert.Contains(t, r.Header.Get("Signature"), pubID) assert.Equal(t, ActivityStreamsContentType, r.Header.Get("Content-Type")) body, err := io.ReadAll(r.Body) diff --git a/modules/gitgraph/graph.go b/modules/gitgraph/graph.go index 331ad6b218..4db5598015 100644 --- a/modules/gitgraph/graph.go +++ b/modules/gitgraph/graph.go @@ -16,7 +16,7 @@ import ( // GetCommitGraph return a list of commit (GraphItems) from all branches func GetCommitGraph(r *git.Repository, page, maxAllowedColors int, hidePRRefs bool, branches, files []string) (*Graph, error) { - format := "DATA:%D|%H|%ad|%h|%s" + format := "DATA:%D|%H|%aD|%h|%s" if page == 0 { page = 1 diff --git a/modules/gitgraph/graph_models.go b/modules/gitgraph/graph_models.go index 82f460ecf0..8ff1a6e916 100644 --- a/modules/gitgraph/graph_models.go +++ b/modules/gitgraph/graph_models.go @@ -8,6 +8,7 @@ import ( "context" "fmt" "strings" + "time" asymkey_model "code.gitea.io/gitea/models/asymkey" "code.gitea.io/gitea/models/db" @@ -198,6 +199,11 @@ func NewCommit(row, column int, line []byte) (*Commit, error) { if len(data) < 5 { return nil, fmt.Errorf("malformed data section on line %d with commit: %s", row, string(line)) } + // Format is a slight modifcation from RFC1123Z + t, err := time.Parse("Mon, _2 Jan 2006 15:04:05 -0700", string(data[2])) + if err != nil { + return nil, fmt.Errorf("could not parse date of commit: %w", err) + } return &Commit{ Row: row, Column: column, @@ -205,8 +211,8 @@ func NewCommit(row, column int, line []byte) (*Commit, error) { Refs: newRefsFromRefNames(data[0]), // 1 matches git log --pretty=format:%H => commit hash Rev: string(data[1]), - // 2 matches git log --pretty=format:%ad => author date (format respects --date= option) - Date: string(data[2]), + // 2 matches git log --pretty=format:%aD => author date, RFC2822 style + Date: t, // 3 matches git log --pretty=format:%h => abbreviated commit hash ShortRev: string(data[3]), // 4 matches git log --pretty=format:%s => subject @@ -245,7 +251,7 @@ type Commit struct { Column int Refs []git.Reference Rev string - Date string + Date time.Time ShortRev string Subject string } diff --git a/modules/gitgraph/graph_test.go b/modules/gitgraph/graph_test.go index 18d427acd9..e7e437e42d 100644 --- a/modules/gitgraph/graph_test.go +++ b/modules/gitgraph/graph_test.go @@ -241,7 +241,7 @@ func TestParseGlyphs(t *testing.T) { } func TestCommitStringParsing(t *testing.T) { - dataFirstPart := "* DATA:|4e61bacab44e9b4730e44a6615d04098dd3a8eaf|2016-12-20 21:10:41 +0100|4e61bac|" + dataFirstPart := "* DATA:|4e61bacab44e9b4730e44a6615d04098dd3a8eaf|Tue, 20 Dec 2016 21:10:41 +0100|4e61bac|" tests := []struct { shouldPass bool testName string diff --git a/modules/indexer/internal/bleve/query.go b/modules/indexer/internal/bleve/query.go index 90626da4f1..0cfda2d0f8 100644 --- a/modules/indexer/internal/bleve/query.go +++ b/modules/indexer/internal/bleve/query.go @@ -19,6 +19,15 @@ func NumericEqualityQuery(value int64, field string) *query.NumericRangeQuery { return q } +// MatchQuery generates a match query for the given phrase, field and analyzer +func MatchQuery(matchTerm, field, analyzer string, fuzziness int) *query.MatchQuery { + q := bleve.NewMatchQuery(matchTerm) + q.FieldVal = field + q.Analyzer = analyzer + q.Fuzziness = fuzziness + return q +} + // MatchPhraseQuery generates a match phrase query for the given phrase, field and analyzer func MatchPhraseQuery(matchPhrase, field, analyzer string, fuzziness int) *query.MatchPhraseQuery { q := bleve.NewMatchPhraseQuery(matchPhrase) diff --git a/modules/indexer/issues/bleve/bleve.go b/modules/indexer/issues/bleve/bleve.go index b20fcc6f80..5552a9deb0 100644 --- a/modules/indexer/issues/bleve/bleve.go +++ b/modules/indexer/issues/bleve/bleve.go @@ -35,13 +35,7 @@ func addUnicodeNormalizeTokenFilter(m *mapping.IndexMappingImpl) error { }) } -const ( - maxBatchSize = 16 - // fuzzyDenominator determines the levenshtein distance per each character of a keyword - fuzzyDenominator = 4 - // see https://github.com/blevesearch/bleve/issues/1563#issuecomment-786822311 - maxFuzziness = 2 -) +const maxBatchSize = 16 // IndexerData an update to the issue indexer type IndexerData internal.IndexerData @@ -162,16 +156,25 @@ func (b *Indexer) Search(ctx context.Context, options *internal.SearchOptions) ( var queries []query.Query if options.Keyword != "" { - fuzziness := 0 if options.IsFuzzyKeyword { - fuzziness = min(maxFuzziness, len(options.Keyword)/fuzzyDenominator) + fuzziness := 1 + if kl := len(options.Keyword); kl > 3 { + fuzziness = 2 + } else if kl < 2 { + fuzziness = 0 + } + queries = append(queries, bleve.NewDisjunctionQuery([]query.Query{ + inner_bleve.MatchQuery(options.Keyword, "title", issueIndexerAnalyzer, fuzziness), + inner_bleve.MatchQuery(options.Keyword, "content", issueIndexerAnalyzer, fuzziness), + inner_bleve.MatchQuery(options.Keyword, "comments", issueIndexerAnalyzer, fuzziness), + }...)) + } else { + queries = append(queries, bleve.NewDisjunctionQuery([]query.Query{ + inner_bleve.MatchPhraseQuery(options.Keyword, "title", issueIndexerAnalyzer, 0), + inner_bleve.MatchPhraseQuery(options.Keyword, "content", issueIndexerAnalyzer, 0), + inner_bleve.MatchPhraseQuery(options.Keyword, "comments", issueIndexerAnalyzer, 0), + }...)) } - - queries = append(queries, bleve.NewDisjunctionQuery([]query.Query{ - inner_bleve.MatchPhraseQuery(options.Keyword, "title", issueIndexerAnalyzer, fuzziness), - inner_bleve.MatchPhraseQuery(options.Keyword, "content", issueIndexerAnalyzer, fuzziness), - inner_bleve.MatchPhraseQuery(options.Keyword, "comments", issueIndexerAnalyzer, fuzziness), - }...)) } if len(options.RepoIDs) > 0 || options.AllPublic { diff --git a/modules/indexer/issues/dboptions.go b/modules/indexer/issues/dboptions.go index c1f454eeee..e34ef607c2 100644 --- a/modules/indexer/issues/dboptions.go +++ b/modules/indexer/issues/dboptions.go @@ -78,7 +78,9 @@ func ToSearchOptions(keyword string, opts *issues_model.IssuesOptions) *SearchOp searchOpt.Paginator = opts.Paginator switch opts.SortType { - case "", "latest": + case "", "relevance": + searchOpt.SortBy = SortByScore + case "latest": searchOpt.SortBy = SortByCreatedDesc case "oldest": searchOpt.SortBy = SortByCreatedAsc diff --git a/modules/indexer/issues/elasticsearch/elasticsearch.go b/modules/indexer/issues/elasticsearch/elasticsearch.go index 42e709a5e8..24e1ac8855 100644 --- a/modules/indexer/issues/elasticsearch/elasticsearch.go +++ b/modules/indexer/issues/elasticsearch/elasticsearch.go @@ -236,7 +236,7 @@ func (b *Indexer) Search(ctx context.Context, options *internal.SearchOptions) ( } if options.SortBy == "" { - options.SortBy = internal.SortByCreatedAsc + options.SortBy = internal.SortByScore } sortBy := []elastic.Sorter{ parseSortBy(options.SortBy), diff --git a/modules/indexer/issues/indexer.go b/modules/indexer/issues/indexer.go index d7310529fc..7edcb3aa6f 100644 --- a/modules/indexer/issues/indexer.go +++ b/modules/indexer/issues/indexer.go @@ -269,6 +269,7 @@ func IsAvailable(ctx context.Context) bool { type SearchOptions = internal.SearchOptions const ( + SortByScore = internal.SortByScore SortByCreatedDesc = internal.SortByCreatedDesc SortByUpdatedDesc = internal.SortByUpdatedDesc SortByCommentsDesc = internal.SortByCommentsDesc diff --git a/modules/indexer/issues/internal/model.go b/modules/indexer/issues/internal/model.go index 2dfee8b72e..dda2b7a5c1 100644 --- a/modules/indexer/issues/internal/model.go +++ b/modules/indexer/issues/internal/model.go @@ -127,6 +127,7 @@ func (o *SearchOptions) Copy(edit ...func(options *SearchOptions)) *SearchOption type SortBy string const ( + SortByScore SortBy = "-_score" SortByCreatedDesc SortBy = "-created_unix" SortByUpdatedDesc SortBy = "-updated_unix" SortByCommentsDesc SortBy = "-comment_count" diff --git a/modules/indexer/issues/internal/tests/tests.go b/modules/indexer/issues/internal/tests/tests.go index a93b2913e9..e8e6a4e7d1 100644 --- a/modules/indexer/issues/internal/tests/tests.go +++ b/modules/indexer/issues/internal/tests/tests.go @@ -126,6 +126,7 @@ var cases = []*testIndexerCase{ }, SearchOptions: &internal.SearchOptions{ Keyword: "hello", + SortBy: internal.SortByCreatedDesc, }, ExpectedIDs: []int64{1002, 1001, 1000}, ExpectedTotal: 3, @@ -139,6 +140,7 @@ var cases = []*testIndexerCase{ }, SearchOptions: &internal.SearchOptions{ Keyword: "hello world", + SortBy: internal.SortByCreatedDesc, IsFuzzyKeyword: true, }, ExpectedIDs: []int64{1002, 1001, 1000}, @@ -157,6 +159,7 @@ var cases = []*testIndexerCase{ }, SearchOptions: &internal.SearchOptions{ Keyword: "hello", + SortBy: internal.SortByCreatedDesc, RepoIDs: []int64{1, 4}, }, ExpectedIDs: []int64{1006, 1002, 1001}, @@ -175,6 +178,7 @@ var cases = []*testIndexerCase{ }, SearchOptions: &internal.SearchOptions{ Keyword: "hello", + SortBy: internal.SortByCreatedDesc, RepoIDs: []int64{1, 4}, AllPublic: true, }, @@ -597,6 +601,22 @@ var cases = []*testIndexerCase{ } }, }, + { + Name: "SortByScore", + SearchOptions: &internal.SearchOptions{ + Paginator: &db.ListOptionsAll, + SortBy: internal.SortByScore, + }, + Expected: func(t *testing.T, data map[int64]*internal.IndexerData, result *internal.SearchResult) { + assert.Equal(t, len(data), len(result.Hits)) + assert.Equal(t, len(data), int(result.Total)) + for i, v := range result.Hits { + if i < len(result.Hits)-1 { + assert.GreaterOrEqual(t, v.Score, result.Hits[i+1].Score) + } + } + }, + }, { Name: "SortByCreatedAsc", SearchOptions: &internal.SearchOptions{ diff --git a/modules/indexer/issues/meilisearch/meilisearch.go b/modules/indexer/issues/meilisearch/meilisearch.go index 7d18444e6c..7c291198f1 100644 --- a/modules/indexer/issues/meilisearch/meilisearch.go +++ b/modules/indexer/issues/meilisearch/meilisearch.go @@ -208,12 +208,18 @@ func (b *Indexer) Search(ctx context.Context, options *internal.SearchOptions) ( query.And(inner_meilisearch.NewFilterLte("updated_unix", options.UpdatedBeforeUnix.Value())) } - if options.SortBy == "" { - options.SortBy = internal.SortByCreatedAsc - } - sortBy := []string{ - parseSortBy(options.SortBy), - "id:desc", + var sortBy []string + switch options.SortBy { + // sort by relevancy (no explicit sorting) + case internal.SortByScore: + fallthrough + case "": + sortBy = []string{} + default: + sortBy = []string{ + parseSortBy(options.SortBy), + "id:desc", + } } skip, limit := indexer_internal.ParsePaginator(options.Paginator, maxTotalHits) diff --git a/modules/lfs/http_client_test.go b/modules/lfs/http_client_test.go index 534a445310..c9415e7d61 100644 --- a/modules/lfs/http_client_test.go +++ b/modules/lfs/http_client_test.go @@ -267,7 +267,7 @@ func TestHTTPClientDownload(t *testing.T) { return nil }) if len(c.expectederror) > 0 { - assert.True(t, strings.Contains(err.Error(), c.expectederror), "case %d: '%s' should contain '%s'", n, err.Error(), c.expectederror) + assert.Contains(t, err.Error(), c.expectederror, "case %d: '%s' should contain '%s'", n, err.Error(), c.expectederror) } else { require.NoError(t, err, "case %d", n) } @@ -369,7 +369,7 @@ func TestHTTPClientUpload(t *testing.T) { return io.NopCloser(new(bytes.Buffer)), objectError }) if len(c.expectederror) > 0 { - assert.True(t, strings.Contains(err.Error(), c.expectederror), "case %d: '%s' should contain '%s'", n, err.Error(), c.expectederror) + assert.Contains(t, err.Error(), c.expectederror, "case %d: '%s' should contain '%s'", n, err.Error(), c.expectederror) } else { require.NoError(t, err, "case %d", n) } diff --git a/modules/lfs/transferadapter_test.go b/modules/lfs/transferadapter_test.go index 0766e4a0a9..0d663d71f6 100644 --- a/modules/lfs/transferadapter_test.go +++ b/modules/lfs/transferadapter_test.go @@ -97,7 +97,7 @@ func TestBasicTransferAdapter(t *testing.T) { for n, c := range cases { _, err := a.Download(context.Background(), c.link) if len(c.expectederror) > 0 { - assert.True(t, strings.Contains(err.Error(), c.expectederror), "case %d: '%s' should contain '%s'", n, err.Error(), c.expectederror) + assert.Contains(t, err.Error(), c.expectederror, "case %d: '%s' should contain '%s'", n, err.Error(), c.expectederror) } else { require.NoError(t, err, "case %d", n) } @@ -130,7 +130,7 @@ func TestBasicTransferAdapter(t *testing.T) { for n, c := range cases { err := a.Upload(context.Background(), c.link, p, bytes.NewBufferString("dummy")) if len(c.expectederror) > 0 { - assert.True(t, strings.Contains(err.Error(), c.expectederror), "case %d: '%s' should contain '%s'", n, err.Error(), c.expectederror) + assert.Contains(t, err.Error(), c.expectederror, "case %d: '%s' should contain '%s'", n, err.Error(), c.expectederror) } else { require.NoError(t, err, "case %d", n) } @@ -163,7 +163,7 @@ func TestBasicTransferAdapter(t *testing.T) { for n, c := range cases { err := a.Verify(context.Background(), c.link, p) if len(c.expectederror) > 0 { - assert.True(t, strings.Contains(err.Error(), c.expectederror), "case %d: '%s' should contain '%s'", n, err.Error(), c.expectederror) + assert.Contains(t, err.Error(), c.expectederror, "case %d: '%s' should contain '%s'", n, err.Error(), c.expectederror) } else { require.NoError(t, err, "case %d", n) } diff --git a/modules/setting/storage_test.go b/modules/setting/storage_test.go index 271607914c..59135b5911 100644 --- a/modules/setting/storage_test.go +++ b/modules/setting/storage_test.go @@ -445,7 +445,7 @@ MINIO_BASE_PATH = /lfs require.NoError(t, loadLFSFrom(cfg)) assert.EqualValues(t, "my_access_key", LFS.Storage.MinioConfig.AccessKeyID) assert.EqualValues(t, "my_secret_key", LFS.Storage.MinioConfig.SecretAccessKey) - assert.True(t, true, LFS.Storage.MinioConfig.UseSSL) + assert.True(t, LFS.Storage.MinioConfig.UseSSL) assert.EqualValues(t, "/lfs", LFS.Storage.MinioConfig.BasePath) cfg, err = NewConfigProviderFromData(` diff --git a/modules/templates/helper.go b/modules/templates/helper.go index a1f3f1aa2d..55de85646c 100644 --- a/modules/templates/helper.go +++ b/modules/templates/helper.go @@ -20,7 +20,6 @@ import ( "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/svg" "code.gitea.io/gitea/modules/templates/eval" - "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/services/gitdiff" ) @@ -65,16 +64,18 @@ func NewFuncMap() template.FuncMap { // ----------------------------------------------------------------- // time / number / format - "FileSize": FileSizePanic, - "CountFmt": base.FormatNumberSI, - "TimeSince": timeutil.TimeSince, - "TimeSinceUnix": timeutil.TimeSinceUnix, - "DateTime": dateTimeLegacy, // for backward compatibility only, do not use it anymore - "Sec2Time": util.SecToTime, + "FileSize": FileSizePanic, + "CountFmt": base.FormatNumberSI, + "Sec2Time": util.SecToTime, "LoadTimes": func(startTime time.Time) string { return fmt.Sprint(time.Since(startTime).Nanoseconds()/1e6) + "ms" }, + // for backward compatibility only, do not use them anymore + "TimeSince": timeSinceLegacy, + "TimeSinceUnix": timeSinceLegacy, + "DateTime": dateTimeLegacy, + // ----------------------------------------------------------------- // setting "AppName": func() string { diff --git a/modules/templates/util_date.go b/modules/templates/util_date.go index 10f7cdb508..f521b39b79 100644 --- a/modules/templates/util_date.go +++ b/modules/templates/util_date.go @@ -4,35 +4,40 @@ package templates import ( - "context" + "fmt" + "html" "html/template" + "strings" "time" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/modules/translation" ) -type DateUtils struct { - ctx context.Context -} +type DateUtils struct{} -func NewDateUtils(ctx context.Context) *DateUtils { - return &DateUtils{ctx} +func NewDateUtils() *DateUtils { + return (*DateUtils)(nil) // the util is stateless, and we do not need to create an instance } // AbsoluteShort renders in "Jan 01, 2006" format func (du *DateUtils) AbsoluteShort(time any) template.HTML { - return timeutil.DateTime("short", time) + return dateTimeFormat("short", time) } // AbsoluteLong renders in "January 01, 2006" format func (du *DateUtils) AbsoluteLong(time any) template.HTML { - return timeutil.DateTime("long", time) + return dateTimeFormat("long", time) } // FullTime renders in "Jan 01, 2006 20:33:44" format func (du *DateUtils) FullTime(time any) template.HTML { - return timeutil.DateTime("full", time) + return dateTimeFormat("full", time) +} + +func (du *DateUtils) TimeSince(time any) template.HTML { + return TimeSince(time) } // ParseLegacy parses the datetime in legacy format, eg: "2016-01-02" in server's timezone. @@ -56,5 +61,91 @@ func dateTimeLegacy(format string, datetime any, _ ...string) template.HTML { if s, ok := datetime.(string); ok { datetime = parseLegacy(s) } - return timeutil.DateTime(format, datetime) + return dateTimeFormat(format, datetime) +} + +func timeSinceLegacy(time any, _ translation.Locale) template.HTML { + if !setting.IsProd || setting.IsInTesting { + panic("timeSinceLegacy is for backward compatibility only, do not use it in new code") + } + return TimeSince(time) +} + +func anyToTime(any any) (t time.Time, isZero bool) { + switch v := any.(type) { + case nil: + // it is zero + case *time.Time: + if v != nil { + t = *v + } + case time.Time: + t = v + case timeutil.TimeStamp: + t = v.AsTime() + case timeutil.TimeStampNano: + t = v.AsTime() + case int: + t = timeutil.TimeStamp(v).AsTime() + case int64: + t = timeutil.TimeStamp(v).AsTime() + default: + panic(fmt.Sprintf("Unsupported time type %T", any)) + } + return t, t.IsZero() || t.Unix() == 0 +} + +func dateTimeFormat(format string, datetime any) template.HTML { + t, isZero := anyToTime(datetime) + if isZero { + return "-" + } + var textEscaped string + datetimeEscaped := html.EscapeString(t.Format(time.RFC3339)) + if format == "full" { + textEscaped = html.EscapeString(t.Format("2006-01-02 15:04:05 -07:00")) + } else { + textEscaped = html.EscapeString(t.Format("2006-01-02")) + } + + attrs := []string{`weekday=""`, `year="numeric"`} + switch format { + case "short", "long": // date only + attrs = append(attrs, `month="`+format+`"`, `day="numeric"`) + return template.HTML(fmt.Sprintf(`%s`, strings.Join(attrs, " "), datetimeEscaped, textEscaped)) + case "full": // full date including time + attrs = append(attrs, `format="datetime"`, `month="short"`, `day="numeric"`, `hour="numeric"`, `minute="numeric"`, `second="numeric"`, `data-tooltip-content`, `data-tooltip-interactive="true"`) + return template.HTML(fmt.Sprintf(`%s`, strings.Join(attrs, " "), datetimeEscaped, textEscaped)) + default: + panic(fmt.Sprintf("Unsupported format %s", format)) + } +} + +func timeSinceTo(then any, now time.Time) template.HTML { + thenTime, isZero := anyToTime(then) + if isZero { + return "-" + } + + friendlyText := thenTime.Format("2006-01-02 15:04:05 -07:00") + + // document: https://github.com/github/relative-time-element + attrs := `tense="past"` + isFuture := now.Before(thenTime) + if isFuture { + attrs = `tense="future"` + } + + // declare data-tooltip-content attribute to switch from "title" tooltip to "tippy" tooltip + htm := fmt.Sprintf(`%s`, + attrs, thenTime.Format(time.RFC3339), friendlyText) + return template.HTML(htm) +} + +// TimeSince renders relative time HTML given a time +func TimeSince(then any) template.HTML { + if setting.UI.PreferredTimestampTense == "absolute" { + return dateTimeFormat("full", then) + } + return timeSinceTo(then, time.Now()) } diff --git a/modules/templates/util_date_test.go b/modules/templates/util_date_test.go index e3dec5c8db..2f5c79f762 100644 --- a/modules/templates/util_date_test.go +++ b/modules/templates/util_date_test.go @@ -22,7 +22,7 @@ func TestDateTime(t *testing.T) { defer test.MockVariableValue(&setting.DefaultUILocation, testTz)() defer test.MockVariableValue(&setting.IsInTesting, false)() - du := NewDateUtils(nil) + du := NewDateUtils() refTimeStr := "2018-01-01T00:00:00Z" refDateStr := "2018-01-01" @@ -59,3 +59,24 @@ func TestDateTime(t *testing.T) { actual = du.FullTime(refTimeStamp) assert.EqualValues(t, `2017-12-31 19:00:00 -05:00`, actual) } + +func TestTimeSince(t *testing.T) { + testTz, _ := time.LoadLocation("America/New_York") + defer test.MockVariableValue(&setting.DefaultUILocation, testTz)() + defer test.MockVariableValue(&setting.IsInTesting, false)() + + du := NewDateUtils() + assert.EqualValues(t, "-", du.TimeSince(nil)) + + refTimeStr := "2018-01-01T00:00:00Z" + refTime, _ := time.Parse(time.RFC3339, refTimeStr) + + actual := du.TimeSince(refTime) + assert.EqualValues(t, `2018-01-01 00:00:00 +00:00`, actual) + + actual = timeSinceTo(&refTime, time.Time{}) + assert.EqualValues(t, `2018-01-01 00:00:00 +00:00`, actual) + + actual = timeSinceLegacy(timeutil.TimeStampNano(refTime.UnixNano()), nil) + assert.EqualValues(t, `2017-12-31 19:00:00 -05:00`, actual) +} diff --git a/modules/templates/util_string.go b/modules/templates/util_string.go index f23b74786a..685759dcbc 100644 --- a/modules/templates/util_string.go +++ b/modules/templates/util_string.go @@ -19,6 +19,10 @@ func NewStringUtils() *StringUtils { return &stringUtils } +func (su *StringUtils) Make(arr ...string) []string { + return arr +} + func (su *StringUtils) HasPrefix(s any, prefix string) bool { switch v := s.(type) { case string: diff --git a/modules/timeutil/datetime.go b/modules/timeutil/datetime.go deleted file mode 100644 index 664e0320b0..0000000000 --- a/modules/timeutil/datetime.go +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2023 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package timeutil - -import ( - "fmt" - "html" - "html/template" - "strings" - "time" -) - -// DateTime renders an absolute time HTML element by datetime. -func DateTime(format string, datetime any) template.HTML { - if p, ok := datetime.(*time.Time); ok { - datetime = *p - } - if p, ok := datetime.(*TimeStamp); ok { - datetime = *p - } - switch v := datetime.(type) { - case TimeStamp: - datetime = v.AsTime() - case int: - datetime = TimeStamp(v).AsTime() - case int64: - datetime = TimeStamp(v).AsTime() - } - - var datetimeEscaped, textEscaped string - switch v := datetime.(type) { - case nil: - return "-" - case time.Time: - if v.IsZero() || v.Unix() == 0 { - return "-" - } - datetimeEscaped = html.EscapeString(v.Format(time.RFC3339)) - if format == "full" { - textEscaped = html.EscapeString(v.Format("2006-01-02 15:04:05 -07:00")) - } else { - textEscaped = html.EscapeString(v.Format("2006-01-02")) - } - default: - panic(fmt.Sprintf("Unsupported time type %T", datetime)) - } - - attrs := []string{`weekday=""`, `year="numeric"`} - switch format { - case "short", "long": // date only - attrs = append(attrs, `month="`+format+`"`, `day="numeric"`) - return template.HTML(fmt.Sprintf(`%s`, strings.Join(attrs, " "), datetimeEscaped, textEscaped)) - case "full": // full date including time - attrs = append(attrs, `format="datetime"`, `month="short"`, `day="numeric"`, `hour="numeric"`, `minute="numeric"`, `second="numeric"`, `data-tooltip-content`, `data-tooltip-interactive="true"`) - return template.HTML(fmt.Sprintf(`%s`, strings.Join(attrs, " "), datetimeEscaped, textEscaped)) - default: - panic(fmt.Sprintf("Unsupported format %s", format)) - } -} diff --git a/modules/timeutil/since.go b/modules/timeutil/since.go index dba42c793a..2c89ae38d5 100644 --- a/modules/timeutil/since.go +++ b/modules/timeutil/since.go @@ -4,12 +4,9 @@ package timeutil import ( - "fmt" - "html/template" "strings" "time" - "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/translation" ) @@ -81,16 +78,11 @@ func computeTimeDiffFloor(diff int64, lang translation.Locale) (int64, string) { return diff, diffStr } -// MinutesToFriendly returns a user friendly string with number of minutes +// MinutesToFriendly returns a user-friendly string with number of minutes // converted to hours and minutes. func MinutesToFriendly(minutes int, lang translation.Locale) string { duration := time.Duration(minutes) * time.Minute - return TimeSincePro(time.Now().Add(-duration), lang) -} - -// TimeSincePro calculates the time interval and generate full user-friendly string. -func TimeSincePro(then time.Time, lang translation.Locale) string { - return timeSincePro(then, time.Now(), lang) + return timeSincePro(time.Now().Add(-duration), time.Now(), lang) } func timeSincePro(then, now time.Time, lang translation.Locale) string { @@ -114,32 +106,3 @@ func timeSincePro(then, now time.Time, lang translation.Locale) string { } return strings.TrimPrefix(timeStr, ", ") } - -func timeSinceUnix(then, now time.Time, _ translation.Locale) template.HTML { - friendlyText := then.Format("2006-01-02 15:04:05 -07:00") - - // document: https://github.com/github/relative-time-element - attrs := `tense="past"` - isFuture := now.Before(then) - if isFuture { - attrs = `tense="future"` - } - - // declare data-tooltip-content attribute to switch from "title" tooltip to "tippy" tooltip - htm := fmt.Sprintf(`%s`, - attrs, then.Format(time.RFC3339), friendlyText) - return template.HTML(htm) -} - -// TimeSince renders relative time HTML given a time.Time -func TimeSince(then time.Time, lang translation.Locale) template.HTML { - if setting.UI.PreferredTimestampTense == "absolute" { - return DateTime("full", then) - } - return timeSinceUnix(then, time.Now(), lang) -} - -// TimeSinceUnix renders relative time HTML given a TimeStamp -func TimeSinceUnix(then TimeStamp, lang translation.Locale) template.HTML { - return TimeSince(then.AsLocalTime(), lang) -} diff --git a/modules/util/keypair_test.go b/modules/util/keypair_test.go index ec9bca7efa..6c05db779a 100644 --- a/modules/util/keypair_test.go +++ b/modules/util/keypair_test.go @@ -10,7 +10,6 @@ import ( "crypto/sha256" "crypto/x509" "encoding/pem" - "regexp" "testing" "github.com/stretchr/testify/assert" @@ -24,8 +23,8 @@ func TestKeygen(t *testing.T) { assert.NotEmpty(t, priv) assert.NotEmpty(t, pub) - assert.Regexp(t, regexp.MustCompile("^-----BEGIN RSA PRIVATE KEY-----.*"), priv) - assert.Regexp(t, regexp.MustCompile("^-----BEGIN PUBLIC KEY-----.*"), pub) + assert.Regexp(t, "^-----BEGIN RSA PRIVATE KEY-----.*", priv) + assert.Regexp(t, "^-----BEGIN PUBLIC KEY-----.*", pub) } func TestSignUsingKeys(t *testing.T) { diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 8299ba83bb..52d5b2e0a8 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -1586,6 +1586,7 @@ issues.filter_type.mentioning_you = Mentioning you issues.filter_type.review_requested = Review requested issues.filter_type.reviewed_by_you = Reviewed by you issues.filter_sort = Sort +issues.filter_sort.relevance = Relevance issues.filter_sort.latest = Newest issues.filter_sort.oldest = Oldest issues.filter_sort.recentupdate = Recently updated diff --git a/package-lock.json b/package-lock.json index 2c5cc23f27..267b1de595 100644 --- a/package-lock.json +++ b/package-lock.json @@ -37,7 +37,7 @@ "monaco-editor": "0.51.0", "monaco-editor-webpack-plugin": "7.1.0", "pdfobject": "2.3.0", - "postcss": "8.4.47", + "postcss": "8.4.48", "postcss-loader": "8.1.1", "postcss-nesting": "13.0.1", "pretty-ms": "9.0.0", @@ -67,7 +67,7 @@ "@stylistic/eslint-plugin-js": "2.10.1", "@stylistic/stylelint-plugin": "3.1.1", "@typescript-eslint/parser": "8.13.0", - "@vitejs/plugin-vue": "5.1.4", + "@vitejs/plugin-vue": "5.1.5", "@vitest/coverage-v8": "2.1.4", "@vitest/eslint-plugin": "1.1.7", "@vue/test-utils": "2.4.6", @@ -5085,9 +5085,9 @@ } }, "node_modules/@vitejs/plugin-vue": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.1.4.tgz", - "integrity": "sha512-N2XSI2n3sQqp5w7Y/AN/L2XDjBIRGqXko+eDp42sydYSBeJuSm5a1sLf8zakmo8u7tA8NmBgoDLA1HeOESjp9A==", + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.1.5.tgz", + "integrity": "sha512-dlnib73G05CDBAUR/YpuZcQQ47fpjihnnNouAAqN62z+oqSsWJ+kh52GRzIxpkgFG3q11eXK7Di7RMmoCwISZA==", "dev": true, "license": "MIT", "engines": { @@ -13083,9 +13083,9 @@ } }, "node_modules/postcss": { - "version": "8.4.47", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz", - "integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==", + "version": "8.4.48", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.48.tgz", + "integrity": "sha512-GCRK8F6+Dl7xYniR5a4FYbpBzU8XnZVeowqsQFYdcXuSbChgiks7qybSkbvnaeqv0G0B+dd9/jJgH8kkLDQeEA==", "funding": [ { "type": "opencollective", @@ -13103,7 +13103,7 @@ "license": "MIT", "dependencies": { "nanoid": "^3.3.7", - "picocolors": "^1.1.0", + "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, "engines": { diff --git a/package.json b/package.json index 82050bbd84..ea2a132df5 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "monaco-editor": "0.51.0", "monaco-editor-webpack-plugin": "7.1.0", "pdfobject": "2.3.0", - "postcss": "8.4.47", + "postcss": "8.4.48", "postcss-loader": "8.1.1", "postcss-nesting": "13.0.1", "pretty-ms": "9.0.0", @@ -66,7 +66,7 @@ "@stylistic/eslint-plugin-js": "2.10.1", "@stylistic/stylelint-plugin": "3.1.1", "@typescript-eslint/parser": "8.13.0", - "@vitejs/plugin-vue": "5.1.4", + "@vitejs/plugin-vue": "5.1.5", "@vitest/coverage-v8": "2.1.4", "@vitest/eslint-plugin": "1.1.7", "@vue/test-utils": "2.4.6", diff --git a/renovate.json b/renovate.json index 28cb82e2df..cd927797f5 100644 --- a/renovate.json +++ b/renovate.json @@ -83,6 +83,12 @@ "matchUpdateTypes": ["minor", "patch"], "groupName": "postcss" }, + { + "description": "Group Forgejo go-chi packages", + "matchUpdateTypes": ["minor", "patch", "digest"], + "matchPackageNames": ["code.forgejo.org/go-chi/**"], + "groupName": "forgejo go-chi packages" + }, { "description": "Split minor and patch updates", "matchPackageNames": [ diff --git a/routers/web/repo/blame.go b/routers/web/repo/blame.go index eea3d4dc00..4f962d4c19 100644 --- a/routers/web/repo/blame.go +++ b/routers/web/repo/blame.go @@ -17,7 +17,6 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/templates" - "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/services/context" files_service "code.gitea.io/gitea/services/repository/files" @@ -254,7 +253,7 @@ func renderBlame(ctx *context.Context, blameParts []*git.BlamePart, commitNames commitCnt++ // User avatar image - commitSince := timeutil.TimeSinceUnix(timeutil.TimeStamp(commit.Author.When.Unix()), ctx.Locale) + commitSince := templates.TimeSince(commit.Author.When) var avatar string if commit.User != nil { diff --git a/routers/web/repo/issue_content_history.go b/routers/web/repo/issue_content_history.go index 16b250abda..4ce76b2bb9 100644 --- a/routers/web/repo/issue_content_history.go +++ b/routers/web/repo/issue_content_history.go @@ -14,7 +14,6 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/templates" - "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/services/context" "github.com/sergi/go-diff/diffmatchpatch" @@ -73,10 +72,10 @@ func GetContentHistoryList(ctx *context.Context) { class := avatars.DefaultAvatarClass + " tw-mr-2" name := html.EscapeString(username) avatarHTML := string(templates.AvatarHTML(src, 28, class, username)) - timeSinceText := string(timeutil.TimeSinceUnix(item.EditedUnix, ctx.Locale)) + timeSinceHTML := string(templates.TimeSince(item.EditedUnix)) results = append(results, map[string]any{ - "name": avatarHTML + "" + name + " " + actionText + " " + timeSinceText, + "name": avatarHTML + "" + name + " " + actionText + " " + timeSinceHTML, "value": item.HistoryID, }) } diff --git a/services/context/context.go b/services/context/context.go index 65796c3ee7..91e7b1849d 100644 --- a/services/context/context.go +++ b/services/context/context.go @@ -102,7 +102,6 @@ func NewTemplateContextForWeb(ctx *Context) TemplateContext { tmplCtx := NewTemplateContext(ctx) tmplCtx["Locale"] = ctx.Base.Locale tmplCtx["AvatarUtils"] = templates.NewAvatarUtils(ctx) - tmplCtx["DateUtils"] = templates.NewDateUtils(ctx) return tmplCtx } diff --git a/services/issue/pull.go b/services/issue/pull.go index c5a12ce7c4..896802108d 100644 --- a/services/issue/pull.go +++ b/services/issue/pull.go @@ -51,14 +51,14 @@ func PullRequestCodeOwnersReview(ctx context.Context, issue *issues_model.Issue, return nil, err } - if pr.HeadRepo.IsFork { - return nil, nil - } - if err := pr.LoadBaseRepo(ctx); err != nil { return nil, err } + if pr.BaseRepo.IsFork { + return nil, nil + } + repo, err := gitrepo.OpenRepository(ctx, pr.BaseRepo) if err != nil { return nil, err diff --git a/services/repository/contributors_graph_test.go b/services/repository/contributors_graph_test.go index 8cfe69d284..3f8d614501 100644 --- a/services/repository/contributors_graph_test.go +++ b/services/repository/contributors_graph_test.go @@ -43,7 +43,7 @@ func TestRepository_ContributorsGraph(t *testing.T) { dataString, isData := mockCache.Get("key2").(string) assert.True(t, isData) // Verify that JSON is actually stored in the cache. - assert.EqualValues(t, `{"ethantkoenig@gmail.com":{"name":"Ethan Koenig","login":"","avatar_link":"https://secure.gravatar.com/avatar/b42fb195faa8c61b8d88abfefe30e9e3?d=identicon","home_link":"","total_commits":1,"weeks":{"1511654400000":{"week":1511654400000,"additions":3,"deletions":0,"commits":1}}},"jimmy.praet@telenet.be":{"name":"Jimmy Praet","login":"","avatar_link":"https://secure.gravatar.com/avatar/93c49b7c89eb156971d11161c9b52795?d=identicon","home_link":"","total_commits":1,"weeks":{"1624752000000":{"week":1624752000000,"additions":2,"deletions":0,"commits":1}}},"jon@allspice.io":{"name":"Jon","login":"","avatar_link":"https://secure.gravatar.com/avatar/00388ce725e6886f3e07c3733007289b?d=identicon","home_link":"","total_commits":1,"weeks":{"1607817600000":{"week":1607817600000,"additions":10,"deletions":0,"commits":1}}},"total":{"name":"Total","login":"","avatar_link":"","home_link":"","total_commits":3,"weeks":{"1511654400000":{"week":1511654400000,"additions":3,"deletions":0,"commits":1},"1607817600000":{"week":1607817600000,"additions":10,"deletions":0,"commits":1},"1624752000000":{"week":1624752000000,"additions":2,"deletions":0,"commits":1}}}}`, dataString) + assert.JSONEq(t, `{"ethantkoenig@gmail.com":{"name":"Ethan Koenig","login":"","avatar_link":"https://secure.gravatar.com/avatar/b42fb195faa8c61b8d88abfefe30e9e3?d=identicon","home_link":"","total_commits":1,"weeks":{"1511654400000":{"week":1511654400000,"additions":3,"deletions":0,"commits":1}}},"jimmy.praet@telenet.be":{"name":"Jimmy Praet","login":"","avatar_link":"https://secure.gravatar.com/avatar/93c49b7c89eb156971d11161c9b52795?d=identicon","home_link":"","total_commits":1,"weeks":{"1624752000000":{"week":1624752000000,"additions":2,"deletions":0,"commits":1}}},"jon@allspice.io":{"name":"Jon","login":"","avatar_link":"https://secure.gravatar.com/avatar/00388ce725e6886f3e07c3733007289b?d=identicon","home_link":"","total_commits":1,"weeks":{"1607817600000":{"week":1607817600000,"additions":10,"deletions":0,"commits":1}}},"total":{"name":"Total","login":"","avatar_link":"","home_link":"","total_commits":3,"weeks":{"1511654400000":{"week":1511654400000,"additions":3,"deletions":0,"commits":1},"1607817600000":{"week":1607817600000,"additions":10,"deletions":0,"commits":1},"1624752000000":{"week":1624752000000,"additions":2,"deletions":0,"commits":1}}}}`, dataString) var data map[string]*ContributorData require.NoError(t, json.Unmarshal([]byte(dataString), &data)) diff --git a/templates/admin/auth/list.tmpl b/templates/admin/auth/list.tmpl index 5b5affad8a..c162b7b74d 100644 --- a/templates/admin/auth/list.tmpl +++ b/templates/admin/auth/list.tmpl @@ -26,8 +26,8 @@ {{.Name}} {{.TypeName}} {{if .IsActive}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}} - {{ctx.DateUtils.AbsoluteShort .UpdatedUnix}} - {{ctx.DateUtils.AbsoluteShort .CreatedUnix}} + {{DateUtils.AbsoluteShort .UpdatedUnix}} + {{DateUtils.AbsoluteShort .CreatedUnix}} {{svg "octicon-pencil"}} {{end}} diff --git a/templates/admin/cron.tmpl b/templates/admin/cron.tmpl index 64ae7858ba..ee37f6ca75 100644 --- a/templates/admin/cron.tmpl +++ b/templates/admin/cron.tmpl @@ -23,8 +23,8 @@ {{ctx.Locale.Tr (printf "admin.dashboard.%s" .Name)}} {{.Spec}} - {{ctx.DateUtils.FullTime .Next}} - {{if gt .Prev.Year 1}}{{ctx.DateUtils.FullTime .Prev}}{{else}}-{{end}} + {{DateUtils.FullTime .Next}} + {{if gt .Prev.Year 1}}{{DateUtils.FullTime .Prev}}{{else}}-{{end}} {{.ExecTimes}} {{if eq .Status ""}}—{{else if eq .Status "finished"}}{{svg "octicon-check" 16}}{{else}}{{svg "octicon-x" 16}}{{end}} diff --git a/templates/admin/notice.tmpl b/templates/admin/notice.tmpl index 2db0384f6d..04a0b64432 100644 --- a/templates/admin/notice.tmpl +++ b/templates/admin/notice.tmpl @@ -21,7 +21,7 @@ {{.ID}} {{ctx.Locale.Tr .TrStr}} {{.Description}} - {{ctx.DateUtils.AbsoluteShort .CreatedUnix}} + {{DateUtils.AbsoluteShort .CreatedUnix}} {{svg "octicon-note" 16}} {{end}} diff --git a/templates/admin/org/list.tmpl b/templates/admin/org/list.tmpl index 6a6dc14609..d0805c85bc 100644 --- a/templates/admin/org/list.tmpl +++ b/templates/admin/org/list.tmpl @@ -63,7 +63,7 @@ {{.NumTeams}} {{.NumMembers}} {{.NumRepos}} - {{ctx.DateUtils.AbsoluteShort .CreatedUnix}} + {{DateUtils.AbsoluteShort .CreatedUnix}} {{svg "octicon-pencil"}} {{end}} diff --git a/templates/admin/packages/list.tmpl b/templates/admin/packages/list.tmpl index 9cc08772b7..aa38731d4f 100644 --- a/templates/admin/packages/list.tmpl +++ b/templates/admin/packages/list.tmpl @@ -71,7 +71,7 @@ {{end}} {{ctx.Locale.TrSize .CalculateBlobSize}} - {{ctx.DateUtils.AbsoluteShort .Version.CreatedUnix}} + {{DateUtils.AbsoluteShort .Version.CreatedUnix}} {{svg "octicon-trash"}} {{end}} diff --git a/templates/admin/repo/list.tmpl b/templates/admin/repo/list.tmpl index 992933154d..c4924c3fac 100644 --- a/templates/admin/repo/list.tmpl +++ b/templates/admin/repo/list.tmpl @@ -82,8 +82,8 @@ {{.NumIssues}} {{ctx.Locale.TrSize .GitSize}} {{ctx.Locale.TrSize .LFSSize}} - {{ctx.DateUtils.AbsoluteShort .UpdatedUnix}} - {{ctx.DateUtils.AbsoluteShort .CreatedUnix}} + {{DateUtils.AbsoluteShort .UpdatedUnix}} + {{DateUtils.AbsoluteShort .CreatedUnix}} {{svg "octicon-trash"}} {{end}} diff --git a/templates/admin/stacktrace-row.tmpl b/templates/admin/stacktrace-row.tmpl index 694bf56d96..97c361ff90 100644 --- a/templates/admin/stacktrace-row.tmpl +++ b/templates/admin/stacktrace-row.tmpl @@ -13,7 +13,7 @@
{{.Process.Description}}
-
{{if ne .Process.Type "none"}}{{TimeSince .Process.Start ctx.Locale}}{{end}}
+
{{if ne .Process.Type "none"}}{{DateUtils.TimeSince .Process.Start}}{{end}}
{{if or (eq .Process.Type "request") (eq .Process.Type "normal")}} diff --git a/templates/admin/user/list.tmpl b/templates/admin/user/list.tmpl index 42879d7917..9b3447f44a 100644 --- a/templates/admin/user/list.tmpl +++ b/templates/admin/user/list.tmpl @@ -96,9 +96,9 @@ {{if .IsActive}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}} {{if .IsRestricted}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}} {{if index $.UsersTwoFaStatus .ID}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}} - {{ctx.DateUtils.AbsoluteShort .CreatedUnix}} + {{DateUtils.AbsoluteShort .CreatedUnix}} {{if .LastLoginUnix}} - {{ctx.DateUtils.AbsoluteShort .LastLoginUnix}} + {{DateUtils.AbsoluteShort .LastLoginUnix}} {{else}} {{ctx.Locale.Tr "admin.users.never_login"}} {{end}} diff --git a/templates/devtest/gitea-ui.tmpl b/templates/devtest/gitea-ui.tmpl index 8c5db4d887..5490f71784 100644 --- a/templates/devtest/gitea-ui.tmpl +++ b/templates/devtest/gitea-ui.tmpl @@ -167,13 +167,13 @@

TimeSince

-
Now: {{TimeSince .TimeNow ctx.Locale}}
-
5s past: {{TimeSince .TimePast5s ctx.Locale}}
-
5s future: {{TimeSince .TimeFuture5s ctx.Locale}}
-
2m past: {{TimeSince .TimePast2m ctx.Locale}}
-
2m future: {{TimeSince .TimeFuture2m ctx.Locale}}
-
1y past: {{TimeSince .TimePast1y ctx.Locale}}
-
1y future: {{TimeSince .TimeFuture1y ctx.Locale}}
+
Now: {{DateUtils.TimeSince .TimeNow}}
+
5s past: {{DateUtils.TimeSince .TimePast5s}}
+
5s future: {{DateUtils.TimeSince .TimeFuture5s}}
+
2m past: {{DateUtils.TimeSince .TimePast2m}}
+
2m future: {{DateUtils.TimeSince .TimeFuture2m}}
+
1y past: {{DateUtils.TimeSince .TimePast1y}}
+
1y future: {{DateUtils.TimeSince .TimeFuture1y}}
diff --git a/templates/explore/repo_list.tmpl b/templates/explore/repo_list.tmpl index 59bc6c8a95..f11f2e94ef 100644 --- a/templates/explore/repo_list.tmpl +++ b/templates/explore/repo_list.tmpl @@ -62,7 +62,7 @@ {{end}}
{{end}} -
{{ctx.Locale.Tr "org.repo_updated" (TimeSinceUnix .UpdatedUnix ctx.Locale)}}
+
{{ctx.Locale.Tr "org.repo_updated" (DateUtils.TimeSince .UpdatedUnix)}}
{{else}} diff --git a/templates/explore/user_list.tmpl b/templates/explore/user_list.tmpl index ff46f13c17..4128a489aa 100644 --- a/templates/explore/user_list.tmpl +++ b/templates/explore/user_list.tmpl @@ -21,7 +21,7 @@ {{.Email}} {{end}} - {{svg "octicon-calendar"}}{{ctx.Locale.Tr "user.joined_on" (ctx.DateUtils.AbsoluteShort .CreatedUnix)}} + {{svg "octicon-calendar"}}{{ctx.Locale.Tr "user.joined_on" (DateUtils.AbsoluteShort .CreatedUnix)}} diff --git a/templates/package/shared/cleanup_rules/preview.tmpl b/templates/package/shared/cleanup_rules/preview.tmpl index ced1e5c11b..da034fec7a 100644 --- a/templates/package/shared/cleanup_rules/preview.tmpl +++ b/templates/package/shared/cleanup_rules/preview.tmpl @@ -22,7 +22,7 @@ {{.Version.Version}} {{.Creator.Name}} {{ctx.Locale.TrSize .CalculateBlobSize}} - {{ctx.DateUtils.AbsoluteShort .Version.CreatedUnix}} + {{DateUtils.AbsoluteShort .Version.CreatedUnix}} {{else}} diff --git a/templates/package/shared/list.tmpl b/templates/package/shared/list.tmpl index 36f8bc1522..19b41d0bc8 100644 --- a/templates/package/shared/list.tmpl +++ b/templates/package/shared/list.tmpl @@ -24,7 +24,7 @@ {{svg .Package.Type.SVGName 16}} {{.Package.Type.Name}}
- {{$timeStr := TimeSinceUnix .Version.CreatedUnix ctx.Locale}} + {{$timeStr := DateUtils.TimeSince .Version.CreatedUnix}} {{$hasRepositoryAccess := false}} {{if .Repository}} {{$hasRepositoryAccess = index $.RepositoryAccessMap .Repository.ID}} diff --git a/templates/package/shared/versionlist.tmpl b/templates/package/shared/versionlist.tmpl index e5c568e059..7a1059e262 100644 --- a/templates/package/shared/versionlist.tmpl +++ b/templates/package/shared/versionlist.tmpl @@ -25,7 +25,7 @@
{{.Version.LowerVersion}}
- {{ctx.Locale.Tr "packages.published_by" (TimeSinceUnix .Version.CreatedUnix ctx.Locale) .Creator.HomeLink .Creator.GetDisplayName}} + {{ctx.Locale.Tr "packages.published_by" (DateUtils.TimeSince .Version.CreatedUnix) .Creator.HomeLink .Creator.GetDisplayName}}
diff --git a/templates/package/view.tmpl b/templates/package/view.tmpl index 59e4e53f12..170f38388d 100644 --- a/templates/package/view.tmpl +++ b/templates/package/view.tmpl @@ -8,7 +8,7 @@

{{.PackageDescriptor.Package.Name}} ({{.PackageDescriptor.Version.Version}})

- {{$timeStr := TimeSinceUnix .PackageDescriptor.Version.CreatedUnix ctx.Locale}} + {{$timeStr := DateUtils.TimeSince .PackageDescriptor.Version.CreatedUnix}} {{if .HasRepositoryAccess}} {{ctx.Locale.Tr "packages.published_by_in" $timeStr .PackageDescriptor.Creator.HomeLink .PackageDescriptor.Creator.GetDisplayName .PackageDescriptor.Repository.Link .PackageDescriptor.Repository.FullName}} {{else}} @@ -48,7 +48,7 @@ {{if .HasRepositoryAccess}}
{{svg "octicon-repo" 16 "tw-mr-2"}} {{.PackageDescriptor.Repository.FullName}}
{{end}} -
{{svg "octicon-calendar" 16 "tw-mr-2"}} {{TimeSinceUnix .PackageDescriptor.Version.CreatedUnix ctx.Locale}}
+
{{svg "octicon-calendar" 16 "tw-mr-2"}} {{DateUtils.TimeSince .PackageDescriptor.Version.CreatedUnix}}
{{svg "octicon-download" 16 "tw-mr-2"}} {{.PackageDescriptor.Version.DownloadCount}}
{{template "package/metadata/alpine" .}} {{template "package/metadata/arch" .}} @@ -94,7 +94,7 @@ {{range .LatestVersions}}
{{.Version}} - {{ctx.DateUtils.AbsoluteShort .CreatedUnix}} + {{DateUtils.AbsoluteShort .CreatedUnix}}
{{end}}
diff --git a/templates/repo/actions/runs_list.tmpl b/templates/repo/actions/runs_list.tmpl index 7bab492d7b..ef764fa357 100644 --- a/templates/repo/actions/runs_list.tmpl +++ b/templates/repo/actions/runs_list.tmpl @@ -33,7 +33,7 @@ {{.PrettyRef}} {{end}}
-
{{svg "octicon-calendar" 16}}{{TimeSinceUnix .Updated ctx.Locale}}
+
{{svg "octicon-calendar" 16}}{{DateUtils.TimeSince .Updated}}
{{svg "octicon-stopwatch" 16}}{{.Duration}}
diff --git a/templates/repo/branch/list.tmpl b/templates/repo/branch/list.tmpl index f5bffb097e..c60017ba87 100644 --- a/templates/repo/branch/list.tmpl +++ b/templates/repo/branch/list.tmpl @@ -27,7 +27,7 @@ {{template "repo/commit_statuses" dict "Status" (index $.CommitStatus .DefaultBranchBranch.DBBranch.CommitID) "Statuses" (index $.CommitStatuses .DefaultBranchBranch.DBBranch.CommitID)}} -

{{svg "octicon-git-commit" 16 "tw-mr-1"}}{{ShortSha .DefaultBranchBranch.DBBranch.CommitID}} · {{RenderCommitMessage $.Context .DefaultBranchBranch.DBBranch.CommitMessage (.Repository.ComposeMetas ctx)}} · {{ctx.Locale.Tr "org.repo_updated" (TimeSince .DefaultBranchBranch.DBBranch.CommitTime.AsTime ctx.Locale)}} {{if .DefaultBranchBranch.DBBranch.Pusher}}  {{template "shared/user/avatarlink" dict "user" .DefaultBranchBranch.DBBranch.Pusher}}{{template "shared/user/namelink" .DefaultBranchBranch.DBBranch.Pusher}}{{end}}

+

{{svg "octicon-git-commit" 16 "tw-mr-1"}}{{ShortSha .DefaultBranchBranch.DBBranch.CommitID}} · {{RenderCommitMessage $.Context .DefaultBranchBranch.DBBranch.CommitMessage (.Repository.ComposeMetas ctx)}} · {{ctx.Locale.Tr "org.repo_updated" (DateUtils.TimeSince .DefaultBranchBranch.DBBranch.CommitTime)}}{{if .DefaultBranchBranch.DBBranch.Pusher}}  {{template "shared/user/avatarlink" dict "user" .DefaultBranchBranch.DBBranch.Pusher}}{{template "shared/user/namelink" .DefaultBranchBranch.DBBranch.Pusher}}{{end}}

{{if and $.IsWriter (not $.Repository.IsArchived) (not .IsDeleted)}} @@ -92,7 +92,7 @@ {{.DBBranch.Name}} -

{{ctx.Locale.Tr "repo.branch.deleted_by" .DBBranch.DeletedBy.Name}} {{TimeSinceUnix .DBBranch.DeletedUnix ctx.Locale}}

+

{{ctx.Locale.Tr "repo.branch.deleted_by" .DBBranch.DeletedBy.Name}} {{DateUtils.TimeSince .DBBranch.DeletedUnix}}

{{else}}
{{.DBBranch.Name}} @@ -102,7 +102,7 @@ {{template "repo/commit_statuses" dict "Status" (index $.CommitStatus .DBBranch.CommitID) "Statuses" (index $.CommitStatuses .DBBranch.CommitID)}}
-

{{svg "octicon-git-commit" 16 "tw-mr-1"}}{{ShortSha .DBBranch.CommitID}} · {{RenderCommitMessage $.Context .DBBranch.CommitMessage ($.Repository.ComposeMetas ctx)}} · {{ctx.Locale.Tr "org.repo_updated" (TimeSince .DBBranch.CommitTime.AsTime ctx.Locale)}} {{if .DBBranch.Pusher}}  {{template "shared/user/avatarlink" dict "user" .DBBranch.Pusher}}  {{template "shared/user/namelink" .DBBranch.Pusher}}{{end}}

+

{{svg "octicon-git-commit" 16 "tw-mr-1"}}{{ShortSha .DBBranch.CommitID}} · {{RenderCommitMessage $.Context .DBBranch.CommitMessage ($.Repository.ComposeMetas ctx)}} · {{ctx.Locale.Tr "org.repo_updated" (DateUtils.TimeSince .DBBranch.CommitTime)}}{{if .DBBranch.Pusher}}  {{template "shared/user/avatarlink" dict "user" .DBBranch.Pusher}}  {{template "shared/user/namelink" .DBBranch.Pusher}}{{end}}

{{end}} diff --git a/templates/repo/code/recently_pushed_new_branches.tmpl b/templates/repo/code/recently_pushed_new_branches.tmpl index d996acc5b2..dd663762db 100644 --- a/templates/repo/code/recently_pushed_new_branches.tmpl +++ b/templates/repo/code/recently_pushed_new_branches.tmpl @@ -1,7 +1,7 @@ {{range .RecentlyPushedNewBranches}}
- {{$timeSince := TimeSince .CommitTime.AsTime ctx.Locale}} + {{$timeSince := DateUtils.TimeSince .CommitTime}} {{$repo := .GetRepo $.Context}} {{$name := .Name}} {{if ne $repo.ID $.Repository.ID}} diff --git a/templates/repo/commit_page.tmpl b/templates/repo/commit_page.tmpl index 96ce8cf747..a25b450dbe 100644 --- a/templates/repo/commit_page.tmpl +++ b/templates/repo/commit_page.tmpl @@ -152,7 +152,7 @@ {{ctx.AvatarUtils.AvatarByEmail .Commit.Author.Email .Commit.Author.Email 28 "tw-mr-2"}} {{.Commit.Author.Name}} {{end}} - {{TimeSince .Commit.Author.When ctx.Locale}} + {{DateUtils.TimeSince .Commit.Author.When}} {{if or (ne .Commit.Committer.Name .Commit.Author.Name) (ne .Commit.Committer.Email .Commit.Author.Email)}} • {{ctx.Locale.Tr "repo.diff.committed_by"}} @@ -274,7 +274,7 @@ {{else}} {{.NoteCommit.Author.Name}} {{end}} - {{TimeSince .NoteCommit.Author.When ctx.Locale}} + {{DateUtils.TimeSince .NoteCommit.Author.When}}
{{.NoteRendered | SanitizeHTML}}
diff --git a/templates/repo/commits_list.tmpl b/templates/repo/commits_list.tmpl index c8c695e332..b23de20583 100644 --- a/templates/repo/commits_list.tmpl +++ b/templates/repo/commits_list.tmpl @@ -74,9 +74,9 @@ {{end}} {{if .Committer}} - {{TimeSince .Committer.When ctx.Locale}} + {{DateUtils.TimeSince .Committer.When}} {{else}} - {{TimeSince .Author.When ctx.Locale}} + {{DateUtils.TimeSince .Author.When}} {{end}} diff --git a/templates/repo/diff/comments.tmpl b/templates/repo/diff/comments.tmpl index e2597af0e3..b36f20269e 100644 --- a/templates/repo/diff/comments.tmpl +++ b/templates/repo/diff/comments.tmpl @@ -1,6 +1,6 @@ {{range .comments}} -{{$createdStr:= TimeSinceUnix .CreatedUnix ctx.Locale}} +{{$createdStr:= DateUtils.TimeSince .CreatedUnix}}
{{if .OriginalAuthor}} {{ctx.AvatarUtils.Avatar nil}} diff --git a/templates/repo/diff/compare.tmpl b/templates/repo/diff/compare.tmpl index 26c6b77971..612d08ec4f 100644 --- a/templates/repo/diff/compare.tmpl +++ b/templates/repo/diff/compare.tmpl @@ -212,7 +212,7 @@ {{if .Repository.ArchivedUnix.IsZero}} {{ctx.Locale.Tr "repo.archive.title"}} {{else}} - {{ctx.Locale.Tr "repo.archive.title_date" (ctx.DateUtils.AbsoluteLong .Repository.ArchivedUnix)}} + {{ctx.Locale.Tr "repo.archive.title_date" (DateUtils.AbsoluteLong .Repository.ArchivedUnix)}} {{end}}
{{end}} diff --git a/templates/repo/empty.tmpl b/templates/repo/empty.tmpl index d7f05223af..d3a81bc51d 100644 --- a/templates/repo/empty.tmpl +++ b/templates/repo/empty.tmpl @@ -10,7 +10,7 @@ {{if .Repository.ArchivedUnix.IsZero}} {{ctx.Locale.Tr "repo.archive.title"}} {{else}} - {{ctx.Locale.Tr "repo.archive.title_date" (ctx.DateUtils.AbsoluteLong .Repository.ArchivedUnix)}} + {{ctx.Locale.Tr "repo.archive.title_date" (DateUtils.AbsoluteLong .Repository.ArchivedUnix)}} {{end}}
{{end}} diff --git a/templates/repo/graph/commits.tmpl b/templates/repo/graph/commits.tmpl index 2ec4166308..f0ff0d2970 100644 --- a/templates/repo/graph/commits.tmpl +++ b/templates/repo/graph/commits.tmpl @@ -71,7 +71,7 @@ {{$userName}} {{end}} - {{ctx.DateUtils.FullTime $commit.Date}} + {{DateUtils.FullTime $commit.Date}} {{end}} {{end}} diff --git a/templates/repo/header.tmpl b/templates/repo/header.tmpl index 777453e4b1..2215c27886 100644 --- a/templates/repo/header.tmpl +++ b/templates/repo/header.tmpl @@ -74,7 +74,7 @@
{{ctx.Locale.Tr "repo.mirror_from"}} {{$.PullMirror.RemoteAddress}} - {{if $.PullMirror.UpdatedUnix}}{{ctx.Locale.Tr "repo.mirror_sync"}} {{TimeSinceUnix $.PullMirror.UpdatedUnix ctx.Locale}}{{end}} + {{if $.PullMirror.UpdatedUnix}}{{ctx.Locale.Tr "repo.mirror_sync"}} {{DateUtils.TimeSince $.PullMirror.UpdatedUnix}}{{end}}
{{end}} {{if .IsFork}}
{{ctx.Locale.Tr "repo.forked_from"}} {{.BaseRepo.FullName}}
{{end}} diff --git a/templates/repo/home.tmpl b/templates/repo/home.tmpl index d16e616a81..5fa31f15c2 100644 --- a/templates/repo/home.tmpl +++ b/templates/repo/home.tmpl @@ -53,7 +53,7 @@ {{if .Repository.ArchivedUnix.IsZero}} {{ctx.Locale.Tr "repo.archive.title"}} {{else}} - {{ctx.Locale.Tr "repo.archive.title_date" (ctx.DateUtils.AbsoluteLong .Repository.ArchivedUnix)}} + {{ctx.Locale.Tr "repo.archive.title_date" (DateUtils.AbsoluteLong .Repository.ArchivedUnix)}} {{end}}
{{end}} diff --git a/templates/repo/issue/card.tmpl b/templates/repo/issue/card.tmpl index 0b255d6705..c29c14a54b 100644 --- a/templates/repo/issue/card.tmpl +++ b/templates/repo/issue/card.tmpl @@ -24,7 +24,7 @@
{{if not $.Page.Repository}}{{.Repo.FullName}}{{end}}#{{.Index}} - {{$timeStr := TimeSinceUnix .GetLastEventTimestamp ctx.Locale}} + {{$timeStr := DateUtils.TimeSince .GetLastEventTimestamp}} {{if .OriginalAuthor}} {{ctx.Locale.Tr .GetLastEventLabelFake $timeStr .OriginalAuthor}} {{else if gt .Poster.ID 0}} diff --git a/templates/repo/issue/filter_list.tmpl b/templates/repo/issue/filter_list.tmpl index 09f87b582f..0e1d8f8036 100644 --- a/templates/repo/issue/filter_list.tmpl +++ b/templates/repo/issue/filter_list.tmpl @@ -146,13 +146,11 @@ {{svg "octicon-triangle-down" 14 "dropdown icon"}}
diff --git a/templates/repo/issue/milestone_issues.tmpl b/templates/repo/issue/milestone_issues.tmpl index bfd64a3205..8b8b194f46 100644 --- a/templates/repo/issue/milestone_issues.tmpl +++ b/templates/repo/issue/milestone_issues.tmpl @@ -30,7 +30,7 @@
- {{$closedDate:= TimeSinceUnix .Milestone.ClosedDateUnix ctx.Locale}} + {{$closedDate:= DateUtils.TimeSince .Milestone.ClosedDateUnix}} {{if .IsClosed}} {{svg "octicon-clock"}} {{ctx.Locale.Tr "repo.milestones.closed" $closedDate}} {{else}} @@ -38,7 +38,7 @@ {{if .Milestone.DeadlineString}} {{svg "octicon-calendar"}} - {{ctx.DateUtils.AbsoluteShort (.Milestone.DeadlineString|ctx.DateUtils.ParseLegacy)}} + {{DateUtils.AbsoluteShort (.Milestone.DeadlineString|DateUtils.ParseLegacy)}} {{else}} {{svg "octicon-calendar"}} diff --git a/templates/repo/issue/milestones.tmpl b/templates/repo/issue/milestones.tmpl index 978f81598e..fab483c79d 100644 --- a/templates/repo/issue/milestones.tmpl +++ b/templates/repo/issue/milestones.tmpl @@ -49,19 +49,19 @@ {{if .UpdatedUnix}}
{{svg "octicon-clock"}} - {{ctx.Locale.Tr "repo.milestones.update_ago" (TimeSinceUnix .UpdatedUnix ctx.Locale)}} + {{ctx.Locale.Tr "repo.milestones.update_ago" (DateUtils.TimeSince .UpdatedUnix)}}
{{end}}
{{if .IsClosed}} - {{$closedDate:= TimeSinceUnix .ClosedDateUnix ctx.Locale}} + {{$closedDate:= DateUtils.TimeSince .ClosedDateUnix}} {{svg "octicon-clock" 14}} {{ctx.Locale.Tr "repo.milestones.closed" $closedDate}} {{else}} {{if .DeadlineString}} {{svg "octicon-calendar" 14}} - {{ctx.DateUtils.AbsoluteShort (.DeadlineString|ctx.DateUtils.ParseLegacy)}} + {{DateUtils.AbsoluteShort (.DeadlineString|DateUtils.ParseLegacy)}} {{else}} {{svg "octicon-calendar" 14}} diff --git a/templates/repo/issue/view_content.tmpl b/templates/repo/issue/view_content.tmpl index 947a480df1..bd52198264 100644 --- a/templates/repo/issue/view_content.tmpl +++ b/templates/repo/issue/view_content.tmpl @@ -6,7 +6,7 @@ - {{$createdStr:= TimeSinceUnix .Issue.CreatedUnix ctx.Locale}} + {{$createdStr:= DateUtils.TimeSince .Issue.CreatedUnix}}
diff --git a/templates/repo/issue/view_content/comments.tmpl b/templates/repo/issue/view_content/comments.tmpl index 828191e5e1..c8eabb9345 100644 --- a/templates/repo/issue/view_content/comments.tmpl +++ b/templates/repo/issue/view_content/comments.tmpl @@ -1,7 +1,7 @@ {{template "base/alert"}} {{range .Issue.Comments}} {{if call $.ShouldShowCommentType .Type}} - {{$createdStr:= TimeSinceUnix .CreatedUnix ctx.Locale}} + {{$createdStr:= DateUtils.TimeSince .CreatedUnix}} @@ -173,7 +173,7 @@

{{ctx.Locale.Tr "repo.activity.opened_prs_label"}} #{{.Index}} {{RenderRefIssueTitle $.Context .Issue.Title}} - {{TimeSinceUnix .Issue.CreatedUnix ctx.Locale}} + {{DateUtils.TimeSince .Issue.CreatedUnix}}

{{end}}
@@ -192,7 +192,7 @@

{{ctx.Locale.Tr "repo.activity.closed_issue_label"}} #{{.Index}} {{RenderRefIssueTitle $.Context .Title}} - {{TimeSinceUnix .ClosedUnix ctx.Locale}} + {{DateUtils.TimeSince .ClosedUnix}}

{{end}}
@@ -211,7 +211,7 @@

{{ctx.Locale.Tr "repo.activity.new_issue_label"}} #{{.Index}} {{RenderRefIssueTitle $.Context .Title}} - {{TimeSinceUnix .CreatedUnix ctx.Locale}} + {{DateUtils.TimeSince .CreatedUnix}}

{{end}}
@@ -232,7 +232,7 @@ {{else}} {{RenderRefIssueTitle $.Context .Title}} {{end}} - {{TimeSinceUnix .UpdatedUnix ctx.Locale}} + {{DateUtils.TimeSince .UpdatedUnix}}

{{end}}
diff --git a/templates/repo/release/list.tmpl b/templates/repo/release/list.tmpl index 4c7f13dda7..a760e0730e 100644 --- a/templates/repo/release/list.tmpl +++ b/templates/repo/release/list.tmpl @@ -51,7 +51,7 @@ {{ctx.Locale.Tr "repo.released_this"}} {{if $release.CreatedUnix}} - {{TimeSinceUnix $release.CreatedUnix ctx.Locale}} + {{DateUtils.TimeSince $release.CreatedUnix}} {{end}} {{if and (not $release.IsDraft) ($.Permission.CanRead $.UnitTypeCode)}} | {{ctx.Locale.Tr "repo.release.ahead.commits" $release.NumCommitsBehind}} {{ctx.Locale.Tr "repo.release.ahead.target" $release.TargetBehind}} diff --git a/templates/repo/settings/deploy_keys.tmpl b/templates/repo/settings/deploy_keys.tmpl index 9c7e1f38cd..91ef1df623 100644 --- a/templates/repo/settings/deploy_keys.tmpl +++ b/templates/repo/settings/deploy_keys.tmpl @@ -55,7 +55,7 @@ {{.Fingerprint}}
-

{{ctx.Locale.Tr "settings.added_on" (ctx.DateUtils.AbsoluteShort .CreatedUnix)}} — {{svg "octicon-info"}} {{if .HasUsed}}{{ctx.Locale.Tr "settings.last_used"}} {{ctx.DateUtils.AbsoluteShort .UpdatedUnix}}{{else}}{{ctx.Locale.Tr "settings.no_activity"}}{{end}} - {{ctx.Locale.Tr "settings.can_read_info"}}{{if not .IsReadOnly}} / {{ctx.Locale.Tr "settings.can_write_info"}} {{end}}

+

{{ctx.Locale.Tr "settings.added_on" (DateUtils.AbsoluteShort .CreatedUnix)}} — {{svg "octicon-info"}} {{if .HasUsed}}{{ctx.Locale.Tr "settings.last_used"}} {{DateUtils.AbsoluteShort .UpdatedUnix}}{{else}}{{ctx.Locale.Tr "settings.no_activity"}}{{end}} - {{ctx.Locale.Tr "settings.can_read_info"}}{{if not .IsReadOnly}} / {{ctx.Locale.Tr "settings.can_write_info"}} {{end}}

diff --git a/templates/repo/settings/lfs.tmpl b/templates/repo/settings/lfs.tmpl index 6d7aac229d..069fdecb33 100644 --- a/templates/repo/settings/lfs.tmpl +++ b/templates/repo/settings/lfs.tmpl @@ -17,7 +17,7 @@ {{ctx.Locale.TrSize .Size}} - {{TimeSince .CreatedUnix.AsTime ctx.Locale}} + {{DateUtils.TimeSince .CreatedUnix}} {{ctx.Locale.Tr "repo.settings.lfs_findcommits"}}
- {{TimeSince .Delivered.AsTime ctx.Locale}} + {{DateUtils.TimeSince .Delivered}}
diff --git a/templates/repo/tag/list.tmpl b/templates/repo/tag/list.tmpl index 82f3dc04a9..8aa4a806c8 100644 --- a/templates/repo/tag/list.tmpl +++ b/templates/repo/tag/list.tmpl @@ -27,7 +27,7 @@
{{if $.Permission.CanRead $.UnitTypeCode}} {{if .CreatedUnix}} - {{svg "octicon-clock" 16 "tw-mr-1"}}{{TimeSinceUnix .CreatedUnix ctx.Locale}} + {{svg "octicon-clock" 16 "tw-mr-1"}}{{DateUtils.TimeSince .CreatedUnix}} {{end}} {{svg "octicon-git-commit" 16 "tw-mr-1"}}{{ShortSha .Sha1}} diff --git a/templates/repo/user_cards.tmpl b/templates/repo/user_cards.tmpl index abf70a9607..fbd4ef0cee 100644 --- a/templates/repo/user_cards.tmpl +++ b/templates/repo/user_cards.tmpl @@ -20,7 +20,7 @@ {{else if .Location}} {{svg "octicon-location"}} {{.Location}} {{else}} - {{svg "octicon-calendar"}} {{ctx.Locale.Tr "user.joined_on" (ctx.DateUtils.AbsoluteShort .CreatedUnix)}} + {{svg "octicon-calendar"}} {{ctx.Locale.Tr "user.joined_on" (DateUtils.AbsoluteShort .CreatedUnix)}} {{end}}
diff --git a/templates/repo/view_file.tmpl b/templates/repo/view_file.tmpl index d127c2ef24..b2443e82c4 100644 --- a/templates/repo/view_file.tmpl +++ b/templates/repo/view_file.tmpl @@ -18,7 +18,7 @@ {{if .LatestCommit}} {{if .LatestCommit.Committer}}
- {{TimeSince .LatestCommit.Committer.When ctx.Locale}} + {{DateUtils.TimeSince .LatestCommit.Committer.When}}
{{end}} {{end}} diff --git a/templates/repo/view_list.tmpl b/templates/repo/view_list.tmpl index b750e9129e..6d6af58c48 100644 --- a/templates/repo/view_list.tmpl +++ b/templates/repo/view_list.tmpl @@ -8,7 +8,7 @@ - {{if .LatestCommit}}{{if .LatestCommit.Committer}}{{TimeSince .LatestCommit.Committer.When ctx.Locale}}{{end}}{{end}} + {{if .LatestCommit}}{{if .LatestCommit.Committer}}{{DateUtils.TimeSince .LatestCommit.Committer.When}}{{end}}{{end}} @@ -62,7 +62,7 @@ {{end}} - {{if $commit}}{{TimeSince $commit.Committer.When ctx.Locale}}{{end}} + {{if $commit}}{{DateUtils.TimeSince $commit.Committer.When}}{{end}} {{end}} diff --git a/templates/repo/wiki/pages.tmpl b/templates/repo/wiki/pages.tmpl index 42c36a9f46..43ab0f9a14 100644 --- a/templates/repo/wiki/pages.tmpl +++ b/templates/repo/wiki/pages.tmpl @@ -19,7 +19,7 @@ {{.Name}} {{svg "octicon-chevron-right"}} - {{$timeSince := TimeSinceUnix .UpdatedUnix ctx.Locale}} + {{$timeSince := DateUtils.TimeSince .UpdatedUnix}} {{ctx.Locale.Tr "repo.wiki.last_updated" $timeSince}} {{end}} diff --git a/templates/repo/wiki/revision.tmpl b/templates/repo/wiki/revision.tmpl index 7fca703843..045cc41d81 100644 --- a/templates/repo/wiki/revision.tmpl +++ b/templates/repo/wiki/revision.tmpl @@ -9,7 +9,7 @@ {{.revision}} {{svg "octicon-home"}} {{$title}}
- {{$timeSince := TimeSince .Author.When ctx.Locale}} + {{$timeSince := DateUtils.TimeSince .Author.When}} {{ctx.Locale.Tr "repo.wiki.last_commit_info" .Author.Name $timeSince}}
diff --git a/templates/repo/wiki/view.tmpl b/templates/repo/wiki/view.tmpl index 40af307524..9f77976f35 100644 --- a/templates/repo/wiki/view.tmpl +++ b/templates/repo/wiki/view.tmpl @@ -48,7 +48,7 @@ {{.CommitCount}} {{svg "octicon-history"}} {{$title}}
- {{$timeSince := TimeSince .Author.When ctx.Locale}} + {{$timeSince := DateUtils.TimeSince .Author.When}} {{ctx.Locale.Tr "repo.wiki.last_commit_info" .Author.Name $timeSince}}
diff --git a/templates/shared/actions/runner_edit.tmpl b/templates/shared/actions/runner_edit.tmpl index d60f10b71f..54250f830b 100644 --- a/templates/shared/actions/runner_edit.tmpl +++ b/templates/shared/actions/runner_edit.tmpl @@ -13,7 +13,7 @@
- {{if .Runner.LastOnline}}{{TimeSinceUnix .Runner.LastOnline ctx.Locale}}{{else}}{{ctx.Locale.Tr "never"}}{{end}} + {{if .Runner.LastOnline}}{{DateUtils.TimeSince .Runner.LastOnline}}{{else}}{{ctx.Locale.Tr "never"}}{{end}}
@@ -70,7 +70,7 @@ {{ShortSha .CommitSHA}} {{if .IsStopped}} - {{TimeSinceUnix .Stopped ctx.Locale}} + {{DateUtils.TimeSince .Stopped}} {{else}}-{{end}} {{end}} diff --git a/templates/shared/actions/runner_list.tmpl b/templates/shared/actions/runner_list.tmpl index abbf2204a8..5bc61f4f64 100644 --- a/templates/shared/actions/runner_list.tmpl +++ b/templates/shared/actions/runner_list.tmpl @@ -73,7 +73,7 @@ {{range .AgentLabels}}{{.}}{{end}} - {{if .LastOnline}}{{TimeSinceUnix .LastOnline ctx.Locale}}{{else}}{{ctx.Locale.Tr "never"}}{{end}} + {{if .LastOnline}}{{DateUtils.TimeSince .LastOnline}}{{else}}{{ctx.Locale.Tr "never"}}{{end}} {{if .Editable $.RunnerOwnerID $.RunnerRepoID}} {{svg "octicon-pencil"}} diff --git a/templates/shared/issuelist.tmpl b/templates/shared/issuelist.tmpl index 941a444612..7ce7cd6795 100644 --- a/templates/shared/issuelist.tmpl +++ b/templates/shared/issuelist.tmpl @@ -60,7 +60,7 @@ #{{.Index}} {{end}} - {{$timeStr := TimeSinceUnix .GetLastEventTimestamp ctx.Locale}} + {{$timeStr := DateUtils.TimeSince .GetLastEventTimestamp}} {{if .OriginalAuthor}} {{ctx.Locale.Tr .GetLastEventLabelFake $timeStr .OriginalAuthor}} {{else if gt .Poster.ID 0}} @@ -117,7 +117,7 @@ {{svg "octicon-calendar" 14}} - {{ctx.DateUtils.AbsoluteShort .DeadlineUnix}} + {{DateUtils.AbsoluteShort .DeadlineUnix}} {{end}} diff --git a/templates/shared/searchbottom.tmpl b/templates/shared/searchbottom.tmpl index bee0397259..4e0bd9570b 100644 --- a/templates/shared/searchbottom.tmpl +++ b/templates/shared/searchbottom.tmpl @@ -7,7 +7,7 @@
{{if not .result.UpdatedUnix.IsZero}} - {{ctx.Locale.Tr "explore.code_last_indexed_at" (TimeSinceUnix .result.UpdatedUnix ctx.Locale)}} + {{ctx.Locale.Tr "explore.code_last_indexed_at" (DateUtils.TimeSince .result.UpdatedUnix)}} {{end}}
diff --git a/templates/shared/secrets/add_list.tmpl b/templates/shared/secrets/add_list.tmpl index 011635a20d..59596d1013 100644 --- a/templates/shared/secrets/add_list.tmpl +++ b/templates/shared/secrets/add_list.tmpl @@ -28,7 +28,7 @@
- {{ctx.Locale.Tr "settings.added_on" (ctx.DateUtils.AbsoluteShort .CreatedUnix)}} + {{ctx.Locale.Tr "settings.added_on" (DateUtils.AbsoluteShort .CreatedUnix)}}
- {{ctx.Locale.Tr "settings.added_on" (ctx.DateUtils.AbsoluteShort .CreatedUnix)}} + {{ctx.Locale.Tr "settings.added_on" (DateUtils.AbsoluteShort .CreatedUnix)}}
{{if or (not .DisablePassword) .LinkAccountMode}} -
+
- {{ctx.Locale.Tr "auth.forgot_password"}}
{{end}} @@ -52,11 +51,15 @@
{{template "user/auth/webauthn_error" .}} - {{if .ShowRegistrationButton}}
+ {{if .ShowRegistrationButton}}
{{ctx.Locale.Tr "auth.hint_register" (printf "%s/user/sign_up" AppSubUrl)}} +
+
+ {{end}} +
- {{end}}
diff --git a/templates/user/dashboard/feeds.tmpl b/templates/user/dashboard/feeds.tmpl index 60aa194534..73698abc71 100644 --- a/templates/user/dashboard/feeds.tmpl +++ b/templates/user/dashboard/feeds.tmpl @@ -78,7 +78,7 @@ {{$reviewer := index .GetIssueInfos 1}} {{ctx.Locale.Tr "action.review_dismissed" (printf "%s/pulls/%s" (.GetRepoLink ctx) $index) $index (.ShortRepoPath ctx) $reviewer}} {{end}} - {{TimeSince .GetCreate ctx.Locale}} + {{DateUtils.TimeSince .GetCreate}}
{{if .GetOpType.InActions "commit_repo" "mirror_sync_push"}} {{$push := ActionContent2Commits .}} diff --git a/templates/user/dashboard/milestones.tmpl b/templates/user/dashboard/milestones.tmpl index 15c14e46d3..6b315eccd3 100644 --- a/templates/user/dashboard/milestones.tmpl +++ b/templates/user/dashboard/milestones.tmpl @@ -104,19 +104,19 @@ {{if .UpdatedUnix}}
{{svg "octicon-clock"}} - {{ctx.Locale.Tr "repo.milestones.update_ago" (TimeSinceUnix .UpdatedUnix ctx.Locale)}} + {{ctx.Locale.Tr "repo.milestones.update_ago" (DateUtils.TimeSince .UpdatedUnix)}}
{{end}}
{{if .IsClosed}} - {{$closedDate:= TimeSinceUnix .ClosedDateUnix ctx.Locale}} + {{$closedDate:= DateUtils.TimeSince .ClosedDateUnix}} {{svg "octicon-clock" 14}} {{ctx.Locale.Tr "repo.milestones.closed" $closedDate}} {{else}} {{if .DeadlineString}} {{svg "octicon-calendar" 14}} - {{ctx.DateUtils.AbsoluteShort (.DeadlineString|ctx.DateUtils.ParseLegacy)}} + {{DateUtils.AbsoluteShort (.DeadlineString|DateUtils.ParseLegacy)}} {{else}} {{svg "octicon-calendar" 14}} diff --git a/templates/user/notification/notification_div.tmpl b/templates/user/notification/notification_div.tmpl index 5c27ba8b41..bf6a94410d 100644 --- a/templates/user/notification/notification_div.tmpl +++ b/templates/user/notification/notification_div.tmpl @@ -67,9 +67,9 @@
{{if .Issue}} - {{TimeSinceUnix .Issue.UpdatedUnix ctx.Locale}} + {{DateUtils.TimeSince .Issue.UpdatedUnix}} {{else}} - {{TimeSinceUnix .UpdatedUnix ctx.Locale}} + {{DateUtils.TimeSince .UpdatedUnix}} {{end}}
diff --git a/templates/user/settings/applications.tmpl b/templates/user/settings/applications.tmpl index 94365f71c0..2aeabc6903 100644 --- a/templates/user/settings/applications.tmpl +++ b/templates/user/settings/applications.tmpl @@ -36,7 +36,7 @@
-

{{ctx.Locale.Tr "settings.added_on" (ctx.DateUtils.AbsoluteShort .CreatedUnix)}} — {{svg "octicon-info"}} {{if .HasUsed}}{{ctx.Locale.Tr "settings.last_used"}} {{ctx.DateUtils.AbsoluteShort .UpdatedUnix}}{{else}}{{ctx.Locale.Tr "settings.no_activity"}}{{end}}

+

{{ctx.Locale.Tr "settings.added_on" (DateUtils.AbsoluteShort .CreatedUnix)}} — {{svg "octicon-info"}} {{if .HasUsed}}{{ctx.Locale.Tr "settings.last_used"}} {{DateUtils.AbsoluteShort .UpdatedUnix}}{{else}}{{ctx.Locale.Tr "settings.no_activity"}}{{end}}

diff --git a/templates/user/settings/grants_oauth2.tmpl b/templates/user/settings/grants_oauth2.tmpl index 41e400767d..23ab8f5696 100644 --- a/templates/user/settings/grants_oauth2.tmpl +++ b/templates/user/settings/grants_oauth2.tmpl @@ -14,7 +14,7 @@
{{.Application.Name}}
-

{{ctx.Locale.Tr "settings.added_on" (ctx.DateUtils.AbsoluteShort .CreatedUnix)}}

+

{{ctx.Locale.Tr "settings.added_on" (DateUtils.AbsoluteShort .CreatedUnix)}}

diff --git a/templates/user/settings/keys_gpg.tmpl b/templates/user/settings/keys_gpg.tmpl index 8e08da7fb3..05a4161661 100644 --- a/templates/user/settings/keys_gpg.tmpl +++ b/templates/user/settings/keys_gpg.tmpl @@ -63,9 +63,9 @@ {{ctx.Locale.Tr "settings.subkeys"}}: {{range .SubsKey}} {{.PaddedKeyID}} {{end}}
-

{{ctx.Locale.Tr "settings.added_on" (ctx.DateUtils.AbsoluteShort .AddedUnix)}}

+

{{ctx.Locale.Tr "settings.added_on" (DateUtils.AbsoluteShort .AddedUnix)}}

- -

{{if not .ExpiredUnix.IsZero}}{{ctx.Locale.Tr "settings.valid_until_date" (ctx.DateUtils.AbsoluteShort .ExpiredUnix)}}{{else}}{{ctx.Locale.Tr "settings.valid_forever"}}{{end}}

+

{{if not .ExpiredUnix.IsZero}}{{ctx.Locale.Tr "settings.valid_until_date" (DateUtils.AbsoluteShort .ExpiredUnix)}}{{else}}{{ctx.Locale.Tr "settings.valid_forever"}}{{end}}

diff --git a/templates/user/settings/keys_principal.tmpl b/templates/user/settings/keys_principal.tmpl index 0bb943054f..754bc374c2 100644 --- a/templates/user/settings/keys_principal.tmpl +++ b/templates/user/settings/keys_principal.tmpl @@ -22,7 +22,7 @@
{{.Name}}
-

{{ctx.Locale.Tr "settings.added_on" (ctx.DateUtils.AbsoluteShort .CreatedUnix)}} — {{svg "octicon-info" 16}} {{if .HasUsed}}{{ctx.Locale.Tr "settings.last_used"}} {{ctx.DateUtils.AbsoluteShort .UpdatedUnix}}{{else}}{{ctx.Locale.Tr "settings.no_activity"}}{{end}}

+

{{ctx.Locale.Tr "settings.added_on" (DateUtils.AbsoluteShort .CreatedUnix)}} — {{svg "octicon-info" 16}} {{if .HasUsed}}{{ctx.Locale.Tr "settings.last_used"}} {{DateUtils.AbsoluteShort .UpdatedUnix}}{{else}}{{ctx.Locale.Tr "settings.no_activity"}}{{end}}

diff --git a/templates/user/settings/keys_ssh.tmpl b/templates/user/settings/keys_ssh.tmpl index 5ba58d2234..9cedc498fe 100644 --- a/templates/user/settings/keys_ssh.tmpl +++ b/templates/user/settings/keys_ssh.tmpl @@ -53,7 +53,7 @@ {{.Fingerprint}}
-

{{ctx.Locale.Tr "settings.added_on" (ctx.DateUtils.AbsoluteShort .CreatedUnix)}} — {{svg "octicon-info"}} {{if .HasUsed}}{{ctx.Locale.Tr "settings.last_used"}} {{ctx.DateUtils.AbsoluteShort .UpdatedUnix}}{{else}}{{ctx.Locale.Tr "settings.no_activity"}}{{end}}

+

{{ctx.Locale.Tr "settings.added_on" (DateUtils.AbsoluteShort .CreatedUnix)}} — {{svg "octicon-info"}} {{if .HasUsed}}{{ctx.Locale.Tr "settings.last_used"}} {{DateUtils.AbsoluteShort .UpdatedUnix}}{{else}}{{ctx.Locale.Tr "settings.no_activity"}}{{end}}

diff --git a/templates/user/settings/security/webauthn.tmpl b/templates/user/settings/security/webauthn.tmpl index 19ac8b28a6..b04bcf4291 100644 --- a/templates/user/settings/security/webauthn.tmpl +++ b/templates/user/settings/security/webauthn.tmpl @@ -12,7 +12,7 @@
{{.Name}}
-

{{ctx.Locale.Tr "settings.added_on" (ctx.DateUtils.AbsoluteShort .CreatedUnix)}}

+

{{ctx.Locale.Tr "settings.added_on" (DateUtils.AbsoluteShort .CreatedUnix)}}

diff --git a/tests/e2e/README.md b/tests/e2e/README.md index d20f2cf633..8fae664564 100644 --- a/tests/e2e/README.md +++ b/tests/e2e/README.md @@ -126,17 +126,16 @@ You can also perform e2e tests using MariaDB/MySQL or PostgreSQL if you want. Setup a MySQL database inside docker ``` -docker run -e "MYSQL_DATABASE=test" -e "MYSQL_ALLOW_EMPTY_PASSWORD=yes" -p 3306:3306 --rm --name mysql mysql:latest #(just ctrl-c to stop db and clean the container) -docker run -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" --rm --name elasticsearch elasticsearch:7.6.0 #(in a second terminal, just ctrl-c to stop db and clean the container) +docker run -e "MYSQL_DATABASE=test" -e "MYSQL_ALLOW_EMPTY_PASSWORD=yes" -p 3306:3306 --rm --name mysql mysql:latest #(Ctrl-c to stop the database) ``` Start tests based on the database container ``` -TEST_MYSQL_HOST=localhost:3306 TEST_MYSQL_DBNAME=test TEST_MYSQL_USERNAME=root TEST_MYSQL_PASSWORD='' make test-e2e-mysql +TEST_MYSQL_HOST=localhost:3306 TEST_MYSQL_DBNAME=test?multiStatements=true TEST_MYSQL_USERNAME=root TEST_MYSQL_PASSWORD='' make test-e2e-mysql ``` Setup a pgsql database inside docker ``` -docker run -e "POSTGRES_DB=test" -p 5432:5432 --rm --name pgsql postgres:latest #(just ctrl-c to stop db and clean the container) +docker run -e POSTGRES_DB=test -e POSTGRES_PASSWORD=password -p 5432:5432 --rm --name pgsql postgres:latest #(Ctrl-c to stop the database) ``` Start tests based on the database container ``` diff --git a/tests/integration/README.md b/tests/integration/README.md index f0fbf94df9..d83685388e 100644 --- a/tests/integration/README.md +++ b/tests/integration/README.md @@ -61,22 +61,21 @@ make test-sqlite ### Run MySQL integration tests Setup a MySQL database inside docker ``` -docker run -e "MYSQL_DATABASE=test" -e "MYSQL_ALLOW_EMPTY_PASSWORD=yes" -p 3306:3306 --rm --name mysql mysql:latest #(just ctrl-c to stop db and clean the container) -docker run -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" --rm --name elasticsearch elasticsearch:7.6.0 #(in a second terminal, just ctrl-c to stop db and clean the container) +docker run -e MYSQL_DATABASE=test -e MYSQL_ALLOW_EMPTY_PASSWORD=yes -p 3306:3306 --rm --name mysql mysql:latest #(Ctrl-c to stop the database) ``` Start tests based on the database container ``` -TEST_MYSQL_HOST=localhost:3306 TEST_MYSQL_DBNAME=test TEST_MYSQL_USERNAME=root TEST_MYSQL_PASSWORD='' make test-mysql +TEST_MYSQL_HOST=localhost:3306 TEST_MYSQL_DBNAME=test?multiStatements=true TEST_MYSQL_USERNAME=root TEST_MYSQL_PASSWORD='' make test-mysql ``` ### Run pgsql integration tests Setup a pgsql database inside docker ``` -docker run -e "POSTGRES_DB=test" -p 5432:5432 --rm --name pgsql postgres:latest #(just ctrl-c to stop db and clean the container) +docker run -e "POSTGRES_DB=test" -e POSTGRES_PASSWORD=postgres -p 5432:5432 --rm --name pgsql postgres:latest #(Ctrl-c to stop the database) ``` Start tests based on the database container ``` -TEST_PGSQL_HOST=localhost:5432 TEST_PGSQL_DBNAME=test TEST_PGSQL_USERNAME=postgres TEST_PGSQL_PASSWORD=postgres make test-pgsql +TEST_STORAGE_TYPE=local TEST_PGSQL_HOST=localhost:5432 TEST_PGSQL_DBNAME=test TEST_PGSQL_USERNAME=postgres TEST_PGSQL_PASSWORD=postgres make test-pgsql ``` ### Running individual tests diff --git a/tests/integration/actions_commit_status_test.go b/tests/integration/actions_commit_status_test.go index 7be40eb0fa..0dae5db344 100644 --- a/tests/integration/actions_commit_status_test.go +++ b/tests/integration/actions_commit_status_test.go @@ -14,6 +14,7 @@ import ( "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/test" "code.gitea.io/gitea/services/actions" "code.gitea.io/gitea/services/automerge" @@ -23,7 +24,7 @@ import ( func TestActionsAutomerge(t *testing.T) { onGiteaRun(t, func(t *testing.T, u *url.URL) { - assert.True(t, setting.Actions.Enabled, "Actions should be enabled") + defer test.MockVariableValue(&setting.Actions.Enabled, true)() ctx := db.DefaultContext diff --git a/tests/integration/actions_trigger_test.go b/tests/integration/actions_trigger_test.go index 25dcacde34..9cf2d4305f 100644 --- a/tests/integration/actions_trigger_test.go +++ b/tests/integration/actions_trigger_test.go @@ -321,7 +321,7 @@ jobs: require.Eventually(t, func() bool { actionRuns = make([]*actions_model.ActionRun, 0) require.NoError(t, db.GetEngine(db.DefaultContext).Where("repo_id=?", baseRepo.ID).Find(&actionRuns)) - return assert.Len(t, actionRuns, count) + return len(actionRuns) == count }, 30*time.Second, 1*time.Second) // verify the expected ActionRuns were created diff --git a/tests/integration/api_admin_org_test.go b/tests/integration/api_admin_org_test.go index a29d0ba1d7..823ef2f136 100644 --- a/tests/integration/api_admin_org_test.go +++ b/tests/integration/api_admin_org_test.go @@ -5,7 +5,6 @@ package integration import ( "net/http" - "net/url" "strings" "testing" @@ -19,57 +18,55 @@ import ( ) func TestAPIAdminOrgCreate(t *testing.T) { - onGiteaRun(t, func(*testing.T, *url.URL) { - session := loginUser(t, "user1") - token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteAdmin) + defer tests.PrepareTestEnv(t)() + session := loginUser(t, "user1") + token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteAdmin) - org := api.CreateOrgOption{ - UserName: "user2_org", - FullName: "User2's organization", - Description: "This organization created by admin for user2", - Website: "https://try.gitea.io", - Location: "Shanghai", - Visibility: "private", - } - req := NewRequestWithJSON(t, "POST", "/api/v1/admin/users/user2/orgs", &org). - AddTokenAuth(token) - resp := MakeRequest(t, req, http.StatusCreated) + org := api.CreateOrgOption{ + UserName: "user2_org", + FullName: "User2's organization", + Description: "This organization created by admin for user2", + Website: "https://try.gitea.io", + Location: "Shanghai", + Visibility: "private", + } + req := NewRequestWithJSON(t, "POST", "/api/v1/admin/users/user2/orgs", &org). + AddTokenAuth(token) + resp := MakeRequest(t, req, http.StatusCreated) - var apiOrg api.Organization - DecodeJSON(t, resp, &apiOrg) + var apiOrg api.Organization + DecodeJSON(t, resp, &apiOrg) - assert.Equal(t, org.UserName, apiOrg.Name) - assert.Equal(t, org.FullName, apiOrg.FullName) - assert.Equal(t, org.Description, apiOrg.Description) - assert.Equal(t, org.Website, apiOrg.Website) - assert.Equal(t, org.Location, apiOrg.Location) - assert.Equal(t, org.Visibility, apiOrg.Visibility) + assert.Equal(t, org.UserName, apiOrg.Name) + assert.Equal(t, org.FullName, apiOrg.FullName) + assert.Equal(t, org.Description, apiOrg.Description) + assert.Equal(t, org.Website, apiOrg.Website) + assert.Equal(t, org.Location, apiOrg.Location) + assert.Equal(t, org.Visibility, apiOrg.Visibility) - unittest.AssertExistsAndLoadBean(t, &user_model.User{ - Name: org.UserName, - LowerName: strings.ToLower(org.UserName), - FullName: org.FullName, - }) + unittest.AssertExistsAndLoadBean(t, &user_model.User{ + Name: org.UserName, + LowerName: strings.ToLower(org.UserName), + FullName: org.FullName, }) } func TestAPIAdminOrgCreateBadVisibility(t *testing.T) { - onGiteaRun(t, func(*testing.T, *url.URL) { - session := loginUser(t, "user1") - token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteAdmin) + defer tests.PrepareTestEnv(t)() + session := loginUser(t, "user1") + token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteAdmin) - org := api.CreateOrgOption{ - UserName: "user2_org", - FullName: "User2's organization", - Description: "This organization created by admin for user2", - Website: "https://try.gitea.io", - Location: "Shanghai", - Visibility: "notvalid", - } - req := NewRequestWithJSON(t, "POST", "/api/v1/admin/users/user2/orgs", &org). - AddTokenAuth(token) - MakeRequest(t, req, http.StatusUnprocessableEntity) - }) + org := api.CreateOrgOption{ + UserName: "user2_org", + FullName: "User2's organization", + Description: "This organization created by admin for user2", + Website: "https://try.gitea.io", + Location: "Shanghai", + Visibility: "notvalid", + } + req := NewRequestWithJSON(t, "POST", "/api/v1/admin/users/user2/orgs", &org). + AddTokenAuth(token) + MakeRequest(t, req, http.StatusUnprocessableEntity) } func TestAPIAdminOrgCreateNotAdmin(t *testing.T) { diff --git a/tests/integration/api_branch_test.go b/tests/integration/api_branch_test.go index 63159f3c41..41b2c2efd1 100644 --- a/tests/integration/api_branch_test.go +++ b/tests/integration/api_branch_test.go @@ -9,14 +9,13 @@ import ( "testing" auth_model "code.gitea.io/gitea/models/auth" - "code.gitea.io/gitea/models/db" git_model "code.gitea.io/gitea/models/git" + "code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/modules/git" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/tests" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func testAPIGetBranch(t *testing.T, branchName string, exists bool) { @@ -234,35 +233,17 @@ func TestAPIBranchProtection(t *testing.T) { } func TestAPICreateBranchWithSyncBranches(t *testing.T) { - defer tests.PrepareTestEnv(t)() - - branches, err := db.Find[git_model.Branch](db.DefaultContext, git_model.FindBranchOptions{ - RepoID: 1, - }) - require.NoError(t, err) - assert.Len(t, branches, 4) - - // make a broke repository with no branch on database - _, err = db.DeleteByBean(db.DefaultContext, git_model.Branch{RepoID: 1}) - require.NoError(t, err) - onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { + unittest.AssertCount(t, &git_model.Branch{RepoID: 1}, 4) + + // make a broke repository with no branch on database + unittest.AssertSuccessfulDelete(t, &git_model.Branch{RepoID: 1}) + ctx := NewAPITestContext(t, "user2", "repo1", auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser) giteaURL.Path = ctx.GitPath() testAPICreateBranch(t, ctx.Session, "user2", "repo1", "", "new_branch", http.StatusCreated) - }) - branches, err = db.Find[git_model.Branch](db.DefaultContext, git_model.FindBranchOptions{ - RepoID: 1, + unittest.AssertExistsIf(t, true, &git_model.Branch{RepoID: 1, Name: "new_branch"}) }) - require.NoError(t, err) - assert.Len(t, branches, 5) - - branches, err = db.Find[git_model.Branch](db.DefaultContext, git_model.FindBranchOptions{ - RepoID: 1, - Keyword: "new_branch", - }) - require.NoError(t, err) - assert.Len(t, branches, 1) } diff --git a/tests/integration/api_fork_test.go b/tests/integration/api_fork_test.go index b80b4c6645..6a6b05f700 100644 --- a/tests/integration/api_fork_test.go +++ b/tests/integration/api_fork_test.go @@ -7,7 +7,6 @@ package integration import ( "fmt" "net/http" - "net/url" "testing" auth_model "code.gitea.io/gitea/models/auth" @@ -86,25 +85,24 @@ func TestCreateForkNoLogin(t *testing.T) { } func TestAPIDisabledForkRepo(t *testing.T) { - onGiteaRun(t, func(t *testing.T, u *url.URL) { - defer test.MockVariableValue(&setting.Repository.DisableForks, true)() - defer test.MockVariableValue(&testWebRoutes, routers.NormalRoutes())() + defer test.MockVariableValue(&setting.Repository.DisableForks, true)() + defer test.MockVariableValue(&testWebRoutes, routers.NormalRoutes())() + defer tests.PrepareTestEnv(t)() - t.Run("fork listing", func(t *testing.T) { - defer tests.PrintCurrentTest(t)() + t.Run("fork listing", func(t *testing.T) { + defer tests.PrintCurrentTest(t)() - req := NewRequest(t, "GET", "/api/v1/repos/user2/repo1/forks") - MakeRequest(t, req, http.StatusNotFound) - }) + req := NewRequest(t, "GET", "/api/v1/repos/user2/repo1/forks") + MakeRequest(t, req, http.StatusNotFound) + }) - t.Run("forking", func(t *testing.T) { - defer tests.PrintCurrentTest(t)() + t.Run("forking", func(t *testing.T) { + defer tests.PrintCurrentTest(t)() - session := loginUser(t, "user5") - token := getTokenForLoggedInUser(t, session) + session := loginUser(t, "user5") + token := getTokenForLoggedInUser(t, session) - req := NewRequestWithJSON(t, "POST", "/api/v1/repos/user2/repo1/forks", &api.CreateForkOption{}).AddTokenAuth(token) - session.MakeRequest(t, req, http.StatusNotFound) - }) + req := NewRequestWithJSON(t, "POST", "/api/v1/repos/user2/repo1/forks", &api.CreateForkOption{}).AddTokenAuth(token) + session.MakeRequest(t, req, http.StatusNotFound) }) } diff --git a/tests/integration/api_nodeinfo_test.go b/tests/integration/api_nodeinfo_test.go index 33d06ed1b4..d000083717 100644 --- a/tests/integration/api_nodeinfo_test.go +++ b/tests/integration/api_nodeinfo_test.go @@ -5,35 +5,31 @@ package integration import ( "net/http" - "net/url" "testing" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/modules/test" "code.gitea.io/gitea/routers" + "code.gitea.io/gitea/tests" "github.com/stretchr/testify/assert" ) func TestNodeinfo(t *testing.T) { - setting.Federation.Enabled = true - testWebRoutes = routers.NormalRoutes() - defer func() { - setting.Federation.Enabled = false - testWebRoutes = routers.NormalRoutes() - }() + defer test.MockVariableValue(&setting.Federation.Enabled, true)() + defer test.MockVariableValue(&testWebRoutes, routers.NormalRoutes())() + defer tests.PrepareTestEnv(t)() - onGiteaRun(t, func(*testing.T, *url.URL) { - req := NewRequest(t, "GET", "/api/v1/nodeinfo") - resp := MakeRequest(t, req, http.StatusOK) - VerifyJSONSchema(t, resp, "nodeinfo_2.1.json") + req := NewRequest(t, "GET", "/api/v1/nodeinfo") + resp := MakeRequest(t, req, http.StatusOK) + VerifyJSONSchema(t, resp, "nodeinfo_2.1.json") - var nodeinfo api.NodeInfo - DecodeJSON(t, resp, &nodeinfo) - assert.True(t, nodeinfo.OpenRegistrations) - assert.Equal(t, "forgejo", nodeinfo.Software.Name) - assert.Equal(t, 29, nodeinfo.Usage.Users.Total) - assert.Equal(t, 22, nodeinfo.Usage.LocalPosts) - assert.Equal(t, 4, nodeinfo.Usage.LocalComments) - }) + var nodeinfo api.NodeInfo + DecodeJSON(t, resp, &nodeinfo) + assert.True(t, nodeinfo.OpenRegistrations) + assert.Equal(t, "forgejo", nodeinfo.Software.Name) + assert.Equal(t, 29, nodeinfo.Usage.Users.Total) + assert.Equal(t, 22, nodeinfo.Usage.LocalPosts) + assert.Equal(t, 4, nodeinfo.Usage.LocalComments) } diff --git a/tests/integration/api_org_test.go b/tests/integration/api_org_test.go index 70d3a446f7..3a7c81ca3a 100644 --- a/tests/integration/api_org_test.go +++ b/tests/integration/api_org_test.go @@ -6,7 +6,6 @@ package integration import ( "fmt" "net/http" - "net/url" "strings" "testing" @@ -19,150 +18,144 @@ import ( user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/modules/test" "code.gitea.io/gitea/tests" "github.com/stretchr/testify/assert" ) func TestAPIOrgCreate(t *testing.T) { - onGiteaRun(t, func(*testing.T, *url.URL) { - token := getUserToken(t, "user1", auth_model.AccessTokenScopeWriteOrganization) + defer tests.PrepareTestEnv(t)() + token := getUserToken(t, "user1", auth_model.AccessTokenScopeWriteOrganization) - org := api.CreateOrgOption{ - UserName: "user1_org", - FullName: "User1's organization", - Description: "This organization created by user1", - Website: "https://try.gitea.io", - Location: "Shanghai", - Visibility: "limited", - } - req := NewRequestWithJSON(t, "POST", "/api/v1/orgs", &org). - AddTokenAuth(token) - resp := MakeRequest(t, req, http.StatusCreated) + org := api.CreateOrgOption{ + UserName: "user1_org", + FullName: "User1's organization", + Description: "This organization created by user1", + Website: "https://try.gitea.io", + Location: "Shanghai", + Visibility: "limited", + } + req := NewRequestWithJSON(t, "POST", "/api/v1/orgs", &org). + AddTokenAuth(token) + resp := MakeRequest(t, req, http.StatusCreated) - var apiOrg api.Organization - DecodeJSON(t, resp, &apiOrg) + var apiOrg api.Organization + DecodeJSON(t, resp, &apiOrg) - assert.Equal(t, org.UserName, apiOrg.Name) - assert.Equal(t, org.FullName, apiOrg.FullName) - assert.Equal(t, org.Description, apiOrg.Description) - assert.Equal(t, org.Website, apiOrg.Website) - assert.Equal(t, org.Location, apiOrg.Location) - assert.Equal(t, org.Visibility, apiOrg.Visibility) + assert.Equal(t, org.UserName, apiOrg.Name) + assert.Equal(t, org.FullName, apiOrg.FullName) + assert.Equal(t, org.Description, apiOrg.Description) + assert.Equal(t, org.Website, apiOrg.Website) + assert.Equal(t, org.Location, apiOrg.Location) + assert.Equal(t, org.Visibility, apiOrg.Visibility) - unittest.AssertExistsAndLoadBean(t, &user_model.User{ - Name: org.UserName, - LowerName: strings.ToLower(org.UserName), - FullName: org.FullName, - }) - - // Check owner team permission - ownerTeam, _ := org_model.GetOwnerTeam(db.DefaultContext, apiOrg.ID) - - for _, ut := range unit_model.AllRepoUnitTypes { - up := perm.AccessModeOwner - if ut == unit_model.TypeExternalTracker || ut == unit_model.TypeExternalWiki { - up = perm.AccessModeRead - } - unittest.AssertExistsAndLoadBean(t, &org_model.TeamUnit{ - OrgID: apiOrg.ID, - TeamID: ownerTeam.ID, - Type: ut, - AccessMode: up, - }) - } - - req = NewRequestf(t, "GET", "/api/v1/orgs/%s", org.UserName). - AddTokenAuth(token) - resp = MakeRequest(t, req, http.StatusOK) - DecodeJSON(t, resp, &apiOrg) - assert.EqualValues(t, org.UserName, apiOrg.Name) - - req = NewRequestf(t, "GET", "/api/v1/orgs/%s/repos", org.UserName). - AddTokenAuth(token) - resp = MakeRequest(t, req, http.StatusOK) - - var repos []*api.Repository - DecodeJSON(t, resp, &repos) - for _, repo := range repos { - assert.False(t, repo.Private) - } - - req = NewRequestf(t, "GET", "/api/v1/orgs/%s/members", org.UserName). - AddTokenAuth(token) - resp = MakeRequest(t, req, http.StatusOK) - - // user1 on this org is public - var users []*api.User - DecodeJSON(t, resp, &users) - assert.Len(t, users, 1) - assert.EqualValues(t, "user1", users[0].UserName) + unittest.AssertExistsAndLoadBean(t, &user_model.User{ + Name: org.UserName, + LowerName: strings.ToLower(org.UserName), + FullName: org.FullName, }) + + // Check owner team permission + ownerTeam, _ := org_model.GetOwnerTeam(db.DefaultContext, apiOrg.ID) + + for _, ut := range unit_model.AllRepoUnitTypes { + up := perm.AccessModeOwner + if ut == unit_model.TypeExternalTracker || ut == unit_model.TypeExternalWiki { + up = perm.AccessModeRead + } + unittest.AssertExistsAndLoadBean(t, &org_model.TeamUnit{ + OrgID: apiOrg.ID, + TeamID: ownerTeam.ID, + Type: ut, + AccessMode: up, + }) + } + + req = NewRequestf(t, "GET", "/api/v1/orgs/%s", org.UserName). + AddTokenAuth(token) + resp = MakeRequest(t, req, http.StatusOK) + DecodeJSON(t, resp, &apiOrg) + assert.EqualValues(t, org.UserName, apiOrg.Name) + + req = NewRequestf(t, "GET", "/api/v1/orgs/%s/repos", org.UserName). + AddTokenAuth(token) + resp = MakeRequest(t, req, http.StatusOK) + + var repos []*api.Repository + DecodeJSON(t, resp, &repos) + for _, repo := range repos { + assert.False(t, repo.Private) + } + + req = NewRequestf(t, "GET", "/api/v1/orgs/%s/members", org.UserName). + AddTokenAuth(token) + resp = MakeRequest(t, req, http.StatusOK) + + // user1 on this org is public + var users []*api.User + DecodeJSON(t, resp, &users) + assert.Len(t, users, 1) + assert.EqualValues(t, "user1", users[0].UserName) } func TestAPIOrgEdit(t *testing.T) { - onGiteaRun(t, func(*testing.T, *url.URL) { - session := loginUser(t, "user1") + defer tests.PrepareTestEnv(t)() + session := loginUser(t, "user1") - token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteOrganization) - org := api.EditOrgOption{ - FullName: "Org3 organization new full name", - Description: "A new description", - Website: "https://try.gitea.io/new", - Location: "Beijing", - Visibility: "private", - } - req := NewRequestWithJSON(t, "PATCH", "/api/v1/orgs/org3", &org). - AddTokenAuth(token) - resp := MakeRequest(t, req, http.StatusOK) + token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteOrganization) + org := api.EditOrgOption{ + FullName: "Org3 organization new full name", + Description: "A new description", + Website: "https://try.gitea.io/new", + Location: "Beijing", + Visibility: "private", + } + req := NewRequestWithJSON(t, "PATCH", "/api/v1/orgs/org3", &org). + AddTokenAuth(token) + resp := MakeRequest(t, req, http.StatusOK) - var apiOrg api.Organization - DecodeJSON(t, resp, &apiOrg) + var apiOrg api.Organization + DecodeJSON(t, resp, &apiOrg) - assert.Equal(t, "org3", apiOrg.Name) - assert.Equal(t, org.FullName, apiOrg.FullName) - assert.Equal(t, org.Description, apiOrg.Description) - assert.Equal(t, org.Website, apiOrg.Website) - assert.Equal(t, org.Location, apiOrg.Location) - assert.Equal(t, org.Visibility, apiOrg.Visibility) - }) + assert.Equal(t, "org3", apiOrg.Name) + assert.Equal(t, org.FullName, apiOrg.FullName) + assert.Equal(t, org.Description, apiOrg.Description) + assert.Equal(t, org.Website, apiOrg.Website) + assert.Equal(t, org.Location, apiOrg.Location) + assert.Equal(t, org.Visibility, apiOrg.Visibility) } func TestAPIOrgEditBadVisibility(t *testing.T) { - onGiteaRun(t, func(*testing.T, *url.URL) { - session := loginUser(t, "user1") + defer tests.PrepareTestEnv(t)() + session := loginUser(t, "user1") - token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteOrganization) - org := api.EditOrgOption{ - FullName: "Org3 organization new full name", - Description: "A new description", - Website: "https://try.gitea.io/new", - Location: "Beijing", - Visibility: "badvisibility", - } - req := NewRequestWithJSON(t, "PATCH", "/api/v1/orgs/org3", &org). - AddTokenAuth(token) - MakeRequest(t, req, http.StatusUnprocessableEntity) - }) + token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteOrganization) + org := api.EditOrgOption{ + FullName: "Org3 organization new full name", + Description: "A new description", + Website: "https://try.gitea.io/new", + Location: "Beijing", + Visibility: "badvisibility", + } + req := NewRequestWithJSON(t, "PATCH", "/api/v1/orgs/org3", &org). + AddTokenAuth(token) + MakeRequest(t, req, http.StatusUnprocessableEntity) } func TestAPIOrgDeny(t *testing.T) { - onGiteaRun(t, func(*testing.T, *url.URL) { - setting.Service.RequireSignInView = true - defer func() { - setting.Service.RequireSignInView = false - }() + defer tests.PrepareTestEnv(t)() + defer test.MockVariableValue(&setting.Service.RequireSignInView, true)() - orgName := "user1_org" - req := NewRequestf(t, "GET", "/api/v1/orgs/%s", orgName) - MakeRequest(t, req, http.StatusNotFound) + orgName := "user1_org" + req := NewRequestf(t, "GET", "/api/v1/orgs/%s", orgName) + MakeRequest(t, req, http.StatusNotFound) - req = NewRequestf(t, "GET", "/api/v1/orgs/%s/repos", orgName) - MakeRequest(t, req, http.StatusNotFound) + req = NewRequestf(t, "GET", "/api/v1/orgs/%s/repos", orgName) + MakeRequest(t, req, http.StatusNotFound) - req = NewRequestf(t, "GET", "/api/v1/orgs/%s/members", orgName) - MakeRequest(t, req, http.StatusNotFound) - }) + req = NewRequestf(t, "GET", "/api/v1/orgs/%s/members", orgName) + MakeRequest(t, req, http.StatusNotFound) } func TestAPIGetAll(t *testing.T) { @@ -192,37 +185,36 @@ func TestAPIGetAll(t *testing.T) { } func TestAPIOrgSearchEmptyTeam(t *testing.T) { - onGiteaRun(t, func(*testing.T, *url.URL) { - token := getUserToken(t, "user1", auth_model.AccessTokenScopeWriteOrganization) - orgName := "org_with_empty_team" + defer tests.PrepareTestEnv(t)() + token := getUserToken(t, "user1", auth_model.AccessTokenScopeWriteOrganization) + orgName := "org_with_empty_team" - // create org - req := NewRequestWithJSON(t, "POST", "/api/v1/orgs", &api.CreateOrgOption{ - UserName: orgName, - }).AddTokenAuth(token) - MakeRequest(t, req, http.StatusCreated) + // create org + req := NewRequestWithJSON(t, "POST", "/api/v1/orgs", &api.CreateOrgOption{ + UserName: orgName, + }).AddTokenAuth(token) + MakeRequest(t, req, http.StatusCreated) - // create team with no member - req = NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/orgs/%s/teams", orgName), &api.CreateTeamOption{ - Name: "Empty", - IncludesAllRepositories: true, - Permission: "read", - Units: []string{"repo.code", "repo.issues", "repo.ext_issues", "repo.wiki", "repo.pulls"}, - }).AddTokenAuth(token) - MakeRequest(t, req, http.StatusCreated) + // create team with no member + req = NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/orgs/%s/teams", orgName), &api.CreateTeamOption{ + Name: "Empty", + IncludesAllRepositories: true, + Permission: "read", + Units: []string{"repo.code", "repo.issues", "repo.ext_issues", "repo.wiki", "repo.pulls"}, + }).AddTokenAuth(token) + MakeRequest(t, req, http.StatusCreated) - // case-insensitive search for teams that have no members - req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/orgs/%s/teams/search?q=%s", orgName, "empty")). - AddTokenAuth(token) - resp := MakeRequest(t, req, http.StatusOK) - data := struct { - Ok bool - Data []*api.Team - }{} - DecodeJSON(t, resp, &data) - assert.True(t, data.Ok) - if assert.Len(t, data.Data, 1) { - assert.EqualValues(t, "Empty", data.Data[0].Name) - } - }) + // case-insensitive search for teams that have no members + req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/orgs/%s/teams/search?q=%s", orgName, "empty")). + AddTokenAuth(token) + resp := MakeRequest(t, req, http.StatusOK) + data := struct { + Ok bool + Data []*api.Team + }{} + DecodeJSON(t, resp, &data) + assert.True(t, data.Ok) + if assert.Len(t, data.Data, 1) { + assert.EqualValues(t, "Empty", data.Data[0].Name) + } } diff --git a/tests/integration/codeowner_test.go b/tests/integration/codeowner_test.go index 71661bc56b..b324711cb5 100644 --- a/tests/integration/codeowner_test.go +++ b/tests/integration/codeowner_test.go @@ -6,6 +6,7 @@ package integration import ( "context" "fmt" + "net/http" "net/url" "os" "path" @@ -136,5 +137,27 @@ func TestCodeOwner(t *testing.T) { unittest.AssertExistsIf(t, true, &issues_model.Review{IssueID: pr.IssueID, Type: issues_model.ReviewTypeRequest, ReviewerID: 4}) unittest.AssertExistsIf(t, false, &issues_model.Review{IssueID: pr.IssueID, Type: issues_model.ReviewTypeRequest, ReviewerID: 5}) }) + t.Run("From a forked repository", func(t *testing.T) { + defer tests.PrintCurrentTest(t)() + + session := loginUser(t, "user1") + + r := fmt.Sprintf("%suser1/repo1.git", u.String()) + remoteURL, _ := url.Parse(r) + remoteURL.User = url.UserPassword("user1", userPassword) + doGitAddRemote(dstPath, "forked-2", remoteURL)(t) + + err := git.NewCommand(git.DefaultContext, "push", "forked-2", "HEAD:branch").Run(&git.RunOpts{Dir: dstPath}) + require.NoError(t, err) + + req := NewRequestWithValues(t, "POST", repo.FullName()+"/compare/main...user1/repo1:branch", map[string]string{ + "_csrf": GetCSRF(t, session, repo.FullName()+"/compare/main...user1/repo1:branch"), + "title": "pull request", + }) + session.MakeRequest(t, req, http.StatusOK) + + pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{BaseRepoID: repo.ID, HeadBranch: "branch"}) + unittest.AssertExistsIf(t, true, &issues_model.Review{IssueID: pr.IssueID, Type: issues_model.ReviewTypeRequest, ReviewerID: 4}) + }) }) } diff --git a/tests/integration/compare_test.go b/tests/integration/compare_test.go index c65335c469..a6f994835b 100644 --- a/tests/integration/compare_test.go +++ b/tests/integration/compare_test.go @@ -40,7 +40,7 @@ func TestCompareTag(t *testing.T) { req = NewRequest(t, "GET", "/user2/repo1/compare/invalid") resp = session.MakeRequest(t, req, http.StatusNotFound) - assert.False(t, strings.Contains(resp.Body.String(), ">500<"), "expect 404 page not 500") + assert.NotContains(t, resp.Body.String(), ">500<", "expect 404 page not 500") } // Compare with inferred default branch (master) diff --git a/tests/integration/last_updated_time_test.go b/tests/integration/last_updated_time_test.go index 54c0eeb629..34ba9a471f 100644 --- a/tests/integration/last_updated_time_test.go +++ b/tests/integration/last_updated_time_test.go @@ -2,60 +2,56 @@ package integration import ( "net/http" - "net/url" "path" "strings" "testing" + "code.gitea.io/gitea/tests" + "github.com/PuerkitoBio/goquery" "github.com/stretchr/testify/assert" ) func TestRepoLastUpdatedTime(t *testing.T) { - onGiteaRun(t, func(t *testing.T, u *url.URL) { - user := "user2" - session := loginUser(t, user) + defer tests.PrepareTestEnv(t)() + user := "user2" + session := loginUser(t, user) - req := NewRequest(t, "GET", "/explore/repos?q=repo1") - resp := session.MakeRequest(t, req, http.StatusOK) - doc := NewHTMLParser(t, resp.Body) - node := doc.doc.Find(".flex-item-body").First() - { - buf := "" - findTextNonNested(t, node, &buf) - assert.Equal(t, "Updated", strings.TrimSpace(buf)) - } + req := NewRequest(t, "GET", "/explore/repos?q=repo1") + resp := session.MakeRequest(t, req, http.StatusOK) + doc := NewHTMLParser(t, resp.Body) + node := doc.doc.Find(".flex-item-main:has(a[href='/user2/repo1']) .flex-item-body").First() + { + buf := "" + findTextNonNested(t, node, &buf) + assert.Equal(t, "Updated", strings.TrimSpace(buf)) + } - // Relative time should be present as a descendent - { - relativeTime := node.Find("relative-time").Text() - assert.True(t, strings.HasPrefix(relativeTime, "19")) // ~1970, might underflow with timezone - } - }) + // Relative time should be present as a descendent + assert.Contains(t, node.Find("relative-time").Text(), "2024-11-10") } func TestBranchLastUpdatedTime(t *testing.T) { - onGiteaRun(t, func(t *testing.T, u *url.URL) { - user := "user2" - repo := "repo1" - session := loginUser(t, user) + defer tests.PrepareTestEnv(t)() + user := "user2" + repo := "repo1" + session := loginUser(t, user) - req := NewRequest(t, "GET", path.Join(user, repo, "branches")) - resp := session.MakeRequest(t, req, http.StatusOK) - doc := NewHTMLParser(t, resp.Body) - node := doc.doc.Find("p:has(span.commit-message)") + req := NewRequest(t, "GET", path.Join(user, repo, "branches")) + resp := session.MakeRequest(t, req, http.StatusOK) + doc := NewHTMLParser(t, resp.Body) + node := doc.doc.Find("p:has(span.commit-message)") - { - buf := "" - findTextNonNested(t, node, &buf) - assert.True(t, strings.Contains(buf, "Updated")) - } + { + buf := "" + findTextNonNested(t, node, &buf) + assert.Contains(t, buf, "Updated") + } - { - relativeTime := node.Find("relative-time").Text() - assert.True(t, strings.HasPrefix(relativeTime, "2017")) - } - }) + { + relativeTime := node.Find("relative-time").Text() + assert.True(t, strings.HasPrefix(relativeTime, "2017")) + } } // Find all text that are direct descendents diff --git a/tests/integration/pull_commit_test.go b/tests/integration/pull_commit_test.go index 477f01725d..5ef6d6ceca 100644 --- a/tests/integration/pull_commit_test.go +++ b/tests/integration/pull_commit_test.go @@ -5,30 +5,29 @@ package integration import ( "net/http" - "net/url" "testing" pull_service "code.gitea.io/gitea/services/pull" + "code.gitea.io/gitea/tests" "github.com/stretchr/testify/assert" ) func TestListPullCommits(t *testing.T) { - onGiteaRun(t, func(t *testing.T, u *url.URL) { - session := loginUser(t, "user5") - req := NewRequest(t, "GET", "/user2/repo1/pulls/3/commits/list") - resp := session.MakeRequest(t, req, http.StatusOK) + defer tests.PrepareTestEnv(t)() + session := loginUser(t, "user5") + req := NewRequest(t, "GET", "/user2/repo1/pulls/3/commits/list") + resp := session.MakeRequest(t, req, http.StatusOK) - var pullCommitList struct { - Commits []pull_service.CommitInfo `json:"commits"` - LastReviewCommitSha string `json:"last_review_commit_sha"` - } - DecodeJSON(t, resp, &pullCommitList) + var pullCommitList struct { + Commits []pull_service.CommitInfo `json:"commits"` + LastReviewCommitSha string `json:"last_review_commit_sha"` + } + DecodeJSON(t, resp, &pullCommitList) - if assert.Len(t, pullCommitList.Commits, 2) { - assert.Equal(t, "5f22f7d0d95d614d25a5b68592adb345a4b5c7fd", pullCommitList.Commits[0].ID) - assert.Equal(t, "4a357436d925b5c974181ff12a994538ddc5a269", pullCommitList.Commits[1].ID) - } - assert.Equal(t, "4a357436d925b5c974181ff12a994538ddc5a269", pullCommitList.LastReviewCommitSha) - }) + if assert.Len(t, pullCommitList.Commits, 2) { + assert.Equal(t, "5f22f7d0d95d614d25a5b68592adb345a4b5c7fd", pullCommitList.Commits[0].ID) + assert.Equal(t, "4a357436d925b5c974181ff12a994538ddc5a269", pullCommitList.Commits[1].ID) + } + assert.Equal(t, "4a357436d925b5c974181ff12a994538ddc5a269", pullCommitList.LastReviewCommitSha) } diff --git a/tests/integration/pull_review_test.go b/tests/integration/pull_review_test.go index d15a7bd130..b3380cc6b8 100644 --- a/tests/integration/pull_review_test.go +++ b/tests/integration/pull_review_test.go @@ -18,7 +18,6 @@ import ( repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/test" issue_service "code.gitea.io/gitea/services/issue" @@ -283,32 +282,18 @@ func TestPullView_CodeOwner(t *testing.T) { onGiteaRun(t, func(t *testing.T, u *url.URL) { user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) - // Create the repo. - repo, err := repo_service.CreateRepositoryDirectly(db.DefaultContext, user2, user2, repo_service.CreateRepoOptions{ - Name: "test_codeowner", - Readme: "Default", - AutoInit: true, - ObjectFormatName: git.Sha1ObjectFormat.Name(), - DefaultBranch: "master", - }) - require.NoError(t, err) - - // add CODEOWNERS to default branch - _, err = files_service.ChangeRepoFiles(db.DefaultContext, repo, user2, &files_service.ChangeRepoFilesOptions{ - OldBranch: repo.DefaultBranch, - Files: []*files_service.ChangeRepoFile{ - { - Operation: "create", - TreePath: "CODEOWNERS", - ContentReader: strings.NewReader("README.md @user5\n"), - }, + repo, _, f := tests.CreateDeclarativeRepo(t, user2, "test_codeowner", nil, nil, []*files_service.ChangeRepoFile{ + { + Operation: "create", + TreePath: "CODEOWNERS", + ContentReader: strings.NewReader("README.md @user5\n"), }, }) - require.NoError(t, err) + defer f() t.Run("First Pull Request", func(t *testing.T) { // create a new branch to prepare for pull request - _, err = files_service.ChangeRepoFiles(db.DefaultContext, repo, user2, &files_service.ChangeRepoFilesOptions{ + _, err := files_service.ChangeRepoFiles(db.DefaultContext, repo, user2, &files_service.ChangeRepoFilesOptions{ NewBranch: "codeowner-basebranch", Files: []*files_service.ChangeRepoFile{ { @@ -328,7 +313,7 @@ func TestPullView_CodeOwner(t *testing.T) { unittest.AssertExistsIf(t, true, &issues_model.Review{IssueID: pr.IssueID, Type: issues_model.ReviewTypeRequest, ReviewerID: 5}) require.NoError(t, pr.LoadIssue(db.DefaultContext)) - err := issue_service.ChangeTitle(db.DefaultContext, pr.Issue, user2, "[WIP] Test Pull Request") + err = issue_service.ChangeTitle(db.DefaultContext, pr.Issue, user2, "[WIP] Test Pull Request") require.NoError(t, err) prUpdated1 := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: pr.ID}) require.NoError(t, prUpdated1.LoadIssue(db.DefaultContext)) @@ -342,7 +327,7 @@ func TestPullView_CodeOwner(t *testing.T) { }) // change the default branch CODEOWNERS file to change README.md's codeowner - _, err = files_service.ChangeRepoFiles(db.DefaultContext, repo, user2, &files_service.ChangeRepoFilesOptions{ + _, err := files_service.ChangeRepoFiles(db.DefaultContext, repo, user2, &files_service.ChangeRepoFilesOptions{ Files: []*files_service.ChangeRepoFile{ { Operation: "update", @@ -397,10 +382,18 @@ func TestPullView_CodeOwner(t *testing.T) { require.NoError(t, err) session := loginUser(t, "user5") - testPullCreate(t, session, "user5", "test_codeowner_fork", false, forkedRepo.DefaultBranch, "codeowner-basebranch-forked", "Test Pull Request2") - pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{BaseRepoID: repo.ID, HeadBranch: "codeowner-basebranch-forked"}) + // create a pull request on the forked repository, code reviewers should not be mentioned + testPullCreateDirectly(t, session, "user5", "test_codeowner_fork", forkedRepo.DefaultBranch, "", "", "codeowner-basebranch-forked", "Test Pull Request on Forked Repository") + + pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{BaseRepoID: forkedRepo.ID, HeadBranch: "codeowner-basebranch-forked"}) unittest.AssertExistsIf(t, false, &issues_model.Review{IssueID: pr.IssueID, Type: issues_model.ReviewTypeRequest, ReviewerID: 8}) + + // create a pull request to base repository, code reviewers should be mentioned + testPullCreateDirectly(t, session, repo.OwnerName, repo.Name, repo.DefaultBranch, forkedRepo.OwnerName, forkedRepo.Name, "codeowner-basebranch-forked", "Test Pull Request3") + + pr = unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{BaseRepoID: repo.ID, HeadRepoID: forkedRepo.ID, HeadBranch: "codeowner-basebranch-forked"}) + unittest.AssertExistsIf(t, true, &issues_model.Review{IssueID: pr.IssueID, Type: issues_model.ReviewTypeRequest, ReviewerID: 8}) }) }) } diff --git a/tests/integration/rename_branch_test.go b/tests/integration/rename_branch_test.go index a96cbf5623..20d4c9b48f 100644 --- a/tests/integration/rename_branch_test.go +++ b/tests/integration/rename_branch_test.go @@ -22,8 +22,6 @@ func TestRenameBranch(t *testing.T) { } func testRenameBranch(t *testing.T, u *url.URL) { - defer tests.PrepareTestEnv(t)() - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) unittest.AssertExistsAndLoadBean(t, &git_model.Branch{RepoID: repo.ID, Name: "master"}) diff --git a/tests/integration/repo_collaborator_test.go b/tests/integration/repo_collaborator_test.go index beeb950f5a..292cd5862b 100644 --- a/tests/integration/repo_collaborator_test.go +++ b/tests/integration/repo_collaborator_test.go @@ -5,33 +5,33 @@ package integration import ( "net/http" - "net/url" "strings" "testing" + "code.gitea.io/gitea/tests" + "github.com/stretchr/testify/assert" ) // TestRepoCollaborators is a test for contents of Collaborators tab in the repo settings // It only covers a few elements and can be extended as needed func TestRepoCollaborators(t *testing.T) { - onGiteaRun(t, func(t *testing.T, u *url.URL) { - session := loginUser(t, "user2") + defer tests.PrepareTestEnv(t)() + session := loginUser(t, "user2") - // Visit Collaborators tab of repo settings - response := session.MakeRequest(t, NewRequest(t, "GET", "/user2/repo1/settings/collaboration"), http.StatusOK) - page := NewHTMLParser(t, response.Body).Find(".repo-setting-content") + // Visit Collaborators tab of repo settings + response := session.MakeRequest(t, NewRequest(t, "GET", "/user2/repo1/settings/collaboration"), http.StatusOK) + page := NewHTMLParser(t, response.Body).Find(".repo-setting-content") - // Veirfy header - assert.EqualValues(t, "Collaborators", strings.TrimSpace(page.Find("h4").Text())) + // Veirfy header + assert.EqualValues(t, "Collaborators", strings.TrimSpace(page.Find("h4").Text())) - // Veirfy button text - page = page.Find("#repo-collab-form") - assert.EqualValues(t, "Add collaborator", strings.TrimSpace(page.Find("button.primary").Text())) + // Veirfy button text + page = page.Find("#repo-collab-form") + assert.EqualValues(t, "Add collaborator", strings.TrimSpace(page.Find("button.primary").Text())) - // Veirfy placeholder - placeholder, exists := page.Find("#search-user-box input").Attr("placeholder") - assert.True(t, exists) - assert.EqualValues(t, "Search users...", placeholder) - }) + // Veirfy placeholder + placeholder, exists := page.Find("#search-user-box input").Attr("placeholder") + assert.True(t, exists) + assert.EqualValues(t, "Search users...", placeholder) } diff --git a/tests/integration/repo_migration_ui_test.go b/tests/integration/repo_migration_ui_test.go index 40688d4a60..594b09b490 100644 --- a/tests/integration/repo_migration_ui_test.go +++ b/tests/integration/repo_migration_ui_test.go @@ -5,26 +5,26 @@ package integration import ( "net/http" - "net/url" "testing" + "code.gitea.io/gitea/tests" + "github.com/PuerkitoBio/goquery" "github.com/stretchr/testify/assert" ) func TestRepoMigrationUI(t *testing.T) { - onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { - sessionUser1 := loginUser(t, "user1") - // Nothing is tested in plain Git migration form right now - testRepoMigrationFormGitHub(t, sessionUser1) - testRepoMigrationFormGitea(t, sessionUser1) - testRepoMigrationFormGitLab(t, sessionUser1) - testRepoMigrationFormGogs(t, sessionUser1) - testRepoMigrationFormOneDev(t, sessionUser1) - testRepoMigrationFormGitBucket(t, sessionUser1) - testRepoMigrationFormCodebase(t, sessionUser1) - testRepoMigrationFormForgejo(t, sessionUser1) - }) + defer tests.PrepareTestEnv(t)() + sessionUser1 := loginUser(t, "user1") + // Nothing is tested in plain Git migration form right now + testRepoMigrationFormGitHub(t, sessionUser1) + testRepoMigrationFormGitea(t, sessionUser1) + testRepoMigrationFormGitLab(t, sessionUser1) + testRepoMigrationFormGogs(t, sessionUser1) + testRepoMigrationFormOneDev(t, sessionUser1) + testRepoMigrationFormGitBucket(t, sessionUser1) + testRepoMigrationFormCodebase(t, sessionUser1) + testRepoMigrationFormForgejo(t, sessionUser1) } func testRepoMigrationFormGitHub(t *testing.T, session *TestSession) { diff --git a/tests/integration/repo_tag_test.go b/tests/integration/repo_tag_test.go index 808d2e17e6..06b6c30383 100644 --- a/tests/integration/repo_tag_test.go +++ b/tests/integration/repo_tag_test.go @@ -11,8 +11,6 @@ import ( "testing" "code.gitea.io/gitea/models" - "code.gitea.io/gitea/models/db" - git_model "code.gitea.io/gitea/models/git" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" @@ -31,20 +29,6 @@ func TestTagViewWithoutRelease(t *testing.T) { repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) - defer func() { - releases, err := db.Find[repo_model.Release](db.DefaultContext, repo_model.FindReleasesOptions{ - IncludeTags: true, - TagNames: []string{"no-release"}, - RepoID: repo.ID, - }) - require.NoError(t, err) - - for _, release := range releases { - _, err = db.DeleteByID[repo_model.Release](db.DefaultContext, release.ID) - require.NoError(t, err) - } - }() - err := release.CreateNewTag(git.DefaultContext, owner, repo, "master", "no-release", "release-less tag") require.NoError(t, err) @@ -70,27 +54,27 @@ func TestTagViewWithoutRelease(t *testing.T) { } func TestCreateNewTagProtected(t *testing.T) { - defer tests.PrepareTestEnv(t)() + onGiteaRun(t, func(t *testing.T, u *url.URL) { + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) + owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) - owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) + t.Run("Code", func(t *testing.T) { + defer tests.PrintCurrentTest(t)() - t.Run("Code", func(t *testing.T) { - defer tests.PrintCurrentTest(t)() + err := release.CreateNewTag(git.DefaultContext, owner, repo, "master", "t-first", "first tag") + require.NoError(t, err) - err := release.CreateNewTag(git.DefaultContext, owner, repo, "master", "t-first", "first tag") - require.NoError(t, err) + err = release.CreateNewTag(git.DefaultContext, owner, repo, "master", "v-2", "second tag") + require.Error(t, err) + assert.True(t, models.IsErrProtectedTagName(err)) - err = release.CreateNewTag(git.DefaultContext, owner, repo, "master", "v-2", "second tag") - require.Error(t, err) - assert.True(t, models.IsErrProtectedTagName(err)) + err = release.CreateNewTag(git.DefaultContext, owner, repo, "master", "v-1.1", "third tag") + require.NoError(t, err) + }) - err = release.CreateNewTag(git.DefaultContext, owner, repo, "master", "v-1.1", "third tag") - require.NoError(t, err) - }) + t.Run("Git", func(t *testing.T) { + defer tests.PrintCurrentTest(t)() - t.Run("Git", func(t *testing.T) { - onGiteaRun(t, func(t *testing.T, u *url.URL) { httpContext := NewAPITestContext(t, owner.Name, repo.Name) dstPath := t.TempDir() @@ -107,10 +91,10 @@ func TestCreateNewTagProtected(t *testing.T) { require.Error(t, err) assert.Contains(t, err.Error(), "Tag v-2 is protected") }) - }) - t.Run("GitTagForce", func(t *testing.T) { - onGiteaRun(t, func(t *testing.T, u *url.URL) { + t.Run("GitTagForce", func(t *testing.T) { + defer tests.PrintCurrentTest(t)() + httpContext := NewAPITestContext(t, owner.Name, repo.Name) dstPath := t.TempDir() @@ -120,13 +104,7 @@ func TestCreateNewTagProtected(t *testing.T) { doGitClone(dstPath, u)(t) - _, _, err := git.NewCommand(git.DefaultContext, "tag", "v-1.1", "-m", "force update", "--force").RunStdString(&git.RunOpts{Dir: dstPath}) - require.NoError(t, err) - - _, _, err = git.NewCommand(git.DefaultContext, "push", "--tags").RunStdString(&git.RunOpts{Dir: dstPath}) - require.NoError(t, err) - - _, _, err = git.NewCommand(git.DefaultContext, "tag", "v-1.1", "-m", "force update v2", "--force").RunStdString(&git.RunOpts{Dir: dstPath}) + _, _, err := git.NewCommand(git.DefaultContext, "tag", "v-1.1", "-m", "force update v2", "--force").RunStdString(&git.RunOpts{Dir: dstPath}) require.NoError(t, err) _, _, err = git.NewCommand(git.DefaultContext, "push", "--tags").RunStdString(&git.RunOpts{Dir: dstPath}) @@ -142,27 +120,6 @@ func TestCreateNewTagProtected(t *testing.T) { assert.Contains(t, tagsTab.Text(), "force update v2") }) }) - - // Cleanup - releases, err := db.Find[repo_model.Release](db.DefaultContext, repo_model.FindReleasesOptions{ - IncludeTags: true, - TagNames: []string{"v-1", "v-1.1"}, - RepoID: repo.ID, - }) - require.NoError(t, err) - - for _, release := range releases { - _, err = db.DeleteByID[repo_model.Release](db.DefaultContext, release.ID) - require.NoError(t, err) - } - - protectedTags, err := git_model.GetProtectedTags(db.DefaultContext, repo.ID) - require.NoError(t, err) - - for _, protectedTag := range protectedTags { - err = git_model.DeleteProtectedTag(db.DefaultContext, protectedTag) - require.NoError(t, err) - } } func TestSyncRepoTags(t *testing.T) { @@ -200,18 +157,5 @@ func TestSyncRepoTags(t *testing.T) { require.NoError(t, repo_module.SyncRepoTags(git.DefaultContext, repo.ID)) testTag(t) }) - - // Cleanup - releases, err := db.Find[repo_model.Release](db.DefaultContext, repo_model.FindReleasesOptions{ - IncludeTags: true, - TagNames: []string{"v2"}, - RepoID: repo.ID, - }) - require.NoError(t, err) - - for _, release := range releases { - _, err = db.DeleteByID[repo_model.Release](db.DefaultContext, release.ID) - require.NoError(t, err) - } }) } diff --git a/tests/integration/repo_test.go b/tests/integration/repo_test.go index 2d12df700b..85a5002cec 100644 --- a/tests/integration/repo_test.go +++ b/tests/integration/repo_test.go @@ -902,7 +902,7 @@ func TestRepoFollowSymlink(t *testing.T) { symlinkURL, ok := htmlDoc.Find(".file-actions .button[data-kind='follow-symlink']").Attr("href") if shouldExist { assert.True(t, ok) - assert.EqualValues(t, expectedSymlinkURL, symlinkURL) + assert.Equal(t, expectedSymlinkURL, symlinkURL) //nolint:testifylint // false positive https://github.com/Antonboom/testifylint/issues/72#issuecomment-2467548358 } else { assert.False(t, ok) } @@ -1048,6 +1048,42 @@ func TestFileHistoryPager(t *testing.T) { }) } +func TestRepoIssueSorting(t *testing.T) { + defer tests.PrepareTestEnv(t)() + + t.Run("Dropdown content", func(t *testing.T) { + defer tests.PrintCurrentTest(t)() + + req := NewRequest(t, "GET", "/user2/repo1/issues") + resp := MakeRequest(t, req, http.StatusOK) + htmlDoc := NewHTMLParser(t, resp.Body) + + assert.Equal(t, + 9, + htmlDoc.Find(`.list-header-sort .menu a`).Length(), + "Wrong amount of sort options in dropdown") + + menuItemsHTML := htmlDoc.Find(`.list-header-sort .menu`).Text() + locale := translation.NewLocale("en-US") + for _, key := range []string{ + "relevance", + "latest", + "oldest", + "recentupdate", + "leastupdate", + "mostcomment", + "leastcomment", + "nearduedate", + "farduedate", + } { + assert.Contains(t, + menuItemsHTML, + locale.Tr("repo.issues.filter_sort."+key), + "Sort option %s ('%s') not found in dropdown", key, locale.Tr("repo.issues.filter_sort."+key)) + } + }) +} + func TestRepoIssueFilterLinks(t *testing.T) { defer tests.PrepareTestEnv(t)() diff --git a/tests/integration/repo_view_test.go b/tests/integration/repo_view_test.go index 7c280e2491..46e75063bc 100644 --- a/tests/integration/repo_view_test.go +++ b/tests/integration/repo_view_test.go @@ -62,8 +62,9 @@ func createRepoAndGetContext(t *testing.T, files []string, deleteMdReadme bool) } func TestRepoView_FindReadme(t *testing.T) { - t.Run("PrioOneLocalizedMdReadme", func(t *testing.T) { - onGiteaRun(t, func(t *testing.T, u *url.URL) { + onGiteaRun(t, func(t *testing.T, u *url.URL) { + t.Run("PrioOneLocalizedMdReadme", func(t *testing.T) { + defer tests.PrintCurrentTest(t)() ctx, f := createRepoAndGetContext(t, []string{"README.en.md", "README.en.org", "README.org", "README.txt", "README.tex"}, false) defer f() @@ -73,9 +74,8 @@ func TestRepoView_FindReadme(t *testing.T) { assert.Equal(t, "README.en.md", file.Name()) }) - }) - t.Run("PrioTwoMdReadme", func(t *testing.T) { - onGiteaRun(t, func(t *testing.T, u *url.URL) { + t.Run("PrioTwoMdReadme", func(t *testing.T) { + defer tests.PrintCurrentTest(t)() ctx, f := createRepoAndGetContext(t, []string{"README.en.org", "README.org", "README.txt", "README.tex"}, false) defer f() @@ -85,9 +85,8 @@ func TestRepoView_FindReadme(t *testing.T) { assert.Equal(t, "README.md", file.Name()) }) - }) - t.Run("PrioThreeLocalizedOrgReadme", func(t *testing.T) { - onGiteaRun(t, func(t *testing.T, u *url.URL) { + t.Run("PrioThreeLocalizedOrgReadme", func(t *testing.T) { + defer tests.PrintCurrentTest(t)() ctx, f := createRepoAndGetContext(t, []string{"README.en.org", "README.org", "README.txt", "README.tex"}, true) defer f() @@ -97,9 +96,8 @@ func TestRepoView_FindReadme(t *testing.T) { assert.Equal(t, "README.en.org", file.Name()) }) - }) - t.Run("PrioFourOrgReadme", func(t *testing.T) { - onGiteaRun(t, func(t *testing.T, u *url.URL) { + t.Run("PrioFourOrgReadme", func(t *testing.T) { + defer tests.PrintCurrentTest(t)() ctx, f := createRepoAndGetContext(t, []string{"README.org", "README.txt", "README.tex"}, true) defer f() @@ -109,9 +107,8 @@ func TestRepoView_FindReadme(t *testing.T) { assert.Equal(t, "README.org", file.Name()) }) - }) - t.Run("PrioFiveTxtReadme", func(t *testing.T) { - onGiteaRun(t, func(t *testing.T, u *url.URL) { + t.Run("PrioFiveTxtReadme", func(t *testing.T) { + defer tests.PrintCurrentTest(t)() ctx, f := createRepoAndGetContext(t, []string{"README.txt", "README", "README.tex"}, true) defer f() @@ -121,9 +118,8 @@ func TestRepoView_FindReadme(t *testing.T) { assert.Equal(t, "README.txt", file.Name()) }) - }) - t.Run("PrioSixWithoutExtensionReadme", func(t *testing.T) { - onGiteaRun(t, func(t *testing.T, u *url.URL) { + t.Run("PrioSixWithoutExtensionReadme", func(t *testing.T) { + defer tests.PrintCurrentTest(t)() ctx, f := createRepoAndGetContext(t, []string{"README", "README.tex"}, true) defer f() @@ -133,9 +129,8 @@ func TestRepoView_FindReadme(t *testing.T) { assert.Equal(t, "README", file.Name()) }) - }) - t.Run("PrioSevenAnyReadme", func(t *testing.T) { - onGiteaRun(t, func(t *testing.T, u *url.URL) { + t.Run("PrioSevenAnyReadme", func(t *testing.T) { + defer tests.PrintCurrentTest(t)() ctx, f := createRepoAndGetContext(t, []string{"README.tex"}, true) defer f() @@ -145,9 +140,8 @@ func TestRepoView_FindReadme(t *testing.T) { assert.Equal(t, "README.tex", file.Name()) }) - }) - t.Run("DoNotPickReadmeIfNonPresent", func(t *testing.T) { - onGiteaRun(t, func(t *testing.T, u *url.URL) { + t.Run("DoNotPickReadmeIfNonPresent", func(t *testing.T) { + defer tests.PrintCurrentTest(t)() ctx, f := createRepoAndGetContext(t, []string{}, true) defer f() diff --git a/tests/integration/repofiles_change_test.go b/tests/integration/repofiles_change_test.go index 9790b36183..1896971046 100644 --- a/tests/integration/repofiles_change_test.go +++ b/tests/integration/repofiles_change_test.go @@ -18,6 +18,7 @@ import ( "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" files_service "code.gitea.io/gitea/services/repository/files" + "code.gitea.io/gitea/tests" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -63,8 +64,8 @@ func getDeleteRepoFilesOptions(repo *repo_model.Repository) *files_service.Chang Files: []*files_service.ChangeRepoFile{ { Operation: "delete", - TreePath: "README.md", - SHA: "4b4851ad51df6a7d9f25c979345979eaeb5b349f", + TreePath: "README_new.md", + SHA: "dbf8d00e022e05b7e5cf7e535de857de57925647", }, }, LastCommitID: "", @@ -244,184 +245,142 @@ func getExpectedFileResponseForRepofilesUpdate(commitID, filename, lastCommitSHA } } -func TestChangeRepoFilesForCreate(t *testing.T) { - // setup +func TestChangeRepoFiles(t *testing.T) { onGiteaRun(t, func(t *testing.T, u *url.URL) { doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) - opts := getCreateRepoFilesOptions(repo) - // test - filesResponse, err := files_service.ChangeRepoFiles(git.DefaultContext, repo, doer, opts) - - // asserts + gitRepo, err := gitrepo.OpenRepository(git.DefaultContext, repo) require.NoError(t, err) - gitRepo, _ := gitrepo.OpenRepository(git.DefaultContext, repo) defer gitRepo.Close() - commitID, _ := gitRepo.GetBranchCommitID(opts.NewBranch) - lastCommit, _ := gitRepo.GetCommitByPath("new/file.txt") - expectedFileResponse := getExpectedFileResponseForRepofilesCreate(commitID, lastCommit.ID.String()) - assert.NotNil(t, expectedFileResponse) - if expectedFileResponse != nil { + t.Run("Create", func(t *testing.T) { + defer tests.PrintCurrentTest(t)() + opts := getCreateRepoFilesOptions(repo) + filesResponse, err := files_service.ChangeRepoFiles(git.DefaultContext, repo, doer, opts) + require.NoError(t, err) + + commitID, err := gitRepo.GetBranchCommitID(opts.NewBranch) + require.NoError(t, err) + lastCommit, err := gitRepo.GetCommitByPath("new/file.txt") + require.NoError(t, err) + expectedFileResponse := getExpectedFileResponseForRepofilesCreate(commitID, lastCommit.ID.String()) assert.EqualValues(t, expectedFileResponse.Content, filesResponse.Files[0]) assert.EqualValues(t, expectedFileResponse.Commit.SHA, filesResponse.Commit.SHA) assert.EqualValues(t, expectedFileResponse.Commit.HTMLURL, filesResponse.Commit.HTMLURL) assert.EqualValues(t, expectedFileResponse.Commit.Author.Email, filesResponse.Commit.Author.Email) assert.EqualValues(t, expectedFileResponse.Commit.Author.Name, filesResponse.Commit.Author.Name) - } - }) -} + }) -func TestChangeRepoFilesForUpdate(t *testing.T) { - // setup - onGiteaRun(t, func(t *testing.T, u *url.URL) { - doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) - opts := getUpdateRepoFilesOptions(repo) + t.Run("Update", func(t *testing.T) { + defer tests.PrintCurrentTest(t)() + opts := getUpdateRepoFilesOptions(repo) + filesResponse, err := files_service.ChangeRepoFiles(git.DefaultContext, repo, doer, opts) + require.NoError(t, err) - // test - filesResponse, err := files_service.ChangeRepoFiles(git.DefaultContext, repo, doer, opts) + commit, err := gitRepo.GetBranchCommit(opts.NewBranch) + require.NoError(t, err) + lastCommit, err := commit.GetCommitByPath(opts.Files[0].TreePath) + require.NoError(t, err) + expectedFileResponse := getExpectedFileResponseForRepofilesUpdate(commit.ID.String(), opts.Files[0].TreePath, lastCommit.ID.String()) + assert.EqualValues(t, expectedFileResponse.Content, filesResponse.Files[0]) + assert.EqualValues(t, expectedFileResponse.Commit.SHA, filesResponse.Commit.SHA) + assert.EqualValues(t, expectedFileResponse.Commit.HTMLURL, filesResponse.Commit.HTMLURL) + assert.EqualValues(t, expectedFileResponse.Commit.Author.Email, filesResponse.Commit.Author.Email) + assert.EqualValues(t, expectedFileResponse.Commit.Author.Name, filesResponse.Commit.Author.Name) + }) - // asserts - require.NoError(t, err) - gitRepo, _ := gitrepo.OpenRepository(git.DefaultContext, repo) - defer gitRepo.Close() + t.Run("Update and move", func(t *testing.T) { + defer tests.PrintCurrentTest(t)() + opts := getUpdateRepoFilesOptions(repo) + opts.Files[0].SHA = "dbf8d00e022e05b7e5cf7e535de857de57925647" + opts.Files[0].FromTreePath = "README.md" + opts.Files[0].TreePath = "README_new.md" // new file name, README_new.md + filesResponse, err := files_service.ChangeRepoFiles(git.DefaultContext, repo, doer, opts) + require.NoError(t, err) - commit, _ := gitRepo.GetBranchCommit(opts.NewBranch) - lastCommit, _ := commit.GetCommitByPath(opts.Files[0].TreePath) - expectedFileResponse := getExpectedFileResponseForRepofilesUpdate(commit.ID.String(), opts.Files[0].TreePath, lastCommit.ID.String()) - assert.EqualValues(t, expectedFileResponse.Content, filesResponse.Files[0]) - assert.EqualValues(t, expectedFileResponse.Commit.SHA, filesResponse.Commit.SHA) - assert.EqualValues(t, expectedFileResponse.Commit.HTMLURL, filesResponse.Commit.HTMLURL) - assert.EqualValues(t, expectedFileResponse.Commit.Author.Email, filesResponse.Commit.Author.Email) - assert.EqualValues(t, expectedFileResponse.Commit.Author.Name, filesResponse.Commit.Author.Name) - }) -} + commit, err := gitRepo.GetBranchCommit(opts.NewBranch) + require.NoError(t, err) + lastCommit, err := commit.GetCommitByPath(opts.Files[0].TreePath) + require.NoError(t, err) + expectedFileResponse := getExpectedFileResponseForRepofilesUpdate(commit.ID.String(), opts.Files[0].TreePath, lastCommit.ID.String()) -func TestChangeRepoFilesForUpdateWithFileMove(t *testing.T) { - // setup - onGiteaRun(t, func(t *testing.T, u *url.URL) { - doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) - opts := getUpdateRepoFilesOptions(repo) - opts.Files[0].FromTreePath = "README.md" - opts.Files[0].TreePath = "README_new.md" // new file name, README_new.md + // assert that the old file no longer exists in the last commit of the branch + fromEntry, err := commit.GetTreeEntryByPath(opts.Files[0].FromTreePath) + switch err.(type) { + case git.ErrNotExist: + // correct, continue + default: + t.Fatalf("expected git.ErrNotExist, got:%v", err) + } + toEntry, err := commit.GetTreeEntryByPath(opts.Files[0].TreePath) + require.NoError(t, err) + assert.Nil(t, fromEntry) // Should no longer exist here + assert.NotNil(t, toEntry) // Should exist here + // assert SHA has remained the same but paths use the new file name + assert.EqualValues(t, expectedFileResponse.Content.SHA, filesResponse.Files[0].SHA) + assert.EqualValues(t, expectedFileResponse.Content.Name, filesResponse.Files[0].Name) + assert.EqualValues(t, expectedFileResponse.Content.Path, filesResponse.Files[0].Path) + assert.EqualValues(t, expectedFileResponse.Content.URL, filesResponse.Files[0].URL) + assert.EqualValues(t, expectedFileResponse.Commit.SHA, filesResponse.Commit.SHA) + assert.EqualValues(t, expectedFileResponse.Commit.HTMLURL, filesResponse.Commit.HTMLURL) + }) - // test - filesResponse, err := files_service.ChangeRepoFiles(git.DefaultContext, repo, doer, opts) + t.Run("Change without branch names", func(t *testing.T) { + defer tests.PrintCurrentTest(t)() + opts := getUpdateRepoFilesOptions(repo) + opts.OldBranch = "" + opts.NewBranch = "" + opts.Files[0].TreePath = "README_new.md" + opts.Files[0].SHA = "dbf8d00e022e05b7e5cf7e535de857de57925647" - // asserts - require.NoError(t, err) - gitRepo, _ := gitrepo.OpenRepository(git.DefaultContext, repo) - defer gitRepo.Close() + filesResponse, err := files_service.ChangeRepoFiles(git.DefaultContext, repo, doer, opts) + require.NoError(t, err) - commit, _ := gitRepo.GetBranchCommit(opts.NewBranch) - lastCommit, _ := commit.GetCommitByPath(opts.Files[0].TreePath) - expectedFileResponse := getExpectedFileResponseForRepofilesUpdate(commit.ID.String(), opts.Files[0].TreePath, lastCommit.ID.String()) - // assert that the old file no longer exists in the last commit of the branch - fromEntry, err := commit.GetTreeEntryByPath(opts.Files[0].FromTreePath) - switch err.(type) { - case git.ErrNotExist: - // correct, continue - default: - t.Fatalf("expected git.ErrNotExist, got:%v", err) - } - toEntry, err := commit.GetTreeEntryByPath(opts.Files[0].TreePath) - require.NoError(t, err) - assert.Nil(t, fromEntry) // Should no longer exist here - assert.NotNil(t, toEntry) // Should exist here - // assert SHA has remained the same but paths use the new file name - assert.EqualValues(t, expectedFileResponse.Content.SHA, filesResponse.Files[0].SHA) - assert.EqualValues(t, expectedFileResponse.Content.Name, filesResponse.Files[0].Name) - assert.EqualValues(t, expectedFileResponse.Content.Path, filesResponse.Files[0].Path) - assert.EqualValues(t, expectedFileResponse.Content.URL, filesResponse.Files[0].URL) - assert.EqualValues(t, expectedFileResponse.Commit.SHA, filesResponse.Commit.SHA) - assert.EqualValues(t, expectedFileResponse.Commit.HTMLURL, filesResponse.Commit.HTMLURL) - }) -} + commit, _ := gitRepo.GetBranchCommit(repo.DefaultBranch) + lastCommit, _ := commit.GetCommitByPath(opts.Files[0].TreePath) + expectedFileResponse := getExpectedFileResponseForRepofilesUpdate(commit.ID.String(), opts.Files[0].TreePath, lastCommit.ID.String()) + assert.EqualValues(t, expectedFileResponse.Content, filesResponse.Files[0]) + }) -// Test opts with branch names removed, should get same results as above test -func TestChangeRepoFilesWithoutBranchNames(t *testing.T) { - // setup - onGiteaRun(t, func(t *testing.T, u *url.URL) { - doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) - opts := getUpdateRepoFilesOptions(repo) - opts.OldBranch = "" - opts.NewBranch = "" + t.Run("Delete files", func(t *testing.T) { + defer tests.PrintCurrentTest(t)() + opts := getDeleteRepoFilesOptions(repo) - // test - filesResponse, err := files_service.ChangeRepoFiles(git.DefaultContext, repo, doer, opts) + filesResponse, err := files_service.ChangeRepoFiles(git.DefaultContext, repo, doer, opts) + require.NoError(t, err) + expectedFileResponse := getExpectedFileResponseForRepofilesDelete() + assert.NotNil(t, filesResponse) + assert.Nil(t, filesResponse.Files[0]) + assert.EqualValues(t, expectedFileResponse.Commit.Message, filesResponse.Commit.Message) + assert.EqualValues(t, expectedFileResponse.Commit.Author.Identity, filesResponse.Commit.Author.Identity) + assert.EqualValues(t, expectedFileResponse.Commit.Committer.Identity, filesResponse.Commit.Committer.Identity) + assert.EqualValues(t, expectedFileResponse.Verification, filesResponse.Verification) - // asserts - require.NoError(t, err) - gitRepo, _ := gitrepo.OpenRepository(git.DefaultContext, repo) - defer gitRepo.Close() + filesResponse, err = files_service.ChangeRepoFiles(git.DefaultContext, repo, doer, opts) + assert.Nil(t, filesResponse) + expectedError := "repository file does not exist [path: " + opts.Files[0].TreePath + "]" + assert.EqualError(t, err, expectedError) + }) - commit, _ := gitRepo.GetBranchCommit(repo.DefaultBranch) - lastCommit, _ := commit.GetCommitByPath(opts.Files[0].TreePath) - expectedFileResponse := getExpectedFileResponseForRepofilesUpdate(commit.ID.String(), opts.Files[0].TreePath, lastCommit.ID.String()) - assert.EqualValues(t, expectedFileResponse.Content, filesResponse.Files[0]) - }) -} + t.Run("Delete without branch name", func(t *testing.T) { + defer tests.PrintCurrentTest(t)() + opts := getDeleteRepoFilesOptions(repo) + opts.OldBranch = "" + opts.NewBranch = "" + opts.Files[0].SHA = "103ff9234cefeee5ec5361d22b49fbb04d385885" + opts.Files[0].TreePath = "new/file.txt" -func TestChangeRepoFilesForDelete(t *testing.T) { - onGiteaRun(t, testDeleteRepoFiles) -} - -func testDeleteRepoFiles(t *testing.T, u *url.URL) { - // setup - unittest.PrepareTestEnv(t) - doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) - opts := getDeleteRepoFilesOptions(repo) - - t.Run("Delete README.md file", func(t *testing.T) { - filesResponse, err := files_service.ChangeRepoFiles(git.DefaultContext, repo, doer, opts) - require.NoError(t, err) - expectedFileResponse := getExpectedFileResponseForRepofilesDelete() - assert.NotNil(t, filesResponse) - assert.Nil(t, filesResponse.Files[0]) - assert.EqualValues(t, expectedFileResponse.Commit.Message, filesResponse.Commit.Message) - assert.EqualValues(t, expectedFileResponse.Commit.Author.Identity, filesResponse.Commit.Author.Identity) - assert.EqualValues(t, expectedFileResponse.Commit.Committer.Identity, filesResponse.Commit.Committer.Identity) - assert.EqualValues(t, expectedFileResponse.Verification, filesResponse.Verification) - }) - - t.Run("Verify README.md has been deleted", func(t *testing.T) { - filesResponse, err := files_service.ChangeRepoFiles(git.DefaultContext, repo, doer, opts) - assert.Nil(t, filesResponse) - expectedError := "repository file does not exist [path: " + opts.Files[0].TreePath + "]" - assert.EqualError(t, err, expectedError) - }) -} - -// Test opts with branch names removed, same results -func TestChangeRepoFilesForDeleteWithoutBranchNames(t *testing.T) { - onGiteaRun(t, testDeleteRepoFilesWithoutBranchNames) -} - -func testDeleteRepoFilesWithoutBranchNames(t *testing.T, u *url.URL) { - // setup - unittest.PrepareTestEnv(t) - doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) - - opts := getDeleteRepoFilesOptions(repo) - opts.OldBranch = "" - opts.NewBranch = "" - - t.Run("Delete README.md without Branch Name", func(t *testing.T) { - filesResponse, err := files_service.ChangeRepoFiles(git.DefaultContext, repo, doer, opts) - require.NoError(t, err) - expectedFileResponse := getExpectedFileResponseForRepofilesDelete() - assert.NotNil(t, filesResponse) - assert.Nil(t, filesResponse.Files[0]) - assert.EqualValues(t, expectedFileResponse.Commit.Message, filesResponse.Commit.Message) - assert.EqualValues(t, expectedFileResponse.Commit.Author.Identity, filesResponse.Commit.Author.Identity) - assert.EqualValues(t, expectedFileResponse.Commit.Committer.Identity, filesResponse.Commit.Committer.Identity) - assert.EqualValues(t, expectedFileResponse.Verification, filesResponse.Verification) + filesResponse, err := files_service.ChangeRepoFiles(git.DefaultContext, repo, doer, opts) + require.NoError(t, err) + expectedFileResponse := getExpectedFileResponseForRepofilesDelete() + assert.NotNil(t, filesResponse) + assert.Nil(t, filesResponse.Files[0]) + assert.EqualValues(t, expectedFileResponse.Commit.Message, filesResponse.Commit.Message) + assert.EqualValues(t, expectedFileResponse.Commit.Author.Identity, filesResponse.Commit.Author.Identity) + assert.EqualValues(t, expectedFileResponse.Commit.Committer.Identity, filesResponse.Commit.Committer.Identity) + assert.EqualValues(t, expectedFileResponse.Verification, filesResponse.Verification) + }) }) } diff --git a/tests/integration/user_avatar_test.go b/tests/integration/user_avatar_test.go index a5805d0eda..a7c0264aaa 100644 --- a/tests/integration/user_avatar_test.go +++ b/tests/integration/user_avatar_test.go @@ -10,85 +10,78 @@ import ( "io" "mime/multipart" "net/http" - "net/url" "testing" "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/avatar" + "code.gitea.io/gitea/tests" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestUserAvatar(t *testing.T) { - onGiteaRun(t, func(t *testing.T, u *url.URL) { - user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // owner of the repo3, is an org + defer tests.PrepareTestEnv(t)() + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // owner of the repo3, is an org - seed := user2.Email - if len(seed) == 0 { - seed = user2.Name - } + seed := user2.Email + if len(seed) == 0 { + seed = user2.Name + } - img, err := avatar.RandomImage([]byte(seed)) - if err != nil { - require.NoError(t, err) - return - } + img, err := avatar.RandomImage([]byte(seed)) + if err != nil { + require.NoError(t, err) + return + } - session := loginUser(t, "user2") - csrf := GetCSRF(t, session, "/user/settings") + session := loginUser(t, "user2") + csrf := GetCSRF(t, session, "/user/settings") - imgData := &bytes.Buffer{} + imgData := &bytes.Buffer{} - body := &bytes.Buffer{} + body := &bytes.Buffer{} - // Setup multi-part - writer := multipart.NewWriter(body) - writer.WriteField("source", "local") - part, err := writer.CreateFormFile("avatar", "avatar-for-testuseravatar.png") - if err != nil { - require.NoError(t, err) - return - } + // Setup multi-part + writer := multipart.NewWriter(body) + writer.WriteField("source", "local") + part, err := writer.CreateFormFile("avatar", "avatar-for-testuseravatar.png") + if err != nil { + require.NoError(t, err) + return + } - if err := png.Encode(imgData, img); err != nil { - require.NoError(t, err) - return - } + if err := png.Encode(imgData, img); err != nil { + require.NoError(t, err) + return + } - if _, err := io.Copy(part, imgData); err != nil { - require.NoError(t, err) - return - } + if _, err := io.Copy(part, imgData); err != nil { + require.NoError(t, err) + return + } - if err := writer.Close(); err != nil { - require.NoError(t, err) - return - } + if err := writer.Close(); err != nil { + require.NoError(t, err) + return + } - req := NewRequestWithBody(t, "POST", "/user/settings/avatar", body) - req.Header.Add("X-Csrf-Token", csrf) - req.Header.Add("Content-Type", writer.FormDataContentType()) + req := NewRequestWithBody(t, "POST", "/user/settings/avatar", body) + req.Header.Add("X-Csrf-Token", csrf) + req.Header.Add("Content-Type", writer.FormDataContentType()) - session.MakeRequest(t, req, http.StatusSeeOther) + session.MakeRequest(t, req, http.StatusSeeOther) - user2 = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // owner of the repo3, is an org + user2 = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // owner of the repo3, is an org - req = NewRequest(t, "GET", user2.AvatarLinkWithSize(db.DefaultContext, 0)) - _ = session.MakeRequest(t, req, http.StatusOK) + req = NewRequest(t, "GET", user2.AvatarLinkWithSize(db.DefaultContext, 0)) + _ = session.MakeRequest(t, req, http.StatusOK) - testGetAvatarRedirect(t, user2) + req = NewRequestf(t, "GET", "/%s.png", user2.Name) + resp := MakeRequest(t, req, http.StatusSeeOther) + assert.EqualValues(t, fmt.Sprintf("/avatars/%s", user2.Avatar), resp.Header().Get("location")) - // Can't test if the response matches because the image is re-generated on upload but checking that this at least doesn't give a 404 should be enough. - }) -} - -func testGetAvatarRedirect(t *testing.T, user *user_model.User) { - t.Run(fmt.Sprintf("getAvatarRedirect_%s", user.Name), func(t *testing.T) { - req := NewRequestf(t, "GET", "/%s.png", user.Name) - resp := MakeRequest(t, req, http.StatusSeeOther) - assert.EqualValues(t, fmt.Sprintf("/avatars/%s", user.Avatar), resp.Header().Get("location")) - }) + // Can't test if the response matches because the image is re-generated on upload but checking that this at least doesn't give a 404 should be enough. } diff --git a/tests/integration/user_profile_activity_test.go b/tests/integration/user_profile_activity_test.go index 8f3042678a..77d188903e 100644 --- a/tests/integration/user_profile_activity_test.go +++ b/tests/integration/user_profile_activity_test.go @@ -5,11 +5,11 @@ package integration import ( "net/http" - "net/url" "strconv" "testing" "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/tests" "github.com/stretchr/testify/assert" ) @@ -23,70 +23,69 @@ import ( // - Profile visibility // - Public activity visibility func TestUserProfileActivity(t *testing.T) { - onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { - // This test needs multiple users with different access statuses to check for all possible states - userAdmin := loginUser(t, "user1") - userRegular := loginUser(t, "user2") - // Activity availability should be the same for guest and another non-admin user, so this is not tested separately - userGuest := emptyTestSession(t) + defer tests.PrepareTestEnv(t)() + // This test needs multiple users with different access statuses to check for all possible states + userAdmin := loginUser(t, "user1") + userRegular := loginUser(t, "user2") + // Activity availability should be the same for guest and another non-admin user, so this is not tested separately + userGuest := emptyTestSession(t) - // = Public profile, public activity = + // = Public profile, public activity = - // Set activity visibility of user2 to public. This is the default, but won't hurt to set it before testing. - testChangeUserActivityVisibility(t, userRegular, "off") + // Set activity visibility of user2 to public. This is the default, but won't hurt to set it before testing. + testChangeUserActivityVisibility(t, userRegular, "off") - // Verify availability of RSS button and activity tab - testUser2ActivityButtonsAvailability(t, userAdmin, true) - testUser2ActivityButtonsAvailability(t, userRegular, true) - testUser2ActivityButtonsAvailability(t, userGuest, true) + // Verify availability of RSS button and activity tab + testUser2ActivityButtonsAvailability(t, userAdmin, true) + testUser2ActivityButtonsAvailability(t, userRegular, true) + testUser2ActivityButtonsAvailability(t, userGuest, true) - // Verify the hint for all types of users: admin, self, guest - testUser2ActivityVisibility(t, userAdmin, "This activity is visible to everyone, but as an administrator you can also see interactions in private spaces.", true) - hintLink := testUser2ActivityVisibility(t, userRegular, "Your activity is visible to everyone, except for interactions in private spaces. Configure.", true) - testUser2ActivityVisibility(t, userGuest, "", true) + // Verify the hint for all types of users: admin, self, guest + testUser2ActivityVisibility(t, userAdmin, "This activity is visible to everyone, but as an administrator you can also see interactions in private spaces.", true) + hintLink := testUser2ActivityVisibility(t, userRegular, "Your activity is visible to everyone, except for interactions in private spaces. Configure.", true) + testUser2ActivityVisibility(t, userGuest, "", true) - // When viewing own profile, the user is offered to configure activity visibility. Verify that the link is correct and works, also check that it links back to the activity tab. - linkCorrect := assert.EqualValues(t, "/user/settings#keep-activity-private", hintLink) - if linkCorrect { - page := NewHTMLParser(t, userRegular.MakeRequest(t, NewRequest(t, "GET", hintLink), http.StatusOK).Body) - activityLink, exists := page.Find(".field:has(.checkbox#keep-activity-private) .help a").Attr("href") - assert.True(t, exists) - assert.EqualValues(t, "/user2?tab=activity", activityLink) - } + // When viewing own profile, the user is offered to configure activity visibility. Verify that the link is correct and works, also check that it links back to the activity tab. + linkCorrect := assert.EqualValues(t, "/user/settings#keep-activity-private", hintLink) + if linkCorrect { + page := NewHTMLParser(t, userRegular.MakeRequest(t, NewRequest(t, "GET", hintLink), http.StatusOK).Body) + activityLink, exists := page.Find(".field:has(.checkbox#keep-activity-private) .help a").Attr("href") + assert.True(t, exists) + assert.EqualValues(t, "/user2?tab=activity", activityLink) + } - // = Private profile, but public activity = + // = Private profile, but public activity = - // Set profile visibility of user2 to private - testChangeUserProfileVisibility(t, userRegular, structs.VisibleTypePrivate) + // Set profile visibility of user2 to private + testChangeUserProfileVisibility(t, userRegular, structs.VisibleTypePrivate) - // When profile activity is configured as public, but the profile is private, tell the user about this and link to visibility settings. - hintLink = testUser2ActivityVisibility(t, userRegular, "Your activity is only visible to you and the instance administrators because your profile is private. Configure.", true) - assert.EqualValues(t, "/user/settings#visibility-setting", hintLink) + // When profile activity is configured as public, but the profile is private, tell the user about this and link to visibility settings. + hintLink = testUser2ActivityVisibility(t, userRegular, "Your activity is only visible to you and the instance administrators because your profile is private. Configure.", true) + assert.EqualValues(t, "/user/settings#visibility-setting", hintLink) - // When the profile is private, tell the admin about this. - testUser2ActivityVisibility(t, userAdmin, "This activity is visible to you because you're an administrator, but the user wants it to remain private.", true) + // When the profile is private, tell the admin about this. + testUser2ActivityVisibility(t, userAdmin, "This activity is visible to you because you're an administrator, but the user wants it to remain private.", true) - // Set profile visibility of user2 back to public - testChangeUserProfileVisibility(t, userRegular, structs.VisibleTypePublic) + // Set profile visibility of user2 back to public + testChangeUserProfileVisibility(t, userRegular, structs.VisibleTypePublic) - // = Private acitivty = + // = Private acitivty = - // Set activity visibility of user2 to private - testChangeUserActivityVisibility(t, userRegular, "on") + // Set activity visibility of user2 to private + testChangeUserActivityVisibility(t, userRegular, "on") - // Verify availability of RSS button and activity tab - testUser2ActivityButtonsAvailability(t, userAdmin, true) - testUser2ActivityButtonsAvailability(t, userRegular, true) - testUser2ActivityButtonsAvailability(t, userGuest, false) + // Verify availability of RSS button and activity tab + testUser2ActivityButtonsAvailability(t, userAdmin, true) + testUser2ActivityButtonsAvailability(t, userRegular, true) + testUser2ActivityButtonsAvailability(t, userGuest, false) - // Verify the hint for all types of users: admin, self, guest - testUser2ActivityVisibility(t, userAdmin, "This activity is visible to you because you're an administrator, but the user wants it to remain private.", true) - hintLink = testUser2ActivityVisibility(t, userRegular, "Your activity is only visible to you and the instance administrators. Configure.", true) - testUser2ActivityVisibility(t, userGuest, "This user has disabled the public visibility of the activity.", false) + // Verify the hint for all types of users: admin, self, guest + testUser2ActivityVisibility(t, userAdmin, "This activity is visible to you because you're an administrator, but the user wants it to remain private.", true) + hintLink = testUser2ActivityVisibility(t, userRegular, "Your activity is only visible to you and the instance administrators. Configure.", true) + testUser2ActivityVisibility(t, userGuest, "This user has disabled the public visibility of the activity.", false) - // Verify that Configure link is correct - assert.EqualValues(t, "/user/settings#keep-activity-private", hintLink) - }) + // Verify that Configure link is correct + assert.EqualValues(t, "/user/settings#keep-activity-private", hintLink) } // testChangeUserActivityVisibility allows to easily change visibility of public activity for a user diff --git a/tests/integration/user_profile_follows_test.go b/tests/integration/user_profile_follows_test.go index bad0944d88..24b74268e6 100644 --- a/tests/integration/user_profile_follows_test.go +++ b/tests/integration/user_profile_follows_test.go @@ -6,10 +6,11 @@ package integration import ( "fmt" "net/http" - "net/url" "strings" "testing" + "code.gitea.io/gitea/tests" + "github.com/stretchr/testify/assert" ) @@ -19,92 +20,92 @@ import ( // - Followers and Following lists have correct amounts of items // - %d followers and %following counters are always present and always have correct numbers and use correct plurals func TestUserProfileFollows(t *testing.T) { - onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { - // This test needs 3 users to check for all possible states - // The accounts of user3 and user4 are not functioning - user1 := loginUser(t, "user1") - user2 := loginUser(t, "user2") - user5 := loginUser(t, "user5") + defer tests.PrepareTestEnv(t)() - followersLink := "#profile-avatar-card a[href='/user1?tab=followers']" - followingLink := "#profile-avatar-card a[href='/user1?tab=following']" - listHeader := ".user-cards h2" - listItems := ".user-cards .list" + // This test needs 3 users to check for all possible states + // The accounts of user3 and user4 are not functioning + user1 := loginUser(t, "user1") + user2 := loginUser(t, "user2") + user5 := loginUser(t, "user5") - // = No follows = + followersLink := "#profile-avatar-card a[href='/user1?tab=followers']" + followingLink := "#profile-avatar-card a[href='/user1?tab=following']" + listHeader := ".user-cards h2" + listItems := ".user-cards .list" - var followCount int + // = No follows = - // Request the profile of user1, the Followers tab - response := user1.MakeRequest(t, NewRequest(t, "GET", "/user1?tab=followers"), http.StatusOK) - page := NewHTMLParser(t, response.Body) + var followCount int - // Verify that user1 has no followers - testSelectorEquals(t, page, followersLink, "0 followers") - testSelectorEquals(t, page, listHeader, "Followers") - testListCount(t, page, listItems, followCount) + // Request the profile of user1, the Followers tab + response := user1.MakeRequest(t, NewRequest(t, "GET", "/user1?tab=followers"), http.StatusOK) + page := NewHTMLParser(t, response.Body) - // Request the profile of user1, the Following tab - response = user1.MakeRequest(t, NewRequest(t, "GET", "/user1?tab=following"), http.StatusOK) - page = NewHTMLParser(t, response.Body) + // Verify that user1 has no followers + testSelectorEquals(t, page, followersLink, "0 followers") + testSelectorEquals(t, page, listHeader, "Followers") + testListCount(t, page, listItems, followCount) - // Verify that user1 does not follow anyone - testSelectorEquals(t, page, followingLink, "0 following") - testSelectorEquals(t, page, listHeader, "Following") - testListCount(t, page, listItems, followCount) + // Request the profile of user1, the Following tab + response = user1.MakeRequest(t, NewRequest(t, "GET", "/user1?tab=following"), http.StatusOK) + page = NewHTMLParser(t, response.Body) - // Make user1 and user2 follow each other - testUserFollowUser(t, user1, "user2") - testUserFollowUser(t, user2, "user1") + // Verify that user1 does not follow anyone + testSelectorEquals(t, page, followingLink, "0 following") + testSelectorEquals(t, page, listHeader, "Following") + testListCount(t, page, listItems, followCount) - // = 1 follow each = + // Make user1 and user2 follow each other + testUserFollowUser(t, user1, "user2") + testUserFollowUser(t, user2, "user1") - followCount++ + // = 1 follow each = - // Request the profile of user1, the Followers tab - response = user1.MakeRequest(t, NewRequest(t, "GET", "/user1?tab=followers"), http.StatusOK) - page = NewHTMLParser(t, response.Body) + followCount++ - // Verify it is now followed by 1 user - testSelectorEquals(t, page, followersLink, "1 follower") - testSelectorEquals(t, page, listHeader, "Follower") - testListCount(t, page, listItems, followCount) + // Request the profile of user1, the Followers tab + response = user1.MakeRequest(t, NewRequest(t, "GET", "/user1?tab=followers"), http.StatusOK) + page = NewHTMLParser(t, response.Body) - // Request the profile of user1, the Following tab - response = user1.MakeRequest(t, NewRequest(t, "GET", "/user1?tab=following"), http.StatusOK) - page = NewHTMLParser(t, response.Body) + // Verify it is now followed by 1 user + testSelectorEquals(t, page, followersLink, "1 follower") + testSelectorEquals(t, page, listHeader, "Follower") + testListCount(t, page, listItems, followCount) - // Verify it now follows follows 1 user - testSelectorEquals(t, page, followingLink, "1 following") - testSelectorEquals(t, page, listHeader, "Following") - testListCount(t, page, listItems, followCount) + // Request the profile of user1, the Following tab + response = user1.MakeRequest(t, NewRequest(t, "GET", "/user1?tab=following"), http.StatusOK) + page = NewHTMLParser(t, response.Body) - // Make user1 and user3 follow each other - testUserFollowUser(t, user1, "user5") - testUserFollowUser(t, user5, "user1") + // Verify it now follows follows 1 user + testSelectorEquals(t, page, followingLink, "1 following") + testSelectorEquals(t, page, listHeader, "Following") + testListCount(t, page, listItems, followCount) - // = 2 follows = + // Make user1 and user3 follow each other + testUserFollowUser(t, user1, "user5") + testUserFollowUser(t, user5, "user1") - followCount++ + // = 2 follows = - // Request the profile of user1, the Followers tab - response = user1.MakeRequest(t, NewRequest(t, "GET", "/user1?tab=followers"), http.StatusOK) - page = NewHTMLParser(t, response.Body) + followCount++ - // Verify it is now followed by 2 users - testSelectorEquals(t, page, followersLink, "2 followers") - testSelectorEquals(t, page, listHeader, "Followers") - testListCount(t, page, listItems, followCount) + // Request the profile of user1, the Followers tab + response = user1.MakeRequest(t, NewRequest(t, "GET", "/user1?tab=followers"), http.StatusOK) + page = NewHTMLParser(t, response.Body) - // Request the profile of user1, the Following tab - response = user1.MakeRequest(t, NewRequest(t, "GET", "/user1?tab=following"), http.StatusOK) - page = NewHTMLParser(t, response.Body) + // Verify it is now followed by 2 users + testSelectorEquals(t, page, followersLink, "2 followers") + testSelectorEquals(t, page, listHeader, "Followers") + testListCount(t, page, listItems, followCount) - // Verify it now follows follows 2 users - testSelectorEquals(t, page, followingLink, "2 following") - testSelectorEquals(t, page, listHeader, "Following") - testListCount(t, page, listItems, followCount) - }) + // Request the profile of user1, the Following tab + response = user1.MakeRequest(t, NewRequest(t, "GET", "/user1?tab=following"), http.StatusOK) + page = NewHTMLParser(t, response.Body) + + // Verify it now follows follows 2 users + testSelectorEquals(t, page, followingLink, "2 following") + testSelectorEquals(t, page, listHeader, "Following") + testListCount(t, page, listItems, followCount) } // testUserFollowUser simply follows a user `following` by session of user `follower` diff --git a/tests/pgsql.ini.tmpl b/tests/pgsql.ini.tmpl index b58d753b6c..01d018c5b7 100644 --- a/tests/pgsql.ini.tmpl +++ b/tests/pgsql.ini.tmpl @@ -112,7 +112,7 @@ MINIO_BASE_PATH = avatars/ MINIO_BASE_PATH = repo-avatars/ [storage] -STORAGE_TYPE = minio +STORAGE_TYPE = {{TEST_STORAGE_TYPE}} SERVE_DIRECT = false MINIO_ENDPOINT = minio:9000 MINIO_ACCESS_KEY_ID = 123456 diff --git a/web_src/css/form.css b/web_src/css/form.css index a8867009bc..fb9364db45 100644 --- a/web_src/css/form.css +++ b/web_src/css/form.css @@ -500,20 +500,6 @@ textarea:focus, } } -/* form fields with additional content besides their label, used on login form - * use like
*/ -.form-field-content-aside-label { - display: grid; - grid-template-columns: 1fr 1fr; -} -.form-field-content-aside-label > *:nth-child(2) { - text-align: right; - margin-bottom: 4px; -} -.form-field-content-aside-label input { - grid-column: span 2; -} - .ui.form .field > .selection.dropdown { min-width: 14em; /* matches the default min width */ } diff --git a/web_src/css/themes/theme-forgejo-dark.css b/web_src/css/themes/theme-forgejo-dark.css index 9622add8e5..bc321f38a8 100644 --- a/web_src/css/themes/theme-forgejo-dark.css +++ b/web_src/css/themes/theme-forgejo-dark.css @@ -140,6 +140,23 @@ --color-pink-dark-2: #b11d5f; --color-brown-dark-2: #a47252; --color-black-dark-2: #111827; + /* ansi colors used for actions console and console files */ + --color-ansi-black: #1d2328; + --color-ansi-red: #cc4848; + --color-ansi-green: #87ab63; + --color-ansi-yellow: #cc9903; + --color-ansi-blue: #3a8ac6; + --color-ansi-magenta: #d22e8b; + --color-ansi-cyan: #00918a; + --color-ansi-white: var(--color-console-fg-subtle); + --color-ansi-bright-black: #424851; + --color-ansi-bright-red: #d15a5a; + --color-ansi-bright-green: #93b373; + --color-ansi-bright-yellow: #eaaf03; + --color-ansi-bright-blue: #4e96cc; + --color-ansi-bright-magenta: #d74397; + --color-ansi-bright-cyan: #00b6ad; + --color-ansi-bright-white: var(--color-console-fg); /* other colors */ --color-gold: #b1983b; --color-white: #ffffff; diff --git a/web_src/css/themes/theme-forgejo-light.css b/web_src/css/themes/theme-forgejo-light.css index 201818964b..fa89cc2ec8 100644 --- a/web_src/css/themes/theme-forgejo-light.css +++ b/web_src/css/themes/theme-forgejo-light.css @@ -157,6 +157,23 @@ --color-pink-dark-2: #b11d5f; --color-brown-dark-2: #835b42; --color-black-dark-2: #000000; + /* ansi colors used for actions console and console files */ + --color-ansi-black: #1f2326; + --color-ansi-red: #cc4848; + --color-ansi-green: #87ab63; + --color-ansi-yellow: #cc9903; + --color-ansi-blue: #3a8ac6; + --color-ansi-magenta: #d22e8b; + --color-ansi-cyan: #00918a; + --color-ansi-white: var(--color-console-fg-subtle); + --color-ansi-bright-black: #46494d; + --color-ansi-bright-red: #d15a5a; + --color-ansi-bright-green: #93b373; + --color-ansi-bright-yellow: #eaaf03; + --color-ansi-bright-blue: #4e96cc; + --color-ansi-bright-magenta: #d74397; + --color-ansi-bright-cyan: #00b6ad; + --color-ansi-bright-white: var(--color-console-fg); /* other colors */ --color-gold: #b1983b; --color-white: #ffffff;