Compare commits

..

No commits in common. "377a0a20f01a62f15a1504a3bba6cf6cc0c98bea" and "3ae997614ad4125d0ef40a528157dba01522c8e0" have entirely different histories.

98 changed files with 1566 additions and 1303 deletions

View File

@ -1,3 +1,749 @@
---
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
@ -21,6 +767,13 @@ 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: {}
@ -149,6 +902,13 @@ 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: {}
@ -253,12 +1013,22 @@ 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/**"
@ -323,9 +1093,19 @@ 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/**"
@ -388,9 +1168,19 @@ 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
@ -451,9 +1241,19 @@ 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
@ -515,12 +1315,22 @@ 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/**"
@ -585,9 +1395,19 @@ 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/**"
@ -650,9 +1470,19 @@ 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/**"
@ -716,9 +1546,19 @@ 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
@ -807,6 +1647,9 @@ steps:
trigger: trigger:
ref: ref:
- "refs/tags/**" - "refs/tags/**"
event:
exclude:
- cron
paths: paths:
exclude: exclude:
- "docs/**" - "docs/**"
@ -854,6 +1697,9 @@ 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

View File

@ -1,133 +0,0 @@
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: "Pull: Compliance testing for documentation" name: Compliance testing for documentation
on: on:
pull_request: pull_request:

View File

@ -1,260 +0,0 @@
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: "Pull: Docker Dry Run" name: Docker build dry run
on: [pull_request] on: [pull_request]

View File

@ -1,28 +0,0 @@
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: "Docs: Publish" name: Publish documentation
on: on:
push: push:

View File

@ -4,19 +4,6 @@ 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,7 +42,8 @@ func runGenerateActionsRunnerToken(c *cli.Context) error {
ctx, cancel := installSignals() ctx, cancel := installSignals()
defer cancel() defer cancel()
setting.Init(&setting.Options{}) setting.InitProviderFromExistingFile()
setting.LoadCommonSettings()
scope := c.String("scope") scope := c.String("scope")

View File

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

View File

@ -87,7 +87,8 @@ 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.Init(&setting.Options{}) setting.InitProviderFromExistingFile()
setting.LoadCommonSettings()
setting.LoadDBSetting() setting.LoadDBSetting()
setting.Log.EnableXORMLog = ctx.Bool("debug") setting.Log.EnableXORMLog = ctx.Bool("debug")

View File

@ -185,7 +185,8 @@ func runDump(ctx *cli.Context) error {
} }
fileName += "." + outType fileName += "." + outType
} }
setting.Init(&setting.Options{}) setting.InitProviderFromExistingFile()
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,9 +106,8 @@ func initEmbeddedExtractor(c *cli.Context) error {
log.DelNamedLogger(log.DEFAULT) log.DelNamedLogger(log.DEFAULT)
// Read configuration file // Read configuration file
setting.Init(&setting.Options{ setting.InitProviderAllowEmpty()
AllowEmpty: true, setting.LoadCommonSettings()
})
patterns, err := compileCollectPatterns(c.Args()) patterns, err := compileCollectPatterns(c.Args())
if err != nil { if err != nil {

View File

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

View File

@ -7,8 +7,14 @@ 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,7 +51,8 @@ func runRestoreRepository(c *cli.Context) error {
ctx, cancel := installSignals() ctx, cancel := installSignals()
defer cancel() defer cancel()
setting.Init(&setting.Options{}) setting.InitProviderFromExistingFile()
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,7 +62,8 @@ 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.Init(&setting.Options{}) setting.InitProviderFromExistingFile()
setting.LoadCommonSettings()
if debug { if debug {
setting.RunMode = "dev" setting.RunMode = "dev"
} }

View File

@ -177,7 +177,8 @@ func runWeb(ctx *cli.Context) error {
log.Info("Global init") log.Info("Global init")
// Perform global initialization // Perform global initialization
setting.Init(&setting.Options{}) setting.InitProviderFromExistingFile()
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,8 +8,14 @@ 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,8 +8,14 @@ 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,6 +9,7 @@ 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"
@ -17,6 +18,11 @@ 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,12 +11,18 @@ 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("", "", "")
unittest.InitSettings() setting.InitProviderAndLoadCommonSettingsForTest()
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,15 +6,12 @@ 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"
@ -42,22 +39,6 @@ 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
@ -69,9 +50,6 @@ 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,7 +12,6 @@ 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"
@ -41,14 +40,15 @@ type HookResponse struct {
// HookTask represents a hook task. // HookTask represents a hook task.
type HookTask struct { type HookTask struct {
ID int64 `xorm:"pk autoincr"` ID int64 `xorm:"pk autoincr"`
HookID int64 `xorm:"index"` HookID int64 `xorm:"index"`
UUID string `xorm:"unique"` UUID string `xorm:"unique"`
api.Payloader `xorm:"-"` api.Payloader `xorm:"-"`
PayloadContent string `xorm:"LONGTEXT"` PayloadContent string `xorm:"LONGTEXT"`
EventType webhook_module.HookEventType EventType webhook_module.HookEventType
IsDelivered bool IsDelivered bool
Delivered timeutil.TimeStampNano Delivered int64
DeliveredString string `xorm:"-"`
// History info. // History info.
IsSucceed bool IsSucceed bool
@ -75,6 +75,8 @@ 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
} }
@ -113,17 +115,12 @@ 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) {
data, err := t.Payloader.JSONPayload()
if err != nil {
return nil, err
}
t.UUID = gouuid.New().String() t.UUID = gouuid.New().String()
if t.Payloader != nil { t.PayloadContent = string(data)
data, err := t.Payloader.JSONPayload()
if err != nil {
return nil, err
}
t.PayloadContent = string(data)
}
if t.Delivered == 0 {
t.Delivered = timeutil.TimeStampNanoNow()
}
return t, db.Insert(ctx, t) return t, db.Insert(ctx, t)
} }
@ -164,11 +161,13 @@ func ReplayHookTask(ctx context.Context, hookID int64, uuid string) (*HookTask,
} }
} }
return CreateHookTask(ctx, &HookTask{ newTask := &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,7 +12,6 @@ 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"
@ -223,6 +222,7 @@ 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: timeutil.TimeStampNanoNow(), Delivered: time.Now().UnixNano(),
} }
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: timeutil.TimeStampNanoNow(), Delivered: time.Now().UnixNano(),
} }
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: timeutil.TimeStampNano(time.Now().AddDate(0, 0, -8).UnixNano()), Delivered: 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: timeutil.TimeStampNano(time.Now().AddDate(0, 0, -6).UnixNano()), Delivered: 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,7 +44,8 @@ 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.Init(&setting.Options{}) setting.InitProviderFromExistingFile()
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,7 +66,8 @@ func checkConfigurationFiles(ctx context.Context, logger log.Logger, autofix boo
return err return err
} }
setting.Init(&setting.Options{}) setting.InitProviderFromExistingFile()
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,9 +28,8 @@ var localMetas = map[string]string{
} }
func TestMain(m *testing.M) { func TestMain(m *testing.M) {
setting.Init(&setting.Options{ setting.InitProviderAllowEmpty()
AllowEmpty: true, setting.LoadCommonSettings()
})
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,9 +33,8 @@ var localMetas = map[string]string{
} }
func TestMain(m *testing.M) { func TestMain(m *testing.M) {
setting.Init(&setting.Options{ setting.InitProviderAllowEmpty()
AllowEmpty: true, setting.LoadCommonSettings()
})
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,7 +16,10 @@ import (
) )
func TestPersistableChannelUniqueQueue(t *testing.T) { func TestPersistableChannelUniqueQueue(t *testing.T) {
// Create a temporary directory for the queue if os.Getenv("CI") != "" {
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}`)
@ -97,7 +100,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 int64) { fillQueue := func(name string, done chan struct{}) {
t.Run("Initial Filling: "+name, func(t *testing.T) { t.Run("Initial Filling: "+name, func(t *testing.T) {
lock := sync.Mutex{} lock := sync.Mutex{}
@ -154,39 +157,33 @@ 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)
} }
hasQueueAChan := make(chan int64) doneA := make(chan struct{})
hasQueueBChan := make(chan int64) doneB := make(chan struct{})
go fillQueue("QueueA", hasQueueAChan) go fillQueue("QueueA", doneA)
go fillQueue("QueueB", hasQueueBChan) go fillQueue("QueueB", doneB)
hasA := <-hasQueueAChan <-doneA
hasB := <-hasQueueBChan <-doneB
executedEmpty := map[string][]string{} executedEmpty := map[string][]string{}
hasEmpty := map[string][]string{} hasEmpty := map[string][]string{}
emptyQueue := func(name string, numInQueue int64, done chan struct{}) { emptyQueue := func(name string, 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()
count := atomic.AddInt64(&atomicCount, 1) if datum.(string) == "final" {
if count >= numInQueue {
close(stop) close(stop)
} }
} }
@ -220,11 +217,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", hasA, doneA) go emptyQueue("QueueA", doneA)
go emptyQueue("QueueB", hasB, doneB) go emptyQueue("QueueB", doneB)
<-doneA <-doneA
<-doneB <-doneB
@ -240,20 +237,20 @@ func TestPersistableChannelUniqueQueue(t *testing.T) {
hasEmpty = map[string][]string{} hasEmpty = map[string][]string{}
mapLock.Unlock() mapLock.Unlock()
hasQueueAChan = make(chan int64) doneA = make(chan struct{})
hasQueueBChan = make(chan int64) doneB = make(chan struct{})
go fillQueue("QueueA", hasQueueAChan) go fillQueue("QueueA", doneA)
go fillQueue("QueueB", hasQueueBChan) go fillQueue("QueueB", doneB)
hasA = <-hasQueueAChan <-doneA
hasB = <-hasQueueBChan <-doneB
doneA = make(chan struct{}) doneA = make(chan struct{})
doneB = make(chan struct{}) doneB = make(chan struct{})
go emptyQueue("QueueA", hasA, doneA) go emptyQueue("QueueA", doneA)
go emptyQueue("QueueB", hasB, doneB) go emptyQueue("QueueB", doneB)
<-doneA <-doneA
<-doneB <-doneB

View File

@ -35,9 +35,10 @@ type ConfigProvider interface {
} }
type iniFileConfigProvider struct { type iniFileConfigProvider struct {
opts *Options
*ini.File *ini.File
newFile bool // whether the file has not existed previously filepath string // the ini file path
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
@ -65,47 +66,41 @@ 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(opts *Options) (*iniFileConfigProvider, error) { func newConfigProviderFromFile(customConf string, allowEmpty bool, extraConfig string) (*iniFileConfigProvider, error) {
cfg := ini.Empty() cfg := ini.Empty()
newFile := true newFile := true
if opts.CustomConf != "" { if customConf != "" {
isFile, err := util.IsFile(opts.CustomConf) isFile, err := util.IsFile(customConf)
if err != nil { if err != nil {
return nil, fmt.Errorf("unable to check if %s is a file. Error: %v", opts.CustomConf, err) return nil, fmt.Errorf("unable to check if %s is a file. Error: %v", customConf, err)
} }
if isFile { if isFile {
if err := cfg.Append(opts.CustomConf); err != nil { if err := cfg.Append(customConf); err != nil {
return nil, fmt.Errorf("failed to load custom conf '%s': %v", opts.CustomConf, err) return nil, fmt.Errorf("failed to load custom conf '%s': %v", customConf, err)
} }
newFile = false newFile = false
} }
} }
if newFile && !opts.AllowEmpty { if newFile && !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 opts.ExtraConfig != "" { if extraConfig != "" {
if err := cfg.Append([]byte(opts.ExtraConfig)); err != nil { if err := cfg.Append([]byte(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
} }
@ -128,8 +123,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.opts.CustomConf == "" { if p.filepath == "" {
if !p.opts.AllowEmpty { if !p.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
@ -140,8 +135,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.opts.CustomConf); err != nil { if err := p.SaveTo(p.filepath); err != nil {
return fmt.Errorf("failed to save '%s': %v", p.opts.CustomConf, err) return fmt.Errorf("failed to save '%s': %v", p.filepath, err)
} }
// Change permissions to be more restrictive // Change permissions to be more restrictive

View File

@ -15,6 +15,7 @@ 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"
) )
@ -202,20 +203,46 @@ func PrepareAppDataPath() error {
return nil return nil
} }
func Init(opts *Options) { // InitProviderFromExistingFile initializes config provider from an existing config file (app.ini)
if opts.CustomConf == "" { func InitProviderFromExistingFile() {
opts.CustomConf = CustomConf
}
var err error var err error
CfgProvider, err = newConfigProviderFromFile(opts) CfgProvider, err = newConfigProviderFromFile(CustomConf, false, "")
if err != nil { if err != nil {
log.Fatal("Init[%v]: %v", opts, err) log.Fatal("InitProviderFromExistingFile: %v", err)
} }
if !opts.DisableLoadCommonSettings { }
loadCommonSettingsFrom(CfgProvider)
// 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)
}
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.
func loadCommonSettingsFrom(cfg ConfigProvider) { func loadCommonSettingsFrom(cfg ConfigProvider) {
// WARNNING: don't change the sequence except you know what you are doing. // WARNNING: don't change the sequence except you know what you are doing.

View File

@ -1,28 +0,0 @@
// 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.comment_pull_merged_at = merged commit %[1]s into %[2]s %[3]s 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_manually_pull_merged_at = manually 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.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,7 +2559,6 @@ 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,12 +119,6 @@ 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,7 +4,6 @@
package cargo package cargo
import ( import (
"errors"
"fmt" "fmt"
"net/http" "net/http"
"strconv" "strconv"
@ -46,35 +45,6 @@ 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,11 +13,10 @@ 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: func() error { SetUp: webhook_service.Init,
setting.LoadQueueSettings()
return webhook_service.Init()
},
}) })
} }

View File

@ -15,9 +15,8 @@ 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.Init(&setting.Options{ setting.InitProviderAllowEmpty()
AllowEmpty: true, setting.LoadCommonSettings()
})
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)
@ -39,7 +38,8 @@ 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.Init(&setting.Options{}) setting.InitProviderFromExistingFile()
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,7 +552,6 @@ 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)
} }
@ -569,13 +568,6 @@ 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,22 +80,19 @@ 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) ctx := test.MockContext(t, "user/settings/security")
setting.PasswordComplexity = req.PasswordComplexity test.LoadUser(t, ctx, 2)
ctx := test.MockContext(t, "user/settings/security") test.LoadRepo(t, ctx, 1)
test.LoadUser(t, ctx, 2)
test.LoadRepo(t, ctx, 1)
web.SetForm(ctx, &forms.ChangePasswordForm{ web.SetForm(ctx, &forms.ChangePasswordForm{
OldPassword: req.OldPassword, OldPassword: req.OldPassword,
Password: req.NewPassword, Password: req.NewPassword,
Retype: req.Retype, Retype: req.Retype,
})
AccountPost(ctx)
assert.Contains(t, ctx.Flash.ErrorMsg, req.Message)
assert.EqualValues(t, http.StatusSeeOther, ctx.Resp.Status())
}) })
AccountPost(ctx)
assert.Contains(t, ctx.Flash.ErrorMsg, req.Message)
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 BuildPackageIndex(ctx context.Context, p *packages_model.Package) (*bytes.Buffer, error) { func addOrUpdatePackageIndex(ctx context.Context, t *files_service.TemporaryUploadRepository, p *packages_model.Package) 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 nil, fmt.Errorf("SearchVersions[%s]: %w", p.Name, err) return fmt.Errorf("SearchVersions[%s]: %w", p.Name, err)
} }
if len(pvs) == 0 { if len(pvs) == 0 {
return nil, nil return nil
} }
pds, err := packages_model.GetPackageDescriptors(ctx, pvs) pds, err := packages_model.GetPackageDescriptors(ctx, pvs)
if err != nil { if err != nil {
return nil, fmt.Errorf("GetPackageDescriptors[%s]: %w", p.Name, err) return fmt.Errorf("GetPackageDescriptors[%s]: %w", p.Name, err)
} }
var b bytes.Buffer var b bytes.Buffer
@ -179,26 +179,14 @@ func BuildPackageIndex(ctx context.Context, p *packages_model.Package) (*bytes.B
Links: metadata.Links, Links: metadata.Links,
}) })
if err != nil { if err != nil {
return nil, err return err
} }
b.Write(entry) b.Write(entry)
b.WriteString("\n") b.WriteString("\n")
} }
return &b, nil return writeObjectToIndex(t, BuildPackagePath(pds[0].Package.LowerName), &b)
}
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) {
@ -224,13 +212,6 @@ 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,
@ -239,7 +220,10 @@ 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(BuildConfig(owner)) err := json.NewEncoder(&b).Encode(Config{
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,7 +25,6 @@ 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"
@ -176,7 +175,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 = timeutil.TimeStampNanoNow() t.Delivered = time.Now().UnixNano()
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: func() error { SetUp: Init,
setting.LoadQueueSettings()
return Init()
},
}) })
} }

View File

@ -1,20 +1,20 @@
{{if .Flash.ErrorMsg}} {{if .Flash.ErrorMsg}}
<div class="ui negative message flash-message flash-error"> <div class="ui negative 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-message flash-success"> <div class="ui positive 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-message flash-info"> <div class="ui info 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-message flash-warning"> <div class="ui warning 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 gt-df"> <div class="ui four wide column" style="display: flex;">
<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,23 +6,17 @@
<div class="image"> <div class="image">
{{avatar $.Context .Organization 140}} {{avatar $.Context .Organization 140}}
</div> </div>
{{if .EmailMismatch}} <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.email_mismatch"}}</div> <div class="meta">{{.locale.Tr "org.teams.invite.by" .Inviter.Name}}</div>
</div> <div class="description">{{.locale.Tr "org.teams.invite.description"}}</div>
{{else}} </div>
<div class="content"> <div class="extra content">
<div class="header">{{.locale.Tr "org.teams.invite.title" .Team.Name .Organization.Name | Str2html}}</div> <form class="ui form" action="" method="post">
<div class="meta">{{.locale.Tr "org.teams.invite.by" .Inviter.Name}}</div> {{.CsrfTokenHtml}}
<div class="description">{{.locale.Tr "org.teams.invite.description"}}</div> <button class="fluid ui green button">{{.locale.Tr "org.teams.join"}}</button>
</div> </form>
<div class="extra content"> </div>
<form class="ui form" action="" method="post">
{{.CsrfTokenHtml}}
<button class="fluid ui green button">{{.locale.Tr "org.teams.join"}}</button>
</form>
</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"> <table class="ui very basic compact table container-labels">
<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 class="top aligned">{{$key}}</td> <td>{{$key}}</td>
<td class="gt-word-break">{{$value}}</td> <td>{{$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 gt-word-break"> <div class="ui warning message text left 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-menu-items ui compact tiny menu"> <div class="small-pill-buttons 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-menu-items ui compact tiny menu"> <div class="small-pill-buttons 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,8 +1,3 @@
{{/* 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}}
@ -67,10 +62,10 @@
window.config.pageData.branchDropdownDataList.push(data); window.config.pageData.branchDropdownDataList.push(data);
</script> </script>
<div class="js-branch-tag-selector {{if .ContainerClasses}}{{.ContainerClasses}}{{end}}"> <div class="fitted item js-branch-tag-selector">
{{/* 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 gt-m-0"> <button class="branch-dropdown-button gt-ellipsis ui basic small compact button gt-df">
<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" . "ContainerClasses" "gt-mr-2"}} {{template "repo/branch_dropdown" dict "root" .}}
<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" . "ContainerClasses" "gt-mr-2"}} {{template "repo/branch_dropdown" dict "root" .}}
{{$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 gt-mb-4"> <div class="navbar">
{{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,6 +10,7 @@
</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,6 +17,9 @@
{{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 gt-mb-4"> <div class="navbar">
{{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,10 +10,11 @@
</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-menu-items ui compact tiny menu"> <div class="small-pill-buttons 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-menu-items"> <h2 class="ui compact small menu header small-pill-buttons">
<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,6 +2,10 @@
<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-menu-items ui compact tiny menu"> <div class="small-pill-buttons 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,11 +2,32 @@
<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">
{{template "repo/issue/view_title" .}} <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}} {{if .Issue.IsPull}}
{{template "repo/issue/view_title" .}}
{{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,4 +1,13 @@
<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.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}} {{$.locale.Tr "repo.issues.manually_pull_merged_at" ($link|Escape) (ShortSha $.Issue.PullRequest.MergedCommitID) ($.BaseTarget|Escape) $createdStr | Safe}}
{{else}} {{else}}
{{$.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}} {{$.locale.Tr "repo.issues.pull_merged_at" ($link|Escape) (ShortSha $.Issue.PullRequest.MergedCommitID) ($.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"> <div class="ui warning message text left">
{{$.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,9 +108,6 @@
</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
@ -134,21 +131,19 @@
{{$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"> <div class="merge-section-info">
{{$.locale.Tr "repo.pulls.merged_success"}} {{$.locale.Tr "repo.pulls.merged_info_text" (printf "<code>%s</code>" (.HeadTarget | Escape)) | Str2html}}
</h3>
<div class="merge-section-info">
{{$.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>
</div> {{end}}
{{end}} </div>
{{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">
@ -490,4 +485,3 @@
</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"> <div class="ui warning message text left">
{{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,119 +1,107 @@
{{if .Flash}} <div class="sixteen wide column title">
<div class="sixteen wide column gt-mb-3">
{{template "base/alert" .}}
</div>
{{end}}
<div class="issue-title-header">
<div class="issue-title" id="issue-title-wrapper"> <div class="issue-title" id="issue-title-wrapper">
<h1 class="gt-word-break"> {{if and (or .HasIssuesOrPullsWritePermission .IsIssuePoster) (not .Repository.IsArchived)}}
<span id="issue-title">{{RenderIssueTitle $.Context .Issue.Title $.RepoLink $.Repository.ComposeMetas | RenderCodeBlock}} <span class="index">#{{.Issue.Index}}</span> <button id="edit-title" class="ui basic button secondary edit-button not-in-edit">{{.locale.Tr "repo.issues.edit"}}</button>
</span> {{end}}
<div id="edit-title-input" class="ui input gt-f1 gt-hidden"> <h1>
<span id="issue-title">{{RenderIssueTitle $.Context .Issue.Title $.RepoLink $.Repository.ComposeMetas | RenderCodeBlock}}</span>
<span class="index">#{{.Issue.Index}}</span>
<div id="edit-title-input" class="ui input gt-ml-4 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 small basic button secondary in-edit gt-hidden">{{.locale.Tr "repo.issues.cancel"}}</button> <button id="cancel-edit-title" class="ui basic button secondary in-edit gt-hidden">{{.locale.Tr "repo.issues.cancel"}}</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> <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>
</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}}
<div class="ui green large label">{{svg "octicon-git-pull-request"}} {{.locale.Tr "repo.issues.open_title"}}</div>
{{end}}
{{else}}
<div class="ui green large label">{{svg "octicon-issue-opened"}} {{.locale.Tr "repo.issues.open_title"}}</div>
{{end}}
{{if .Issue.IsPull}}
{{$headHref := .HeadTarget|Escape}}
{{if .HeadBranchLink}}
{{$headHref = printf "<a href=\"%s\">%s</a>" (.HeadBranchLink | Escape) $headHref}}
{{end}}
{{$headHref = printf "%s <a data-tooltip-content=\"%s\" data-clipboard-text=\"%s\">%s</a>" $headHref (.locale.Tr "copy_branch") (.HeadTarget | Escape) (svg "octicon-copy" 14)}}
{{$baseHref := .BaseTarget|Escape}}
{{if .BaseBranchLink}}
{{$baseHref = printf "<a href=\"%s\">%s</a>" (.BaseBranchLink | Escape) $baseHref}}
{{end}}
{{if .Issue.PullRequest.HasMerged}}
{{$mergedStr:= TimeSinceUnix .Issue.PullRequest.MergedUnix $.locale}}
{{if .Issue.OriginalAuthor}}
{{.Issue.OriginalAuthor}}
<span class="pull-desc">{{$.locale.Tr "repo.pulls.merged_title_desc" .NumCommits $headHref $baseHref $mergedStr | Safe}}</span>
{{else}} {{else}}
<div class="ui green label issue-state-label">{{svg "octicon-git-pull-request"}} {{.locale.Tr "repo.issues.open_title"}}</div> <a {{if gt .Issue.PullRequest.Merger.ID 0}}href="{{.Issue.PullRequest.Merger.HomeLink}}"{{end}}>{{.Issue.PullRequest.Merger.GetDisplayName}}</a>
<span class="pull-desc">{{$.locale.Tr "repo.pulls.merged_title_desc" .NumCommits $headHref $baseHref $mergedStr | Safe}}</span>
{{end}} {{end}}
{{else}} {{else}}
<div class="ui green label issue-state-label">{{svg "octicon-issue-opened"}} {{.locale.Tr "repo.issues.open_title"}}</div> {{if .Issue.OriginalAuthor}}
{{end}} <span id="pull-desc" class="pull-desc">{{.Issue.OriginalAuthor}} {{$.locale.Tr "repo.pulls.title_desc" .NumCommits $headHref $baseHref | Safe}}</span>
<div class="gt-ml-3">
{{if .Issue.IsPull}}
{{$headHref := .HeadTarget|Escape}}
{{if .HeadBranchLink}}
{{$headHref = printf "<a href=\"%s\">%s</a>" (.HeadBranchLink | Escape) $headHref}}
{{end}}
{{$headHref = printf "%s <a data-tooltip-content=\"%s\" data-clipboard-text=\"%s\">%s</a>" $headHref (.locale.Tr "copy_branch") (.HeadTarget | Escape) (svg "octicon-copy" 14)}}
{{$baseHref := .BaseTarget|Escape}}
{{if .BaseBranchLink}}
{{$baseHref = printf "<a href=\"%s\">%s</a>" (.BaseBranchLink | Escape) $baseHref}}
{{end}}
{{if .Issue.PullRequest.HasMerged}}
{{$mergedStr:= TimeSinceUnix .Issue.PullRequest.MergedUnix $.locale}}
{{if .Issue.OriginalAuthor}}
{{.Issue.OriginalAuthor}}
<span class="pull-desc">{{$.locale.Tr "repo.pulls.merged_title_desc" .NumCommits $headHref $baseHref $mergedStr | Safe}}</span>
{{else}}
<a {{if gt .Issue.PullRequest.Merger.ID 0}}href="{{.Issue.PullRequest.Merger.HomeLink}}"{{end}}>{{.Issue.PullRequest.Merger.GetDisplayName}}</a>
<span class="pull-desc">{{$.locale.Tr "repo.pulls.merged_title_desc" .NumCommits $headHref $baseHref $mergedStr | Safe}}</span>
{{end}}
{{else}}
{{if .Issue.OriginalAuthor}}
<span id="pull-desc" class="pull-desc">{{.Issue.OriginalAuthor}} {{$.locale.Tr "repo.pulls.title_desc" .NumCommits $headHref $baseHref | Safe}}</span>
{{else}}
<span id="pull-desc" class="pull-desc">
<a {{if gt .Issue.Poster.ID 0}}href="{{.Issue.Poster.HomeLink}}"{{end}}>{{.Issue.Poster.GetDisplayName}}</a>
{{$.locale.Tr "repo.pulls.title_desc" .NumCommits $headHref $baseHref | Safe}}
</span>
{{end}}
<span id="pull-desc-edit" class="gt-hidden">
<div class="ui floating filter dropdown">
<div class="ui basic small button">
<span class="text">{{.locale.Tr "repo.pulls.compare_compare"}}: {{$.HeadTarget}}</span>
</div>
</div>
{{svg "octicon-arrow-right"}}
<div class="ui floating filter dropdown" data-no-results="{{.locale.Tr "repo.pulls.no_results"}}">
<div class="ui basic small button">
<span class="text" id="pull-target-branch" data-basename="{{$.BaseName}}" data-branch="{{$.BaseBranch}}">{{.locale.Tr "repo.pulls.compare_base"}}: {{$.BaseName}}:{{$.BaseBranch}}</span>
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
</div>
<div class="menu">
<div class="ui icon search input">
<i class="icon gt-df gt-ac gt-jc gt-m-0">{{svg "octicon-filter" 16}}</i>
<input name="search" placeholder="{{.locale.Tr "repo.pulls.filter_branch"}}...">
</div>
<div class="scrolling menu" id="branch-select">
{{range .Branches}}
{{$sameBase := ne $.BaseName $.HeadUserName}}
{{$differentBranch := ne . $.HeadBranch}}
{{if or $sameBase $differentBranch}}
<div class="item {{if eq $.BaseBranch .}}selected{{end}}" data-branch="{{.}}">{{$.BaseName}}{{if $.HeadRepo}}/{{$.HeadRepo}}{{end}}:{{.}}</div>
{{end}}
{{end}}
</div>
</div>
</div>
</span>
{{end}}
{{else}} {{else}}
{{$createdStr:= TimeSinceUnix .Issue.CreatedUnix $.locale}} <span id="pull-desc" class="pull-desc">
<span class="time-desc"> <a {{if gt .Issue.Poster.ID 0}}href="{{.Issue.Poster.HomeLink}}"{{end}}>{{.Issue.Poster.GetDisplayName}}</a>
{{if .Issue.OriginalAuthor}} {{$.locale.Tr "repo.pulls.title_desc" .NumCommits $headHref $baseHref | Safe}}
{{$.locale.Tr "repo.issues.opened_by_fake" $createdStr (.Issue.OriginalAuthor|Escape) | Safe}}
{{else if gt .Issue.Poster.ID 0}}
{{$.locale.Tr "repo.issues.opened_by" $createdStr (.Issue.Poster.HomeLink|Escape) (.Issue.Poster.GetDisplayName|Escape) | Safe}}
{{else}}
{{$.locale.Tr "repo.issues.opened_by_fake" $createdStr (.Issue.Poster.GetDisplayName|Escape) | Safe}}
{{end}}
·
{{$.locale.Tr "repo.issues.num_comments" .Issue.NumComments}}
</span> </span>
{{end}} {{end}}
</div> <span id="pull-desc-edit" class="gt-hidden">
</div> <div class="ui floating filter dropdown">
<div class="ui basic small button">
<span class="text">{{.locale.Tr "repo.pulls.compare_compare"}}: {{$.HeadTarget}}</span>
</div>
</div>
{{svg "octicon-arrow-right"}}
<div class="ui floating filter dropdown" data-no-results="{{.locale.Tr "repo.pulls.no_results"}}">
<div class="ui basic small button">
<span class="text" id="pull-target-branch" data-basename="{{$.BaseName}}" data-branch="{{$.BaseBranch}}">{{.locale.Tr "repo.pulls.compare_base"}}: {{$.BaseName}}:{{$.BaseBranch}}</span>
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
</div>
<div class="menu">
<div class="ui icon search input">
<i class="icon gt-df gt-ac gt-jc gt-m-0">{{svg "octicon-filter" 16}}</i>
<input name="search" placeholder="{{.locale.Tr "repo.pulls.filter_branch"}}...">
</div>
<div class="scrolling menu" id="branch-select">
{{range .Branches}}
{{$sameBase := ne $.BaseName $.HeadUserName}}
{{$differentBranch := ne . $.HeadBranch}}
{{if or $sameBase $differentBranch}}
<div class="item {{if eq $.BaseBranch .}}selected{{end}}" data-branch="{{.}}">{{$.BaseName}}{{if $.HeadRepo}}/{{$.HeadRepo}}{{end}}:{{.}}</div>
{{end}}
{{end}}
</div>
</div>
</div>
</span>
{{end}}
{{else}}
{{$createdStr:= TimeSinceUnix .Issue.CreatedUnix $.locale}}
<span class="time-desc">
{{if .Issue.OriginalAuthor}}
{{$.locale.Tr "repo.issues.opened_by_fake" $createdStr (.Issue.OriginalAuthor|Escape) | Safe}}
{{else if gt .Issue.Poster.ID 0}}
{{$.locale.Tr "repo.issues.opened_by" $createdStr (.Issue.Poster.HomeLink|Escape) (.Issue.Poster.GetDisplayName|Escape) | Safe}}
{{else}}
{{$.locale.Tr "repo.issues.opened_by_fake" $createdStr (.Issue.Poster.GetDisplayName|Escape) | Safe}}
{{end}}
·
{{$.locale.Tr "repo.issues.num_comments" .Issue.NumComments}}
</span>
{{end}}
<div class="ui divider"></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"> <div class="ui warning message text left">
{{.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,39 +2,41 @@
<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 gt-mb-4"> <div class="navbar">
<div> {{template "repo/issue/navbar" .}}
<div class="small-menu-items ui compact tiny menu"> {{if and .CanWriteProjects (not .Repository.IsArchived)}}
<a class="item{{if not .IsShowClosed}} active{{end}}" href="{{.RepoLink}}/projects?state=open"> <div class="ui right">
{{svg "octicon-project" 16 "gt-mr-3"}} <a class="ui small green button" href="{{$.Link}}/new">{{.locale.Tr "repo.projects.new"}}</a>
{{.locale.PrettyNumber .OpenCount}}&nbsp;{{.locale.Tr "repo.issues.open_title"}}
</a>
<a class="item{{if .IsShowClosed}} active{{end}}" href="{{.RepoLink}}/projects?state=closed">
{{svg "octicon-check" 16 "gt-mr-3"}}
{{.locale.PrettyNumber .ClosedCount}}&nbsp;{{.locale.Tr "repo.issues.closed_title"}}
</a>
</div> </div>
</div> {{end}}
<div> </div>
<!-- Sort --> <div class="ui divider"></div>
<div class="ui small dropdown type jump item"> {{template "base/alert" .}}
<span class="text"> <div class="small-pill-buttons ui compact tiny menu">
{{.locale.Tr "repo.issues.filter_sort"}} <a class="item{{if not .IsShowClosed}} active{{end}}" href="{{.RepoLink}}/projects?state=open">
{{svg "octicon-triangle-down" 14 "dropdown icon"}} {{svg "octicon-project" 16 "gt-mr-3"}}
</span> {{.locale.PrettyNumber .OpenCount}}&nbsp;{{.locale.Tr "repo.issues.open_title"}}
<div class="menu"> </a>
<a class="{{if eq .SortType "oldest"}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&sort=oldest&state={{$.State}}">{{.locale.Tr "repo.issues.filter_sort.oldest"}}</a> <a class="item{{if .IsShowClosed}} active{{end}}" href="{{.RepoLink}}/projects?state=closed">
<a class="{{if eq .SortType "recentupdate"}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&sort=recentupdate&state={{$.State}}">{{.locale.Tr "repo.issues.filter_sort.recentupdate"}}</a> {{svg "octicon-check" 16 "gt-mr-3"}}
<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> {{.locale.PrettyNumber .ClosedCount}}&nbsp;{{.locale.Tr "repo.issues.closed_title"}}
</div> </a>
</div>
<div class="ui right floated secondary filter menu">
<!-- Sort -->
<div class="ui dropdown type jump item">
<span class="text">
{{.locale.Tr "repo.issues.filter_sort"}}
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
</span>
<div class="menu">
<a class="{{if eq .SortType "oldest"}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&sort=oldest&state={{$.State}}">{{.locale.Tr "repo.issues.filter_sort.oldest"}}</a>
<a class="{{if eq .SortType "recentupdate"}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&sort=recentupdate&state={{$.State}}">{{.locale.Tr "repo.issues.filter_sort.recentupdate"}}</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>
{{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> </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,9 +2,18 @@
<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" .}}
{{template "repo/commits_table" .}} <div class="ui bottom attached tab pull active">
{{template "repo/commits_table" .}}
</div>
</div> </div>
</div> </div>
{{template "base/footer" .}} {{template "base/footer" .}}

View File

@ -5,10 +5,20 @@
<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"> <div class="ui container fluid padded">
<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 "repo/diff/box" .}} {{template "base/alert" .}}
<div class="ui bottom attached tab pull active">
{{template "repo/diff/box" .}}
</div>
</div> </div>
</div> </div>
{{template "base/footer" .}} {{template "base/footer" .}}

View File

@ -14,11 +14,13 @@
<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"> <div class="ui four wide column meta gt-mt-2">
<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> <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>
{{if .Sha1}} {{if .Sha1}}
<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> <span class="commit">
{{template "repo/branch_dropdown" dict "root" $ "release" . "ContainerClasses" "gt-mt-4"}} <a class="gt-mono muted" href="{{$.RepoLink}}/src/commit/{{.Sha1}}" rel="nofollow">{{svg "octicon-git-commit" 16 "gt-mr-2"}}{{ShortSha .Sha1}}</a>
</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 gt-dib"> <form method="post" style="display: inline-block">
{{.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 gt-dib"> <form method="post" style="display: inline-block">
{{$.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 gt-dib"> <form method="post" style="display: inline-block">
{{$.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"> <div class="ui warning message text left">
{{.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"> <div class="ui warning message text left">
{{.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"> <div class="ui warning message text left">
{{.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"> <div class="ui warning message text left">
{{.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"> <div class="ui warning message text left">
{{.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">
{{TimeSince .Delivered.AsTime $.locale}} {{.DeliveredString}}
</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-menu-items"> <h2 class="ui compact small menu header small-pill-buttons">
<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-menu-items ui compact tiny menu"> <div class="small-pill-buttons 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-menu-items ui compact tiny menu"> <div class="small-pill-buttons 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-menu-items ui compact tiny menu"> <div class="small-pill-buttons 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("Git/Config", func(t *testing.T) { t.Run("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,20 +110,6 @@ 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) {
@ -206,72 +192,40 @@ 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)()
content := readGitContent(t, cargo_service.BuildPackagePath(packageName)) content := readGitContent(t, cargo_service.BuildPackagePath(packageName))
var entry cargo_service.IndexVersionEntry var entry cargo_service.IndexVersionEntry
err := json.Unmarshal([]byte(content), &entry) err := json.Unmarshal([]byte(content), &entry)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, packageName, entry.Name) assert.Equal(t, packageName, entry.Name)
assert.Equal(t, packageVersion, entry.Version) assert.Equal(t, packageVersion, entry.Version)
assert.Equal(t, pb.HashSHA256, entry.FileChecksum) assert.Equal(t, pb.HashSHA256, entry.FileChecksum)
assert.False(t, entry.Yanked) assert.False(t, entry.Yanked)
assert.Len(t, entry.Dependencies, 1) assert.Len(t, entry.Dependencies, 1)
dep := entry.Dependencies[0] dep := entry.Dependencies[0]
assert.Equal(t, "dep", dep.Name) assert.Equal(t, "dep", dep.Name)
assert.Equal(t, "1.0", dep.Req) assert.Equal(t, "1.0", dep.Req)
assert.Equal(t, "normal", dep.Kind) assert.Equal(t, "normal", dep.Kind)
assert.True(t, dep.DefaultFeatures) assert.True(t, dep.DefaultFeatures)
assert.Empty(t, dep.Features) assert.Empty(t, dep.Features)
assert.False(t, dep.Optional) assert.False(t, dep.Optional)
assert.Nil(t, dep.Target) assert.Nil(t, dep.Target)
assert.NotNil(t, dep.Registry) assert.NotNil(t, dep.Registry)
assert.Equal(t, "https://gitea.io/user/_cargo-index", *dep.Registry) assert.Equal(t, "https://gitea.io/user/_cargo-index", *dep.Registry)
assert.Nil(t, dep.Package) assert.Nil(t, dep.Package)
})
t.Run("Rebuild", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
err := cargo_service.RebuildIndex(db.DefaultContext, user, user)
assert.NoError(t, err)
_ = readGitContent(t, cargo_service.BuildPackagePath(packageName))
})
}) })
t.Run("HTTP", func(t *testing.T) { t.Run("Rebuild", func(t *testing.T) {
t.Run("Entry", func(t *testing.T) { defer tests.PrintCurrentTest(t)()
defer tests.PrintCurrentTest(t)()
req := NewRequest(t, "GET", root+"/"+cargo_service.BuildPackagePath(packageName)) err := cargo_service.RebuildIndex(db.DefaultContext, user, user)
resp := MakeRequest(t, req, http.StatusOK) assert.NoError(t, err)
var entry cargo_service.IndexVersionEntry _ = readGitContent(t, cargo_service.BuildPackagePath(packageName))
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.Contains(t, val, title) assert.Equal(t, title, val)
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
} }
unittest.InitSettings() setting.InitProviderAndLoadCommonSettingsForTest()
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("", "", "")
unittest.InitSettings() setting.InitProviderAndLoadCommonSettingsForTest()
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.flash-message { .ui .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: 7px; left: 5px;
top: -9px; top: -8px;
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: 2.75px; padding: 2px;
border-radius: 1em; border-radius: 1em;
font-size: 11px; font-size: 10px;
font-weight: 700; font-weight: 700;
line-height: .67em; line-height: 0.7;
} }
table th[data-sortt-asc]:hover, table th[data-sortt-asc]:hover,

View File

@ -41,5 +41,6 @@
@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";

7
web_src/css/package.css Normal file
View File

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

View File

@ -591,83 +591,87 @@
display: inline-block; display: inline-block;
} }
.issue-title-header { .repository.view.issue .title {
width: 100%; padding-bottom: 0 !important;
padding-bottom: 4px;
margin-bottom: 1rem;
} }
.issue-title-meta { .repository.view.issue .title .issue-title {
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 .issue-title-buttons, .repository.view.issue .title .issue-title.edit-active h1 {
.repository.view.issue .edit-buttons {
display: flex; display: flex;
width: 100%;
} }
@media (max-width: 767px) { @media (max-width: 767px) {
.repository.view.issue .issue-title { .repository.view.issue .title .issue-title.edit-active {
flex-direction: column; flex-direction: column;
} }
.repository.view.issue .edit-buttons { .repository.view.issue .title .issue-title.edit-active h1 {
margin-top: .5rem; margin-right: 0;
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 .issue-title { .repository.view.issue .title .issue-title h1 {
display: flex;
align-items: center;
margin-bottom: 8px;
}
.repository.view.issue .issue-title h1 {
display: flex;
align-items: center;
flex: 1;
width: 100%;
font-weight: 300; font-weight: 300;
font-size: 32px; font-size: 2.3rem;
line-height: 40px;
margin: 0; margin: 0;
padding-right: 0.25rem; padding-right: 0.5rem;
min-height: 41px; /* avoid layout shift on edit */
} }
.repository.view.issue .issue-title h1 .ui.input { .repository.view.issue .title .issue-title h1 .ui.input {
font-size: 0.5em; font-size: 0.5em;
width: 100%;
} }
.repository.view.issue .issue-title h1 .ui.input input { .repository.view.issue .title .issue-title h1 .ui.input input {
font-size: 1.5em; font-size: 1.5em;
padding: 2px .5rem; padding: 6px 1rem;
} }
.repository.view.issue .issue-title .index { .repository.view.issue .title .issue-title .edit-button {
float: right;
padding-left: 1rem;
}
.repository.view.issue .title .issue-title .edit-buttons {
display: flex;
}
.repository.view.issue .title .issue-title .index {
color: var(--color-text-light-2); color: var(--color-text-light-2);
} }
.repository.view.issue .issue-title .label { .repository.view.issue .title .issue-title .label {
margin-right: 10px; margin-right: 10px;
} }
.repository.view.issue .issue-title .edit-zone { .repository.view.issue .title .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);
} }
@ -1189,15 +1193,13 @@
.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 {
@ -2598,6 +2600,39 @@
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,7 +3,6 @@
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-menu-items { .small-pill-buttons {
min-height: 35.4px !important; /* match .small.button in height */ min-height: 35.4px !important; /* match .small.button in height */
} }
.small-menu-items .item { .small-pill-buttons .item {
padding-top: 6px !important; padding-top: 6px !important;
padding-bottom: 6px !important; padding-bottom: 6px !important;
} }

View File

@ -1,6 +1,7 @@
.repository.releases #release-list { .repository.releases #release-list {
margin-top: 12px; border-top: 1px solid var(--color-secondary);
padding-top: 12px; margin-top: 20px;
padding-top: 15px;
padding-left: 0; padding-left: 0;
} }
@ -22,13 +23,29 @@
} }
.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: 1px solid var(--color-secondary); border-left: 2px solid var(--color-secondary);
} }
.repository.releases #release-list > li .detail .author img { .repository.releases #release-list > li .detail .author img {
@ -75,7 +92,7 @@
z-index: 9; z-index: 9;
position: absolute; position: absolute;
display: block; display: block;
left: -5.5px; left: -6px;
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: #525767; --color-secondary: #454a57;
--color-secondary-dark-1: #5c6374; --color-secondary-dark-1: #505665;
--color-secondary-dark-2: #666e81; --color-secondary-dark-2: #5b6273;
--color-secondary-dark-3: #7c8497; --color-secondary-dark-3: #71798e;
--color-secondary-dark-4: #8990a1; --color-secondary-dark-4: #7f8699;
--color-secondary-dark-5: #959cab; --color-secondary-dark-5: #8c93a4;
--color-secondary-dark-6: #a2a8b5; --color-secondary-dark-6: #9aa0af;
--color-secondary-dark-7: #afb4c0; --color-secondary-dark-7: #a8adba;
--color-secondary-dark-8: #bcc0ca; --color-secondary-dark-8: #b6bac5;
--color-secondary-dark-9: #c9cbd4; --color-secondary-dark-9: #c4c7d0;
--color-secondary-dark-10: #d6d7de; --color-secondary-dark-10: #d2d4db;
--color-secondary-dark-11: #e2e3e8; --color-secondary-dark-11: #dfe1e6;
--color-secondary-dark-12: #eeeff2; --color-secondary-dark-12: #edeef1;
--color-secondary-dark-13: #fbfbfc; --color-secondary-dark-13: #fbfbfc;
--color-secondary-light-1: #454a57; --color-secondary-light-1: #373b46;
--color-secondary-light-2: #383c47; --color-secondary-light-2: #292c34;
--color-secondary-light-3: #2c2f37; --color-secondary-light-3: #1c1e23;
--color-secondary-light-4: #1f2226; --color-secondary-light-4: #0e0f11;
--color-secondary-alpha-10: #52576719; --color-secondary-alpha-10: #454a5719;
--color-secondary-alpha-20: #52576733; --color-secondary-alpha-20: #454a5733;
--color-secondary-alpha-30: #5257674b; --color-secondary-alpha-30: #454a574b;
--color-secondary-alpha-40: #52576766; --color-secondary-alpha-40: #454a5766;
--color-secondary-alpha-50: #52576780; --color-secondary-alpha-50: #454a5780;
--color-secondary-alpha-60: #52576799; --color-secondary-alpha-60: #454a5799;
--color-secondary-alpha-70: #525767b3; --color-secondary-alpha-70: #454a57b3;
--color-secondary-alpha-80: #525767cc; --color-secondary-alpha-80: #454a57cc;
--color-secondary-alpha-90: #525767e1; --color-secondary-alpha-90: #454a57e1;
/* 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 gt-m-0" @click="menuVisible = !menuVisible" @keyup.enter="menuVisible = !menuVisible"> <button class="branch-dropdown-button gt-ellipsis ui basic small compact button gt-df" @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 {easyMDEToolbarActions} from './EasyMDEToolbarActions.js'; import {svg} from '../../svg.js';
let elementIdCounter = 0; let elementIdCounter = 0;
@ -206,20 +206,66 @@ class ComboMarkdownEditor {
prepareEasyMDEToolbarActions() { prepareEasyMDEToolbarActions() {
this.easyMDEToolbarDefault = [ this.easyMDEToolbarDefault = [
'bold', 'italic', 'strikethrough', '|', 'heading-1', 'heading-2', 'heading-3', 'bold', 'italic', 'strikethrough', '|', 'heading-1', 'heading-2', 'heading-3', 'heading-bigger', 'heading-smaller', '|',
'heading-bigger', 'heading-smaller', '|', 'code', 'quote', '|', 'gitea-checkbox-empty', 'code', 'quote', '|', 'gitea-checkbox-empty', 'gitea-checkbox-checked', '|',
'gitea-checkbox-checked', '|', 'unordered-list', 'ordered-list', '|', 'link', 'image', 'unordered-list', 'ordered-list', '|', 'link', 'image', 'table', 'horizontal-rule', '|', 'clean-block', '|',
'table', 'horizontal-rule', '|', 'gitea-switch-to-textarea', '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(EasyMDE, actions) { parseEasyMDEToolbar(actions) {
this.easyMDEToolbarActions = this.easyMDEToolbarActions || easyMDEToolbarActions(EasyMDE, this);
const processed = []; const processed = [];
for (const action of actions) { for (const action of actions) {
const actionButton = this.easyMDEToolbarActions[action]; if (action.startsWith('gitea-')) {
if (!actionButton) throw new Error(`Unknown EasyMDE toolbar action ${action}`); const giteaAction = this.easyMDEToolbarActions[action];
processed.push(actionButton); if (!giteaAction) throw new Error(`Unknown EasyMDE toolbar action ${action}`);
processed.push(giteaAction);
} else {
processed.push(action);
}
} }
return processed; return processed;
} }
@ -247,7 +293,7 @@ class ComboMarkdownEditor {
nativeSpellcheck: true, nativeSpellcheck: true,
...this.options.easyMDEOptions, ...this.options.easyMDEOptions,
}; };
easyMDEOpt.toolbar = this.parseEasyMDEToolbar(EasyMDE, easyMDEOpt.toolbar ?? this.easyMDEToolbarDefault); easyMDEOpt.toolbar = this.parseEasyMDEToolbar(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

@ -1,152 +0,0 @@
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,10 +572,8 @@ 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[0].focus(); $editInput.trigger('focus');
$editInput[0].select();
return false; return false;
}; };

View File

@ -469,7 +469,11 @@ export function initRepository() {
return; return;
} }
initRepoBranchTagSelector('.js-branch-tag-selector'); // 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');
}
// 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', '|',
'preview', 'fullscreen', 'side-by-side', '|', 'gitea-switch-to-textarea' 'clean-block', 'preview', 'fullscreen', 'side-by-side', '|', 'gitea-switch-to-textarea'
], ],
}, },
}); });

View File

@ -1,106 +1,80 @@
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-bold': octiconBold,
'octicon-check-circle-fill': octiconCheckCircleFill,
'octicon-checkbox': octiconCheckbox, 'octicon-checkbox': octiconCheckbox,
'octicon-check-circle-fill': octiconCheckCircleFill,
'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,
'octicon-eye': octiconEye, 'gitea-double-chevron-left': giteaDoubleChevronLeft,
'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,
@ -109,20 +83,16 @@ 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,