Compare commits

..

11 Commits

Author SHA1 Message Date
Lunny Xiao
377a0a20f0
Merge setting.InitXXX into one function with options (#24389)
This PR will merge 3 Init functions on setting packages as 1 and
introduce an options struct.
2023-05-04 11:55:35 +08:00
Yarden Shoham
a2fe68e50b
Changelog for 1.19.3 (#24495) (#24506)
Frontport #24495

Co-authored-by: techknowlogick <techknowlogick@gitea.io>
Co-authored-by: John Olheiser <john.olheiser@gmail.com>
2023-05-03 22:05:47 -04:00
techknowlogick
f7f0782132
Use Actions for DB & E2E tests (#24494)
following https://github.com/go-gitea/gitea/pull/24314 and
https://github.com/go-gitea/gitea/pull/24434, this PR moves drone cron
pipelines to (GitHub) Actions. As these are mostly compatible with Gitea
Actions, when we start to dogfood, these will already be migrated.

---------

Co-authored-by: silverwind <me@silverwind.io>
2023-05-04 02:04:02 +00:00
zeripath
ad8631c069
Fix intermittent CI failure in EmptyQueue (#23753)
The ordering of the final token causing a close of the queue in this
test may be out of sync due to concurrency. Instead just use ensure that
the queue is closed when everything expected is done.

Fixes: https://github.com/go-gitea/gitea/issues/23608
Fixes: https://github.com/go-gitea/gitea/issues/23977

---------

Signed-off-by: Andrew Thornton <art27@cantab.net>
Co-authored-by: KN4CK3R <admin@oldschoolhack.me>
2023-05-03 21:37:30 -04:00
Jack Hay
402df1d6b4
Prevent a user with a different email from accepting the team invite (#24491)
## Changes
- Fixes the case where a logged in user can accept an email invitation
even if their email address does not match the address in the invitation
2023-05-03 21:21:58 -04:00
yp05327
dbb3736785
Fix incorrect webhook time and use relative-time to display it (#24477)
Fixes #24414
After click replay this webhook, it will display `now`

![image](https://user-images.githubusercontent.com/18380374/235559399-05a23927-13f5-442d-8f10-2c7cd24022a0.png)

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Giteabot <teabot@gitea.io>
2023-05-03 19:53:43 -04:00
silverwind
4a722c9a45
Make Issue/PR/projects more compact, misc CSS tweaks (#24459)
- Remove various horizontal dividers on repo pages that didn't provide
visual benefit
- Remove label/milestone pills on single issue/pr page
- Remove issue-related pill buttons on projects page
- Increase contrast of color-secondary on arc-green
- Improve notifications icon, make circle bigger
- Remove some inline styles
- Fix focus in issue/pr title edit and select all text on button click

### Issue and PR before and after

<img width="1249" alt="Screenshot 2023-05-01 at 11 44 22"
src="https://user-images.githubusercontent.com/115237/235436662-a708288e-84fb-4b2e-a5a2-3a1c17d28f6c.png">
<img width="1248" alt="Screenshot 2023-05-01 at 11 58 51"
src="https://user-images.githubusercontent.com/115237/235437992-f863e483-f3cc-4cc1-8204-fd223647a0c9.png">



### Projects before and after

<img width="1255" alt="Screenshot 2023-05-01 at 11 41 02"
src="https://user-images.githubusercontent.com/115237/235436433-0deb85d6-4e7d-4e74-847f-254cc70a0cf9.png">
<img width="1267" alt="Screenshot 2023-05-01 at 11 40 03"
src="https://user-images.githubusercontent.com/115237/235436431-715b13cb-f78c-4d86-b27a-9229f9738c5b.png">


### Releases before and after

<img width="1243" alt="Screenshot 2023-05-01 at 11 41 12"
src="https://user-images.githubusercontent.com/115237/235436457-b655ee6f-03b8-4595-8d8c-b15ea469e988.png">
<img width="1240" alt="Screenshot 2023-05-01 at 11 40 10"
src="https://user-images.githubusercontent.com/115237/235436456-05a2a0dd-7cbb-4f26-b0d3-4f667df4bb95.png">

### Misc

<img width="58" alt="Screenshot 2023-05-01 at 10 49 13"
src="https://user-images.githubusercontent.com/115237/235432494-936ce995-6e22-47bc-ab2d-c9e93d31987d.png">
<img width="57" alt="Screenshot 2023-05-01 at 18 57 08"
src="https://user-images.githubusercontent.com/115237/235492430-1d32cfe0-0f2c-467c-b2fa-925b27e30e0e.png">


Issue title edit and wrap:

<img width="1238" alt="Screenshot 2023-05-01 at 12 34 40"
src="https://user-images.githubusercontent.com/115237/235441407-d5067a57-e586-4865-a652-282e5944abb4.png">
<img width="1232" alt="Screenshot 2023-05-01 at 12 06 24"
src="https://user-images.githubusercontent.com/115237/235438710-1a543dda-220f-4d87-8f93-f1710c0695f0.png">

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2023-05-03 17:58:59 -04:00
KN4CK3R
723598b803
Implement Cargo HTTP index (#24452)
This implements the HTTP index
[RFC](https://rust-lang.github.io/rfcs/2789-sparse-index.html) for Cargo
registries.

Currently this is a preview feature and you need to use the nightly of
`cargo`:

`cargo +nightly -Z sparse-registry update`

See https://github.com/rust-lang/cargo/issues/9069 for more information.

---------

Co-authored-by: Giteabot <teabot@gitea.io>
2023-05-03 16:58:43 -04:00
wxiaoguang
48e3e38ee0
Clean up polluted styles and remove dead CSS code (#24497)
Follow #24393


The funny history:

* At the beginning, `.ui.message` was polluted by `text-align: center`
* Then people do `<div class="ui ... message text left">`
* But `.ui.left` is polluted by `float: left`
* Then people do `#xxx .ui.message { width: 100% !important;}`

The code just becomes more and more hacky.

After removing the pollution,  everything becomes clear and straight.


And, this PR also does:

1. Remove the `package.css`, its styles could be provided by `top
aligned`
2. Remove `#avatar-arrow`, dead code



Screenshot:


![image](https://user-images.githubusercontent.com/2114189/235862130-a9eb5d8f-7d01-457c-99f7-21d0abc3075e.png)


![image](https://user-images.githubusercontent.com/2114189/235862222-139709a7-95c2-4f89-a40f-100b2d76d9bb.png)

Co-authored-by: Giteabot <teabot@gitea.io>
2023-05-03 14:32:10 -04:00
Lunny Xiao
e9b39250b2
Improve pull request merge box when pull request merged and branch deleted. (#24397)
This PR hide the pull request merge box totally if it's merged and branch deleted.

It's also add a bold for merge base commit id in merged message comment

Before:

<img width="989" alt="图片"
src="https://user-images.githubusercontent.com/81045/235066590-28deb506-e824-4a42-a9a2-791cd136756e.png">

After:

<img width="1030" alt="图片"
src="https://user-images.githubusercontent.com/81045/235080749-11d5efe8-a06e-4528-a75f-f6c6d191db50.png">

---------

Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2023-05-03 21:52:19 +08:00
silverwind
a9ed87ce4a
Fix EasyMDE toolbar (#24489)
Fixes https://github.com/go-gitea/gitea/issues/24486

The "clean block" button is gone because I could not find a matching
octicon. Order of buttons is roughly equal to textarea.

<img width="824" alt="Screenshot 2023-05-02 at 21 10 00"
src="https://user-images.githubusercontent.com/115237/235762593-ceccb260-e665-4932-ac8a-ef6fe8406a3c.png">

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2023-05-03 01:23:39 -04:00
98 changed files with 1311 additions and 1574 deletions

View File

@ -1,749 +1,3 @@
---
kind: pipeline
type: docker
name: compliance
platform:
os: linux
arch: amd64
trigger:
event:
- pull_request
paths:
exclude:
- "docs/**"
- "*.md"
volumes:
- name: deps
temp: {}
steps:
- name: deps-frontend
image: node:18
pull: always
commands:
- make deps-frontend
- name: deps-backend
image: gitea/test_env:linux-1.20-amd64
pull: always
commands:
- make deps-backend
- make deps-tools
volumes:
- name: deps
path: /go
- name: lint-frontend
image: node:18
commands:
- make lint-frontend
depends_on: [deps-frontend]
- name: lint-backend
image: gitea/test_env:linux-1.20-amd64 # https://gitea.com/gitea/test-env
pull: always
commands:
- make lint-backend
environment:
GOPROXY: https://goproxy.io # proxy.golang.org is blocked in China, this proxy is not
GOSUMDB: sum.golang.org
TAGS: bindata sqlite sqlite_unlock_notify
depends_on: [deps-backend]
volumes:
- name: deps
path: /go
- name: lint-backend-windows
image: gitea/test_env:linux-1.20-amd64 # https://gitea.com/gitea/test-env
commands:
- make lint-go-windows lint-go-vet
environment:
GOPROXY: https://goproxy.io # proxy.golang.org is blocked in China, this proxy is not
GOSUMDB: sum.golang.org
TAGS: bindata sqlite sqlite_unlock_notify
GOOS: windows
GOARCH: amd64
depends_on: [deps-backend]
volumes:
- name: deps
path: /go
- name: lint-backend-gogit
image: gitea/test_env:linux-1.20-amd64 # https://gitea.com/gitea/test-env
commands:
- make lint-backend
environment:
GOPROXY: https://goproxy.io # proxy.golang.org is blocked in China, this proxy is not
GOSUMDB: sum.golang.org
TAGS: bindata gogit sqlite sqlite_unlock_notify
depends_on: [deps-backend]
volumes:
- name: deps
path: /go
- name: checks-frontend
image: node:18
commands:
- make checks-frontend
depends_on: [deps-frontend]
- name: checks-backend
image: gitea/test_env:linux-1.20-amd64
commands:
- make --always-make checks-backend # ensure the 'go-licenses' make target runs
depends_on: [deps-backend]
volumes:
- name: deps
path: /go
- name: test-frontend
image: node:18
commands:
- make test-frontend
depends_on: [lint-frontend]
- name: build-frontend
image: node:18
commands:
- make frontend
depends_on: [deps-frontend]
- name: build-backend-no-gcc
image: gitea/test_env:linux-1.19-amd64 # this step is kept as the lowest version of golang that we support
pull: always
environment:
GOPROXY: https://goproxy.io
commands:
- go build -o gitea_no_gcc # test if build succeeds without the sqlite tag
depends_on: [deps-backend, checks-backend]
volumes:
- name: deps
path: /go
- name: build-backend-arm64
image: gitea/test_env:linux-1.20-amd64
environment:
GOPROXY: https://goproxy.io
GOOS: linux
GOARCH: arm64
TAGS: bindata gogit
commands:
- make backend # test cross compile
- rm ./gitea # clean
depends_on: [deps-backend, checks-backend]
volumes:
- name: deps
path: /go
- name: build-backend-windows
image: gitea/test_env:linux-1.20-amd64
environment:
GOPROXY: https://goproxy.io
GOOS: windows
GOARCH: amd64
TAGS: bindata gogit
commands:
- go build -o gitea_windows
depends_on: [deps-backend, checks-backend]
volumes:
- name: deps
path: /go
- name: build-backend-386
image: gitea/test_env:linux-1.20-amd64
environment:
GOPROXY: https://goproxy.io
GOOS: linux
GOARCH: 386
commands:
- go build -o gitea_linux_386 # test if compatible with 32 bit
depends_on: [deps-backend, checks-backend]
volumes:
- name: deps
path: /go
---
kind: pipeline
type: docker
name: testing-pgsql
platform:
os: linux
arch: amd64
depends_on:
- compliance
trigger:
event:
- pull_request
paths:
exclude:
- "docs/**"
volumes:
- name: deps
temp: {}
services:
- name: pgsql
pull: default
image: postgres:15
environment:
POSTGRES_DB: test
POSTGRES_PASSWORD: postgres
- name: ldap
image: gitea/test-openldap:latest
pull: always
- name: minio
image: minio/minio:RELEASE.2021-03-12T00-00-47Z
pull: always
commands:
- minio server /data
environment:
MINIO_ACCESS_KEY: 123456
MINIO_SECRET_KEY: 12345678
steps:
- name: fetch-tags
image: docker:git
pull: always
commands:
- git fetch --tags --force
when:
event:
exclude:
- pull_request
- name: deps-backend
image: gitea/test_env:linux-1.20-amd64
pull: always
commands:
- make deps-backend
volumes:
- name: deps
path: /go
- name: prepare-test-env
image: gitea/test_env:linux-1.20-amd64 # https://gitea.com/gitea/test-env
pull: always
commands:
- ./build/test-env-prepare.sh
- name: build
image: gitea/test_env:linux-1.20-amd64 # https://gitea.com/gitea/test-env
user: gitea
commands:
- ./build/test-env-check.sh
- make backend
environment:
GOPROXY: https://goproxy.io # proxy.golang.org is blocked in China, this proxy is not
GOSUMDB: sum.golang.org
TAGS: bindata
depends_on: [deps-backend, prepare-test-env]
volumes:
- name: deps
path: /go
- name: test-pgsql
image: gitea/test_env:linux-1.20-amd64 # https://gitea.com/gitea/test-env
user: gitea
commands:
- timeout -s ABRT 50m make test-pgsql-migration test-pgsql
environment:
GOPROXY: https://goproxy.io
TAGS: bindata gogit
RACE_ENABLED: true
TEST_TAGS: gogit
TEST_LDAP: 1
USE_REPO_TEST_DIR: 1
depends_on: [build]
volumes:
- name: deps
path: /go
---
kind: pipeline
type: docker
name: testing-mysql
platform:
os: linux
arch: amd64
depends_on:
- compliance
trigger:
event:
- pull_request
paths:
exclude:
- "docs/**"
volumes:
- name: deps
temp: {}
services:
- name: mysql
image: mysql:5.7
pull: always
environment:
MYSQL_ALLOW_EMPTY_PASSWORD: yes
MYSQL_DATABASE: test
- name: elasticsearch
image: elasticsearch:7.5.0
pull: always
environment:
discovery.type: single-node
- name: smtpimap
image: tabascoterrier/docker-imap-devel:latest
pull: always
steps:
- name: fetch-tags
image: docker:git
pull: always
commands:
- git fetch --tags --force
when:
event:
exclude:
- pull_request
- name: deps-backend
image: gitea/test_env:linux-1.20-amd64
pull: always
commands:
- make deps-backend
volumes:
- name: deps
path: /go
- name: prepare-test-env
image: gitea/test_env:linux-1.20-amd64 # https://gitea.com/gitea/test-env
pull: always
commands:
- ./build/test-env-prepare.sh
- name: build
image: gitea/test_env:linux-1.20-amd64 # https://gitea.com/gitea/test-env
user: gitea
commands:
- ./build/test-env-check.sh
- make backend
environment:
GOPROXY: https://goproxy.io # proxy.golang.org is blocked in China, this proxy is not
GOSUMDB: sum.golang.org
TAGS: bindata
depends_on: [deps-backend, prepare-test-env]
volumes:
- name: deps
path: /go
- name: unit-test
image: gitea/test_env:linux-1.20-amd64 # https://gitea.com/gitea/test-env
user: gitea
commands:
- make unit-test-coverage test-check
environment:
GOPROXY: https://goproxy.io
TAGS: bindata
RACE_ENABLED: true
GITHUB_READ_TOKEN:
from_secret: github_read_token
depends_on: [deps-backend, prepare-test-env]
volumes:
- name: deps
path: /go
- name: unit-test-gogit
image: gitea/test_env:linux-1.20-amd64 # https://gitea.com/gitea/test-env
user: gitea
commands:
- make unit-test-coverage test-check
environment:
GOPROXY: https://goproxy.io
TAGS: bindata gogit
RACE_ENABLED: true
GITHUB_READ_TOKEN:
from_secret: github_read_token
depends_on: [deps-backend, prepare-test-env]
volumes:
- name: deps
path: /go
- name: test-mysql
image: gitea/test_env:linux-1.20-amd64 # https://gitea.com/gitea/test-env
user: gitea
commands:
- make test-mysql-migration integration-test-coverage
environment:
GOPROXY: https://goproxy.io
TAGS: bindata
RACE_ENABLED: true
USE_REPO_TEST_DIR: 1
TEST_INDEXER_CODE_ES_URL: "http://elastic:changeme@elasticsearch:9200"
depends_on: [build]
volumes:
- name: deps
path: /go
- name: generate-coverage
image: gitea/test_env:linux-1.20-amd64
commands:
- make coverage
environment:
GOPROXY: https://goproxy.io
TAGS: bindata
depends_on: [unit-test, test-mysql]
when:
branch:
- main
event:
- push
- pull_request
- name: coverage-codecov
image: woodpeckerci/plugin-codecov:next-alpine
pull: always
settings:
files:
- coverage.all
token:
from_secret: codecov_token
depends_on: [generate-coverage]
when:
branch:
- main
event:
- push
- pull_request
---
kind: pipeline
type: docker
name: testing-mysql8
platform:
os: linux
arch: amd64
depends_on:
- compliance
trigger:
event:
- pull_request
paths:
exclude:
- "docs/**"
volumes:
- name: deps
temp: {}
services:
- name: mysql8
image: mysql:8
pull: always
environment:
MYSQL_ALLOW_EMPTY_PASSWORD: yes
MYSQL_DATABASE: testgitea
steps:
- name: fetch-tags
image: docker:git
pull: always
commands:
- git fetch --tags --force
when:
event:
exclude:
- pull_request
- name: deps-backend
image: gitea/test_env:linux-1.20-amd64
pull: always
commands:
- make deps-backend
volumes:
- name: deps
path: /go
- name: prepare-test-env
image: gitea/test_env:linux-1.20-amd64 # https://gitea.com/gitea/test-env
pull: always
commands:
- ./build/test-env-prepare.sh
- name: build
image: gitea/test_env:linux-1.20-amd64 # https://gitea.com/gitea/test-env
user: gitea
commands:
- ./build/test-env-check.sh
- make backend
environment:
GOPROXY: https://goproxy.io # proxy.golang.org is blocked in China, this proxy is not
GOSUMDB: sum.golang.org
TAGS: bindata
depends_on: [deps-backend, prepare-test-env]
volumes:
- name: deps
path: /go
- name: test-mysql8
image: gitea/test_env:linux-1.20-amd64 # https://gitea.com/gitea/test-env
user: gitea
commands:
- timeout -s ABRT 50m make test-mysql8-migration test-mysql8
environment:
GOPROXY: https://goproxy.io
TAGS: bindata
USE_REPO_TEST_DIR: 1
depends_on: [build]
volumes:
- name: deps
path: /go
---
kind: pipeline
type: docker
name: testing-mssql
platform:
os: linux
arch: amd64
depends_on:
- compliance
trigger:
event:
- pull_request
paths:
exclude:
- "docs/**"
volumes:
- name: deps
temp: {}
services:
- name: mssql
image: mcr.microsoft.com/mssql/server:latest
pull: always
environment:
ACCEPT_EULA: Y
MSSQL_PID: Standard
SA_PASSWORD: MwantsaSecurePassword1
steps:
- name: fetch-tags
image: docker:git
pull: always
commands:
- git fetch --tags --force
when:
event:
exclude:
- pull_request
- name: deps-backend
image: gitea/test_env:linux-1.20-amd64
pull: always
commands:
- make deps-backend
volumes:
- name: deps
path: /go
- name: prepare-test-env
image: gitea/test_env:linux-1.20-amd64 # https://gitea.com/gitea/test-env
pull: always
commands:
- ./build/test-env-prepare.sh
- name: build
image: gitea/test_env:linux-1.20-amd64 # https://gitea.com/gitea/test-env
user: gitea
commands:
- ./build/test-env-check.sh
- make backend
environment:
GOPROXY: https://goproxy.io # proxy.golang.org is blocked in China, this proxy is not
GOSUMDB: sum.golang.org
TAGS: bindata
depends_on: [deps-backend, prepare-test-env]
volumes:
- name: deps
path: /go
- name: test-mssql
image: gitea/test_env:linux-1.20-amd64 # https://gitea.com/gitea/test-env
user: gitea
commands:
- make test-mssql-migration test-mssql
environment:
GOPROXY: https://goproxy.io
TAGS: bindata
USE_REPO_TEST_DIR: 1
depends_on: [build]
volumes:
- name: deps
path: /go
---
kind: pipeline
name: testing-sqlite
platform:
os: linux
arch: arm64
depends_on:
- compliance
trigger:
event:
- pull_request
paths:
exclude:
- "docs/**"
volumes:
- name: deps
temp: {}
steps:
- name: fetch-tags
image: docker:git
pull: always
commands:
- git fetch --tags --force
when:
event:
exclude:
- pull_request
- name: deps-backend
image: gitea/test_env:linux-1.20-arm64
pull: always
commands:
- make deps-backend
volumes:
- name: deps
path: /go
- name: prepare-test-env
image: gitea/test_env:linux-1.20-arm64 # https://gitea.com/gitea/test-env
pull: always
commands:
- ./build/test-env-prepare.sh
- name: build
image: gitea/test_env:linux-1.20-arm64 # https://gitea.com/gitea/test-env
user: gitea
commands:
- ./build/test-env-check.sh
- make backend
environment:
GOPROXY: https://goproxy.io # proxy.golang.org is blocked in China, this proxy is not
GOSUMDB: sum.golang.org
TAGS: bindata gogit sqlite sqlite_unlock_notify
depends_on: [deps-backend, prepare-test-env]
volumes:
- name: deps
path: /go
- name: test-sqlite
image: gitea/test_env:linux-1.20-arm64 # https://gitea.com/gitea/test-env
user: gitea
commands:
- timeout -s ABRT 50m make test-sqlite-migration test-sqlite
environment:
GOPROXY: https://goproxy.io
TAGS: bindata gogit sqlite sqlite_unlock_notify
RACE_ENABLED: true
TEST_TAGS: gogit sqlite sqlite_unlock_notify
USE_REPO_TEST_DIR: 1
depends_on: [build]
volumes:
- name: deps
path: /go
---
kind: pipeline
type: docker
name: testing-e2e
platform:
os: linux
arch: amd64
depends_on:
- compliance
trigger:
event:
- pull_request
paths:
exclude:
- "docs/**"
volumes:
- name: deps
temp: {}
steps:
- name: deps-frontend
image: node:18
pull: always
commands:
- make deps-frontend
- name: build-frontend
image: node:18
commands:
- make frontend
depends_on: [deps-frontend]
- name: deps-backend
image: gitea/test_env:linux-1.20-amd64
pull: always
commands:
- make deps-backend
volumes:
- name: deps
path: /go
# TODO: We should probably build all dependencies into a test image
- name: test-e2e
image: mcr.microsoft.com/playwright:v1.32.3-focal
commands:
- apt-get -qq update && apt-get -qqy install jq build-essential
- curl -fsSL "https://go.dev/dl/$(curl -s 'https://go.dev/dl/?mode=json' | jq -r '.[].version' | sort -Vr | head -1).linux-amd64.tar.gz" | tar -xz -C /usr/local
- groupadd --gid 1001 gitea && useradd -m --gid 1001 --uid 1001 gitea
- ./build/test-env-prepare.sh
- su gitea bash -c "export PATH=$PATH:/usr/local/go/bin && timeout -s ABRT 40m make test-e2e-sqlite"
environment:
GOPROXY: https://goproxy.io
GOSUMDB: sum.golang.org
USE_REPO_TEST_DIR: 1
DEBIAN_FRONTEND: noninteractive
depends_on: [build-frontend, deps-backend]
volumes:
- name: deps
path: /go
--- ---
kind: pipeline kind: pipeline
type: docker type: docker
@ -767,13 +21,6 @@ trigger:
exclude: exclude:
- "docs/**" - "docs/**"
depends_on:
- testing-mysql
- testing-mysql8
- testing-mssql
- testing-pgsql
- testing-sqlite
volumes: volumes:
- name: deps - name: deps
temp: {} temp: {}
@ -902,13 +149,6 @@ trigger:
event: event:
- tag - tag
depends_on:
- testing-mysql
- testing-mysql8
- testing-mssql
- testing-pgsql
- testing-sqlite
volumes: volumes:
- name: deps - name: deps
temp: {} temp: {}
@ -1013,22 +253,12 @@ platform:
os: linux os: linux
arch: amd64 arch: amd64
depends_on:
- testing-mysql
- testing-mysql8
- testing-mssql
- testing-pgsql
- testing-sqlite
trigger: trigger:
ref: ref:
include: include:
- "refs/tags/**" - "refs/tags/**"
exclude: exclude:
- "refs/tags/**-rc*" - "refs/tags/**-rc*"
event:
exclude:
- cron
paths: paths:
exclude: exclude:
- "docs/**" - "docs/**"
@ -1093,19 +323,9 @@ platform:
os: linux os: linux
arch: amd64 arch: amd64
depends_on:
- testing-mysql
- testing-mysql8
- testing-mssql
- testing-pgsql
- testing-sqlite
trigger: trigger:
ref: ref:
- "refs/tags/**-rc*" - "refs/tags/**-rc*"
event:
exclude:
- cron
paths: paths:
exclude: exclude:
- "docs/**" - "docs/**"
@ -1168,19 +388,9 @@ platform:
os: linux os: linux
arch: amd64 arch: amd64
depends_on:
- testing-mysql
- testing-mysql8
- testing-mssql
- testing-pgsql
- testing-sqlite
trigger: trigger:
ref: ref:
- refs/heads/main - refs/heads/main
event:
exclude:
- cron
steps: steps:
- name: fetch-tags - name: fetch-tags
@ -1241,19 +451,9 @@ platform:
os: linux os: linux
arch: amd64 arch: amd64
depends_on:
- testing-mysql
- testing-mysql8
- testing-mssql
- testing-pgsql
- testing-sqlite
trigger: trigger:
ref: ref:
- "refs/heads/release/v*" - "refs/heads/release/v*"
event:
exclude:
- cron
steps: steps:
- name: fetch-tags - name: fetch-tags
@ -1315,22 +515,12 @@ platform:
os: linux os: linux
arch: arm64 arch: arm64
depends_on:
- testing-mysql
- testing-mysql8
- testing-mssql
- testing-pgsql
- testing-sqlite
trigger: trigger:
ref: ref:
include: include:
- "refs/tags/**" - "refs/tags/**"
exclude: exclude:
- "refs/tags/**-rc*" - "refs/tags/**-rc*"
event:
exclude:
- cron
paths: paths:
exclude: exclude:
- "docs/**" - "docs/**"
@ -1395,19 +585,9 @@ platform:
os: linux os: linux
arch: arm64 arch: arm64
depends_on:
- testing-mysql
- testing-mysql8
- testing-mssql
- testing-pgsql
- testing-sqlite
trigger: trigger:
ref: ref:
- "refs/tags/**-rc*" - "refs/tags/**-rc*"
event:
exclude:
- cron
paths: paths:
exclude: exclude:
- "docs/**" - "docs/**"
@ -1470,19 +650,9 @@ platform:
os: linux os: linux
arch: arm64 arch: arm64
depends_on:
- testing-mysql
- testing-mysql8
- testing-mssql
- testing-pgsql
- testing-sqlite
trigger: trigger:
ref: ref:
- refs/heads/main - refs/heads/main
event:
exclude:
- cron
paths: paths:
exclude: exclude:
- "docs/**" - "docs/**"
@ -1546,19 +716,9 @@ platform:
os: linux os: linux
arch: arm64 arch: arm64
depends_on:
- testing-mysql
- testing-mysql8
- testing-mssql
- testing-pgsql
- testing-sqlite
trigger: trigger:
ref: ref:
- "refs/heads/release/v*" - "refs/heads/release/v*"
event:
exclude:
- cron
steps: steps:
- name: fetch-tags - name: fetch-tags
@ -1647,9 +807,6 @@ steps:
trigger: trigger:
ref: ref:
- "refs/tags/**" - "refs/tags/**"
event:
exclude:
- cron
paths: paths:
exclude: exclude:
- "docs/**" - "docs/**"
@ -1697,9 +854,6 @@ trigger:
ref: ref:
- refs/heads/main - refs/heads/main
- "refs/heads/release/v*" - "refs/heads/release/v*"
event:
exclude:
- cron
paths: paths:
exclude: exclude:
- "docs/**" - "docs/**"

View File

@ -1,10 +1,10 @@
name: "Cron: Update licenses and gitignores"
on: on:
schedule: schedule:
# weekly on Monday at 0:07 UTC # weekly on Monday at 0:07 UTC
- cron: "7 0 * * 1" - cron: "7 0 * * 1"
name: Update licenses and gitignores
jobs: jobs:
cron: cron:
runs-on: ubuntu-latest runs-on: ubuntu-latest

View File

@ -1,9 +1,9 @@
name: "Cron: Pull translations from Crowdin"
on: on:
schedule: schedule:
- cron: "7 0 * * *" # every day at 0:07 UTC - cron: "7 0 * * *" # every day at 0:07 UTC
name: Pull translations from Crowdin
jobs: jobs:
crowdin_pull: crowdin_pull:
runs-on: ubuntu-latest runs-on: ubuntu-latest

133
.github/workflows/pull-compliance.yml vendored Normal file
View File

@ -0,0 +1,133 @@
name: "Pull: Compliance Tests"
on: [pull_request]
jobs:
lint_basic:
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/checkout@v3
- name: setup go
uses: actions/setup-go@v4
with:
go-version: '>=1.20'
- name: deps-backend
run: make deps-backend deps-tools
- name: lint backend
run: make lint-backend
env:
GOPROXY: https://goproxy.io # proxy.golang.org is blocked in China, this proxy is not
GOSUMDB: sum.golang.org
TAGS: bindata sqlite sqlite_unlock_notify
lint_windows:
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/checkout@v3
- name: setup go
uses: actions/setup-go@v4
with:
go-version: '>=1.20'
- name: deps-backend
run: make deps-backend deps-tools
- name: lint-backend-windows
run: make lint-go-windows lint-go-vet
env:
GOPROXY: https://goproxy.io # proxy.golang.org is blocked in China, this proxy is not
GOSUMDB: sum.golang.org
TAGS: bindata sqlite sqlite_unlock_notify
GOOS: windows
GOARCH: amd64
lint_gogit:
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/checkout@v3
- name: setup go
uses: actions/setup-go@v4
with:
go-version: '>=1.20'
- name: deps-backend
run: make deps-backend deps-tools
- name: lint-backend-gogit
run: make lint-backend
env:
GOPROXY: https://goproxy.io # proxy.golang.org is blocked in China, this proxy is not
GOSUMDB: sum.golang.org
TAGS: bindata gogit sqlite sqlite_unlock_notify
- name: checks backend
run: make --always-make checks-backend # ensure the 'go-licenses' make target runs
check_backend:
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/checkout@v3
- name: setup go
uses: actions/setup-go@v4
with:
go-version: '>=1.20'
- name: deps-backend
run: make deps-backend deps-tools
- name: checks backend
run: make --always-make checks-backend # ensure the 'go-licenses' make target runs
frontend:
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/checkout@v3
- name: setup node
uses: actions/setup-node@v3
with:
node-version: 18
- name: deps-frontend
run: make deps-frontend
- name: lint frontend
run: make lint-frontend
- name: checks frontend
run: make checks-frontend
- name: test frontend
run: make test-frontend
backend:
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/checkout@v3
- name: setup go
uses: actions/setup-go@v4
with:
go-version: '>=1.20'
- name: setup node
uses: actions/setup-node@v3
with:
node-version: 18
- name: deps-backend
run: make deps-backend deps-tools
- name: deps-frontend
run: make deps-frontend
- name: build frontend
run: make frontend
- name: build-backend-no-gcc
run: go build -o gitea_no_gcc # test if build succeeds without the sqlite tag
env:
GOPROXY: https://goproxy.io
- name: build-backend-arm64
run: make backend # test cross compile
env:
GOPROXY: https://goproxy.io
GOOS: linux
GOARCH: arm64
TAGS: bindata gogit
- name: build-backend-windows
run: go build -o gitea_windows
env:
GOPROXY: https://goproxy.io
GOOS: windows
GOARCH: amd64
TAGS: bindata gogit
- name: build-backend-386
run: go build -o gitea_linux_386 # test if compatible with 32 bit
env:
GOPROXY: https://goproxy.io
GOOS: linux
GOARCH: 386

View File

@ -1,4 +1,4 @@
name: Compliance testing for documentation name: "Pull: Compliance testing for documentation"
on: on:
pull_request: pull_request:

260
.github/workflows/pull-db_test.yml vendored Normal file
View File

@ -0,0 +1,260 @@
name: "Pull: Database Tests"
on: [pull_request]
jobs:
# PostgreSQL Tests
db_pgsql_test:
runs-on: ubuntu-latest
services:
pgsql:
image: postgres:15
env:
POSTGRES_DB: test
POSTGRES_PASSWORD: postgres
ports:
- "5432:5432"
ldap:
image: gitea/test-openldap:latest
ports:
- "389:389"
- "636:636"
minio:
# as github actions doesn't support "entrypoint", we need to use a non-official image
# that has a custom entrypoint set to "minio server /data"
image: bitnami/minio:2021.3.17
env:
MINIO_ACCESS_KEY: 123456
MINIO_SECRET_KEY: 12345678
ports:
- "9000:9000"
steps:
- name: checkout
uses: actions/checkout@v3
- name: setup go
uses: actions/setup-go@v4
with:
go-version: '>=1.20.0'
- name: Add hosts to /etc/hosts
run: echo "127.0.0.1 pgsql ldap minio" | sudo tee -a /etc/hosts
- name: install dependencies
run: make deps-backend
- name: build
run: make backend
env:
GOPROXY: https://goproxy.io
GOSUMDB: sum.golang.org
TAGS: bindata
- name: run tests
run: timeout -s ABRT 50m make test-pgsql-migration test-pgsql
env:
GOPROXY: https://goproxy.io
TAGS: bindata gogit
RACE_ENABLED: true
TEST_TAGS: gogit
TEST_LDAP: 1
USE_REPO_TEST_DIR: 1
# SQLite Tests
db_sqlite_test:
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/checkout@v3
- name: setup go
uses: actions/setup-go@v4
with:
go-version: '>=1.20.0'
- name: install dependencies
run: make deps-backend
- name: build
run: make backend
env:
GOPROXY: https://goproxy.io
GOSUMDB: sum.golang.org
TAGS: bindata gogit sqlite sqlite_unlock_notify
- name: run tests
run: timeout -s ABRT 50m make test-sqlite-migration test-sqlite
env:
GOPROXY: https://goproxy.io
TAGS: bindata gogit sqlite sqlite_unlock_notify
RACE_ENABLED: true
TEST_TAGS: gogit sqlite sqlite_unlock_notify
USE_REPO_TEST_DIR: 1
# Unit Tests
db_unit_tests:
runs-on: ubuntu-latest
services:
mysql:
image: mysql:5.7
env:
MYSQL_ALLOW_EMPTY_PASSWORD: yes
MYSQL_DATABASE: test
ports:
- "3306:3306"
elasticsearch:
image: elasticsearch:7.5.0
env:
discovery.type: single-node
ports:
- "9200:9200"
smtpimap:
image: tabascoterrier/docker-imap-devel:latest
ports:
- "25:25"
- "143:143"
- "587:587"
- "993:993"
steps:
- name: checkout
uses: actions/checkout@v3
- name: setup go
uses: actions/setup-go@v4
with:
go-version: '>=1.20.0'
- name: Add hosts to /etc/hosts
run: echo "127.0.0.1 mysql elasticsearch smtpimap" | sudo tee -a /etc/hosts
- name: install dependencies
run: make deps-backend
- name: build
run: make backend
env:
GOPROXY: https://goproxy.io
GOSUMDB: sum.golang.org
TAGS: bindata
- name: unit tests
run: make unit-test-coverage test-check
env:
GOPROXY: https://goproxy.io
TAGS: bindata
RACE_ENABLED: true
GITHUB_READ_TOKEN: ${{ secrets.GITHUB_READ_TOKEN }}
- name: unit tests (gogit)
run: make unit-test-coverage test-check
env:
GOPROXY: https://goproxy.io
TAGS: bindata gogit
RACE_ENABLED: true
GITHUB_READ_TOKEN: ${{ secrets.GITHUB_READ_TOKEN }}
# MySQL Tests
db_mysql_test:
runs-on: ubuntu-latest
services:
mysql:
image: mysql:5.7
env:
MYSQL_ALLOW_EMPTY_PASSWORD: yes
MYSQL_DATABASE: test
ports:
- "3306:3306"
elasticsearch:
image: elasticsearch:7.5.0
env:
discovery.type: single-node
ports:
- "9200:9200"
smtpimap:
image: tabascoterrier/docker-imap-devel:latest
ports:
- "25:25"
- "143:143"
- "587:587"
- "993:993"
steps:
- name: checkout
uses: actions/checkout@v3
- name: setup go
uses: actions/setup-go@v4
with:
go-version: '>=1.20.0'
- name: Add hosts to /etc/hosts
run: echo "127.0.0.1 mysql elasticsearch smtpimap" | sudo tee -a /etc/hosts
- name: install dependencies
run: make deps-backend
- name: build
run: make backend
env:
GOPROXY: https://goproxy.io
GOSUMDB: sum.golang.org
TAGS: bindata
- name: run tests
run: make test-mysql-migration integration-test-coverage
env:
GOPROXY: https://goproxy.io
TAGS: bindata
RACE_ENABLED: true
USE_REPO_TEST_DIR: 1
TEST_INDEXER_CODE_ES_URL: "http://elastic:changeme@elasticsearch:9200"
# MySQL8 Tests
db_mysql8_test:
runs-on: ubuntu-latest
services:
mysql8:
image: mysql:8
env:
MYSQL_ALLOW_EMPTY_PASSWORD: yes
MYSQL_DATABASE: testgitea
ports:
- "3306:3306"
steps:
- name: checkout
uses: actions/checkout@v3
- name: setup go
uses: actions/setup-go@v4
with:
go-version: '>=1.20.0'
- name: Add hosts to /etc/hosts
run: echo "127.0.0.1 mysql8" | sudo tee -a /etc/hosts
- name: install dependencies
run: make deps-backend
- name: build
run: make backend
env:
GOPROXY: https://goproxy.io
GOSUMDB: sum.golang.org
TAGS: bindata
- name: run tests
run: timeout -s ABRT 50m make test-mysql8-migration test-mysql8
env:
GOPROXY: https://goproxy.io
TAGS: bindata
USE_REPO_TEST_DIR: 1
# MSSQL Tests
db_mssql_test:
runs-on: ubuntu-latest
services:
mssql:
image: mcr.microsoft.com/mssql/server:latest
env:
ACCEPT_EULA: Y
MSSQL_PID: Standard
SA_PASSWORD: MwantsaSecurePassword1
ports:
- "1433:1433"
steps:
- name: checkout
uses: actions/checkout@v3
- name: setup go
uses: actions/setup-go@v4
with:
go-version: '>=1.20.0'
- name: Add hosts to /etc/hosts
run: echo "127.0.0.1 mssql" | sudo tee -a /etc/hosts
- name: install dependencies
run: make deps-backend
- name: build
run: make backend
env:
GOPROXY: https://goproxy.io
GOSUMDB: sum.golang.org
TAGS: bindata
- name: run tests
run: timeout -s ABRT 50m make test-mssql-migration test-mssql
env:
GOPROXY: https://goproxy.io
TAGS: bindata
USE_REPO_TEST_DIR: 1

View File

@ -1,4 +1,4 @@
name: Docker build dry run name: "Pull: Docker Dry Run"
on: [pull_request] on: [pull_request]

28
.github/workflows/pull-e2e.yml vendored Normal file
View File

@ -0,0 +1,28 @@
name: "Pull: E2E Tests"
on: [pull_request]
jobs:
e2e_tests:
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/checkout@v3
- name: setup go
uses: actions/setup-go@v4
with:
go-version: '>=1.20'
- name: setup node
uses: actions/setup-node@v3
with:
node-version: 18
- name: build
run: make deps-frontend frontend deps-backend
- name: Install playwright browsers
run: npx playwright install --with-deps
- name: run tests
run: timeout -s ABRT 40m make test-e2e-sqlite
env:
GOPROXY: https://goproxy.io
GOSUMDB: sum.golang.org
USE_REPO_TEST_DIR: 1

View File

@ -1,4 +1,4 @@
name: Publish documentation name: "Docs: Publish"
on: on:
push: push:

View File

@ -4,6 +4,19 @@ This changelog goes through all the changes that have been made in each release
without substantial changes to our git log; to see the highlights of what has without substantial changes to our git log; to see the highlights of what has
been added to each release, please refer to the [blog](https://blog.gitea.io). been added to each release, please refer to the [blog](https://blog.gitea.io).
## [1.19.3](https://github.com/go-gitea/gitea/releases/tag/1.19.3) - 2023-05-03
* SECURITY
* Use golang 1.20.4 to fix CVE-2023-24539, CVE-2023-24540, and CVE-2023-29400
* ENHANCEMENTS
* Enable whitespace rendering on selection in Monaco (#24444) (#24485)
* Improve milestone filter on issues page (#22423) (#24440)
* BUGFIXES
* Fix api error message if fork exists (#24487) (#24493)
* Fix user-cards format (#24428) (#24431)
* Fix incorrect CurrentUser check for docker rootless (#24435)
* Getting the tag list does not require being signed in (#24413) (#24416)
## [1.19.2](https://github.com/go-gitea/gitea/releases/tag/1.19.2) - 2023-04-26 ## [1.19.2](https://github.com/go-gitea/gitea/releases/tag/1.19.2) - 2023-04-26
* SECURITY * SECURITY

View File

@ -42,8 +42,7 @@ func runGenerateActionsRunnerToken(c *cli.Context) error {
ctx, cancel := installSignals() ctx, cancel := installSignals()
defer cancel() defer cancel()
setting.InitProviderFromExistingFile() setting.Init(&setting.Options{})
setting.LoadCommonSettings()
scope := c.String("scope") scope := c.String("scope")

View File

@ -57,8 +57,7 @@ func confirm() (bool, error) {
} }
func initDB(ctx context.Context) error { func initDB(ctx context.Context) error {
setting.InitProviderFromExistingFile() setting.Init(&setting.Options{})
setting.LoadCommonSettings()
setting.LoadDBSetting() setting.LoadDBSetting()
setting.InitSQLLog(false) setting.InitSQLLog(false)

View File

@ -87,8 +87,7 @@ func runRecreateTable(ctx *cli.Context) error {
golog.SetPrefix("") golog.SetPrefix("")
golog.SetOutput(log.NewLoggerAsWriter("INFO", log.GetLogger(log.DEFAULT))) golog.SetOutput(log.NewLoggerAsWriter("INFO", log.GetLogger(log.DEFAULT)))
setting.InitProviderFromExistingFile() setting.Init(&setting.Options{})
setting.LoadCommonSettings()
setting.LoadDBSetting() setting.LoadDBSetting()
setting.Log.EnableXORMLog = ctx.Bool("debug") setting.Log.EnableXORMLog = ctx.Bool("debug")

View File

@ -185,8 +185,7 @@ func runDump(ctx *cli.Context) error {
} }
fileName += "." + outType fileName += "." + outType
} }
setting.InitProviderFromExistingFile() setting.Init(&setting.Options{})
setting.LoadCommonSettings()
// make sure we are logging to the console no matter what the configuration tells us do to // make sure we are logging to the console no matter what the configuration tells us do to
// FIXME: don't use CfgProvider directly // FIXME: don't use CfgProvider directly

View File

@ -106,8 +106,9 @@ func initEmbeddedExtractor(c *cli.Context) error {
log.DelNamedLogger(log.DEFAULT) log.DelNamedLogger(log.DEFAULT)
// Read configuration file // Read configuration file
setting.InitProviderAllowEmpty() setting.Init(&setting.Options{
setting.LoadCommonSettings() AllowEmpty: true,
})
patterns, err := compileCollectPatterns(c.Args()) patterns, err := compileCollectPatterns(c.Args())
if err != nil { if err != nil {

View File

@ -16,8 +16,7 @@ func runSendMail(c *cli.Context) error {
ctx, cancel := installSignals() ctx, cancel := installSignals()
defer cancel() defer cancel()
setting.InitProviderFromExistingFile() setting.Init(&setting.Options{})
setting.LoadCommonSettings()
if err := argsSet(c, "title"); err != nil { if err := argsSet(c, "title"); err != nil {
return err return err

View File

@ -7,14 +7,8 @@ import (
"testing" "testing"
"code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/models/unittest"
"code.gitea.io/gitea/modules/setting"
) )
func init() {
setting.SetCustomPathAndConf("", "", "")
setting.InitProviderAndLoadCommonSettingsForTest()
}
func TestMain(m *testing.M) { func TestMain(m *testing.M) {
unittest.MainTest(m, &unittest.TestOptions{ unittest.MainTest(m, &unittest.TestOptions{
GiteaRootPath: "..", GiteaRootPath: "..",

View File

@ -51,8 +51,7 @@ func runRestoreRepository(c *cli.Context) error {
ctx, cancel := installSignals() ctx, cancel := installSignals()
defer cancel() defer cancel()
setting.InitProviderFromExistingFile() setting.Init(&setting.Options{})
setting.LoadCommonSettings()
var units []string var units []string
if s := c.String("units"); s != "" { if s := c.String("units"); s != "" {
units = strings.Split(s, ",") units = strings.Split(s, ",")

View File

@ -62,8 +62,7 @@ func setup(ctx context.Context, debug bool) {
} else { } else {
_ = log.NewLogger(1000, "console", "console", `{"level":"fatal","stacktracelevel":"NONE","stderr":true}`) _ = log.NewLogger(1000, "console", "console", `{"level":"fatal","stacktracelevel":"NONE","stderr":true}`)
} }
setting.InitProviderFromExistingFile() setting.Init(&setting.Options{})
setting.LoadCommonSettings()
if debug { if debug {
setting.RunMode = "dev" setting.RunMode = "dev"
} }

View File

@ -177,8 +177,7 @@ func runWeb(ctx *cli.Context) error {
log.Info("Global init") log.Info("Global init")
// Perform global initialization // Perform global initialization
setting.InitProviderFromExistingFile() setting.Init(&setting.Options{})
setting.LoadCommonSettings()
routers.GlobalInitInstalled(graceful.GetManager().HammerContext()) routers.GlobalInitInstalled(graceful.GetManager().HammerContext())
// We check that AppDataPath exists here (it should have been created during installation) // We check that AppDataPath exists here (it should have been created during installation)

View File

@ -8,14 +8,8 @@ import (
"testing" "testing"
"code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/models/unittest"
"code.gitea.io/gitea/modules/setting"
) )
func init() {
setting.SetCustomPathAndConf("", "", "")
setting.InitProviderAndLoadCommonSettingsForTest()
}
func TestMain(m *testing.M) { func TestMain(m *testing.M) {
unittest.MainTest(m, &unittest.TestOptions{ unittest.MainTest(m, &unittest.TestOptions{
GiteaRootPath: filepath.Join("..", ".."), GiteaRootPath: filepath.Join("..", ".."),

View File

@ -8,14 +8,8 @@ import (
"testing" "testing"
"code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/models/unittest"
"code.gitea.io/gitea/modules/setting"
) )
func init() {
setting.SetCustomPathAndConf("", "", "")
setting.InitProviderAndLoadCommonSettingsForTest()
}
func TestMain(m *testing.M) { func TestMain(m *testing.M) {
unittest.MainTest(m, &unittest.TestOptions{ unittest.MainTest(m, &unittest.TestOptions{
GiteaRootPath: filepath.Join("..", ".."), GiteaRootPath: filepath.Join("..", ".."),

View File

@ -9,7 +9,6 @@ import (
issues_model "code.gitea.io/gitea/models/issues" issues_model "code.gitea.io/gitea/models/issues"
"code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/models/unittest"
"code.gitea.io/gitea/modules/setting"
_ "code.gitea.io/gitea/models" _ "code.gitea.io/gitea/models"
_ "code.gitea.io/gitea/models/repo" _ "code.gitea.io/gitea/models/repo"
@ -18,11 +17,6 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func init() {
setting.SetCustomPathAndConf("", "", "")
setting.InitProviderAndLoadCommonSettingsForTest()
}
func TestFixturesAreConsistent(t *testing.T) { func TestFixturesAreConsistent(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase()) assert.NoError(t, unittest.PrepareTestDatabase())
unittest.CheckConsistencyFor(t, unittest.CheckConsistencyFor(t,

View File

@ -11,18 +11,12 @@ import (
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/setting"
_ "code.gitea.io/gitea/models/system" _ "code.gitea.io/gitea/models/system"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func init() {
setting.SetCustomPathAndConf("", "", "")
setting.InitProviderAndLoadCommonSettingsForTest()
}
// TestFixturesAreConsistent assert that test fixtures are consistent // TestFixturesAreConsistent assert that test fixtures are consistent
func TestFixturesAreConsistent(t *testing.T) { func TestFixturesAreConsistent(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase()) assert.NoError(t, unittest.PrepareTestDatabase())

View File

@ -150,7 +150,7 @@ func MainTest(m *testing.M) {
setting.AppDataPath = tmpDataPath setting.AppDataPath = tmpDataPath
setting.SetCustomPathAndConf("", "", "") setting.SetCustomPathAndConf("", "", "")
setting.InitProviderAndLoadCommonSettingsForTest() unittest.InitSettings()
if err = git.InitFull(context.Background()); err != nil { if err = git.InitFull(context.Background()); err != nil {
fmt.Printf("Unable to InitFull: %v\n", err) fmt.Printf("Unable to InitFull: %v\n", err)
os.Exit(1) os.Exit(1)

View File

@ -6,12 +6,15 @@ package unittest
import ( import (
"context" "context"
"fmt" "fmt"
"log"
"os" "os"
"path/filepath" "path/filepath"
"strings"
"testing" "testing"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
system_model "code.gitea.io/gitea/models/system" system_model "code.gitea.io/gitea/models/system"
"code.gitea.io/gitea/modules/auth/password/hash"
"code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
@ -39,6 +42,22 @@ func fatalTestError(fmtStr string, args ...interface{}) {
os.Exit(1) os.Exit(1)
} }
// InitSettings initializes config provider and load common setttings for tests
func InitSettings(extraConfigs ...string) {
setting.Init(&setting.Options{
AllowEmpty: true,
ExtraConfig: strings.Join(extraConfigs, "\n"),
})
if err := setting.PrepareAppDataPath(); err != nil {
log.Fatalf("Can not prepare APP_DATA_PATH: %v", err)
}
// register the dummy hash algorithm function used in the test fixtures
_ = hash.Register("dummy", hash.NewDummyHasher)
setting.PasswordHashAlgo, _ = hash.SetDefaultPasswordHashAlgorithm("dummy")
}
// TestOptions represents test options // TestOptions represents test options
type TestOptions struct { type TestOptions struct {
GiteaRootPath string GiteaRootPath string
@ -50,6 +69,9 @@ type TestOptions struct {
// MainTest a reusable TestMain(..) function for unit tests that need to use a // MainTest a reusable TestMain(..) function for unit tests that need to use a
// test database. Creates the test database, and sets necessary settings. // test database. Creates the test database, and sets necessary settings.
func MainTest(m *testing.M, testOpts *TestOptions) { func MainTest(m *testing.M, testOpts *TestOptions) {
setting.SetCustomPathAndConf("", "", "")
InitSettings()
var err error var err error
giteaRoot = testOpts.GiteaRootPath giteaRoot = testOpts.GiteaRootPath

View File

@ -12,6 +12,7 @@ import (
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs" api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/timeutil"
webhook_module "code.gitea.io/gitea/modules/webhook" webhook_module "code.gitea.io/gitea/modules/webhook"
gouuid "github.com/google/uuid" gouuid "github.com/google/uuid"
@ -47,8 +48,7 @@ type HookTask struct {
PayloadContent string `xorm:"LONGTEXT"` PayloadContent string `xorm:"LONGTEXT"`
EventType webhook_module.HookEventType EventType webhook_module.HookEventType
IsDelivered bool IsDelivered bool
Delivered int64 Delivered timeutil.TimeStampNano
DeliveredString string `xorm:"-"`
// History info. // History info.
IsSucceed bool IsSucceed bool
@ -75,8 +75,6 @@ func (t *HookTask) BeforeUpdate() {
// AfterLoad updates the webhook object upon setting a column // AfterLoad updates the webhook object upon setting a column
func (t *HookTask) AfterLoad() { func (t *HookTask) AfterLoad() {
t.DeliveredString = time.Unix(0, t.Delivered).Format("2006-01-02 15:04:05 MST")
if len(t.RequestContent) == 0 { if len(t.RequestContent) == 0 {
return return
} }
@ -115,12 +113,17 @@ func HookTasks(hookID int64, page int) ([]*HookTask, error) {
// CreateHookTask creates a new hook task, // CreateHookTask creates a new hook task,
// it handles conversion from Payload to PayloadContent. // it handles conversion from Payload to PayloadContent.
func CreateHookTask(ctx context.Context, t *HookTask) (*HookTask, error) { func CreateHookTask(ctx context.Context, t *HookTask) (*HookTask, error) {
t.UUID = gouuid.New().String()
if t.Payloader != nil {
data, err := t.Payloader.JSONPayload() data, err := t.Payloader.JSONPayload()
if err != nil { if err != nil {
return nil, err return nil, err
} }
t.UUID = gouuid.New().String()
t.PayloadContent = string(data) t.PayloadContent = string(data)
}
if t.Delivered == 0 {
t.Delivered = timeutil.TimeStampNanoNow()
}
return t, db.Insert(ctx, t) return t, db.Insert(ctx, t)
} }
@ -161,13 +164,11 @@ func ReplayHookTask(ctx context.Context, hookID int64, uuid string) (*HookTask,
} }
} }
newTask := &HookTask{ return CreateHookTask(ctx, &HookTask{
UUID: gouuid.New().String(),
HookID: task.HookID, HookID: task.HookID,
PayloadContent: task.PayloadContent, PayloadContent: task.PayloadContent,
EventType: task.EventType, EventType: task.EventType,
} })
return newTask, db.Insert(ctx, newTask)
} }
// FindUndeliveredHookTaskIDs will find the next 100 undelivered hook tasks with ID greater than the provided lowerID // FindUndeliveredHookTaskIDs will find the next 100 undelivered hook tasks with ID greater than the provided lowerID

View File

@ -12,6 +12,7 @@ import (
"code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/models/unittest"
"code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/json"
api "code.gitea.io/gitea/modules/structs" api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/util"
webhook_module "code.gitea.io/gitea/modules/webhook" webhook_module "code.gitea.io/gitea/modules/webhook"
@ -222,7 +223,6 @@ func TestUpdateHookTask(t *testing.T) {
hook := unittest.AssertExistsAndLoadBean(t, &HookTask{ID: 1}) hook := unittest.AssertExistsAndLoadBean(t, &HookTask{ID: 1})
hook.PayloadContent = "new payload content" hook.PayloadContent = "new payload content"
hook.DeliveredString = "new delivered string"
hook.IsDelivered = true hook.IsDelivered = true
unittest.AssertNotExistsBean(t, hook) unittest.AssertNotExistsBean(t, hook)
assert.NoError(t, UpdateHookTask(hook)) assert.NoError(t, UpdateHookTask(hook))
@ -235,7 +235,7 @@ func TestCleanupHookTaskTable_PerWebhook_DeletesDelivered(t *testing.T) {
HookID: 3, HookID: 3,
Payloader: &api.PushPayload{}, Payloader: &api.PushPayload{},
IsDelivered: true, IsDelivered: true,
Delivered: time.Now().UnixNano(), Delivered: timeutil.TimeStampNanoNow(),
} }
unittest.AssertNotExistsBean(t, hookTask) unittest.AssertNotExistsBean(t, hookTask)
_, err := CreateHookTask(db.DefaultContext, hookTask) _, err := CreateHookTask(db.DefaultContext, hookTask)
@ -268,7 +268,7 @@ func TestCleanupHookTaskTable_PerWebhook_LeavesMostRecentTask(t *testing.T) {
HookID: 4, HookID: 4,
Payloader: &api.PushPayload{}, Payloader: &api.PushPayload{},
IsDelivered: true, IsDelivered: true,
Delivered: time.Now().UnixNano(), Delivered: timeutil.TimeStampNanoNow(),
} }
unittest.AssertNotExistsBean(t, hookTask) unittest.AssertNotExistsBean(t, hookTask)
_, err := CreateHookTask(db.DefaultContext, hookTask) _, err := CreateHookTask(db.DefaultContext, hookTask)
@ -285,7 +285,7 @@ func TestCleanupHookTaskTable_OlderThan_DeletesDelivered(t *testing.T) {
HookID: 3, HookID: 3,
Payloader: &api.PushPayload{}, Payloader: &api.PushPayload{},
IsDelivered: true, IsDelivered: true,
Delivered: time.Now().AddDate(0, 0, -8).UnixNano(), Delivered: timeutil.TimeStampNano(time.Now().AddDate(0, 0, -8).UnixNano()),
} }
unittest.AssertNotExistsBean(t, hookTask) unittest.AssertNotExistsBean(t, hookTask)
_, err := CreateHookTask(db.DefaultContext, hookTask) _, err := CreateHookTask(db.DefaultContext, hookTask)
@ -318,7 +318,7 @@ func TestCleanupHookTaskTable_OlderThan_LeavesTaskEarlierThanAgeToDelete(t *test
HookID: 4, HookID: 4,
Payloader: &api.PushPayload{}, Payloader: &api.PushPayload{},
IsDelivered: true, IsDelivered: true,
Delivered: time.Now().AddDate(0, 0, -6).UnixNano(), Delivered: timeutil.TimeStampNano(time.Now().AddDate(0, 0, -6).UnixNano()),
} }
unittest.AssertNotExistsBean(t, hookTask) unittest.AssertNotExistsBean(t, hookTask)
_, err := CreateHookTask(db.DefaultContext, hookTask) _, err := CreateHookTask(db.DefaultContext, hookTask)

View File

@ -44,8 +44,7 @@ func (w *wrappedLevelLogger) Log(skip int, level log.Level, format string, v ...
} }
func initDBDisableConsole(ctx context.Context, disableConsole bool) error { func initDBDisableConsole(ctx context.Context, disableConsole bool) error {
setting.InitProviderFromExistingFile() setting.Init(&setting.Options{})
setting.LoadCommonSettings()
setting.LoadDBSetting() setting.LoadDBSetting()
setting.InitSQLLog(disableConsole) setting.InitSQLLog(disableConsole)
if err := db.InitEngine(ctx); err != nil { if err := db.InitEngine(ctx); err != nil {

View File

@ -66,8 +66,7 @@ func checkConfigurationFiles(ctx context.Context, logger log.Logger, autofix boo
return err return err
} }
setting.InitProviderFromExistingFile() setting.Init(&setting.Options{})
setting.LoadCommonSettings()
configurationFiles := []configurationFile{ configurationFiles := []configurationFile{
{"Configuration File Path", setting.CustomConf, false, true, false}, {"Configuration File Path", setting.CustomConf, false, true, false},

View File

@ -28,8 +28,9 @@ var localMetas = map[string]string{
} }
func TestMain(m *testing.M) { func TestMain(m *testing.M) {
setting.InitProviderAllowEmpty() setting.Init(&setting.Options{
setting.LoadCommonSettings() AllowEmpty: true,
})
if err := git.InitSimple(context.Background()); err != nil { if err := git.InitSimple(context.Background()); err != nil {
log.Fatal("git init failed, err: %v", err) log.Fatal("git init failed, err: %v", err)
} }

View File

@ -33,8 +33,9 @@ var localMetas = map[string]string{
} }
func TestMain(m *testing.M) { func TestMain(m *testing.M) {
setting.InitProviderAllowEmpty() setting.Init(&setting.Options{
setting.LoadCommonSettings() AllowEmpty: true,
})
if err := git.InitSimple(context.Background()); err != nil { if err := git.InitSimple(context.Background()); err != nil {
log.Fatal("git init failed, err: %v", err) log.Fatal("git init failed, err: %v", err)
} }

View File

@ -4,9 +4,9 @@
package queue package queue
import ( import (
"os"
"strconv" "strconv"
"sync" "sync"
"sync/atomic"
"testing" "testing"
"time" "time"
@ -16,10 +16,7 @@ import (
) )
func TestPersistableChannelUniqueQueue(t *testing.T) { func TestPersistableChannelUniqueQueue(t *testing.T) {
if os.Getenv("CI") != "" { // Create a temporary directory for the queue
t.Skip("Skipping because test is flaky on CI")
}
tmpDir := t.TempDir() tmpDir := t.TempDir()
_ = log.NewLogger(1000, "console", "console", `{"level":"warn","stacktracelevel":"NONE","stderr":true}`) _ = log.NewLogger(1000, "console", "console", `{"level":"warn","stacktracelevel":"NONE","stderr":true}`)
@ -100,7 +97,7 @@ func TestPersistableChannelUniqueQueue(t *testing.T) {
executedInitial := map[string][]string{} executedInitial := map[string][]string{}
hasInitial := map[string][]string{} hasInitial := map[string][]string{}
fillQueue := func(name string, done chan struct{}) { fillQueue := func(name string, done chan int64) {
t.Run("Initial Filling: "+name, func(t *testing.T) { t.Run("Initial Filling: "+name, func(t *testing.T) {
lock := sync.Mutex{} lock := sync.Mutex{}
@ -157,33 +154,39 @@ func TestPersistableChannelUniqueQueue(t *testing.T) {
assert.Equal(t, 101, len(executedInitial[name])+len(hasInitial[name])) assert.Equal(t, 101, len(executedInitial[name])+len(hasInitial[name]))
mapLock.Unlock() mapLock.Unlock()
}) })
mapLock.Lock()
count := int64(len(hasInitial[name]))
mapLock.Unlock()
done <- count
close(done) close(done)
} }
doneA := make(chan struct{}) hasQueueAChan := make(chan int64)
doneB := make(chan struct{}) hasQueueBChan := make(chan int64)
go fillQueue("QueueA", doneA) go fillQueue("QueueA", hasQueueAChan)
go fillQueue("QueueB", doneB) go fillQueue("QueueB", hasQueueBChan)
<-doneA hasA := <-hasQueueAChan
<-doneB hasB := <-hasQueueBChan
executedEmpty := map[string][]string{} executedEmpty := map[string][]string{}
hasEmpty := map[string][]string{} hasEmpty := map[string][]string{}
emptyQueue := func(name string, done chan struct{}) { emptyQueue := func(name string, numInQueue int64, done chan struct{}) {
t.Run("Empty Queue: "+name, func(t *testing.T) { t.Run("Empty Queue: "+name, func(t *testing.T) {
lock := sync.Mutex{} lock := sync.Mutex{}
stop := make(chan struct{}) stop := make(chan struct{})
// collect the tasks that have been executed // collect the tasks that have been executed
atomicCount := int64(0)
handle := func(data ...Data) []Data { handle := func(data ...Data) []Data {
lock.Lock() lock.Lock()
for _, datum := range data { for _, datum := range data {
mapLock.Lock() mapLock.Lock()
executedEmpty[name] = append(executedEmpty[name], datum.(string)) executedEmpty[name] = append(executedEmpty[name], datum.(string))
mapLock.Unlock() mapLock.Unlock()
if datum.(string) == "final" { count := atomic.AddInt64(&atomicCount, 1)
if count >= numInQueue {
close(stop) close(stop)
} }
} }
@ -217,11 +220,11 @@ func TestPersistableChannelUniqueQueue(t *testing.T) {
close(done) close(done)
} }
doneA = make(chan struct{}) doneA := make(chan struct{})
doneB = make(chan struct{}) doneB := make(chan struct{})
go emptyQueue("QueueA", doneA) go emptyQueue("QueueA", hasA, doneA)
go emptyQueue("QueueB", doneB) go emptyQueue("QueueB", hasB, doneB)
<-doneA <-doneA
<-doneB <-doneB
@ -237,20 +240,20 @@ func TestPersistableChannelUniqueQueue(t *testing.T) {
hasEmpty = map[string][]string{} hasEmpty = map[string][]string{}
mapLock.Unlock() mapLock.Unlock()
doneA = make(chan struct{}) hasQueueAChan = make(chan int64)
doneB = make(chan struct{}) hasQueueBChan = make(chan int64)
go fillQueue("QueueA", doneA) go fillQueue("QueueA", hasQueueAChan)
go fillQueue("QueueB", doneB) go fillQueue("QueueB", hasQueueBChan)
<-doneA hasA = <-hasQueueAChan
<-doneB hasB = <-hasQueueBChan
doneA = make(chan struct{}) doneA = make(chan struct{})
doneB = make(chan struct{}) doneB = make(chan struct{})
go emptyQueue("QueueA", doneA) go emptyQueue("QueueA", hasA, doneA)
go emptyQueue("QueueB", doneB) go emptyQueue("QueueB", hasB, doneB)
<-doneA <-doneA
<-doneB <-doneB

View File

@ -35,10 +35,9 @@ type ConfigProvider interface {
} }
type iniFileConfigProvider struct { type iniFileConfigProvider struct {
opts *Options
*ini.File *ini.File
filepath string // the ini file path
newFile bool // whether the file has not existed previously newFile bool // whether the file has not existed previously
allowEmpty bool // whether not finding configuration files is allowed (only true for the tests)
} }
// NewEmptyConfigProvider create a new empty config provider // NewEmptyConfigProvider create a new empty config provider
@ -66,41 +65,47 @@ func newConfigProviderFromData(configContent string) (ConfigProvider, error) {
}, nil }, nil
} }
type Options struct {
CustomConf string // the ini file path
AllowEmpty bool // whether not finding configuration files is allowed (only true for the tests)
ExtraConfig string
DisableLoadCommonSettings bool
}
// newConfigProviderFromFile load configuration from file. // newConfigProviderFromFile load configuration from file.
// NOTE: do not print any log except error. // NOTE: do not print any log except error.
func newConfigProviderFromFile(customConf string, allowEmpty bool, extraConfig string) (*iniFileConfigProvider, error) { func newConfigProviderFromFile(opts *Options) (*iniFileConfigProvider, error) {
cfg := ini.Empty() cfg := ini.Empty()
newFile := true newFile := true
if customConf != "" { if opts.CustomConf != "" {
isFile, err := util.IsFile(customConf) isFile, err := util.IsFile(opts.CustomConf)
if err != nil { if err != nil {
return nil, fmt.Errorf("unable to check if %s is a file. Error: %v", customConf, err) return nil, fmt.Errorf("unable to check if %s is a file. Error: %v", opts.CustomConf, err)
} }
if isFile { if isFile {
if err := cfg.Append(customConf); err != nil { if err := cfg.Append(opts.CustomConf); err != nil {
return nil, fmt.Errorf("failed to load custom conf '%s': %v", customConf, err) return nil, fmt.Errorf("failed to load custom conf '%s': %v", opts.CustomConf, err)
} }
newFile = false newFile = false
} }
} }
if newFile && !allowEmpty { if newFile && !opts.AllowEmpty {
return nil, fmt.Errorf("unable to find configuration file: %q, please ensure you are running in the correct environment or set the correct configuration file with -c", CustomConf) return nil, fmt.Errorf("unable to find configuration file: %q, please ensure you are running in the correct environment or set the correct configuration file with -c", CustomConf)
} }
if extraConfig != "" { if opts.ExtraConfig != "" {
if err := cfg.Append([]byte(extraConfig)); err != nil { if err := cfg.Append([]byte(opts.ExtraConfig)); err != nil {
return nil, fmt.Errorf("unable to append more config: %v", err) return nil, fmt.Errorf("unable to append more config: %v", err)
} }
} }
cfg.NameMapper = ini.SnackCase cfg.NameMapper = ini.SnackCase
return &iniFileConfigProvider{ return &iniFileConfigProvider{
opts: opts,
File: cfg, File: cfg,
filepath: customConf,
newFile: newFile, newFile: newFile,
allowEmpty: allowEmpty,
}, nil }, nil
} }
@ -123,8 +128,8 @@ func (p *iniFileConfigProvider) DeleteSection(name string) error {
// Save save the content into file // Save save the content into file
func (p *iniFileConfigProvider) Save() error { func (p *iniFileConfigProvider) Save() error {
if p.filepath == "" { if p.opts.CustomConf == "" {
if !p.allowEmpty { if !p.opts.AllowEmpty {
return fmt.Errorf("custom config path must not be empty") return fmt.Errorf("custom config path must not be empty")
} }
return nil return nil
@ -135,8 +140,8 @@ func (p *iniFileConfigProvider) Save() error {
return fmt.Errorf("failed to create '%s': %v", CustomConf, err) return fmt.Errorf("failed to create '%s': %v", CustomConf, err)
} }
} }
if err := p.SaveTo(p.filepath); err != nil { if err := p.SaveTo(p.opts.CustomConf); err != nil {
return fmt.Errorf("failed to save '%s': %v", p.filepath, err) return fmt.Errorf("failed to save '%s': %v", p.opts.CustomConf, err)
} }
// Change permissions to be more restrictive // Change permissions to be more restrictive

View File

@ -15,7 +15,6 @@ import (
"strings" "strings"
"time" "time"
"code.gitea.io/gitea/modules/auth/password/hash"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/user" "code.gitea.io/gitea/modules/user"
) )
@ -203,44 +202,18 @@ func PrepareAppDataPath() error {
return nil return nil
} }
// InitProviderFromExistingFile initializes config provider from an existing config file (app.ini) func Init(opts *Options) {
func InitProviderFromExistingFile() { if opts.CustomConf == "" {
opts.CustomConf = CustomConf
}
var err error var err error
CfgProvider, err = newConfigProviderFromFile(CustomConf, false, "") CfgProvider, err = newConfigProviderFromFile(opts)
if err != nil { if err != nil {
log.Fatal("InitProviderFromExistingFile: %v", err) log.Fatal("Init[%v]: %v", opts, err)
}
}
// InitProviderAllowEmpty initializes config provider from file, it's also fine that if the config file (app.ini) doesn't exist
func InitProviderAllowEmpty() {
var err error
CfgProvider, err = newConfigProviderFromFile(CustomConf, true, "")
if err != nil {
log.Fatal("InitProviderAllowEmpty: %v", err)
}
}
// InitProviderAndLoadCommonSettingsForTest initializes config provider and load common setttings for tests
func InitProviderAndLoadCommonSettingsForTest(extraConfigs ...string) {
var err error
CfgProvider, err = newConfigProviderFromFile(CustomConf, true, strings.Join(extraConfigs, "\n"))
if err != nil {
log.Fatal("InitProviderAndLoadCommonSettingsForTest: %v", err)
} }
if !opts.DisableLoadCommonSettings {
loadCommonSettingsFrom(CfgProvider) loadCommonSettingsFrom(CfgProvider)
if err := PrepareAppDataPath(); err != nil {
log.Fatal("Can not prepare APP_DATA_PATH: %v", err)
} }
// register the dummy hash algorithm function used in the test fixtures
_ = hash.Register("dummy", hash.NewDummyHasher)
PasswordHashAlgo, _ = hash.SetDefaultPasswordHashAlgorithm("dummy")
}
// LoadCommonSettings loads common configurations from a configuration provider.
func LoadCommonSettings() {
loadCommonSettingsFrom(CfgProvider)
} }
// loadCommonSettingsFrom loads common configurations from a configuration provider. // loadCommonSettingsFrom loads common configurations from a configuration provider.

View File

@ -0,0 +1,28 @@
// Copyright 2017 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package timeutil
import (
"time"
"code.gitea.io/gitea/modules/setting"
)
// TimeStampNano is for nano time in database, do not use it unless there is a real requirement.
type TimeStampNano int64
// TimeStampNanoNow returns now nano int64
func TimeStampNanoNow() TimeStampNano {
return TimeStampNano(time.Now().UnixNano())
}
// AsTime convert timestamp as time.Time in Local locale
func (tsn TimeStampNano) AsTime() (tm time.Time) {
return tsn.AsTimeInLocation(setting.DefaultUILocation)
}
// AsTimeInLocation convert timestamp as time.Time in Local locale
func (tsn TimeStampNano) AsTimeInLocation(loc *time.Location) time.Time {
return time.Unix(0, int64(tsn)).In(loc)
}

View File

@ -1414,8 +1414,8 @@ issues.context.edit = Edit
issues.context.delete = Delete issues.context.delete = Delete
issues.no_content = There is no content yet. issues.no_content = There is no content yet.
issues.close = Close Issue issues.close = Close Issue
issues.pull_merged_at = `merged commit <a class="ui sha" href="%[1]s"><code>%[2]s</code></a> into <b>%[3]s</b> %[4]s` issues.comment_pull_merged_at = merged commit %[1]s into %[2]s %[3]s
issues.manually_pull_merged_at = `merged commit <a class="ui sha" href="%[1]s"><code>%[2]s</code></a> into <b>%[3]s</b> manually %[4]s` issues.comment_manually_pull_merged_at = manually merged commit %[1]s into %[2]s %[3]s
issues.close_comment_issue = Comment and Close issues.close_comment_issue = Comment and Close
issues.reopen_issue = Reopen issues.reopen_issue = Reopen
issues.reopen_comment_issue = Comment and Reopen issues.reopen_comment_issue = Comment and Reopen
@ -2559,6 +2559,7 @@ teams.all_repositories_admin_permission_desc = This team grants <strong>Admin</s
teams.invite.title = You've been invited to join team <strong>%s</strong> in organization <strong>%s</strong>. teams.invite.title = You've been invited to join team <strong>%s</strong> in organization <strong>%s</strong>.
teams.invite.by = Invited by %s teams.invite.by = Invited by %s
teams.invite.description = Please click the button below to join the team. teams.invite.description = Please click the button below to join the team.
teams.invite.email_mismatch = Your email address does not match this invite.
[admin] [admin]
dashboard = Dashboard dashboard = Dashboard

View File

@ -119,6 +119,12 @@ func CommonRoutes(ctx gocontext.Context) *web.Route {
r.Get("/owners", cargo.ListOwners) r.Get("/owners", cargo.ListOwners)
}) })
}) })
r.Get("/config.json", cargo.RepositoryConfig)
r.Get("/1/{package}", cargo.EnumeratePackageVersions)
r.Get("/2/{package}", cargo.EnumeratePackageVersions)
// Use dummy placeholders because these parts are not of interest
r.Get("/3/{_}/{package}", cargo.EnumeratePackageVersions)
r.Get("/{_}/{__}/{package}", cargo.EnumeratePackageVersions)
}, reqPackageAccess(perm.AccessModeRead)) }, reqPackageAccess(perm.AccessModeRead))
r.Group("/chef", func() { r.Group("/chef", func() {
r.Group("/api/v1", func() { r.Group("/api/v1", func() {

View File

@ -4,6 +4,7 @@
package cargo package cargo
import ( import (
"errors"
"fmt" "fmt"
"net/http" "net/http"
"strconv" "strconv"
@ -45,6 +46,35 @@ func apiError(ctx *context.Context, status int, obj interface{}) {
}) })
} }
// https://rust-lang.github.io/rfcs/2789-sparse-index.html
func RepositoryConfig(ctx *context.Context) {
ctx.JSON(http.StatusOK, cargo_service.BuildConfig(ctx.Package.Owner))
}
func EnumeratePackageVersions(ctx *context.Context) {
p, err := packages_model.GetPackageByName(ctx, ctx.Package.Owner.ID, packages_model.TypeCargo, ctx.Params("package"))
if err != nil {
if errors.Is(err, util.ErrNotExist) {
apiError(ctx, http.StatusNotFound, err)
} else {
apiError(ctx, http.StatusInternalServerError, err)
}
return
}
b, err := cargo_service.BuildPackageIndex(ctx, p)
if err != nil {
apiError(ctx, http.StatusInternalServerError, err)
return
}
if b == nil {
apiError(ctx, http.StatusNotFound, nil)
return
}
ctx.PlainTextBytes(http.StatusOK, b.Bytes())
}
type SearchResult struct { type SearchResult struct {
Crates []*SearchResultCrate `json:"crates"` Crates []*SearchResultCrate `json:"crates"`
Meta SearchResultMeta `json:"meta"` Meta SearchResultMeta `json:"meta"`

View File

@ -13,10 +13,11 @@ import (
) )
func TestMain(m *testing.M) { func TestMain(m *testing.M) {
setting.InitProviderAndLoadCommonSettingsForTest()
setting.LoadQueueSettings()
unittest.MainTest(m, &unittest.TestOptions{ unittest.MainTest(m, &unittest.TestOptions{
GiteaRootPath: filepath.Join("..", "..", "..", ".."), GiteaRootPath: filepath.Join("..", "..", "..", ".."),
SetUp: webhook_service.Init, SetUp: func() error {
setting.LoadQueueSettings()
return webhook_service.Init()
},
}) })
} }

View File

@ -15,8 +15,9 @@ import (
// PreloadSettings preloads the configuration to check if we need to run install // PreloadSettings preloads the configuration to check if we need to run install
func PreloadSettings(ctx context.Context) bool { func PreloadSettings(ctx context.Context) bool {
setting.InitProviderAllowEmpty() setting.Init(&setting.Options{
setting.LoadCommonSettings() AllowEmpty: true,
})
if !setting.InstallLock { if !setting.InstallLock {
log.Info("AppPath: %s", setting.AppPath) log.Info("AppPath: %s", setting.AppPath)
log.Info("AppWorkPath: %s", setting.AppWorkPath) log.Info("AppWorkPath: %s", setting.AppWorkPath)
@ -38,8 +39,7 @@ func PreloadSettings(ctx context.Context) bool {
// reloadSettings reloads the existing settings and starts up the database // reloadSettings reloads the existing settings and starts up the database
func reloadSettings(ctx context.Context) { func reloadSettings(ctx context.Context) {
setting.InitProviderFromExistingFile() setting.Init(&setting.Options{})
setting.LoadCommonSettings()
setting.LoadDBSetting() setting.LoadDBSetting()
if setting.InstallLock { if setting.InstallLock {
if err := common.InitDBEngine(ctx); err == nil { if err := common.InitDBEngine(ctx); err == nil {

View File

@ -552,6 +552,7 @@ func TeamInvite(ctx *context.Context) {
ctx.Data["Organization"] = org ctx.Data["Organization"] = org
ctx.Data["Team"] = team ctx.Data["Team"] = team
ctx.Data["Inviter"] = inviter ctx.Data["Inviter"] = inviter
ctx.Data["EmailMismatch"] = ctx.Doer.Email != invite.Email
ctx.HTML(http.StatusOK, tplTeamInvite) ctx.HTML(http.StatusOK, tplTeamInvite)
} }
@ -568,6 +569,13 @@ func TeamInvitePost(ctx *context.Context) {
return return
} }
// check that the Doer is the invitee
if ctx.Doer.Email != invite.Email {
log.Info("invite %d does not apply to the current user %d", invite.ID, ctx.Doer.ID)
ctx.NotFound("ErrTeamInviteNotFound", err)
return
}
if err := models.AddTeamMember(team, ctx.Doer.ID); err != nil { if err := models.AddTeamMember(team, ctx.Doer.ID); err != nil {
ctx.ServerError("AddTeamMember", err) ctx.ServerError("AddTeamMember", err)
return return

View File

@ -80,7 +80,9 @@ func TestChangePassword(t *testing.T) {
PasswordComplexity: pcLU, PasswordComplexity: pcLU,
}, },
} { } {
t.Run(req.OldPassword+"__"+req.NewPassword, func(t *testing.T) {
unittest.PrepareTestEnv(t) unittest.PrepareTestEnv(t)
setting.PasswordComplexity = req.PasswordComplexity
ctx := test.MockContext(t, "user/settings/security") ctx := test.MockContext(t, "user/settings/security")
test.LoadUser(t, ctx, 2) test.LoadUser(t, ctx, 2)
test.LoadRepo(t, ctx, 1) test.LoadRepo(t, ctx, 1)
@ -94,5 +96,6 @@ func TestChangePassword(t *testing.T) {
assert.Contains(t, ctx.Flash.ErrorMsg, req.Message) assert.Contains(t, ctx.Flash.ErrorMsg, req.Message)
assert.EqualValues(t, http.StatusSeeOther, ctx.Resp.Status()) assert.EqualValues(t, http.StatusSeeOther, ctx.Resp.Status())
})
} }
} }

View File

@ -137,21 +137,21 @@ type IndexVersionEntry struct {
Links string `json:"links,omitempty"` Links string `json:"links,omitempty"`
} }
func addOrUpdatePackageIndex(ctx context.Context, t *files_service.TemporaryUploadRepository, p *packages_model.Package) error { func BuildPackageIndex(ctx context.Context, p *packages_model.Package) (*bytes.Buffer, error) {
pvs, _, err := packages_model.SearchVersions(ctx, &packages_model.PackageSearchOptions{ pvs, _, err := packages_model.SearchVersions(ctx, &packages_model.PackageSearchOptions{
PackageID: p.ID, PackageID: p.ID,
Sort: packages_model.SortVersionAsc, Sort: packages_model.SortVersionAsc,
}) })
if err != nil { if err != nil {
return fmt.Errorf("SearchVersions[%s]: %w", p.Name, err) return nil, fmt.Errorf("SearchVersions[%s]: %w", p.Name, err)
} }
if len(pvs) == 0 { if len(pvs) == 0 {
return nil return nil, nil
} }
pds, err := packages_model.GetPackageDescriptors(ctx, pvs) pds, err := packages_model.GetPackageDescriptors(ctx, pvs)
if err != nil { if err != nil {
return fmt.Errorf("GetPackageDescriptors[%s]: %w", p.Name, err) return nil, fmt.Errorf("GetPackageDescriptors[%s]: %w", p.Name, err)
} }
var b bytes.Buffer var b bytes.Buffer
@ -179,14 +179,26 @@ func addOrUpdatePackageIndex(ctx context.Context, t *files_service.TemporaryUplo
Links: metadata.Links, Links: metadata.Links,
}) })
if err != nil { if err != nil {
return err return nil, err
} }
b.Write(entry) b.Write(entry)
b.WriteString("\n") b.WriteString("\n")
} }
return writeObjectToIndex(t, BuildPackagePath(pds[0].Package.LowerName), &b) return &b, nil
}
func addOrUpdatePackageIndex(ctx context.Context, t *files_service.TemporaryUploadRepository, p *packages_model.Package) error {
b, err := BuildPackageIndex(ctx, p)
if err != nil {
return err
}
if b == nil {
return nil
}
return writeObjectToIndex(t, BuildPackagePath(p.LowerName), b)
} }
func getOrCreateIndexRepository(ctx context.Context, doer, owner *user_model.User) (*repo_model.Repository, error) { func getOrCreateIndexRepository(ctx context.Context, doer, owner *user_model.User) (*repo_model.Repository, error) {
@ -212,6 +224,13 @@ type Config struct {
APIURL string `json:"api"` APIURL string `json:"api"`
} }
func BuildConfig(owner *user_model.User) *Config {
return &Config{
DownloadURL: setting.AppURL + "api/packages/" + owner.Name + "/cargo/api/v1/crates",
APIURL: setting.AppURL + "api/packages/" + owner.Name + "/cargo",
}
}
func createOrUpdateConfigFile(ctx context.Context, repo *repo_model.Repository, doer, owner *user_model.User) error { func createOrUpdateConfigFile(ctx context.Context, repo *repo_model.Repository, doer, owner *user_model.User) error {
return alterRepositoryContent( return alterRepositoryContent(
ctx, ctx,
@ -220,10 +239,7 @@ func createOrUpdateConfigFile(ctx context.Context, repo *repo_model.Repository,
"Initialize Cargo Config", "Initialize Cargo Config",
func(t *files_service.TemporaryUploadRepository) error { func(t *files_service.TemporaryUploadRepository) error {
var b bytes.Buffer var b bytes.Buffer
err := json.NewEncoder(&b).Encode(Config{ err := json.NewEncoder(&b).Encode(BuildConfig(owner))
DownloadURL: setting.AppURL + "api/packages/" + owner.Name + "/cargo/api/v1/crates",
APIURL: setting.AppURL + "api/packages/" + owner.Name + "/cargo",
})
if err != nil { if err != nil {
return err return err
} }

View File

@ -25,6 +25,7 @@ import (
"code.gitea.io/gitea/modules/proxy" "code.gitea.io/gitea/modules/proxy"
"code.gitea.io/gitea/modules/queue" "code.gitea.io/gitea/modules/queue"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/timeutil"
webhook_module "code.gitea.io/gitea/modules/webhook" webhook_module "code.gitea.io/gitea/modules/webhook"
"github.com/gobwas/glob" "github.com/gobwas/glob"
@ -175,7 +176,7 @@ func Deliver(ctx context.Context, t *webhook_model.HookTask) error {
// All code from this point will update the hook task // All code from this point will update the hook task
defer func() { defer func() {
t.Delivered = time.Now().UnixNano() t.Delivered = timeutil.TimeStampNanoNow()
if t.IsSucceed { if t.IsSucceed {
log.Trace("Hook delivered: %s", t.UUID) log.Trace("Hook delivered: %s", t.UUID)
} else if !w.IsActive { } else if !w.IsActive {

View File

@ -15,13 +15,13 @@ import (
) )
func TestMain(m *testing.M) { func TestMain(m *testing.M) {
setting.InitProviderAndLoadCommonSettingsForTest()
setting.LoadQueueSettings()
// for tests, allow only loopback IPs // for tests, allow only loopback IPs
setting.Webhook.AllowedHostList = hostmatcher.MatchBuiltinLoopback setting.Webhook.AllowedHostList = hostmatcher.MatchBuiltinLoopback
unittest.MainTest(m, &unittest.TestOptions{ unittest.MainTest(m, &unittest.TestOptions{
GiteaRootPath: filepath.Join("..", ".."), GiteaRootPath: filepath.Join("..", ".."),
SetUp: Init, SetUp: func() error {
setting.LoadQueueSettings()
return Init()
},
}) })
} }

View File

@ -1,20 +1,20 @@
{{if .Flash.ErrorMsg}} {{if .Flash.ErrorMsg}}
<div class="ui negative message flash-error"> <div class="ui negative message flash-message flash-error">
<p>{{.Flash.ErrorMsg | Str2html}}</p> <p>{{.Flash.ErrorMsg | Str2html}}</p>
</div> </div>
{{end}} {{end}}
{{if .Flash.SuccessMsg}} {{if .Flash.SuccessMsg}}
<div class="ui positive message flash-success"> <div class="ui positive message flash-message flash-success">
<p>{{.Flash.SuccessMsg | Str2html}}</p> <p>{{.Flash.SuccessMsg | Str2html}}</p>
</div> </div>
{{end}} {{end}}
{{if .Flash.InfoMsg}} {{if .Flash.InfoMsg}}
<div class="ui info message flash-info"> <div class="ui info message flash-message flash-info">
<p>{{.Flash.InfoMsg | Str2html}}</p> <p>{{.Flash.InfoMsg | Str2html}}</p>
</div> </div>
{{end}} {{end}}
{{if .Flash.WarningMsg}} {{if .Flash.WarningMsg}}
<div class="ui warning message flash-warning"> <div class="ui warning message flash-message flash-warning">
<p>{{.Flash.WarningMsg | Str2html}}</p> <p>{{.Flash.WarningMsg | Str2html}}</p>
</div> </div>
{{end}} {{end}}

View File

@ -7,7 +7,7 @@
<div class="list"> <div class="list">
{{range .Members}} {{range .Members}}
<div class="item ui grid"> <div class="item ui grid">
<div class="ui four wide column" style="display: flex;"> <div class="ui four wide column gt-df">
<a href="{{.HomeLink}}">{{avatar $.Context . 48}}</a> <a href="{{.HomeLink}}">{{avatar $.Context . 48}}</a>
<div> <div>
<div class="meta"><a href="{{.HomeLink}}">{{.Name}}</a></div> <div class="meta"><a href="{{.HomeLink}}">{{.Name}}</a></div>

View File

@ -6,6 +6,11 @@
<div class="image"> <div class="image">
{{avatar $.Context .Organization 140}} {{avatar $.Context .Organization 140}}
</div> </div>
{{if .EmailMismatch}}
<div class="content">
<div class="header">{{.locale.Tr "org.teams.invite.email_mismatch"}}</div>
</div>
{{else}}
<div class="content"> <div class="content">
<div class="header">{{.locale.Tr "org.teams.invite.title" .Team.Name .Organization.Name | Str2html}}</div> <div class="header">{{.locale.Tr "org.teams.invite.title" .Team.Name .Organization.Name | Str2html}}</div>
<div class="meta">{{.locale.Tr "org.teams.invite.by" .Inviter.Name}}</div> <div class="meta">{{.locale.Tr "org.teams.invite.by" .Inviter.Name}}</div>
@ -17,6 +22,7 @@
<button class="fluid ui green button">{{.locale.Tr "org.teams.join"}}</button> <button class="fluid ui green button">{{.locale.Tr "org.teams.join"}}</button>
</form> </form>
</div> </div>
{{end}}
</div> </div>
</div> </div>
</div> </div>

View File

@ -69,7 +69,7 @@
{{if .PackageDescriptor.Metadata.Labels}} {{if .PackageDescriptor.Metadata.Labels}}
<h4 class="ui top attached header">{{.locale.Tr "packages.container.labels"}}</h4> <h4 class="ui top attached header">{{.locale.Tr "packages.container.labels"}}</h4>
<div class="ui attached segment"> <div class="ui attached segment">
<table class="ui very basic compact table container-labels"> <table class="ui very basic compact table">
<thead> <thead>
<tr> <tr>
<th>{{.locale.Tr "packages.container.labels.key"}}</th> <th>{{.locale.Tr "packages.container.labels.key"}}</th>
@ -79,8 +79,8 @@
<tbody> <tbody>
{{range $key, $value := .PackageDescriptor.Metadata.Labels}} {{range $key, $value := .PackageDescriptor.Metadata.Labels}}
<tr> <tr>
<td>{{$key}}</td> <td class="top aligned">{{$key}}</td>
<td>{{$value}}</td> <td class="gt-word-break">{{$value}}</td>
</tr> </tr>
{{end}} {{end}}
</tbody> </tbody>

View File

@ -51,7 +51,7 @@
{{.locale.Tr "packages.settings.delete"}} {{.locale.Tr "packages.settings.delete"}}
</div> </div>
<div class="content"> <div class="content">
<div class="ui warning message text left gt-word-break"> <div class="ui warning message gt-word-break">
{{.locale.Tr "packages.settings.delete.notice" .PackageDescriptor.Package.Name .PackageDescriptor.Version.Version}} {{.locale.Tr "packages.settings.delete.notice" .PackageDescriptor.Package.Name .PackageDescriptor.Version.Version}}
</div> </div>
<form class="ui form" action="{{.Link}}" method="post"> <form class="ui form" action="{{.Link}}" method="post">

View File

@ -10,7 +10,7 @@
{{end}} {{end}}
{{template "base/alert" .}} {{template "base/alert" .}}
<div class="small-pill-buttons ui compact tiny menu"> <div class="small-menu-items ui compact tiny menu">
<a class="item{{if not .IsShowClosed}} active{{end}}" href="{{$.Link}}?state=open"> <a class="item{{if not .IsShowClosed}} active{{end}}" href="{{$.Link}}?state=open">
{{svg "octicon-project-symlink" 16 "gt-mr-3"}} {{svg "octicon-project-symlink" 16 "gt-mr-3"}}
{{.locale.PrettyNumber .OpenCount}}&nbsp;{{.locale.Tr "repo.issues.open_title"}} {{.locale.PrettyNumber .OpenCount}}&nbsp;{{.locale.Tr "repo.issues.open_title"}}

View File

@ -1,4 +1,4 @@
<div class="small-pill-buttons ui compact tiny menu"> <div class="small-menu-items ui compact tiny menu">
<a class="{{if not .IsShowClosed}}active {{end}}item" href="{{$.Link}}?workflow={{.CurWorkflow}}&state=open"> <a class="{{if not .IsShowClosed}}active {{end}}item" href="{{$.Link}}?workflow={{.CurWorkflow}}&state=open">
{{svg "octicon-issue-opened" 16 "gt-mr-3"}} {{svg "octicon-issue-opened" 16 "gt-mr-3"}}
{{.locale.Tr "actions.runs.open_tab" $.NumOpenActionRuns}} {{.locale.Tr "actions.runs.open_tab" $.NumOpenActionRuns}}

View File

@ -1,3 +1,8 @@
{{/* Attributes:
* root
* ContainerClasses
* (TODO: search "branch_dropdown" in the template direcotry)
*/}}
{{$defaultBranch := $.root.BranchName}} {{$defaultBranch := $.root.BranchName}}
{{if and .root.IsViewTag (not .noTag)}} {{if and .root.IsViewTag (not .noTag)}}
{{$defaultBranch = .root.TagName}} {{$defaultBranch = .root.TagName}}
@ -62,10 +67,10 @@
window.config.pageData.branchDropdownDataList.push(data); window.config.pageData.branchDropdownDataList.push(data);
</script> </script>
<div class="fitted item js-branch-tag-selector"> <div class="js-branch-tag-selector {{if .ContainerClasses}}{{.ContainerClasses}}{{end}}">
{{/* show dummy elements before Vue componment is mounted, this code must match the code in BranchTagSelector.vue */}} {{/* show dummy elements before Vue componment is mounted, this code must match the code in BranchTagSelector.vue */}}
<div class="ui floating filter dropdown custom"> <div class="ui floating filter dropdown custom">
<button class="branch-dropdown-button gt-ellipsis ui basic small compact button gt-df"> <button class="branch-dropdown-button gt-ellipsis ui basic small compact button gt-df gt-m-0">
<span class="text gt-df gt-ac gt-mr-2"> <span class="text gt-df gt-ac gt-mr-2">
{{if .release}} {{if .release}}
{{.root.locale.Tr "repo.release.compare"}} {{.root.locale.Tr "repo.release.compare"}}

View File

@ -5,7 +5,7 @@
{{template "repo/sub_menu" .}} {{template "repo/sub_menu" .}}
<div class="repo-button-row gt-df gt-ac gt-sb gt-fw gt-mb-4 gt-mt-3"> <div class="repo-button-row gt-df gt-ac gt-sb gt-fw gt-mb-4 gt-mt-3">
<div class="gt-df gt-ac"> <div class="gt-df gt-ac">
{{template "repo/branch_dropdown" dict "root" .}} {{template "repo/branch_dropdown" dict "root" . "ContainerClasses" "gt-mr-2"}}
<a href="{{.RepoLink}}/graph" class="ui basic small compact button"> <a href="{{.RepoLink}}/graph" class="ui basic small compact button">
<span class="text"> <span class="text">
{{svg "octicon-git-branch"}} {{svg "octicon-git-branch"}}

View File

@ -63,7 +63,7 @@
{{template "repo/sub_menu" .}} {{template "repo/sub_menu" .}}
<div class="repo-button-row gt-df gt-ac gt-sb gt-fw"> <div class="repo-button-row gt-df gt-ac gt-sb gt-fw">
<div class="gt-df gt-ac gt-fw gt-gap-y-3"> <div class="gt-df gt-ac gt-fw gt-gap-y-3">
{{template "repo/branch_dropdown" dict "root" .}} {{template "repo/branch_dropdown" dict "root" . "ContainerClasses" "gt-mr-2"}}
{{$n := len .TreeNames}} {{$n := len .TreeNames}}
{{$l := Eval $n "-" 1}} {{$l := Eval $n "-" 1}}
<!-- If home page, show new pr. If not, show breadcrumb --> <!-- If home page, show new pr. If not, show breadcrumb -->

View File

@ -2,7 +2,7 @@
<div role="main" aria-label="{{.Title}}" class="page-content repository labels"> <div role="main" aria-label="{{.Title}}" class="page-content repository labels">
{{template "repo/header" .}} {{template "repo/header" .}}
<div class="ui container"> <div class="ui container">
<div class="navbar"> <div class="navbar gt-mb-4">
{{template "repo/issue/navbar" .}} {{template "repo/issue/navbar" .}}
{{if and (or .CanWriteIssues .CanWritePulls) (not .Repository.IsArchived)}} {{if and (or .CanWriteIssues .CanWritePulls) (not .Repository.IsArchived)}}
<div class="ui right"> <div class="ui right">
@ -10,7 +10,6 @@
</div> </div>
{{end}} {{end}}
</div> </div>
<div class="ui divider"></div>
{{if and (or .CanWriteIssues .CanWritePulls) (not .Repository.IsArchived)}} {{if and (or .CanWriteIssues .CanWritePulls) (not .Repository.IsArchived)}}
{{template "repo/issue/labels/label_new" .}} {{template "repo/issue/labels/label_new" .}}
{{end}} {{end}}

View File

@ -17,9 +17,6 @@
{{end}} {{end}}
{{end}} {{end}}
</div> </div>
<div class="ui divider"></div>
<div id="issue-filters" class="issue-list-toolbar"> <div id="issue-filters" class="issue-list-toolbar">
<div class="issue-list-toolbar-left"> <div class="issue-list-toolbar-left">
{{if $.CanWriteIssuesOrPulls}} {{if $.CanWriteIssuesOrPulls}}

View File

@ -2,7 +2,7 @@
<div role="main" aria-label="{{.Title}}" class="page-content repository milestones"> <div role="main" aria-label="{{.Title}}" class="page-content repository milestones">
{{template "repo/header" .}} {{template "repo/header" .}}
<div class="ui container"> <div class="ui container">
<div class="navbar"> <div class="navbar gt-mb-4">
{{template "repo/issue/navbar" .}} {{template "repo/issue/navbar" .}}
{{if and (or .CanWriteIssues .CanWritePulls) (not .Repository.IsArchived)}} {{if and (or .CanWriteIssues .CanWritePulls) (not .Repository.IsArchived)}}
<div class="ui right"> <div class="ui right">
@ -10,11 +10,10 @@
</div> </div>
{{end}} {{end}}
</div> </div>
<div class="ui divider"></div>
{{template "base/alert" .}} {{template "base/alert" .}}
<div class="list-header"> <div class="list-header">
<div class="small-pill-buttons ui compact tiny menu"> <div class="small-menu-items ui compact tiny menu">
<a class="item{{if not .IsShowClosed}} active{{end}}" href="{{.RepoLink}}/milestones?state=open&q={{$.Keyword}}"> <a class="item{{if not .IsShowClosed}} active{{end}}" href="{{.RepoLink}}/milestones?state=open&q={{$.Keyword}}">
{{svg "octicon-milestone" 16 "gt-mr-3"}} {{svg "octicon-milestone" 16 "gt-mr-3"}}
{{.locale.PrettyNumber .OpenCount}}&nbsp;{{.locale.Tr "repo.issues.open_title"}} {{.locale.PrettyNumber .OpenCount}}&nbsp;{{.locale.Tr "repo.issues.open_title"}}

View File

@ -1,4 +1,4 @@
<h2 class="ui compact small menu header small-pill-buttons"> <h2 class="ui compact small menu header small-menu-items">
<a class="{{if .PageIsLabels}}active {{end}}item" href="{{.RepoLink}}/labels">{{.locale.Tr "repo.labels"}}</a> <a class="{{if .PageIsLabels}}active {{end}}item" href="{{.RepoLink}}/labels">{{.locale.Tr "repo.labels"}}</a>
<a class="{{if .PageIsMilestones}}active {{end}}item" href="{{.RepoLink}}/milestones">{{.locale.Tr "repo.milestones"}}</a> <a class="{{if .PageIsMilestones}}active {{end}}item" href="{{.RepoLink}}/milestones">{{.locale.Tr "repo.milestones"}}</a>
</h2> </h2>

View File

@ -2,10 +2,6 @@
<div role="main" aria-label="{{.Title}}" class="page-content repository new issue"> <div role="main" aria-label="{{.Title}}" class="page-content repository new issue">
{{template "repo/header" .}} {{template "repo/header" .}}
<div class="ui container"> <div class="ui container">
<div class="navbar">
{{template "repo/issue/navbar" .}}
</div>
<div class="ui divider"></div>
{{if .Flash.WarningMsg}} {{if .Flash.WarningMsg}}
{{/* {{/*
There's already an importing of alert.tmpl in new_form.tmpl, There's already an importing of alert.tmpl in new_form.tmpl,

View File

@ -1,4 +1,4 @@
<div class="small-pill-buttons ui compact tiny menu"> <div class="small-menu-items ui compact tiny menu">
<a class="{{if not .IsShowClosed}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort={{$.SortType}}&state=open&labels={{.SelectLabels}}&milestone={{.MilestoneID}}&project={{.ProjectID}}&assignee={{.AssigneeID}}&poster={{.PosterID}}"> <a class="{{if not .IsShowClosed}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort={{$.SortType}}&state=open&labels={{.SelectLabels}}&milestone={{.MilestoneID}}&project={{.ProjectID}}&assignee={{.AssigneeID}}&poster={{.PosterID}}">
{{if .PageIsPullList}} {{if .PageIsPullList}}
{{svg "octicon-git-pull-request" 16 "gt-mr-3"}} {{svg "octicon-git-pull-request" 16 "gt-mr-3"}}

View File

@ -2,32 +2,11 @@
<div role="main" aria-label="{{.Title}}" class="page-content repository view issue pull"> <div role="main" aria-label="{{.Title}}" class="page-content repository view issue pull">
{{template "repo/header" .}} {{template "repo/header" .}}
<div class="ui container"> <div class="ui container">
<div class="ui two column grid">
<div class="column">
{{template "repo/issue/navbar" .}}
</div>
{{if and (not .Repository.IsArchived) (not .Issue.IsPull)}}
<div class="column right aligned">
{{if .PageIsIssueList}}
<a class="ui green button" href="{{.RepoLink}}/issues/new{{if .NewIssueChooseTemplate}}/choose{{end}}">{{.locale.Tr "repo.issues.new"}}</a>
{{else}}
<a class="ui green button {{if not .PullRequestCtx.Allowed}}disabled{{end}}" href="{{.RepoLink}}/compare/{{.BranchName | PathEscapeSegments}}...{{.PullRequestCtx.HeadInfoSubURL}}">{{.locale.Tr "repo.pulls.new"}}</a>
{{end}}
</div>
{{end}}
</div>
<div class="ui divider"></div>
{{if .Issue.IsPull}}
{{template "repo/issue/view_title" .}} {{template "repo/issue/view_title" .}}
{{if .Issue.IsPull}}
{{template "repo/pulls/tab_menu" .}} {{template "repo/pulls/tab_menu" .}}
<div class="ui bottom attached tab pull active" data-tab="request-{{.ID}}">
{{template "repo/issue/view_content" .}}
</div>
{{else}}
<div>
{{template "repo/issue/view_content" .}}
</div>
{{end}} {{end}}
{{template "repo/issue/view_content" .}}
</div> </div>
</div> </div>
{{template "base/footer" .}} {{template "base/footer" .}}

View File

@ -1,13 +1,4 @@
<div class="ui stackable grid"> <div class="ui stackable grid">
{{if .Flash}}
<div class="sixteen wide column">
{{template "base/alert" .}}
</div>
{{end}}
{{if not .Issue.IsPull}}
{{template "repo/issue/view_title" .}}
{{end}}
<!-- I know, there is probably a better way to do this (moved from sidebar.tmpl, original author: 6543 @ 2021-02-28) --> <!-- I know, there is probably a better way to do this (moved from sidebar.tmpl, original author: 6543 @ 2021-02-28) -->
<!-- Agree, there should be a better way, eg: introduce window.config.pageData (original author: wxiaoguang @ 2021-09-05) --> <!-- Agree, there should be a better way, eg: introduce window.config.pageData (original author: wxiaoguang @ 2021-09-05) -->
<input type="hidden" id="repolink" value="{{$.RepoRelPath}}"> <input type="hidden" id="repolink" value="{{$.RepoRelPath}}">

View File

@ -125,9 +125,9 @@
{{template "shared/user/authorlink" .Poster}} {{template "shared/user/authorlink" .Poster}}
{{$link := printf "%s/commit/%s" $.Repository.Link ($.Issue.PullRequest.MergedCommitID|PathEscape)}} {{$link := printf "%s/commit/%s" $.Repository.Link ($.Issue.PullRequest.MergedCommitID|PathEscape)}}
{{if eq $.Issue.PullRequest.Status 3}} {{if eq $.Issue.PullRequest.Status 3}}
{{$.locale.Tr "repo.issues.manually_pull_merged_at" ($link|Escape) (ShortSha $.Issue.PullRequest.MergedCommitID) ($.BaseTarget|Escape) $createdStr | Safe}} {{$.locale.Tr "repo.issues.comment_manually_pull_merged_at" (printf "<a class='ui sha' href='%[1]s'><b>%[2]s</b></a>" ($link|Escape) (ShortSha $.Issue.PullRequest.MergedCommitID)) (printf "<b>%[1]s</b>" ($.BaseTarget|Escape)) $createdStr | Safe}}
{{else}} {{else}}
{{$.locale.Tr "repo.issues.pull_merged_at" ($link|Escape) (ShortSha $.Issue.PullRequest.MergedCommitID) ($.BaseTarget|Escape) $createdStr | Safe}} {{$.locale.Tr "repo.issues.comment_pull_merged_at" (printf "<a class='ui sha' href='%[1]s'><b>%[2]s</b></a>" ($link|Escape) (ShortSha $.Issue.PullRequest.MergedCommitID)) (printf "<b>%[1]s</b>" ($.BaseTarget|Escape)) $createdStr | Safe}}
{{end}} {{end}}
</span> </span>
</div> </div>

View File

@ -47,7 +47,7 @@
{{$.locale.Tr "repo.issues.dismiss_review"}} {{$.locale.Tr "repo.issues.dismiss_review"}}
</div> </div>
<div class="content"> <div class="content">
<div class="ui warning message text left"> <div class="ui warning message">
{{$.locale.Tr "repo.issues.dismiss_review_warning"}} {{$.locale.Tr "repo.issues.dismiss_review_warning"}}
</div> </div>
<form class="ui form dismiss-review-form" id="dismiss-review-{{.Review.ID}}" action="{{$.RepoLink}}/issues/dismiss_review" method="post"> <form class="ui form dismiss-review-form" id="dismiss-review-{{.Review.ID}}" action="{{$.RepoLink}}/issues/dismiss_review" method="post">
@ -108,6 +108,9 @@
</div> </div>
</div> </div>
{{end}} {{end}}
{{if and .Issue.PullRequest.HasMerged (not .IsPullBranchDeletable)}}
{{/* Then the merge box will not be displayed because this page already contains enough information */}}
{{else}}
<div class="timeline-item comment merge box"> <div class="timeline-item comment merge box">
<a class="timeline-avatar text {{if .Issue.PullRequest.HasMerged}}purple <a class="timeline-avatar text {{if .Issue.PullRequest.HasMerged}}purple
{{- else if .Issue.IsClosed}}grey {{- else if .Issue.IsClosed}}grey
@ -131,19 +134,21 @@
{{$showGeneralMergeForm := false}} {{$showGeneralMergeForm := false}}
<div class="ui attached merge-section segment {{if not $.LatestCommitStatus}}no-header{{end}}"> <div class="ui attached merge-section segment {{if not $.LatestCommitStatus}}no-header{{end}}">
{{if .Issue.PullRequest.HasMerged}} {{if .Issue.PullRequest.HasMerged}}
{{if .IsPullBranchDeletable}}
<div class="item item-section text gt-f1"> <div class="item item-section text gt-f1">
<div class="item-section-left"> <div class="item-section-left">
<h3 class="gt-mb-3">{{$.locale.Tr "repo.pulls.merged_success"}}</h3> <h3 class="gt-mb-3">
{{$.locale.Tr "repo.pulls.merged_success"}}
</h3>
<div class="merge-section-info"> <div class="merge-section-info">
{{$.locale.Tr "repo.pulls.merged_info_text" (printf "<code>%s</code>" (.HeadTarget | Escape)) | Str2html}} {{$.locale.Tr "repo.pulls.merged_info_text" (printf "<code>%s</code>" (.HeadTarget | Escape)) | Str2html}}
</div> </div>
</div> </div>
{{if .IsPullBranchDeletable}}
<div class="item-section-right"> <div class="item-section-right">
<button class="delete-button ui button" data-url="{{.DeleteBranchLink}}">{{$.locale.Tr "repo.branch.delete_html"}}</button> <button class="delete-button ui button" data-url="{{.DeleteBranchLink}}">{{$.locale.Tr "repo.branch.delete_html"}}</button>
</div> </div>
{{end}}
</div> </div>
{{end}}
{{else if .Issue.IsClosed}} {{else if .Issue.IsClosed}}
<div class="item item-section text gt-f1"> <div class="item item-section text gt-f1">
<div class="item-section-left"> <div class="item-section-left">
@ -485,3 +490,4 @@
</div> </div>
</div> </div>
</div> </div>
{{end}}

View File

@ -560,7 +560,7 @@
{{end}} {{end}}
</div> </div>
<div class="content"> <div class="content">
<div class="ui warning message text left"> <div class="ui warning message">
{{if .Issue.IsLocked}} {{if .Issue.IsLocked}}
{{.locale.Tr "repo.issues.unlock.notice_1"}}<br> {{.locale.Tr "repo.issues.unlock.notice_1"}}<br>
{{.locale.Tr "repo.issues.unlock.notice_2"}}<br> {{.locale.Tr "repo.issues.unlock.notice_2"}}<br>

View File

@ -1,36 +1,47 @@
<div class="sixteen wide column title"> {{if .Flash}}
<div class="issue-title" id="issue-title-wrapper"> <div class="sixteen wide column gt-mb-3">
{{if and (or .HasIssuesOrPullsWritePermission .IsIssuePoster) (not .Repository.IsArchived)}} {{template "base/alert" .}}
<button id="edit-title" class="ui basic button secondary edit-button not-in-edit">{{.locale.Tr "repo.issues.edit"}}</button> </div>
{{end}} {{end}}
<h1> <div class="issue-title-header">
<span id="issue-title">{{RenderIssueTitle $.Context .Issue.Title $.RepoLink $.Repository.ComposeMetas | RenderCodeBlock}}</span> <div class="issue-title" id="issue-title-wrapper">
<span class="index">#{{.Issue.Index}}</span> <h1 class="gt-word-break">
<div id="edit-title-input" class="ui input gt-ml-4 gt-hidden"> <span id="issue-title">{{RenderIssueTitle $.Context .Issue.Title $.RepoLink $.Repository.ComposeMetas | RenderCodeBlock}} <span class="index">#{{.Issue.Index}}</span>
</span>
<div id="edit-title-input" class="ui input gt-f1 gt-hidden">
<input value="{{.Issue.Title}}" maxlength="255" autocomplete="off"> <input value="{{.Issue.Title}}" maxlength="255" autocomplete="off">
</div> </div>
</h1> </h1>
<div class="issue-title-buttons">
{{if and (or .HasIssuesOrPullsWritePermission .IsIssuePoster) (not .Repository.IsArchived)}}
<button id="edit-title" class="ui small basic button secondary edit-button not-in-edit{{if .Issue.IsPull}} gt-mr-0{{end}}">{{.locale.Tr "repo.issues.edit"}}</button>
{{end}}
{{if not .Issue.IsPull}}
<a role="button" class="ui small green button new-issue-button gt-mr-0" href="{{.RepoLink}}/issues/new{{if .NewIssueChooseTemplate}}/choose{{end}}">{{.locale.Tr "repo.issues.new"}}</a>
{{end}}
</div>
{{if and (or .HasIssuesOrPullsWritePermission .IsIssuePoster) (not .Repository.IsArchived)}} {{if and (or .HasIssuesOrPullsWritePermission .IsIssuePoster) (not .Repository.IsArchived)}}
<div class="edit-buttons"> <div class="edit-buttons">
<button id="cancel-edit-title" class="ui basic button secondary in-edit gt-hidden">{{.locale.Tr "repo.issues.cancel"}}</button> <button id="cancel-edit-title" class="ui small basic button secondary in-edit gt-hidden">{{.locale.Tr "repo.issues.cancel"}}</button>
<button id="save-edit-title" class="ui primary button in-edit gt-hidden" data-update-url="{{$.RepoLink}}/issues/{{.Issue.Index}}/title" {{if .Issue.IsPull}}data-target-update-url="{{$.RepoLink}}/pull/{{.Issue.Index}}/target_branch"{{end}}>{{.locale.Tr "repo.issues.save"}}</button> <button id="save-edit-title" class="ui small primary button in-edit gt-hidden gt-mr-0" data-update-url="{{$.RepoLink}}/issues/{{.Issue.Index}}/title" {{if .Issue.IsPull}}data-target-update-url="{{$.RepoLink}}/pull/{{.Issue.Index}}/target_branch"{{end}}>{{.locale.Tr "repo.issues.save"}}</button>
</div> </div>
{{end}} {{end}}
</div> </div>
<div class="issue-title-meta">
{{if .HasMerged}} {{if .HasMerged}}
<div class="ui purple large label">{{svg "octicon-git-merge" 16}} {{if eq .Issue.PullRequest.Status 3}}{{.locale.Tr "repo.pulls.manually_merged"}}{{else}}{{.locale.Tr "repo.pulls.merged"}}{{end}}</div> <div class="ui purple label issue-state-label">{{svg "octicon-git-merge" 16 "gt-mr-2"}} {{if eq .Issue.PullRequest.Status 3}}{{.locale.Tr "repo.pulls.manually_merged"}}{{else}}{{.locale.Tr "repo.pulls.merged"}}{{end}}</div>
{{else if .Issue.IsClosed}} {{else if .Issue.IsClosed}}
<div class="ui red large label">{{if .Issue.IsPull}}{{svg "octicon-git-pull-request"}}{{else}}{{svg "octicon-issue-closed"}}{{end}} {{.locale.Tr "repo.issues.closed_title"}}</div> <div class="ui red label issue-state-label">{{if .Issue.IsPull}}{{svg "octicon-git-pull-request"}}{{else}}{{svg "octicon-issue-closed"}}{{end}} {{.locale.Tr "repo.issues.closed_title"}}</div>
{{else if .Issue.IsPull}} {{else if .Issue.IsPull}}
{{if .IsPullWorkInProgress}} {{if .IsPullWorkInProgress}}
<div class="ui grey large label">{{svg "octicon-git-pull-request-draft"}} {{.locale.Tr "repo.issues.draft_title"}}</div> <div class="ui grey label issue-state-label">{{svg "octicon-git-pull-request-draft"}} {{.locale.Tr "repo.issues.draft_title"}}</div>
{{else}} {{else}}
<div class="ui green large label">{{svg "octicon-git-pull-request"}} {{.locale.Tr "repo.issues.open_title"}}</div> <div class="ui green label issue-state-label">{{svg "octicon-git-pull-request"}} {{.locale.Tr "repo.issues.open_title"}}</div>
{{end}} {{end}}
{{else}} {{else}}
<div class="ui green large label">{{svg "octicon-issue-opened"}} {{.locale.Tr "repo.issues.open_title"}}</div> <div class="ui green label issue-state-label">{{svg "octicon-issue-opened"}} {{.locale.Tr "repo.issues.open_title"}}</div>
{{end}} {{end}}
<div class="gt-ml-3">
{{if .Issue.IsPull}} {{if .Issue.IsPull}}
{{$headHref := .HeadTarget|Escape}} {{$headHref := .HeadTarget|Escape}}
{{if .HeadBranchLink}} {{if .HeadBranchLink}}
@ -103,5 +114,6 @@
{{$.locale.Tr "repo.issues.num_comments" .Issue.NumComments}} {{$.locale.Tr "repo.issues.num_comments" .Issue.NumComments}}
</span> </span>
{{end}} {{end}}
<div class="ui divider"></div> </div>
</div>
</div> </div>

View File

@ -50,7 +50,7 @@
{{.locale.Tr "repo.settings.delete"}} {{.locale.Tr "repo.settings.delete"}}
</div> </div>
<div class="content"> <div class="content">
<div class="ui warning message text left"> <div class="ui warning message">
{{.locale.Tr "repo.settings.delete_notices_1" | Safe}}<br> {{.locale.Tr "repo.settings.delete_notices_1" | Safe}}<br>
{{.locale.Tr "repo.settings.delete_notices_2" .Repository.FullName | Safe}} {{.locale.Tr "repo.settings.delete_notices_2" .Repository.FullName | Safe}}
{{if .Repository.NumForks}}<br> {{if .Repository.NumForks}}<br>

View File

@ -2,17 +2,9 @@
<div role="main" aria-label="{{.Title}}" class="page-content repository projects milestones"> <div role="main" aria-label="{{.Title}}" class="page-content repository projects milestones">
{{template "repo/header" .}} {{template "repo/header" .}}
<div class="ui container"> <div class="ui container">
<div class="navbar"> <div class="navbar gt-mb-4">
{{template "repo/issue/navbar" .}} <div>
{{if and .CanWriteProjects (not .Repository.IsArchived)}} <div class="small-menu-items ui compact tiny menu">
<div class="ui right">
<a class="ui small green button" href="{{$.Link}}/new">{{.locale.Tr "repo.projects.new"}}</a>
</div>
{{end}}
</div>
<div class="ui divider"></div>
{{template "base/alert" .}}
<div class="small-pill-buttons ui compact tiny menu">
<a class="item{{if not .IsShowClosed}} active{{end}}" href="{{.RepoLink}}/projects?state=open"> <a class="item{{if not .IsShowClosed}} active{{end}}" href="{{.RepoLink}}/projects?state=open">
{{svg "octicon-project" 16 "gt-mr-3"}} {{svg "octicon-project" 16 "gt-mr-3"}}
{{.locale.PrettyNumber .OpenCount}}&nbsp;{{.locale.Tr "repo.issues.open_title"}} {{.locale.PrettyNumber .OpenCount}}&nbsp;{{.locale.Tr "repo.issues.open_title"}}
@ -22,10 +14,10 @@
{{.locale.PrettyNumber .ClosedCount}}&nbsp;{{.locale.Tr "repo.issues.closed_title"}} {{.locale.PrettyNumber .ClosedCount}}&nbsp;{{.locale.Tr "repo.issues.closed_title"}}
</a> </a>
</div> </div>
</div>
<div class="ui right floated secondary filter menu"> <div>
<!-- Sort --> <!-- Sort -->
<div class="ui dropdown type jump item"> <div class="ui small dropdown type jump item">
<span class="text"> <span class="text">
{{.locale.Tr "repo.issues.filter_sort"}} {{.locale.Tr "repo.issues.filter_sort"}}
{{svg "octicon-triangle-down" 14 "dropdown icon"}} {{svg "octicon-triangle-down" 14 "dropdown icon"}}
@ -36,7 +28,13 @@
<a class="{{if eq .SortType "leastupdate"}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&sort=leastupdate&state={{$.State}}">{{.locale.Tr "repo.issues.filter_sort.leastupdate"}}</a> <a class="{{if eq .SortType "leastupdate"}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&sort=leastupdate&state={{$.State}}">{{.locale.Tr "repo.issues.filter_sort.leastupdate"}}</a>
</div> </div>
</div> </div>
{{if and .CanWriteProjects (not .Repository.IsArchived)}}
<a class="ui small green button gt-ml-4" href="{{$.Link}}/new">{{.locale.Tr "repo.projects.new"}}</a>
{{end}}
</div> </div>
</div>
{{template "base/alert" .}}
<div class="milestone list"> <div class="milestone list">
{{range .Projects}} {{range .Projects}}
<li class="item"> <li class="item">

View File

@ -2,18 +2,9 @@
<div role="main" aria-label="{{.Title}}" class="page-content repository view issue pull commits"> <div role="main" aria-label="{{.Title}}" class="page-content repository view issue pull commits">
{{template "repo/header" .}} {{template "repo/header" .}}
<div class="ui container"> <div class="ui container">
<div class="navbar">
{{template "repo/issue/navbar" .}}
<div class="ui right">
<a class="ui green button {{if not .PullRequestCtx.Allowed}}disabled{{end}}" href="{{.RepoLink}}/compare/{{.BranchName | PathEscapeSegments}}...{{.PullRequestCtx.HeadInfoSubURL}}">{{.locale.Tr "repo.pulls.new"}}</a>
</div>
</div>
<div class="ui divider"></div>
{{template "repo/issue/view_title" .}} {{template "repo/issue/view_title" .}}
{{template "repo/pulls/tab_menu" .}} {{template "repo/pulls/tab_menu" .}}
<div class="ui bottom attached tab pull active">
{{template "repo/commits_table" .}} {{template "repo/commits_table" .}}
</div> </div>
</div> </div>
</div>
{{template "base/footer" .}} {{template "base/footer" .}}

View File

@ -5,20 +5,10 @@
<div role="main" aria-label="{{.Title}}" class="page-content repository view issue pull files diff"> <div role="main" aria-label="{{.Title}}" class="page-content repository view issue pull files diff">
{{template "repo/header" .}} {{template "repo/header" .}}
<div class="ui container fluid padded"> <div class="ui container">
<div class="navbar">
{{template "repo/issue/navbar" .}}
<div class="ui right">
<a class="ui green button {{if not .PullRequestCtx.Allowed}}disabled{{end}}" href="{{.RepoLink}}/compare/{{.BranchName | PathEscapeSegments}}...{{.PullRequestCtx.HeadInfoSubURL}}">{{.locale.Tr "repo.pulls.new"}}</a>
</div>
</div>
<div class="ui divider"></div>
{{template "repo/issue/view_title" .}} {{template "repo/issue/view_title" .}}
{{template "repo/pulls/tab_menu" .}} {{template "repo/pulls/tab_menu" .}}
{{template "base/alert" .}}
<div class="ui bottom attached tab pull active">
{{template "repo/diff/box" .}} {{template "repo/diff/box" .}}
</div> </div>
</div> </div>
</div>
{{template "base/footer" .}} {{template "base/footer" .}}

View File

@ -14,13 +14,11 @@
<ul id="release-list"> <ul id="release-list">
{{range $idx, $release := .Releases}} {{range $idx, $release := .Releases}}
<li class="ui grid"> <li class="ui grid">
<div class="ui four wide column meta gt-mt-2"> <div class="ui four wide column meta">
<a class="gt-df gt-ac gt-je muted" href="{{if not .Sha1}}#{{else}}{{$.RepoLink}}/src/tag/{{.TagName | PathEscapeSegments}}{{end}}" rel="nofollow">{{svg "octicon-tag" 16 "gt-mr-2"}}{{.TagName}}</a> <a class="gt-db muted" href="{{if not .Sha1}}#{{else}}{{$.RepoLink}}/src/tag/{{.TagName | PathEscapeSegments}}{{end}}" rel="nofollow">{{svg "octicon-tag" 16 "gt-mr-2"}}{{.TagName}}</a>
{{if .Sha1}} {{if .Sha1}}
<span class="commit"> <a class="gt-mono muted gt-db gt-mt-4 gt-pt-1" href="{{$.RepoLink}}/src/commit/{{.Sha1}}" rel="nofollow">{{svg "octicon-git-commit" 16 "gt-mr-2"}}{{ShortSha .Sha1}}</a>
<a class="gt-mono muted" href="{{$.RepoLink}}/src/commit/{{.Sha1}}" rel="nofollow">{{svg "octicon-git-commit" 16 "gt-mr-2"}}{{ShortSha .Sha1}}</a> {{template "repo/branch_dropdown" dict "root" $ "release" . "ContainerClasses" "gt-mt-4"}}
</span>
{{template "repo/branch_dropdown" dict "root" $ "release" .}}
{{end}} {{end}}
</div> </div>
<div class="ui twelve wide column detail"> <div class="ui twelve wide column detail">

View File

@ -91,7 +91,7 @@
<td>{{$.locale.Tr "repo.settings.mirror_settings.direction.pull"}}</td> <td>{{$.locale.Tr "repo.settings.mirror_settings.direction.pull"}}</td>
<td>{{DateTime "full" .Mirror.UpdatedUnix}}</td> <td>{{DateTime "full" .Mirror.UpdatedUnix}}</td>
<td class="right aligned"> <td class="right aligned">
<form method="post" style="display: inline-block"> <form method="post gt-dib">
{{.CsrfTokenHtml}} {{.CsrfTokenHtml}}
<input type="hidden" name="action" value="mirror-sync"> <input type="hidden" name="action" value="mirror-sync">
<button class="ui primary tiny button inline text-thin">{{$.locale.Tr "repo.settings.sync_mirror"}}</button> <button class="ui primary tiny button inline text-thin">{{$.locale.Tr "repo.settings.sync_mirror"}}</button>
@ -169,13 +169,13 @@
<td>{{$.locale.Tr "repo.settings.mirror_settings.direction.push"}}</td> <td>{{$.locale.Tr "repo.settings.mirror_settings.direction.push"}}</td>
<td>{{if .LastUpdateUnix}}{{DateTime "full" .LastUpdateUnix}}{{else}}{{$.locale.Tr "never"}}{{end}} {{if .LastError}}<div class="ui red label" data-tooltip-content="{{.LastError}}">{{$.locale.Tr "error"}}</div>{{end}}</td> <td>{{if .LastUpdateUnix}}{{DateTime "full" .LastUpdateUnix}}{{else}}{{$.locale.Tr "never"}}{{end}} {{if .LastError}}<div class="ui red label" data-tooltip-content="{{.LastError}}">{{$.locale.Tr "error"}}</div>{{end}}</td>
<td class="right aligned"> <td class="right aligned">
<form method="post" style="display: inline-block"> <form method="post gt-dib">
{{$.CsrfTokenHtml}} {{$.CsrfTokenHtml}}
<input type="hidden" name="action" value="push-mirror-remove"> <input type="hidden" name="action" value="push-mirror-remove">
<input type="hidden" name="push_mirror_id" value="{{.ID}}"> <input type="hidden" name="push_mirror_id" value="{{.ID}}">
<button class="ui basic red tiny button inline text-thin">{{$.locale.Tr "remove"}}</button> <button class="ui basic red tiny button inline text-thin">{{$.locale.Tr "remove"}}</button>
</form> </form>
<form method="post" style="display: inline-block"> <form method="post gt-dib">
{{$.CsrfTokenHtml}} {{$.CsrfTokenHtml}}
<input type="hidden" name="action" value="push-mirror-sync"> <input type="hidden" name="action" value="push-mirror-sync">
<input type="hidden" name="push_mirror_id" value="{{.ID}}"> <input type="hidden" name="push_mirror_id" value="{{.ID}}">
@ -803,7 +803,7 @@
{{.locale.Tr "repo.settings.convert"}} {{.locale.Tr "repo.settings.convert"}}
</div> </div>
<div class="content"> <div class="content">
<div class="ui warning message text left"> <div class="ui warning message">
{{.locale.Tr "repo.settings.convert_notices_1"}} {{.locale.Tr "repo.settings.convert_notices_1"}}
</div> </div>
<form class="ui form" action="{{.Link}}" method="post"> <form class="ui form" action="{{.Link}}" method="post">
@ -834,7 +834,7 @@
{{.locale.Tr "repo.settings.convert_fork"}} {{.locale.Tr "repo.settings.convert_fork"}}
</div> </div>
<div class="content"> <div class="content">
<div class="ui warning message text left"> <div class="ui warning message">
{{.locale.Tr "repo.settings.convert_fork_notices_1"}} {{.locale.Tr "repo.settings.convert_fork_notices_1"}}
</div> </div>
<form class="ui form" action="{{.Link}}" method="post"> <form class="ui form" action="{{.Link}}" method="post">
@ -864,7 +864,7 @@
{{.locale.Tr "repo.settings.transfer"}} {{.locale.Tr "repo.settings.transfer"}}
</div> </div>
<div class="content"> <div class="content">
<div class="ui warning message text left"> <div class="ui warning message">
{{.locale.Tr "repo.settings.transfer_notices_1"}} <br> {{.locale.Tr "repo.settings.transfer_notices_1"}} <br>
{{.locale.Tr "repo.settings.transfer_notices_2"}} <br> {{.locale.Tr "repo.settings.transfer_notices_2"}} <br>
{{.locale.Tr "repo.settings.transfer_notices_3"}} {{.locale.Tr "repo.settings.transfer_notices_3"}}
@ -900,7 +900,7 @@
{{.locale.Tr "repo.settings.delete"}} {{.locale.Tr "repo.settings.delete"}}
</div> </div>
<div class="content"> <div class="content">
<div class="ui warning message text left"> <div class="ui warning message">
{{.locale.Tr "repo.settings.delete_notices_1" | Safe}}<br> {{.locale.Tr "repo.settings.delete_notices_1" | Safe}}<br>
{{.locale.Tr "repo.settings.delete_notices_2" .Repository.FullName | Safe}} {{.locale.Tr "repo.settings.delete_notices_2" .Repository.FullName | Safe}}
{{if .Repository.NumForks}}<br> {{if .Repository.NumForks}}<br>
@ -935,7 +935,7 @@
{{.locale.Tr "repo.settings.wiki_delete"}} {{.locale.Tr "repo.settings.wiki_delete"}}
</div> </div>
<div class="content"> <div class="content">
<div class="ui warning message text left"> <div class="ui warning message">
{{.locale.Tr "repo.settings.delete_notices_1" | Safe}}<br> {{.locale.Tr "repo.settings.delete_notices_1" | Safe}}<br>
{{.locale.Tr "repo.settings.wiki_delete_notices_1" .Repository.Name | Safe}} {{.locale.Tr "repo.settings.wiki_delete_notices_1" .Repository.Name | Safe}}
</div> </div>

View File

@ -21,7 +21,7 @@
<a class="ui primary sha label toggle button show-panel" data-panel="#info-{{.ID}}">{{.UUID}}</a> <a class="ui primary sha label toggle button show-panel" data-panel="#info-{{.ID}}">{{.UUID}}</a>
<div class="ui right"> <div class="ui right">
<span class="text grey time"> <span class="text grey time">
{{.DeliveredString}} {{TimeSince .Delivered.AsTime $.locale}}
</span> </span>
</div> </div>
</div> </div>

View File

@ -2,7 +2,7 @@
{{$canReadCode := $.Permission.CanRead $.UnitTypeCode}} {{$canReadCode := $.Permission.CanRead $.UnitTypeCode}}
{{if $canReadReleases}} {{if $canReadReleases}}
<h2 class="ui compact small menu header small-pill-buttons"> <h2 class="ui compact small menu header small-menu-items">
<a class="{{if .PageIsReleaseList}}active {{end}}item" href="{{.RepoLink}}/releases">{{.locale.Tr "repo.release.releases"}}</a> <a class="{{if .PageIsReleaseList}}active {{end}}item" href="{{.RepoLink}}/releases">{{.locale.Tr "repo.release.releases"}}</a>
{{if $canReadCode}} {{if $canReadCode}}
<a class="{{if .PageIsTagList}}active {{end}}item" href="{{.RepoLink}}/tags">{{.locale.Tr "repo.release.tags"}}</a> <a class="{{if .PageIsTagList}}active {{end}}item" href="{{.RepoLink}}/tags">{{.locale.Tr "repo.release.tags"}}</a>

View File

@ -61,7 +61,7 @@
</div> </div>
<div class="twelve wide column content"> <div class="twelve wide column content">
<div class="list-header"> <div class="list-header">
<div class="small-pill-buttons ui compact tiny menu"> <div class="small-menu-items ui compact tiny menu">
<a class="item{{if not .IsShowClosed}} active{{end}}" href="{{.Link}}?type={{$.ViewType}}&repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort={{$.SortType}}&state=open&q={{$.Keyword}}"> <a class="item{{if not .IsShowClosed}} active{{end}}" href="{{.Link}}?type={{$.ViewType}}&repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort={{$.SortType}}&state=open&q={{$.Keyword}}">
{{svg "octicon-issue-opened" 16 "gt-mr-3"}} {{svg "octicon-issue-opened" 16 "gt-mr-3"}}
{{.locale.PrettyNumber .IssueStats.OpenCount}}&nbsp;{{.locale.Tr "repo.issues.open_title"}} {{.locale.PrettyNumber .IssueStats.OpenCount}}&nbsp;{{.locale.Tr "repo.issues.open_title"}}

View File

@ -35,7 +35,7 @@
</div> </div>
<div class="twelve wide column content"> <div class="twelve wide column content">
<div class="list-header"> <div class="list-header">
<div class="small-pill-buttons ui compact tiny menu"> <div class="small-menu-items ui compact tiny menu">
<a class="item{{if not .IsShowClosed}} active{{end}}" href="{{.Link}}?repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort={{$.SortType}}&state=open&q={{$.Keyword}}"> <a class="item{{if not .IsShowClosed}} active{{end}}" href="{{.Link}}?repos=[{{range $.RepoIDs}}{{.}}%2C{{end}}]&sort={{$.SortType}}&state=open&q={{$.Keyword}}">
{{svg "octicon-milestone" 16 "gt-mr-3"}} {{svg "octicon-milestone" 16 "gt-mr-3"}}
{{.locale.PrettyNumber .MilestoneStats.OpenCount}}&nbsp;{{.locale.Tr "repo.issues.open_title"}} {{.locale.PrettyNumber .MilestoneStats.OpenCount}}&nbsp;{{.locale.Tr "repo.issues.open_title"}}

View File

@ -13,7 +13,7 @@
{{if eq .Status 1}} {{if eq .Status 1}}
<div class="ui stackable grid"> <div class="ui stackable grid">
<div class="six wide column"> <div class="six wide column">
<div class="small-pill-buttons ui compact tiny menu"> <div class="small-menu-items ui compact tiny menu">
<a class="{{if eq .State "all"}}active {{end}}item" href="{{$.Link}}?sort={{$.SortType}}&state=all&issueType={{$.IssueType}}&labels={{$.Labels}}"> <a class="{{if eq .State "all"}}active {{end}}item" href="{{$.Link}}?sort={{$.SortType}}&state=all&issueType={{$.IssueType}}&labels={{$.Labels}}">
{{.locale.Tr "all"}} {{.locale.Tr "all"}}
</a> </a>

View File

@ -98,7 +98,7 @@ func testPackageCargo(t *testing.T, _ *neturl.URL) {
url := fmt.Sprintf("%s/api/v1/crates", root) url := fmt.Sprintf("%s/api/v1/crates", root)
t.Run("Index", func(t *testing.T) { t.Run("Index", func(t *testing.T) {
t.Run("Config", func(t *testing.T) { t.Run("Git/Config", func(t *testing.T) {
defer tests.PrintCurrentTest(t)() defer tests.PrintCurrentTest(t)()
content := readGitContent(t, cargo_service.ConfigFileName) content := readGitContent(t, cargo_service.ConfigFileName)
@ -110,6 +110,20 @@ func testPackageCargo(t *testing.T, _ *neturl.URL) {
assert.Equal(t, url, config.DownloadURL) assert.Equal(t, url, config.DownloadURL)
assert.Equal(t, root, config.APIURL) assert.Equal(t, root, config.APIURL)
}) })
t.Run("HTTP/Config", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
req := NewRequest(t, "GET", root+"/"+cargo_service.ConfigFileName)
resp := MakeRequest(t, req, http.StatusOK)
var config cargo_service.Config
err := json.Unmarshal(resp.Body.Bytes(), &config)
assert.NoError(t, err)
assert.Equal(t, url, config.DownloadURL)
assert.Equal(t, root, config.APIURL)
})
}) })
t.Run("Upload", func(t *testing.T) { t.Run("Upload", func(t *testing.T) {
@ -192,6 +206,7 @@ func testPackageCargo(t *testing.T, _ *neturl.URL) {
MakeRequest(t, req, http.StatusConflict) MakeRequest(t, req, http.StatusConflict)
t.Run("Index", func(t *testing.T) { t.Run("Index", func(t *testing.T) {
t.Run("Git", func(t *testing.T) {
t.Run("Entry", func(t *testing.T) { t.Run("Entry", func(t *testing.T) {
defer tests.PrintCurrentTest(t)() defer tests.PrintCurrentTest(t)()
@ -228,6 +243,37 @@ func testPackageCargo(t *testing.T, _ *neturl.URL) {
_ = readGitContent(t, cargo_service.BuildPackagePath(packageName)) _ = readGitContent(t, cargo_service.BuildPackagePath(packageName))
}) })
}) })
t.Run("HTTP", func(t *testing.T) {
t.Run("Entry", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
req := NewRequest(t, "GET", root+"/"+cargo_service.BuildPackagePath(packageName))
resp := MakeRequest(t, req, http.StatusOK)
var entry cargo_service.IndexVersionEntry
err := json.Unmarshal(resp.Body.Bytes(), &entry)
assert.NoError(t, err)
assert.Equal(t, packageName, entry.Name)
assert.Equal(t, packageVersion, entry.Version)
assert.Equal(t, pb.HashSHA256, entry.FileChecksum)
assert.False(t, entry.Yanked)
assert.Len(t, entry.Dependencies, 1)
dep := entry.Dependencies[0]
assert.Equal(t, "dep", dep.Name)
assert.Equal(t, "1.0", dep.Req)
assert.Equal(t, "normal", dep.Kind)
assert.True(t, dep.DefaultFeatures)
assert.Empty(t, dep.Features)
assert.False(t, dep.Optional)
assert.Nil(t, dep.Target)
assert.NotNil(t, dep.Registry)
assert.Equal(t, "https://gitea.io/user/_cargo-index", *dep.Registry)
assert.Nil(t, dep.Package)
})
})
})
}) })
}) })

View File

@ -143,7 +143,7 @@ func testNewIssue(t *testing.T, session *TestSession, user, repo, title, content
htmlDoc = NewHTMLParser(t, resp.Body) htmlDoc = NewHTMLParser(t, resp.Body)
val := htmlDoc.doc.Find("#issue-title").Text() val := htmlDoc.doc.Find("#issue-title").Text()
assert.Equal(t, title, val) assert.Contains(t, val, title)
val = htmlDoc.doc.Find(".comment .render-content p").First().Text() val = htmlDoc.doc.Find(".comment .render-content p").First().Text()
assert.Equal(t, content, val) assert.Equal(t, content, val)

View File

@ -57,7 +57,7 @@ func initMigrationTest(t *testing.T) func() {
setting.CustomConf = giteaConf setting.CustomConf = giteaConf
} }
setting.InitProviderAndLoadCommonSettingsForTest() unittest.InitSettings()
assert.True(t, len(setting.RepoRootPath) != 0) assert.True(t, len(setting.RepoRootPath) != 0)
assert.NoError(t, util.RemoveAll(setting.RepoRootPath)) assert.NoError(t, util.RemoveAll(setting.RepoRootPath))

View File

@ -74,7 +74,7 @@ func InitTest(requireGitea bool) {
} }
setting.SetCustomPathAndConf("", "", "") setting.SetCustomPathAndConf("", "", "")
setting.InitProviderAndLoadCommonSettingsForTest() unittest.InitSettings()
setting.Repository.DefaultBranch = "master" // many test code still assume that default branch is called "master" setting.Repository.DefaultBranch = "master" // many test code still assume that default branch is called "master"
_ = util.RemoveAll(repo_module.LocalCopyPath()) _ = util.RemoveAll(repo_module.LocalCopyPath())

View File

@ -1556,7 +1556,7 @@ img.ui.avatar,
vertical-align: middle; vertical-align: middle;
} }
.ui .message { .ui .message.flash-message {
text-align: center; text-align: center;
} }
@ -2559,18 +2559,18 @@ a.ui.basic.label:hover {
.notification_count { .notification_count {
position: absolute; position: absolute;
left: 5px; left: 7px;
top: -8px; top: -9px;
min-width: 1.5em; min-width: 1.5em;
text-align: center; text-align: center;
background: var(--color-primary); background: var(--color-primary);
border: 2px solid var(--color-header-bar); border: 2px solid var(--color-header-bar);
color: var(--color-header-bar); color: var(--color-header-bar);
padding: 2px; padding: 2.75px;
border-radius: 1em; border-radius: 1em;
font-size: 10px; font-size: 11px;
font-weight: 700; font-weight: 700;
line-height: 0.7; line-height: .67em;
} }
table th[data-sortt-asc]:hover, table th[data-sortt-asc]:hover,

View File

@ -41,6 +41,5 @@
@import "./admin.css"; @import "./admin.css";
@import "./explore.css"; @import "./explore.css";
@import "./review.css"; @import "./review.css";
@import "./package.css";
@import "./runner.css"; @import "./runner.css";
@import "./helpers.css"; @import "./helpers.css";

View File

@ -1,7 +0,0 @@
.container-labels td:nth-child(1) {
vertical-align: top;
}
.container-labels td:nth-child(2) {
overflow-wrap: anywhere;
}

View File

@ -591,87 +591,83 @@
display: inline-block; display: inline-block;
} }
.repository.view.issue .title { .issue-title-header {
padding-bottom: 0 !important; width: 100%;
padding-bottom: 4px;
margin-bottom: 1rem;
} }
.repository.view.issue .title .issue-title { .issue-title-meta {
margin-bottom: 0.5rem;
}
.repository.view.issue .title .issue-title.edit-active {
display: flex; display: flex;
align-items: center; align-items: center;
} }
.repository.view.issue .title .issue-title.edit-active h1 { .repository.view.issue .issue-title-buttons,
.repository.view.issue .edit-buttons {
display: flex; display: flex;
width: 100%;
} }
@media (max-width: 767px) { @media (max-width: 767px) {
.repository.view.issue .title .issue-title.edit-active { .repository.view.issue .issue-title {
flex-direction: column; flex-direction: column;
} }
.repository.view.issue .title .issue-title.edit-active h1 { .repository.view.issue .edit-buttons {
margin-right: 0; margin-top: .5rem;
margin-bottom: 1rem;
padding-right: 0;
}
.repository.view.issue .title .issue-title.edit-active h1 .ui.input input {
width: calc(100% - 2rem);
}
.repository.view.issue .title .issue-title.edit-active .edit-buttons {
padding-bottom: 1rem;
width: 100%;
}
.repository.view.issue .title .issue-title.edit-active .edit-buttons .button {
width: 100%;
margin-right: 0.5rem;
}
.repository.view.issue .title .issue-title.edit-active .edit-buttons .button:last-child {
margin-right: 0;
} }
} }
.repository.view.issue .title .issue-title h1 { .repository.view.issue .issue-title {
font-weight: 300;
font-size: 2.3rem;
margin: 0;
padding-right: 0.5rem;
}
.repository.view.issue .title .issue-title h1 .ui.input {
font-size: 0.5em;
width: 100%;
}
.repository.view.issue .title .issue-title h1 .ui.input input {
font-size: 1.5em;
padding: 6px 1rem;
}
.repository.view.issue .title .issue-title .edit-button {
float: right;
padding-left: 1rem;
}
.repository.view.issue .title .issue-title .edit-buttons {
display: flex; display: flex;
align-items: center;
margin-bottom: 8px;
} }
.repository.view.issue .title .issue-title .index { .repository.view.issue .issue-title h1 {
display: flex;
align-items: center;
flex: 1;
width: 100%;
font-weight: 300;
font-size: 32px;
line-height: 40px;
margin: 0;
padding-right: 0.25rem;
min-height: 41px; /* avoid layout shift on edit */
}
.repository.view.issue .issue-title h1 .ui.input {
font-size: 0.5em;
}
.repository.view.issue .issue-title h1 .ui.input input {
font-size: 1.5em;
padding: 2px .5rem;
}
.repository.view.issue .issue-title .index {
color: var(--color-text-light-2); color: var(--color-text-light-2);
} }
.repository.view.issue .title .issue-title .label { .repository.view.issue .issue-title .label {
margin-right: 10px; margin-right: 10px;
} }
.repository.view.issue .title .issue-title .edit-zone { .repository.view.issue .issue-title .edit-zone {
margin-top: 10px; margin-top: 10px;
} }
.issue-state-label {
display: flex !important;
align-items: center !important;
font-size: 14px !important;
padding: 7px 10px !important;
border-radius: 6px !important;
}
.issue-state-label .svg {
margin-right: 4px;
}
.repository.view.issue .pull-desc code { .repository.view.issue .pull-desc code {
color: var(--color-primary); color: var(--color-primary);
} }
@ -1193,13 +1189,15 @@
.repository .milestone.list { .repository .milestone.list {
list-style: none; list-style: none;
padding-top: 15px;
} }
.repository .milestone.list > .item { .repository .milestone.list > .item {
padding-top: 10px; padding-top: 10px;
padding-bottom: 10px; padding-bottom: 10px;
border-bottom: 1px dashed var(--color-secondary); }
.repository .milestone.list > .item + .item {
border-top: 1px solid var(--color-secondary);
} }
.repository .milestone.list > .item progress { .repository .milestone.list > .item progress {
@ -2600,39 +2598,6 @@
height: 15px; height: 15px;
} }
#avatar-arrow::before,
#avatar-arrow::after {
right: 100%;
top: 20px;
border: solid transparent;
content: " ";
height: 0;
width: 0;
position: absolute;
pointer-events: none;
}
#avatar-arrow::before {
border-right-color: var(--color-secondary);
border-width: 9px;
margin-top: -9px;
}
#avatar-arrow::after {
border-right-color: var(--color-box-header);
border-width: 8px;
margin-top: -8px;
}
#transfer-repo-modal .ui.message,
#delete-repo-modal .ui.message,
#delete-wiki-modal .ui.message,
#convert-fork-repo-modal .ui.message,
#convert-mirror-repo-modal .ui.message,
#fork-repo-modal .ui.message {
width: 100% !important;
}
.tab-size-1 { .tab-size-1 {
tab-size: 1 !important; tab-size: 1 !important;
-moz-tab-size: 1 !important; -moz-tab-size: 1 !important;

View File

@ -3,6 +3,7 @@
flex-wrap: wrap; flex-wrap: wrap;
align-items: flex-start; align-items: flex-start;
gap: 1rem; gap: 1rem;
margin-top: 1rem;
} }
.issue-list-toolbar-left { .issue-list-toolbar-left {

View File

@ -26,11 +26,11 @@
flex: 1; flex: 1;
} }
.small-pill-buttons { .small-menu-items {
min-height: 35.4px !important; /* match .small.button in height */ min-height: 35.4px !important; /* match .small.button in height */
} }
.small-pill-buttons .item { .small-menu-items .item {
padding-top: 6px !important; padding-top: 6px !important;
padding-bottom: 6px !important; padding-bottom: 6px !important;
} }

View File

@ -1,7 +1,6 @@
.repository.releases #release-list { .repository.releases #release-list {
border-top: 1px solid var(--color-secondary); margin-top: 12px;
margin-top: 20px; padding-top: 12px;
padding-top: 15px;
padding-left: 0; padding-left: 0;
} }
@ -23,29 +22,13 @@
} }
.repository.releases #release-list > li .meta { .repository.releases #release-list > li .meta {
margin-top: 4px;
text-align: right; text-align: right;
position: relative; position: relative;
} }
.repository.releases #release-list > li .meta .label {
margin-right: 0;
}
.repository.releases #release-list > li .meta .commit {
display: block;
margin-top: 10px;
}
.repository.releases #release-list > li .meta .choose {
margin-top: 15px;
}
.repository.releases #release-list > li .meta .choose .button {
margin-right: 0;
}
.repository.releases #release-list > li .detail { .repository.releases #release-list > li .detail {
border-left: 2px solid var(--color-secondary); border-left: 1px solid var(--color-secondary);
} }
.repository.releases #release-list > li .detail .author img { .repository.releases #release-list > li .detail .author img {
@ -92,7 +75,7 @@
z-index: 9; z-index: 9;
position: absolute; position: absolute;
display: block; display: block;
left: -6px; left: -5.5px;
top: 40px; top: 40px;
border-radius: 100%; border-radius: 100%;
border: 2.5px solid var(--color-body); border: 2.5px solid var(--color-body);

View File

@ -29,33 +29,33 @@
--color-primary-alpha-70: #87ab63b3; --color-primary-alpha-70: #87ab63b3;
--color-primary-alpha-80: #87ab63cc; --color-primary-alpha-80: #87ab63cc;
--color-primary-alpha-90: #87ab63e1; --color-primary-alpha-90: #87ab63e1;
--color-secondary: #454a57; --color-secondary: #525767;
--color-secondary-dark-1: #505665; --color-secondary-dark-1: #5c6374;
--color-secondary-dark-2: #5b6273; --color-secondary-dark-2: #666e81;
--color-secondary-dark-3: #71798e; --color-secondary-dark-3: #7c8497;
--color-secondary-dark-4: #7f8699; --color-secondary-dark-4: #8990a1;
--color-secondary-dark-5: #8c93a4; --color-secondary-dark-5: #959cab;
--color-secondary-dark-6: #9aa0af; --color-secondary-dark-6: #a2a8b5;
--color-secondary-dark-7: #a8adba; --color-secondary-dark-7: #afb4c0;
--color-secondary-dark-8: #b6bac5; --color-secondary-dark-8: #bcc0ca;
--color-secondary-dark-9: #c4c7d0; --color-secondary-dark-9: #c9cbd4;
--color-secondary-dark-10: #d2d4db; --color-secondary-dark-10: #d6d7de;
--color-secondary-dark-11: #dfe1e6; --color-secondary-dark-11: #e2e3e8;
--color-secondary-dark-12: #edeef1; --color-secondary-dark-12: #eeeff2;
--color-secondary-dark-13: #fbfbfc; --color-secondary-dark-13: #fbfbfc;
--color-secondary-light-1: #373b46; --color-secondary-light-1: #454a57;
--color-secondary-light-2: #292c34; --color-secondary-light-2: #383c47;
--color-secondary-light-3: #1c1e23; --color-secondary-light-3: #2c2f37;
--color-secondary-light-4: #0e0f11; --color-secondary-light-4: #1f2226;
--color-secondary-alpha-10: #454a5719; --color-secondary-alpha-10: #52576719;
--color-secondary-alpha-20: #454a5733; --color-secondary-alpha-20: #52576733;
--color-secondary-alpha-30: #454a574b; --color-secondary-alpha-30: #5257674b;
--color-secondary-alpha-40: #454a5766; --color-secondary-alpha-40: #52576766;
--color-secondary-alpha-50: #454a5780; --color-secondary-alpha-50: #52576780;
--color-secondary-alpha-60: #454a5799; --color-secondary-alpha-60: #52576799;
--color-secondary-alpha-70: #454a57b3; --color-secondary-alpha-70: #525767b3;
--color-secondary-alpha-80: #454a57cc; --color-secondary-alpha-80: #525767cc;
--color-secondary-alpha-90: #454a57e1; --color-secondary-alpha-90: #525767e1;
/* colors */ /* colors */
--color-red: #cc4848; --color-red: #cc4848;
--color-orange: #cc580c; --color-orange: #cc580c;

View File

@ -1,6 +1,6 @@
<template> <template>
<div class="ui floating filter dropdown custom"> <div class="ui floating filter dropdown custom">
<button class="branch-dropdown-button gt-ellipsis ui basic small compact button gt-df" @click="menuVisible = !menuVisible" @keyup.enter="menuVisible = !menuVisible"> <button class="branch-dropdown-button gt-ellipsis ui basic small compact button gt-df gt-m-0" @click="menuVisible = !menuVisible" @keyup.enter="menuVisible = !menuVisible">
<span class="text gt-df gt-ac gt-mr-2"> <span class="text gt-df gt-ac gt-mr-2">
<template v-if="release">{{ textReleaseCompare }}</template> <template v-if="release">{{ textReleaseCompare }}</template>
<template v-else> <template v-else>

View File

@ -8,7 +8,7 @@ import {handleGlobalEnterQuickSubmit} from './QuickSubmit.js';
import {emojiString} from '../emoji.js'; import {emojiString} from '../emoji.js';
import {renderPreviewPanelContent} from '../repo-editor.js'; import {renderPreviewPanelContent} from '../repo-editor.js';
import {matchEmoji, matchMention} from '../../utils/match.js'; import {matchEmoji, matchMention} from '../../utils/match.js';
import {svg} from '../../svg.js'; import {easyMDEToolbarActions} from './EasyMDEToolbarActions.js';
let elementIdCounter = 0; let elementIdCounter = 0;
@ -206,66 +206,20 @@ class ComboMarkdownEditor {
prepareEasyMDEToolbarActions() { prepareEasyMDEToolbarActions() {
this.easyMDEToolbarDefault = [ this.easyMDEToolbarDefault = [
'bold', 'italic', 'strikethrough', '|', 'heading-1', 'heading-2', 'heading-3', 'heading-bigger', 'heading-smaller', '|', 'bold', 'italic', 'strikethrough', '|', 'heading-1', 'heading-2', 'heading-3',
'code', 'quote', '|', 'gitea-checkbox-empty', 'gitea-checkbox-checked', '|', 'heading-bigger', 'heading-smaller', '|', 'code', 'quote', '|', 'gitea-checkbox-empty',
'unordered-list', 'ordered-list', '|', 'link', 'image', 'table', 'horizontal-rule', '|', 'clean-block', '|', 'gitea-checkbox-checked', '|', 'unordered-list', 'ordered-list', '|', 'link', 'image',
'gitea-switch-to-textarea', 'table', 'horizontal-rule', '|', 'gitea-switch-to-textarea',
]; ];
this.easyMDEToolbarActions = {
'gitea-checkbox-empty': {
action(e) {
const cm = e.codemirror;
cm.replaceSelection(`\n- [ ] ${cm.getSelection()}`);
cm.focus();
},
icon: svg('gitea-empty-checkbox'),
title: 'Add Checkbox (empty)',
},
'gitea-checkbox-checked': {
action(e) {
const cm = e.codemirror;
cm.replaceSelection(`\n- [x] ${cm.getSelection()}`);
cm.focus();
},
icon: svg('octicon-checkbox'),
title: 'Add Checkbox (checked)',
},
'gitea-switch-to-textarea': {
action: () => {
this.userPreferredEditor = 'textarea';
this.switchToTextarea();
},
icon: svg('octicon-file'),
title: 'Revert to simple textarea',
},
'gitea-code-inline': {
action(e) {
const cm = e.codemirror;
const selection = cm.getSelection();
cm.replaceSelection(`\`${selection}\``);
if (!selection) {
const cursorPos = cm.getCursor();
cm.setCursor(cursorPos.line, cursorPos.ch - 1);
}
cm.focus();
},
icon: svg('octicon-chevron-right'),
title: 'Add Inline Code',
}
};
} }
parseEasyMDEToolbar(actions) { parseEasyMDEToolbar(EasyMDE, actions) {
this.easyMDEToolbarActions = this.easyMDEToolbarActions || easyMDEToolbarActions(EasyMDE, this);
const processed = []; const processed = [];
for (const action of actions) { for (const action of actions) {
if (action.startsWith('gitea-')) { const actionButton = this.easyMDEToolbarActions[action];
const giteaAction = this.easyMDEToolbarActions[action]; if (!actionButton) throw new Error(`Unknown EasyMDE toolbar action ${action}`);
if (!giteaAction) throw new Error(`Unknown EasyMDE toolbar action ${action}`); processed.push(actionButton);
processed.push(giteaAction);
} else {
processed.push(action);
}
} }
return processed; return processed;
} }
@ -293,7 +247,7 @@ class ComboMarkdownEditor {
nativeSpellcheck: true, nativeSpellcheck: true,
...this.options.easyMDEOptions, ...this.options.easyMDEOptions,
}; };
easyMDEOpt.toolbar = this.parseEasyMDEToolbar(easyMDEOpt.toolbar ?? this.easyMDEToolbarDefault); easyMDEOpt.toolbar = this.parseEasyMDEToolbar(EasyMDE, easyMDEOpt.toolbar ?? this.easyMDEToolbarDefault);
this.easyMDE = new EasyMDE(easyMDEOpt); this.easyMDE = new EasyMDE(easyMDEOpt);
this.easyMDE.codemirror.on('change', (...args) => {this.options?.onContentChanged?.(this, ...args)}); this.easyMDE.codemirror.on('change', (...args) => {this.options?.onContentChanged?.(this, ...args)});

View File

@ -0,0 +1,152 @@
import {svg} from '../../svg.js';
export function easyMDEToolbarActions(EasyMDE, editor) {
const actions = {
'|': '|',
'heading-1': {
action: EasyMDE.toggleHeading1,
icon: svg('octicon-heading'),
title: 'Heading 1',
},
'heading-2': {
action: EasyMDE.toggleHeading2,
icon: svg('octicon-heading'),
title: 'Heading 2',
},
'heading-3': {
action: EasyMDE.toggleHeading3,
icon: svg('octicon-heading'),
title: 'Heading 3',
},
'heading-smaller': {
action: EasyMDE.toggleHeadingSmaller,
icon: svg('octicon-heading'),
title: 'Decrease Heading',
},
'heading-bigger': {
action: EasyMDE.toggleHeadingBigger,
icon: svg('octicon-heading'),
title: 'Increase Heading',
},
'bold': {
action: EasyMDE.toggleBold,
icon: svg('octicon-bold'),
title: 'Bold',
},
'italic': {
action: EasyMDE.toggleItalic,
icon: svg('octicon-italic'),
title: 'Italic',
},
'strikethrough': {
action: EasyMDE.toggleStrikethrough,
icon: svg('octicon-strikethrough'),
title: 'Strikethrough',
},
'quote': {
action: EasyMDE.toggleBlockquote,
icon: svg('octicon-quote'),
title: 'Quote',
},
'code': {
action: EasyMDE.toggleCodeBlock,
icon: svg('octicon-code'),
title: 'Code',
},
'link': {
action: EasyMDE.drawLink,
icon: svg('octicon-link'),
title: 'Link',
},
'unordered-list': {
action: EasyMDE.toggleUnorderedList,
icon: svg('octicon-list-unordered'),
title: 'Unordered List',
},
'ordered-list': {
action: EasyMDE.toggleOrderedList,
icon: svg('octicon-list-ordered'),
title: 'Ordered List',
},
'image': {
action: EasyMDE.drawImage,
icon: svg('octicon-image'),
title: 'Image',
},
'table': {
action: EasyMDE.drawTable,
icon: svg('octicon-table'),
title: 'Table',
},
'horizontal-rule': {
action: EasyMDE.drawHorizontalRule,
icon: svg('octicon-horizontal-rule'),
title: 'Horizontal Rule',
},
'preview': {
action: EasyMDE.togglePreview,
icon: svg('octicon-eye'),
title: 'Preview',
},
'fullscreen': {
action: EasyMDE.toggleFullScreen,
icon: svg('octicon-screen-full'),
title: 'Fullscreen',
},
'side-by-side': {
action: EasyMDE.toggleSideBySide,
icon: svg('octicon-columns'),
title: 'Side by Side',
},
// gitea's custom actions
'gitea-checkbox-empty': {
action(e) {
const cm = e.codemirror;
cm.replaceSelection(`\n- [ ] ${cm.getSelection()}`);
cm.focus();
},
icon: svg('gitea-empty-checkbox'),
title: 'Add Checkbox (empty)',
},
'gitea-checkbox-checked': {
action(e) {
const cm = e.codemirror;
cm.replaceSelection(`\n- [x] ${cm.getSelection()}`);
cm.focus();
},
icon: svg('octicon-checkbox'),
title: 'Add Checkbox (checked)',
},
'gitea-switch-to-textarea': {
action: () => {
editor.userPreferredEditor = 'textarea';
editor.switchToTextarea();
},
icon: svg('octicon-arrow-switch'),
title: 'Revert to simple textarea',
},
'gitea-code-inline': {
action(e) {
const cm = e.codemirror;
const selection = cm.getSelection();
cm.replaceSelection(`\`${selection}\``);
if (!selection) {
const cursorPos = cm.getCursor();
cm.setCursor(cursorPos.line, cursorPos.ch - 1);
}
cm.focus();
},
icon: svg('octicon-chevron-right'),
title: 'Add Inline Code',
}
};
for (const [key, value] of Object.entries(actions)) {
if (typeof value !== 'string') {
value.name = key;
}
}
return actions;
}

View File

@ -572,8 +572,10 @@ export function initRepoIssueTitleEdit() {
toggleElem($('#pull-desc')); toggleElem($('#pull-desc'));
toggleElem($('#pull-desc-edit')); toggleElem($('#pull-desc-edit'));
toggleElem($('.in-edit')); toggleElem($('.in-edit'));
toggleElem($('.new-issue-button'));
$('#issue-title-wrapper').toggleClass('edit-active'); $('#issue-title-wrapper').toggleClass('edit-active');
$editInput.trigger('focus'); $editInput[0].focus();
$editInput[0].select();
return false; return false;
}; };

View File

@ -469,11 +469,7 @@ export function initRepository() {
return; return;
} }
// File list and commits
if ($('.repository.file.list').length > 0 || $('.branch-dropdown').length > 0 ||
$('.repository.commits').length > 0 || $('.repository.release').length > 0) {
initRepoBranchTagSelector('.js-branch-tag-selector'); initRepoBranchTagSelector('.js-branch-tag-selector');
}
// Options // Options
if ($('.repository.settings.options').length > 0) { if ($('.repository.settings.options').length > 0) {

View File

@ -58,7 +58,7 @@ async function initRepoWikiFormEditor() {
'gitea-code-inline', 'code', 'quote', '|', 'gitea-checkbox-empty', 'gitea-checkbox-checked', '|', 'gitea-code-inline', 'code', 'quote', '|', 'gitea-checkbox-empty', 'gitea-checkbox-checked', '|',
'unordered-list', 'ordered-list', '|', 'unordered-list', 'ordered-list', '|',
'link', 'image', 'table', 'horizontal-rule', '|', 'link', 'image', 'table', 'horizontal-rule', '|',
'clean-block', 'preview', 'fullscreen', 'side-by-side', '|', 'gitea-switch-to-textarea' 'preview', 'fullscreen', 'side-by-side', '|', 'gitea-switch-to-textarea'
], ],
}, },
}); });

View File

@ -1,80 +1,106 @@
import {h} from 'vue'; import {h} from 'vue';
import giteaDoubleChevronLeft from '../../public/img/svg/gitea-double-chevron-left.svg';
import giteaDoubleChevronRight from '../../public/img/svg/gitea-double-chevron-right.svg';
import giteaEmptyCheckbox from '../../public/img/svg/gitea-empty-checkbox.svg';
import octiconArchive from '../../public/img/svg/octicon-archive.svg';
import octiconArrowSwitch from '../../public/img/svg/octicon-arrow-switch.svg';
import octiconBlocked from '../../public/img/svg/octicon-blocked.svg';
import octiconBold from '../../public/img/svg/octicon-bold.svg';
import octiconCheckbox from '../../public/img/svg/octicon-checkbox.svg';
import octiconCheckCircleFill from '../../public/img/svg/octicon-check-circle-fill.svg';
import octiconChevronDown from '../../public/img/svg/octicon-chevron-down.svg'; import octiconChevronDown from '../../public/img/svg/octicon-chevron-down.svg';
import octiconChevronLeft from '../../public/img/svg/octicon-chevron-left.svg';
import octiconChevronRight from '../../public/img/svg/octicon-chevron-right.svg'; import octiconChevronRight from '../../public/img/svg/octicon-chevron-right.svg';
import octiconClock from '../../public/img/svg/octicon-clock.svg'; import octiconClock from '../../public/img/svg/octicon-clock.svg';
import octiconCode from '../../public/img/svg/octicon-code.svg';
import octiconColumns from '../../public/img/svg/octicon-columns.svg';
import octiconCopy from '../../public/img/svg/octicon-copy.svg'; import octiconCopy from '../../public/img/svg/octicon-copy.svg';
import octiconDiffAdded from '../../public/img/svg/octicon-diff-added.svg'; import octiconDiffAdded from '../../public/img/svg/octicon-diff-added.svg';
import octiconDiffModified from '../../public/img/svg/octicon-diff-modified.svg'; import octiconDiffModified from '../../public/img/svg/octicon-diff-modified.svg';
import octiconDiffRemoved from '../../public/img/svg/octicon-diff-removed.svg'; import octiconDiffRemoved from '../../public/img/svg/octicon-diff-removed.svg';
import octiconDiffRenamed from '../../public/img/svg/octicon-diff-renamed.svg'; import octiconDiffRenamed from '../../public/img/svg/octicon-diff-renamed.svg';
import octiconEye from '../../public/img/svg/octicon-eye.svg';
import octiconFile from '../../public/img/svg/octicon-file.svg'; import octiconFile from '../../public/img/svg/octicon-file.svg';
import octiconFileDirectoryFill from '../../public/img/svg/octicon-file-directory-fill.svg'; import octiconFileDirectoryFill from '../../public/img/svg/octicon-file-directory-fill.svg';
import octiconFilter from '../../public/img/svg/octicon-filter.svg';
import octiconGitBranch from '../../public/img/svg/octicon-git-branch.svg';
import octiconGitMerge from '../../public/img/svg/octicon-git-merge.svg'; import octiconGitMerge from '../../public/img/svg/octicon-git-merge.svg';
import octiconGitPullRequest from '../../public/img/svg/octicon-git-pull-request.svg'; import octiconGitPullRequest from '../../public/img/svg/octicon-git-pull-request.svg';
import octiconHeading from '../../public/img/svg/octicon-heading.svg';
import octiconHorizontalRule from '../../public/img/svg/octicon-horizontal-rule.svg';
import octiconImage from '../../public/img/svg/octicon-image.svg';
import octiconIssueClosed from '../../public/img/svg/octicon-issue-closed.svg'; import octiconIssueClosed from '../../public/img/svg/octicon-issue-closed.svg';
import octiconIssueOpened from '../../public/img/svg/octicon-issue-opened.svg'; import octiconIssueOpened from '../../public/img/svg/octicon-issue-opened.svg';
import octiconItalic from '../../public/img/svg/octicon-italic.svg';
import octiconKebabHorizontal from '../../public/img/svg/octicon-kebab-horizontal.svg'; import octiconKebabHorizontal from '../../public/img/svg/octicon-kebab-horizontal.svg';
import octiconLink from '../../public/img/svg/octicon-link.svg'; import octiconLink from '../../public/img/svg/octicon-link.svg';
import octiconListOrdered from '../../public/img/svg/octicon-list-ordered.svg';
import octiconListUnordered from '../../public/img/svg/octicon-list-unordered.svg';
import octiconLock from '../../public/img/svg/octicon-lock.svg'; import octiconLock from '../../public/img/svg/octicon-lock.svg';
import octiconMeter from '../../public/img/svg/octicon-meter.svg';
import octiconMilestone from '../../public/img/svg/octicon-milestone.svg'; import octiconMilestone from '../../public/img/svg/octicon-milestone.svg';
import octiconMirror from '../../public/img/svg/octicon-mirror.svg'; import octiconMirror from '../../public/img/svg/octicon-mirror.svg';
import octiconOrganization from '../../public/img/svg/octicon-organization.svg';
import octiconPlay from '../../public/img/svg/octicon-play.svg'; import octiconPlay from '../../public/img/svg/octicon-play.svg';
import octiconPlus from '../../public/img/svg/octicon-plus.svg';
import octiconProject from '../../public/img/svg/octicon-project.svg'; import octiconProject from '../../public/img/svg/octicon-project.svg';
import octiconQuote from '../../public/img/svg/octicon-quote.svg';
import octiconRepo from '../../public/img/svg/octicon-repo.svg'; import octiconRepo from '../../public/img/svg/octicon-repo.svg';
import octiconRepoForked from '../../public/img/svg/octicon-repo-forked.svg'; import octiconRepoForked from '../../public/img/svg/octicon-repo-forked.svg';
import octiconRepoTemplate from '../../public/img/svg/octicon-repo-template.svg'; import octiconRepoTemplate from '../../public/img/svg/octicon-repo-template.svg';
import octiconRss from '../../public/img/svg/octicon-rss.svg';
import octiconScreenFull from '../../public/img/svg/octicon-screen-full.svg';
import octiconSearch from '../../public/img/svg/octicon-search.svg';
import octiconSidebarCollapse from '../../public/img/svg/octicon-sidebar-collapse.svg'; import octiconSidebarCollapse from '../../public/img/svg/octicon-sidebar-collapse.svg';
import octiconSidebarExpand from '../../public/img/svg/octicon-sidebar-expand.svg'; import octiconSidebarExpand from '../../public/img/svg/octicon-sidebar-expand.svg';
import octiconSkip from '../../public/img/svg/octicon-skip.svg';
import octiconStar from '../../public/img/svg/octicon-star.svg';
import octiconStrikethrough from '../../public/img/svg/octicon-strikethrough.svg';
import octiconSync from '../../public/img/svg/octicon-sync.svg';
import octiconTable from '../../public/img/svg/octicon-table.svg';
import octiconTag from '../../public/img/svg/octicon-tag.svg';
import octiconTriangleDown from '../../public/img/svg/octicon-triangle-down.svg'; import octiconTriangleDown from '../../public/img/svg/octicon-triangle-down.svg';
import octiconX from '../../public/img/svg/octicon-x.svg'; import octiconX from '../../public/img/svg/octicon-x.svg';
import octiconCheckCircleFill from '../../public/img/svg/octicon-check-circle-fill.svg';
import octiconXCircleFill from '../../public/img/svg/octicon-x-circle-fill.svg'; import octiconXCircleFill from '../../public/img/svg/octicon-x-circle-fill.svg';
import octiconSkip from '../../public/img/svg/octicon-skip.svg';
import octiconMeter from '../../public/img/svg/octicon-meter.svg';
import octiconBlocked from '../../public/img/svg/octicon-blocked.svg';
import octiconSync from '../../public/img/svg/octicon-sync.svg';
import octiconFilter from '../../public/img/svg/octicon-filter.svg';
import octiconPlus from '../../public/img/svg/octicon-plus.svg';
import octiconSearch from '../../public/img/svg/octicon-search.svg';
import octiconArchive from '../../public/img/svg/octicon-archive.svg';
import octiconStar from '../../public/img/svg/octicon-star.svg';
import giteaDoubleChevronLeft from '../../public/img/svg/gitea-double-chevron-left.svg';
import giteaDoubleChevronRight from '../../public/img/svg/gitea-double-chevron-right.svg';
import octiconChevronLeft from '../../public/img/svg/octicon-chevron-left.svg';
import octiconOrganization from '../../public/img/svg/octicon-organization.svg';
import octiconTag from '../../public/img/svg/octicon-tag.svg';
import octiconGitBranch from '../../public/img/svg/octicon-git-branch.svg';
import octiconRss from '../../public/img/svg/octicon-rss.svg';
import octiconCheckbox from '../../public/img/svg/octicon-checkbox.svg';
import giteaEmptyCheckbox from '../../public/img/svg/gitea-empty-checkbox.svg';
const svgs = { const svgs = {
'gitea-double-chevron-left': giteaDoubleChevronLeft,
'gitea-double-chevron-right': giteaDoubleChevronRight,
'gitea-empty-checkbox': giteaEmptyCheckbox,
'octicon-archive': octiconArchive, 'octicon-archive': octiconArchive,
'octicon-arrow-switch': octiconArrowSwitch,
'octicon-blocked': octiconBlocked, 'octicon-blocked': octiconBlocked,
'octicon-checkbox': octiconCheckbox, 'octicon-bold': octiconBold,
'octicon-check-circle-fill': octiconCheckCircleFill, 'octicon-check-circle-fill': octiconCheckCircleFill,
'octicon-checkbox': octiconCheckbox,
'octicon-chevron-down': octiconChevronDown, 'octicon-chevron-down': octiconChevronDown,
'octicon-chevron-left': octiconChevronLeft, 'octicon-chevron-left': octiconChevronLeft,
'octicon-chevron-right': octiconChevronRight, 'octicon-chevron-right': octiconChevronRight,
'octicon-clock': octiconClock, 'octicon-clock': octiconClock,
'octicon-code': octiconCode,
'octicon-columns': octiconColumns,
'octicon-copy': octiconCopy, 'octicon-copy': octiconCopy,
'octicon-diff-added': octiconDiffAdded, 'octicon-diff-added': octiconDiffAdded,
'octicon-diff-modified': octiconDiffModified, 'octicon-diff-modified': octiconDiffModified,
'octicon-diff-removed': octiconDiffRemoved, 'octicon-diff-removed': octiconDiffRemoved,
'octicon-diff-renamed': octiconDiffRenamed, 'octicon-diff-renamed': octiconDiffRenamed,
'gitea-double-chevron-left': giteaDoubleChevronLeft, 'octicon-eye': octiconEye,
'gitea-double-chevron-right': giteaDoubleChevronRight,
'gitea-empty-checkbox': giteaEmptyCheckbox,
'octicon-file': octiconFile, 'octicon-file': octiconFile,
'octicon-file-directory-fill': octiconFileDirectoryFill, 'octicon-file-directory-fill': octiconFileDirectoryFill,
'octicon-filter': octiconFilter, 'octicon-filter': octiconFilter,
'octicon-git-branch': octiconGitBranch, 'octicon-git-branch': octiconGitBranch,
'octicon-git-merge': octiconGitMerge, 'octicon-git-merge': octiconGitMerge,
'octicon-git-pull-request': octiconGitPullRequest, 'octicon-git-pull-request': octiconGitPullRequest,
'octicon-heading': octiconHeading,
'octicon-horizontal-rule': octiconHorizontalRule,
'octicon-image': octiconImage,
'octicon-issue-closed': octiconIssueClosed, 'octicon-issue-closed': octiconIssueClosed,
'octicon-issue-opened': octiconIssueOpened, 'octicon-issue-opened': octiconIssueOpened,
'octicon-italic': octiconItalic,
'octicon-kebab-horizontal': octiconKebabHorizontal, 'octicon-kebab-horizontal': octiconKebabHorizontal,
'octicon-link': octiconLink, 'octicon-link': octiconLink,
'octicon-list-ordered': octiconListOrdered,
'octicon-list-unordered': octiconListUnordered,
'octicon-lock': octiconLock, 'octicon-lock': octiconLock,
'octicon-meter': octiconMeter, 'octicon-meter': octiconMeter,
'octicon-milestone': octiconMilestone, 'octicon-milestone': octiconMilestone,
@ -83,16 +109,20 @@ const svgs = {
'octicon-play': octiconPlay, 'octicon-play': octiconPlay,
'octicon-plus': octiconPlus, 'octicon-plus': octiconPlus,
'octicon-project': octiconProject, 'octicon-project': octiconProject,
'octicon-quote': octiconQuote,
'octicon-repo': octiconRepo, 'octicon-repo': octiconRepo,
'octicon-repo-forked': octiconRepoForked, 'octicon-repo-forked': octiconRepoForked,
'octicon-repo-template': octiconRepoTemplate, 'octicon-repo-template': octiconRepoTemplate,
'octicon-rss': octiconRss, 'octicon-rss': octiconRss,
'octicon-screen-full': octiconScreenFull,
'octicon-search': octiconSearch, 'octicon-search': octiconSearch,
'octicon-sidebar-collapse': octiconSidebarCollapse, 'octicon-sidebar-collapse': octiconSidebarCollapse,
'octicon-sidebar-expand': octiconSidebarExpand, 'octicon-sidebar-expand': octiconSidebarExpand,
'octicon-skip': octiconSkip, 'octicon-skip': octiconSkip,
'octicon-star': octiconStar, 'octicon-star': octiconStar,
'octicon-strikethrough': octiconStrikethrough,
'octicon-sync': octiconSync, 'octicon-sync': octiconSync,
'octicon-table': octiconTable,
'octicon-tag': octiconTag, 'octicon-tag': octiconTag,
'octicon-triangle-down': octiconTriangleDown, 'octicon-triangle-down': octiconTriangleDown,
'octicon-x': octiconX, 'octicon-x': octiconX,