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 @@
-
{{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}}
{{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}}
{{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}}{{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}}
@@ -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 .When ctx.Locale}} |
+ {{DateUtils.TimeSince .When}} |
{{else}}
diff --git a/templates/repo/settings/lfs_locks.tmpl b/templates/repo/settings/lfs_locks.tmpl
index 9a18f525e9..64c6b3a550 100644
--- a/templates/repo/settings/lfs_locks.tmpl
+++ b/templates/repo/settings/lfs_locks.tmpl
@@ -35,7 +35,7 @@
{{$lock.Owner.DisplayName}}
- {{TimeSince .Created ctx.Locale}} |
+ {{DateUtils.TimeSince .Created}} |
|
{{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}}
-
+
{{end}}
@@ -52,11 +51,15 @@
{{template "user/auth/webauthn_error" .}}
- {{if .ShowRegistrationButton}}
- {{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/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;
|
{{ctx.Locale.Tr "repo.activity.merged_prs_label"}} #{{.Index}} {{RenderRefIssueTitle $.Context .Issue.Title}} - {{TimeSinceUnix .MergedUnix ctx.Locale}} + {{DateUtils.TimeSince .MergedUnix}}
{{end}}{{ctx.Locale.Tr "repo.activity.opened_prs_label"}} #{{.Index}} {{RenderRefIssueTitle $.Context .Issue.Title}} - {{TimeSinceUnix .Issue.CreatedUnix ctx.Locale}} + {{DateUtils.TimeSince .Issue.CreatedUnix}}
{{end}}{{ctx.Locale.Tr "repo.activity.closed_issue_label"}} #{{.Index}} {{RenderRefIssueTitle $.Context .Title}} - {{TimeSinceUnix .ClosedUnix ctx.Locale}} + {{DateUtils.TimeSince .ClosedUnix}}
{{end}}{{ctx.Locale.Tr "repo.activity.new_issue_label"}} #{{.Index}} {{RenderRefIssueTitle $.Context .Title}} - {{TimeSinceUnix .CreatedUnix ctx.Locale}} + {{DateUtils.TimeSince .CreatedUnix}}
{{end}}