mirror of
https://github.com/go-gitea/gitea.git
synced 2026-08-29 02:12:28 +02:00
Merge remote-tracking branch 'upstream/main' into limit-repo-size
This commit is contained in:
@@ -4,7 +4,9 @@ tmp_dir = ".air"
|
||||
[build]
|
||||
cmd = "make backend"
|
||||
bin = "gitea"
|
||||
delay = 1000
|
||||
include_ext = ["go", "tmpl"]
|
||||
exclude_dir = ["modules/git/tests", "services/gitdiff/testdata", "modules/avatar/testdata", "models/fixtures", "models/migrations/fixtures", "modules/migration/file_format_testdata", "modules/avatar/identicon/testdata"]
|
||||
include_file = ["main.go"]
|
||||
include_dir = ["cmd", "models", "modules", "options", "routers", "services"]
|
||||
exclude_dir = ["modules/git/tests", "services/gitdiff/testdata", "modules/avatar/testdata", "models/fixtures", "models/migrations/fixtures", "modules/migration/file_format_testdata", "modules/avatar/identicon/testdata"]
|
||||
exclude_regex = ["_test.go$", "_gen.go$"]
|
||||
|
||||
+8
-111
@@ -59,7 +59,7 @@ steps:
|
||||
- name: lint-backend-windows
|
||||
image: gitea/test_env:linux-1.20-amd64 # https://gitea.com/gitea/test-env
|
||||
commands:
|
||||
- make golangci-lint-windows vet
|
||||
- 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
|
||||
@@ -756,11 +756,11 @@ steps:
|
||||
|
||||
# TODO: We should probably build all dependencies into a test image
|
||||
- name: test-e2e
|
||||
image: mcr.microsoft.com/playwright:v1.32.1-focal
|
||||
image: mcr.microsoft.com/playwright:v1.32.3-focal
|
||||
commands:
|
||||
- curl -sLO https://go.dev/dl/go1.20.linux-amd64.tar.gz && tar -C /usr/local -xzf go1.20.linux-amd64.tar.gz
|
||||
- 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
|
||||
- apt-get -qq update && apt-get -qqy install build-essential
|
||||
- ./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:
|
||||
@@ -773,109 +773,6 @@ steps:
|
||||
- name: deps
|
||||
path: /go
|
||||
|
||||
---
|
||||
kind: pipeline
|
||||
name: update_translations
|
||||
|
||||
platform:
|
||||
os: linux
|
||||
arch: arm64
|
||||
|
||||
trigger:
|
||||
branch:
|
||||
- main
|
||||
event:
|
||||
- cron
|
||||
cron:
|
||||
- update_translations
|
||||
|
||||
steps:
|
||||
- name: download
|
||||
image: jonasfranz/crowdin
|
||||
pull: always
|
||||
settings:
|
||||
download: true
|
||||
export_dir: options/locale/
|
||||
ignore_branch: true
|
||||
project_identifier: gitea
|
||||
environment:
|
||||
CROWDIN_KEY:
|
||||
from_secret: crowdin_key
|
||||
|
||||
- name: update
|
||||
image: alpine:3.17
|
||||
pull: always
|
||||
commands:
|
||||
- ./build/update-locales.sh
|
||||
|
||||
- name: push
|
||||
image: appleboy/drone-git-push
|
||||
pull: always
|
||||
settings:
|
||||
author_email: "teabot@gitea.io"
|
||||
author_name: GiteaBot
|
||||
branch: main
|
||||
commit: true
|
||||
commit_message: "[skip ci] Updated translations via Crowdin"
|
||||
remote: "git@github.com:go-gitea/gitea.git"
|
||||
environment:
|
||||
DRONE_COMMIT_AUTHOR_EMAIL: "teabot@gitea.io"
|
||||
DRONE_COMMIT_AUTHOR: GiteaBot
|
||||
GIT_PUSH_SSH_KEY:
|
||||
from_secret: git_push_ssh_key
|
||||
|
||||
- name: upload_translations
|
||||
image: jonasfranz/crowdin
|
||||
pull: always
|
||||
settings:
|
||||
files:
|
||||
locale_en-US.ini: options/locale/locale_en-US.ini
|
||||
ignore_branch: true
|
||||
project_identifier: gitea
|
||||
environment:
|
||||
CROWDIN_KEY:
|
||||
from_secret: crowdin_key
|
||||
|
||||
---
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: update_gitignore_and_licenses
|
||||
|
||||
platform:
|
||||
os: linux
|
||||
arch: arm64
|
||||
|
||||
trigger:
|
||||
branch:
|
||||
- main
|
||||
event:
|
||||
- cron
|
||||
cron:
|
||||
- update_gitignore_and_licenses
|
||||
|
||||
steps:
|
||||
- name: download
|
||||
image: gitea/test_env:linux-1.20-amd64
|
||||
pull: always
|
||||
commands:
|
||||
- timeout -s ABRT 40m make generate-license generate-gitignore
|
||||
|
||||
- name: push
|
||||
image: appleboy/drone-git-push
|
||||
pull: always
|
||||
settings:
|
||||
author_email: "teabot@gitea.io"
|
||||
author_name: "GiteaBot"
|
||||
branch: main
|
||||
commit: true
|
||||
commit_message: "[skip ci] Updated licenses and gitignores"
|
||||
remote: "git@github.com:go-gitea/gitea.git"
|
||||
environment:
|
||||
DRONE_COMMIT_AUTHOR_EMAIL: "teabot@gitea.io"
|
||||
DRONE_COMMIT_AUTHOR: "GiteaBot"
|
||||
GIT_PUSH_SSH_KEY:
|
||||
from_secret: git_push_ssh_key
|
||||
|
||||
---
|
||||
kind: pipeline
|
||||
type: docker
|
||||
@@ -1369,7 +1266,7 @@ steps:
|
||||
pull: always
|
||||
settings:
|
||||
auto_tag: false
|
||||
tags: dev-linux-amd64
|
||||
tags: nightly-linux-amd64
|
||||
repo: gitea/gitea
|
||||
build_args:
|
||||
- GOPROXY=https://goproxy.io
|
||||
@@ -1391,7 +1288,7 @@ steps:
|
||||
settings:
|
||||
dockerfile: Dockerfile.rootless
|
||||
auto_tag: false
|
||||
tags: dev-linux-amd64-rootless
|
||||
tags: nightly-linux-amd64-rootless
|
||||
repo: gitea/gitea
|
||||
build_args:
|
||||
- GOPROXY=https://goproxy.io
|
||||
@@ -1711,7 +1608,7 @@ steps:
|
||||
pull: always
|
||||
settings:
|
||||
auto_tag: false
|
||||
tags: dev-linux-arm64
|
||||
tags: nightly-linux-arm64
|
||||
repo: gitea/gitea
|
||||
build_args:
|
||||
- GOPROXY=https://goproxy.io
|
||||
@@ -1733,7 +1630,7 @@ steps:
|
||||
settings:
|
||||
dockerfile: Dockerfile.rootless
|
||||
auto_tag: false
|
||||
tags: dev-linux-arm64-rootless
|
||||
tags: nightly-linux-arm64-rootless
|
||||
repo: gitea/gitea
|
||||
build_args:
|
||||
- GOPROXY=https://goproxy.io
|
||||
|
||||
+96
-2
@@ -12,6 +12,7 @@ plugins:
|
||||
- eslint-plugin-unicorn
|
||||
- eslint-plugin-import
|
||||
- eslint-plugin-jquery
|
||||
- eslint-plugin-no-jquery
|
||||
- eslint-plugin-sonarjs
|
||||
- eslint-plugin-custom-elements
|
||||
|
||||
@@ -65,7 +66,7 @@ rules:
|
||||
curly: [0]
|
||||
custom-elements/expose-class-on-global: [0]
|
||||
custom-elements/extends-correct-class: [2]
|
||||
custom-elements/file-name-matches-element: [0]
|
||||
custom-elements/file-name-matches-element: [2]
|
||||
custom-elements/no-constructor: [2]
|
||||
custom-elements/no-customized-built-in-elements: [2]
|
||||
custom-elements/no-dom-traversal-in-attributechangedcallback: [2]
|
||||
@@ -270,6 +271,99 @@ rules:
|
||||
no-invalid-this: [0]
|
||||
no-irregular-whitespace: [2]
|
||||
no-iterator: [2]
|
||||
no-jquery/no-ajax-events: [2]
|
||||
no-jquery/no-ajax: [0]
|
||||
no-jquery/no-and-self: [2]
|
||||
no-jquery/no-animate-toggle: [2]
|
||||
no-jquery/no-animate: [2]
|
||||
no-jquery/no-append-html: [0]
|
||||
no-jquery/no-attr: [0]
|
||||
no-jquery/no-bind: [2]
|
||||
no-jquery/no-box-model: [2]
|
||||
no-jquery/no-browser: [2]
|
||||
no-jquery/no-camel-case: [2]
|
||||
no-jquery/no-class-state: [0]
|
||||
no-jquery/no-class: [0]
|
||||
no-jquery/no-clone: [2]
|
||||
no-jquery/no-closest: [0]
|
||||
no-jquery/no-constructor-attributes: [2]
|
||||
no-jquery/no-contains: [2]
|
||||
no-jquery/no-context-prop: [2]
|
||||
no-jquery/no-css: [0]
|
||||
no-jquery/no-data: [0]
|
||||
no-jquery/no-deferred: [2]
|
||||
no-jquery/no-delegate: [2]
|
||||
no-jquery/no-each-collection: [0]
|
||||
no-jquery/no-each-util: [0]
|
||||
no-jquery/no-each: [0]
|
||||
no-jquery/no-error-shorthand: [2]
|
||||
no-jquery/no-error: [2]
|
||||
no-jquery/no-escape-selector: [2]
|
||||
no-jquery/no-event-shorthand: [2]
|
||||
no-jquery/no-extend: [2]
|
||||
no-jquery/no-fade: [2]
|
||||
no-jquery/no-filter: [0]
|
||||
no-jquery/no-find-collection: [0]
|
||||
no-jquery/no-find-util: [2]
|
||||
no-jquery/no-find: [0]
|
||||
no-jquery/no-fx-interval: [2]
|
||||
no-jquery/no-global-eval: [2]
|
||||
no-jquery/no-global-selector: [0]
|
||||
no-jquery/no-grep: [2]
|
||||
no-jquery/no-has: [2]
|
||||
no-jquery/no-hold-ready: [2]
|
||||
no-jquery/no-html: [0]
|
||||
no-jquery/no-in-array: [2]
|
||||
no-jquery/no-is-array: [2]
|
||||
no-jquery/no-is-empty-object: [2]
|
||||
no-jquery/no-is-function: [2]
|
||||
no-jquery/no-is-numeric: [2]
|
||||
no-jquery/no-is-plain-object: [2]
|
||||
no-jquery/no-is-window: [2]
|
||||
no-jquery/no-is: [0]
|
||||
no-jquery/no-jquery-constructor: [0]
|
||||
no-jquery/no-live: [2]
|
||||
no-jquery/no-load-shorthand: [2]
|
||||
no-jquery/no-load: [2]
|
||||
no-jquery/no-map-collection: [0]
|
||||
no-jquery/no-map-util: [2]
|
||||
no-jquery/no-map: [0]
|
||||
no-jquery/no-merge: [2]
|
||||
no-jquery/no-node-name: [2]
|
||||
no-jquery/no-noop: [2]
|
||||
no-jquery/no-now: [2]
|
||||
no-jquery/no-on-ready: [2]
|
||||
no-jquery/no-other-methods: [0]
|
||||
no-jquery/no-other-utils: [2]
|
||||
no-jquery/no-param: [2]
|
||||
no-jquery/no-parent: [0]
|
||||
no-jquery/no-parents: [0]
|
||||
no-jquery/no-parse-html-literal: [0]
|
||||
no-jquery/no-parse-html: [2]
|
||||
no-jquery/no-parse-json: [2]
|
||||
no-jquery/no-parse-xml: [2]
|
||||
no-jquery/no-prop: [0]
|
||||
no-jquery/no-proxy: [2]
|
||||
no-jquery/no-ready-shorthand: [2]
|
||||
no-jquery/no-ready: [2]
|
||||
no-jquery/no-selector-prop: [2]
|
||||
no-jquery/no-serialize: [2]
|
||||
no-jquery/no-size: [2]
|
||||
no-jquery/no-sizzle: [0]
|
||||
no-jquery/no-slide: [2]
|
||||
no-jquery/no-sub: [2]
|
||||
no-jquery/no-support: [2]
|
||||
no-jquery/no-text: [0]
|
||||
no-jquery/no-trigger: [0]
|
||||
no-jquery/no-trim: [2]
|
||||
no-jquery/no-type: [2]
|
||||
no-jquery/no-unique: [2]
|
||||
no-jquery/no-unload-shorthand: [2]
|
||||
no-jquery/no-val: [0]
|
||||
no-jquery/no-visibility: [2]
|
||||
no-jquery/no-when: [2]
|
||||
no-jquery/no-wrap: [2]
|
||||
no-jquery/variable-pattern: [0]
|
||||
no-label-var: [2]
|
||||
no-labels: [0] # handled by no-restricted-syntax
|
||||
no-lone-blocks: [2]
|
||||
@@ -500,7 +594,7 @@ rules:
|
||||
unicorn/prefer-default-parameters: [0]
|
||||
unicorn/prefer-event-key: [2]
|
||||
unicorn/prefer-event-target: [2]
|
||||
unicorn/prefer-export-from: [2]
|
||||
unicorn/prefer-export-from: [2, {ignoreUsedVariables: true}]
|
||||
unicorn/prefer-includes: [2]
|
||||
unicorn/prefer-json-parse-buffer: [0]
|
||||
unicorn/prefer-logical-operator-over-ternary: [2]
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
* text=auto eol=lf
|
||||
*.tmpl linguist-language=Handlebars
|
||||
/assets/*.json linguist-generated
|
||||
/public/img/svg/*.svg linguist-generated
|
||||
/public/vendor/** -text -eol linguist-vendored
|
||||
/templates/swagger/v1_json.tmpl linguist-generated
|
||||
/vendor/** -text -eol linguist-vendored
|
||||
/web_src/fomantic/build/** linguist-generated
|
||||
/web_src/js/vendor/** -text -eol linguist-vendored
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
on:
|
||||
schedule:
|
||||
# weekly on Monday at 0:07 UTC
|
||||
- cron: "7 0 * * 1"
|
||||
|
||||
name: Update licenses and gitignores
|
||||
|
||||
jobs:
|
||||
cron:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
- uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: '>=1.20.1'
|
||||
- name: update licenses and gitignores
|
||||
run: timeout -s ABRT 40m make generate-license generate-gitignore
|
||||
- name: push translations to repo
|
||||
uses: appleboy/git-push-action@v0.0.2
|
||||
with:
|
||||
author_email: "teabot@gitea.io"
|
||||
author_name: GiteaBot
|
||||
branch: main
|
||||
commit: true
|
||||
commit_message: "[skip ci] Updated licenses and gitignores"
|
||||
remote: "git@github.com:go-gitea/gitea.git"
|
||||
ssh_key: ${{ secrets.DEPLOY_KEY }}
|
||||
@@ -0,0 +1,47 @@
|
||||
on:
|
||||
schedule:
|
||||
- cron: "7 0 * * *" # every day at 0:07 UTC
|
||||
|
||||
name: Pull translations from Crowdin
|
||||
|
||||
jobs:
|
||||
crowdin_pull:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
- name: download from crowdin
|
||||
uses: docker://jonasfranz/crowdin
|
||||
env:
|
||||
CROWDIN_KEY: ${{ secrets.CROWDIN_KEY }}
|
||||
PLUGIN_DOWNLOAD: true
|
||||
PLUGIN_EXPORT_DIR: options/locale/
|
||||
PLUGIN_IGNORE_BRANCH: true
|
||||
PLUGIN_PROJECT_IDENTIFIER: gitea
|
||||
- name: update locales
|
||||
run: ./build/update-locales.sh
|
||||
- name: push translations to repo
|
||||
uses: appleboy/git-push-action@v0.0.2
|
||||
with:
|
||||
author_email: "teabot@gitea.io"
|
||||
author_name: GiteaBot
|
||||
branch: main
|
||||
commit: true
|
||||
commit_message: "[skip ci] Updated translations via Crowdin"
|
||||
remote: "git@github.com:go-gitea/gitea.git"
|
||||
ssh_key: ${{ secrets.DEPLOY_KEY }}
|
||||
crowdin_push:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
- name: push translations to crowdin
|
||||
uses: docker://jonasfranz/crowdin
|
||||
env:
|
||||
CROWDIN_KEY: ${{ secrets.CROWDIN_KEY }}
|
||||
PLUGIN_UPLOAD: true
|
||||
PLUGIN_IGNORE_BRANCH: true
|
||||
PLUGIN_PROJECT_IDENTIFIER: gitea
|
||||
PLUGIN_FILES: |
|
||||
locale_en-US.ini: options/locale/locale_en-US.ini
|
||||
PLUGIN_BRANCH: main
|
||||
@@ -71,6 +71,7 @@ cpu.out
|
||||
/tests/e2e/test-artifacts
|
||||
/tests/e2e/test-snapshots
|
||||
/tests/*.ini
|
||||
/tests/**/*.git/**/*.sample
|
||||
/node_modules
|
||||
/yarn.lock
|
||||
/yarn-error.log
|
||||
|
||||
+5
-52
@@ -5,6 +5,7 @@ linters:
|
||||
- depguard
|
||||
- dupl
|
||||
- errcheck
|
||||
- forbidigo
|
||||
- gocritic
|
||||
# - gocyclo # The cyclomatic complexety of a lot of functions is too high, we should refactor those another time.
|
||||
- gofmt
|
||||
@@ -22,7 +23,7 @@ linters:
|
||||
- unconvert
|
||||
- unused
|
||||
# - varcheck # deprecated - https://github.com/golangci/golangci-lint/issues/1841
|
||||
# - wastedassign # disabled - https://github.com/golangci/golangci-lint/issues/2649
|
||||
- wastedassign
|
||||
enable-all: false
|
||||
disable-all: true
|
||||
fast: false
|
||||
@@ -105,73 +106,25 @@ issues:
|
||||
- errcheck
|
||||
- dupl
|
||||
- gosec
|
||||
- path: cmd
|
||||
linters:
|
||||
- forbidigo
|
||||
- linters:
|
||||
- dupl
|
||||
text: "webhook"
|
||||
- linters:
|
||||
- gocritic
|
||||
text: "`ID' should not be capitalized"
|
||||
- path: modules/templates/helper.go
|
||||
linters:
|
||||
- gocritic
|
||||
- linters:
|
||||
- unused
|
||||
- deadcode
|
||||
text: "swagger"
|
||||
- path: contrib/pr/checkout.go
|
||||
linters:
|
||||
- errcheck
|
||||
- path: models/issue.go
|
||||
linters:
|
||||
- errcheck
|
||||
- path: models/migrations/
|
||||
linters:
|
||||
- errcheck
|
||||
- path: modules/log/
|
||||
linters:
|
||||
- errcheck
|
||||
- path: routers/api/v1/repo/issue_subscription.go
|
||||
linters:
|
||||
- dupl
|
||||
- path: routers/repo/view.go
|
||||
linters:
|
||||
- dupl
|
||||
- path: models/migrations/
|
||||
linters:
|
||||
- unused
|
||||
- linters:
|
||||
- staticcheck
|
||||
text: "argument x is overwritten before first use"
|
||||
- path: modules/httplib/httplib.go
|
||||
linters:
|
||||
- staticcheck
|
||||
# Enabling this would require refactoring the methods and how they are called.
|
||||
- path: models/issue_comment_list.go
|
||||
linters:
|
||||
- dupl
|
||||
- path: models/update.go
|
||||
linters:
|
||||
- unused
|
||||
- path: cmd/dump.go
|
||||
linters:
|
||||
- dupl
|
||||
- path: services/webhook/webhook.go
|
||||
linters:
|
||||
- structcheck
|
||||
- text: "commentFormatting: put a space between `//` and comment text"
|
||||
linters:
|
||||
- gocritic
|
||||
- text: "exitAfterDefer:"
|
||||
linters:
|
||||
- gocritic
|
||||
- path: modules/graceful/manager_windows.go
|
||||
linters:
|
||||
- staticcheck
|
||||
text: "svc.IsAnInteractiveSession is deprecated: Use IsWindowsService instead."
|
||||
- path: models/user/openid.go
|
||||
linters:
|
||||
- golint
|
||||
- path: models/user/badge.go
|
||||
linters:
|
||||
- revive
|
||||
text: "exported: type name will be used as user.UserBadge by other packages, and that stutters; consider calling this Badge"
|
||||
|
||||
+2
-1
@@ -41,7 +41,7 @@ Patrick Schratz <patrick.schratz@gmail.com> (@pat-s)
|
||||
Janis Estelmann <admin@oldschoolhack.me> (@KN4CK3R)
|
||||
Steven Kriegler <sk.bunsenbrenner@gmail.com> (@justusbunsi)
|
||||
Jimmy Praet <jimmy.praet@telenet.be> (@jpraet)
|
||||
Leon Hofmeister <dev.lh@web.de> (@delvh)
|
||||
Leon Hofmeister <dev.lh@web.de> (@delvh)
|
||||
Wim <wim@42.be> (@42wim)
|
||||
Jason Song <i@wolfogre.com> (@wolfogre)
|
||||
Yarden Shoham <git@yardenshoham.com> (@yardenshoham)
|
||||
@@ -49,3 +49,4 @@ Yu Tian <zettat123@gmail.com> (@Zettat123)
|
||||
Eddie Yang <576951401@qq.com> (@yp05327)
|
||||
Dong Ge <gedong_1994@163.com> (@sillyguodong)
|
||||
Xinyi Gong <hestergong@gmail.com> (@HesterG)
|
||||
wxiaoguang <wxiaoguang@gmail.com> (@wxiaoguang)
|
||||
|
||||
@@ -25,16 +25,15 @@ COMMA := ,
|
||||
|
||||
XGO_VERSION := go-1.20.x
|
||||
|
||||
AIR_PACKAGE ?= github.com/cosmtrek/air@v1.40.4
|
||||
EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/cmd/editorconfig-checker@2.6.0
|
||||
ERRCHECK_PACKAGE ?= github.com/kisielk/errcheck@v1.6.2
|
||||
GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.4.0
|
||||
GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.51.2
|
||||
GXZ_PAGAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.10
|
||||
AIR_PACKAGE ?= github.com/cosmtrek/air@v1.43.0
|
||||
EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/cmd/editorconfig-checker@2.7.0
|
||||
GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.5.0
|
||||
GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.52.2
|
||||
GXZ_PAGAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.11
|
||||
MISSPELL_PACKAGE ?= github.com/client9/misspell/cmd/misspell@v0.3.4
|
||||
SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@v0.30.4
|
||||
XGO_PACKAGE ?= src.techknowlogick.com/xgo@latest
|
||||
GO_LICENSES_PACKAGE ?= github.com/google/go-licenses@v1.5.0
|
||||
GO_LICENSES_PACKAGE ?= github.com/google/go-licenses@v1.6.0
|
||||
GOVULNCHECK_PACKAGE ?= golang.org/x/vuln/cmd/govulncheck@latest
|
||||
|
||||
DOCKER_IMAGE ?= gitea/gitea
|
||||
@@ -97,6 +96,11 @@ else
|
||||
endif
|
||||
endif
|
||||
|
||||
# if version = "main" then update version to "nightly"
|
||||
ifeq ($(VERSION),main)
|
||||
VERSION := main-nightly
|
||||
endif
|
||||
|
||||
LDFLAGS := $(LDFLAGS) -X "main.MakeVersion=$(MAKE_VERSION)" -X "main.Version=$(GITEA_VERSION)" -X "main.Tags=$(TAGS)"
|
||||
|
||||
LINUX_ARCHS ?= linux/amd64,linux/386,linux/arm-5,linux/arm-6,linux/arm64
|
||||
@@ -194,9 +198,20 @@ help:
|
||||
@echo " - deps-backend install backend dependencies"
|
||||
@echo " - deps-tools install tool dependencies"
|
||||
@echo " - lint lint everything"
|
||||
@echo " - lint-fix lint everything and fix issues"
|
||||
@echo " - lint-frontend lint frontend files"
|
||||
@echo " - lint-frontend-fix lint frontend files and fix issues"
|
||||
@echo " - lint-backend lint backend files"
|
||||
@echo " - lint-backend-fix lint backend files and fix issues"
|
||||
@echo " - lint-go lint go files"
|
||||
@echo " - lint-go-fix lint go files and fix issues"
|
||||
@echo " - lint-go-vet lint go files with vet"
|
||||
@echo " - lint-js lint js files"
|
||||
@echo " - lint-js-fix lint js files and fix issues"
|
||||
@echo " - lint-css lint css files"
|
||||
@echo " - lint-css-fix lint css files and fix issues"
|
||||
@echo " - lint-md lint markdown files"
|
||||
@echo " - lint-swagger lint swagger files"
|
||||
@echo " - checks run various consistency checks"
|
||||
@echo " - checks-frontend check frontend files"
|
||||
@echo " - checks-backend check backend files"
|
||||
@@ -214,9 +229,7 @@ help:
|
||||
@echo " - generate-manpage generate manpage"
|
||||
@echo " - generate-swagger generate the swagger spec from code comments"
|
||||
@echo " - swagger-validate check if the swagger spec is valid"
|
||||
@echo " - golangci-lint run golangci-lint linter"
|
||||
@echo " - go-licenses regenerate go licenses"
|
||||
@echo " - vet examines Go source code and reports suspicious constructs"
|
||||
@echo " - tidy run go mod tidy"
|
||||
@echo " - test[\#TestSpecificName] run unit test"
|
||||
@echo " - test-sqlite[\#TestSpecificName] run integration test for sqlite"
|
||||
@@ -270,8 +283,12 @@ clean:
|
||||
fmt:
|
||||
GOFUMPT_PACKAGE=$(GOFUMPT_PACKAGE) $(GO) run build/code-batch-process.go gitea-fmt -w '{file-list}'
|
||||
$(eval TEMPLATES := $(shell find templates -type f -name '*.tmpl'))
|
||||
@# strip whitespace after '{{' and before `}}` unless there is only whitespace before it
|
||||
@$(SED_INPLACE) -e 's/{{[ ]\{1,\}/{{/g' -e '/^[ ]\{1,\}}}/! s/[ ]\{1,\}}}/}}/g' $(TEMPLATES)
|
||||
@# strip whitespace after '{{' or '(' and before '}}' or ')' unless there is only
|
||||
@# whitespace before it
|
||||
@$(SED_INPLACE) \
|
||||
-e 's/{{[ ]\{1,\}/{{/g' -e '/^[ ]\{1,\}}}/! s/[ ]\{1,\}}}/}}/g' \
|
||||
-e 's/([ ]\{1,\}/(/g' -e '/^[ ]\{1,\})/! s/[ ]\{1,\})/)/g' \
|
||||
$(TEMPLATES)
|
||||
|
||||
.PHONY: fmt-check
|
||||
fmt-check: fmt
|
||||
@@ -286,12 +303,6 @@ fmt-check: fmt
|
||||
misspell-check:
|
||||
go run $(MISSPELL_PACKAGE) -error $(GO_DIRS) $(WEB_DIRS)
|
||||
|
||||
.PHONY: vet
|
||||
vet:
|
||||
@echo "Running go vet..."
|
||||
@GOOS= GOARCH= $(GO) build code.gitea.io/gitea-vet
|
||||
@$(GO) vet -vettool=gitea-vet $(GO_PACKAGES)
|
||||
|
||||
.PHONY: $(TAGS_EVIDENCE)
|
||||
$(TAGS_EVIDENCE):
|
||||
@mkdir -p $(MAKE_EVIDENCE_DIR)
|
||||
@@ -324,11 +335,6 @@ swagger-validate:
|
||||
$(GO) run $(SWAGGER_PACKAGE) validate './$(SWAGGER_SPEC)'
|
||||
$(SED_INPLACE) '$(SWAGGER_SPEC_S_TMPL)' './$(SWAGGER_SPEC)'
|
||||
|
||||
.PHONY: errcheck
|
||||
errcheck:
|
||||
@echo "Running errcheck..."
|
||||
$(GO) run $(ERRCHECK_PACKAGE) $(GO_PACKAGES)
|
||||
|
||||
.PHONY: checks
|
||||
checks: checks-frontend checks-backend
|
||||
|
||||
@@ -341,18 +347,69 @@ checks-backend: tidy-check swagger-check fmt-check misspell-check swagger-valida
|
||||
.PHONY: lint
|
||||
lint: lint-frontend lint-backend
|
||||
|
||||
.PHONY: lint-fix
|
||||
lint-fix: lint-frontend-fix lint-backend-fix
|
||||
|
||||
.PHONY: lint-frontend
|
||||
lint-frontend: node_modules lint-md
|
||||
lint-frontend: lint-js lint-css lint-md lint-swagger
|
||||
|
||||
.PHONY: lint-frontend-fix
|
||||
lint-frontend-fix: lint-js-fix lint-css-fix lint-md lint-swagger
|
||||
|
||||
.PHONY: lint-backend
|
||||
lint-backend: lint-go lint-go-vet lint-editorconfig
|
||||
|
||||
.PHONY: lint-backend-fix
|
||||
lint-backend-fix: lint-go-fix lint-go-vet lint-editorconfig
|
||||
|
||||
.PHONY: lint-js
|
||||
lint-js: node_modules
|
||||
npx eslint --color --max-warnings=0 --ext js,vue web_src/js build *.config.js docs/assets/js tests/e2e
|
||||
|
||||
.PHONY: lint-js-fix
|
||||
lint-js-fix: node_modules
|
||||
npx eslint --color --max-warnings=0 --ext js,vue web_src/js build *.config.js docs/assets/js tests/e2e --fix
|
||||
|
||||
.PHONY: lint-css
|
||||
lint-css: node_modules
|
||||
npx stylelint --color --max-warnings=0 web_src/css
|
||||
|
||||
.PHONY: lint-css-fix
|
||||
lint-css-fix: node_modules
|
||||
npx stylelint --color --max-warnings=0 web_src/css --fix
|
||||
|
||||
.PHONY: lint-swagger
|
||||
lint-swagger: node_modules
|
||||
npx spectral lint -q -F hint $(SWAGGER_SPEC)
|
||||
|
||||
.PHONY: lint-md
|
||||
lint-md: node_modules
|
||||
npx markdownlint docs *.md
|
||||
|
||||
.PHONY: lint-backend
|
||||
lint-backend: golangci-lint vet editorconfig-checker
|
||||
.PHONY: lint-go
|
||||
lint-go:
|
||||
$(GO) run $(GOLANGCI_LINT_PACKAGE) run
|
||||
|
||||
.PHONY: lint-go-fix
|
||||
lint-go-fix:
|
||||
$(GO) run $(GOLANGCI_LINT_PACKAGE) run --fix
|
||||
|
||||
# workaround step for the lint-backend-windows CI task because 'go run' can not
|
||||
# have distinct GOOS/GOARCH for its build and run steps
|
||||
.PHONY: lint-go-windows
|
||||
lint-go-windows:
|
||||
@GOOS= GOARCH= $(GO) install $(GOLANGCI_LINT_PACKAGE)
|
||||
golangci-lint run
|
||||
|
||||
.PHONY: lint-go-vet
|
||||
lint-go-vet:
|
||||
@echo "Running go vet..."
|
||||
@GOOS= GOARCH= $(GO) build code.gitea.io/gitea-vet
|
||||
@$(GO) vet -vettool=gitea-vet $(GO_PACKAGES)
|
||||
|
||||
.PHONY: lint-editorconfig
|
||||
lint-editorconfig:
|
||||
$(GO) run $(EDITORCONFIG_CHECKER_PACKAGE) templates
|
||||
|
||||
.PHONY: watch
|
||||
watch:
|
||||
@@ -843,7 +900,6 @@ deps-backend:
|
||||
deps-tools:
|
||||
$(GO) install $(AIR_PACKAGE)
|
||||
$(GO) install $(EDITORCONFIG_CHECKER_PACKAGE)
|
||||
$(GO) install $(ERRCHECK_PACKAGE)
|
||||
$(GO) install $(GOFUMPT_PACKAGE)
|
||||
$(GO) install $(GOLANGCI_LINT_PACKAGE)
|
||||
$(GO) install $(GXZ_PAGAGE)
|
||||
@@ -942,21 +998,6 @@ generate-manpage:
|
||||
@gzip -9 man/man1/gitea.1 && echo man/man1/gitea.1.gz created
|
||||
@#TODO A small script that formats config-cheat-sheet.en-us.md nicely for use as a config man page
|
||||
|
||||
.PHONY: golangci-lint
|
||||
golangci-lint:
|
||||
$(GO) run $(GOLANGCI_LINT_PACKAGE) run
|
||||
|
||||
# workaround step for the lint-backend-windows CI task because 'go run' can not
|
||||
# have distinct GOOS/GOARCH for its build and run steps
|
||||
.PHONY: golangci-lint-windows
|
||||
golangci-lint-windows:
|
||||
@GOOS= GOARCH= $(GO) install $(GOLANGCI_LINT_PACKAGE)
|
||||
golangci-lint run
|
||||
|
||||
.PHONY: editorconfig-checker
|
||||
editorconfig-checker:
|
||||
$(GO) run $(EDITORCONFIG_CHECKER_PACKAGE) templates
|
||||
|
||||
.PHONY: docker
|
||||
docker:
|
||||
docker build --disable-content-trust=false -t $(DOCKER_REF) .
|
||||
|
||||
Generated
+5
@@ -1004,6 +1004,11 @@
|
||||
"path": "golang.org/x/crypto/LICENSE",
|
||||
"licenseText": "Copyright (c) 2009 The Go Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
|
||||
},
|
||||
{
|
||||
"name": "golang.org/x/image",
|
||||
"path": "golang.org/x/image/LICENSE",
|
||||
"licenseText": "Copyright (c) 2009 The Go Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
|
||||
},
|
||||
{
|
||||
"name": "golang.org/x/mod/semver",
|
||||
"path": "golang.org/x/mod/semver/LICENSE",
|
||||
|
||||
@@ -67,7 +67,7 @@ func TestMigratePackages(t *testing.T) {
|
||||
|
||||
entries, err := os.ReadDir(p)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 2, len(entries))
|
||||
assert.Len(t, entries, 2)
|
||||
assert.EqualValues(t, "01", entries[0].Name())
|
||||
assert.EqualValues(t, "tmp", entries[1].Name())
|
||||
}
|
||||
|
||||
+4
-4
@@ -24,7 +24,6 @@ import (
|
||||
|
||||
"github.com/felixge/fgprof"
|
||||
"github.com/urfave/cli"
|
||||
ini "gopkg.in/ini.v1"
|
||||
)
|
||||
|
||||
// PIDFile could be set from build tag
|
||||
@@ -223,9 +222,10 @@ func setPort(port string) error {
|
||||
defaultLocalURL += ":" + setting.HTTPPort + "/"
|
||||
|
||||
// Save LOCAL_ROOT_URL if port changed
|
||||
setting.CreateOrAppendToCustomConf("server.LOCAL_ROOT_URL", func(cfg *ini.File) {
|
||||
cfg.Section("server").Key("LOCAL_ROOT_URL").SetValue(defaultLocalURL)
|
||||
})
|
||||
setting.CfgProvider.Section("server").Key("LOCAL_ROOT_URL").SetValue(defaultLocalURL)
|
||||
if err := setting.CfgProvider.Save(); err != nil {
|
||||
return fmt.Errorf("Failed to save config file: %v", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
//nolint:forbidigo
|
||||
package main
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
//nolint:forbidigo
|
||||
package main
|
||||
|
||||
import (
|
||||
|
||||
+12
-3
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
# This is an update script for gitea installed via the binary distribution
|
||||
# from dl.gitea.io on linux as systemd service. It performs a backup and updates
|
||||
# from dl.gitea.com on linux as systemd service. It performs a backup and updates
|
||||
# Gitea in place.
|
||||
# NOTE: This adds the GPG Signing Key of the Gitea maintainers to the keyring.
|
||||
# Depends on: bash, curl, xz, sha256sum. optionally jq, gpg
|
||||
@@ -10,6 +10,15 @@
|
||||
# upgrade.sh 1.15.10
|
||||
# giteahome=/opt/gitea giteaconf=$giteahome/app.ini upgrade.sh
|
||||
|
||||
# Check if gitea service is running
|
||||
if ! pidof gitea &> /dev/null; then
|
||||
echo "Error: gitea is not running."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Continue with rest of the script if gitea is running
|
||||
echo "Gitea is running. Continuing with rest of script..."
|
||||
|
||||
# apply variables from environment
|
||||
: "${giteabin:="/usr/local/bin/gitea"}"
|
||||
: "${giteahome:="/var/lib/gitea"}"
|
||||
@@ -69,7 +78,7 @@ require curl xz sha256sum "$sudocmd"
|
||||
# select version to install
|
||||
if [[ -z "${giteaversion:-}" ]]; then
|
||||
require jq
|
||||
giteaversion=$(curl --connect-timeout 10 -sL https://dl.gitea.io/gitea/version.json | jq -r .latest.version)
|
||||
giteaversion=$(curl --connect-timeout 10 -sL https://dl.gitea.com/gitea/version.json | jq -r .latest.version)
|
||||
echo "Latest available version is $giteaversion"
|
||||
fi
|
||||
|
||||
@@ -91,7 +100,7 @@ cd "$giteahome" # needed for gitea dump later
|
||||
|
||||
# download new binary
|
||||
binname="gitea-${giteaversion}-${arch}"
|
||||
binurl="https://dl.gitea.io/gitea/${giteaversion}/${binname}.xz"
|
||||
binurl="https://dl.gitea.com/gitea/${giteaversion}/${binname}.xz"
|
||||
echo "Downloading $binurl..."
|
||||
curl --connect-timeout 10 --silent --show-error --fail --location -O "$binurl{,.sha256,.asc}"
|
||||
|
||||
|
||||
@@ -1203,10 +1203,9 @@ ROUTER = console
|
||||
;; Number of line of codes shown for a code comment
|
||||
;CODE_COMMENT_LINES = 4
|
||||
;;
|
||||
;; Value of `theme-color` meta tag, used by Android >= 5.0
|
||||
;; An invalid color like "none" or "disable" will have the default style
|
||||
;; More info: https://developers.google.com/web/updates/2014/11/Support-for-theme-color-in-Chrome-39-for-Android
|
||||
;THEME_COLOR_META_TAG = `#6cc644`
|
||||
;; Value of `theme-color` meta tag, used by some mobile browers for chrome and
|
||||
;; out-of-viewport areas. Default is unset which uses body color.
|
||||
;THEME_COLOR_META_TAG =
|
||||
;;
|
||||
;; Max size of files to be displayed (default is 8MiB)
|
||||
;MAX_DISPLAY_FILE_SIZE = 8388608
|
||||
@@ -2340,7 +2339,6 @@ ROUTER = console
|
||||
;[other]
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;SHOW_FOOTER_BRANDING = false
|
||||
;; Show version information about Gitea and Go in the footer
|
||||
;SHOW_FOOTER_VERSION = true
|
||||
;; Show template execution time in the footer
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}{{#if (hasPrefix "refs/heads/release/v" build.ref)}}{{trimPrefix "refs/heads/release/v" build.ref}}-{{/if}}dev{{/if}}-rootless
|
||||
image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}{{#if (hasPrefix "refs/heads/release/v" build.ref)}}{{trimPrefix "refs/heads/release/v" build.ref}}-{{/if}}nightly{{/if}}-rootless
|
||||
{{#if build.tags}}
|
||||
{{#unless (contains "-rc" build.tag)}}
|
||||
tags:
|
||||
@@ -10,12 +10,12 @@ tags:
|
||||
{{/if}}
|
||||
manifests:
|
||||
-
|
||||
image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}{{#if (hasPrefix "refs/heads/release/v" build.ref)}}{{trimPrefix "refs/heads/release/v" build.ref}}-{{/if}}dev{{/if}}-linux-amd64-rootless
|
||||
image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}{{#if (hasPrefix "refs/heads/release/v" build.ref)}}{{trimPrefix "refs/heads/release/v" build.ref}}-{{/if}}nightly{{/if}}-linux-amd64-rootless
|
||||
platform:
|
||||
architecture: amd64
|
||||
os: linux
|
||||
-
|
||||
image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}{{#if (hasPrefix "refs/heads/release/v" build.ref)}}{{trimPrefix "refs/heads/release/v" build.ref}}-{{/if}}dev{{/if}}-linux-arm64-rootless
|
||||
image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}{{#if (hasPrefix "refs/heads/release/v" build.ref)}}{{trimPrefix "refs/heads/release/v" build.ref}}-{{/if}}nightly{{/if}}-linux-arm64-rootless
|
||||
platform:
|
||||
architecture: arm64
|
||||
os: linux
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}{{#if (hasPrefix "refs/heads/release/v" build.ref)}}{{trimPrefix "refs/heads/release/v" build.ref}}-{{/if}}dev{{/if}}
|
||||
image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}{{#if (hasPrefix "refs/heads/release/v" build.ref)}}{{trimPrefix "refs/heads/release/v" build.ref}}-{{/if}}nightly{{/if}}
|
||||
{{#if build.tags}}
|
||||
{{#unless (contains "-rc" build.tag)}}
|
||||
tags:
|
||||
@@ -10,12 +10,12 @@ tags:
|
||||
{{/if}}
|
||||
manifests:
|
||||
-
|
||||
image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}{{#if (hasPrefix "refs/heads/release/v" build.ref)}}{{trimPrefix "refs/heads/release/v" build.ref}}-{{/if}}dev{{/if}}-linux-amd64
|
||||
image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}{{#if (hasPrefix "refs/heads/release/v" build.ref)}}{{trimPrefix "refs/heads/release/v" build.ref}}-{{/if}}nightly{{/if}}-linux-amd64
|
||||
platform:
|
||||
architecture: amd64
|
||||
os: linux
|
||||
-
|
||||
image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}{{#if (hasPrefix "refs/heads/release/v" build.ref)}}{{trimPrefix "refs/heads/release/v" build.ref}}-{{/if}}dev{{/if}}-linux-arm64
|
||||
image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}{{#if (hasPrefix "refs/heads/release/v" build.ref)}}{{trimPrefix "refs/heads/release/v" build.ref}}-{{/if}}nightly{{/if}}-linux-arm64
|
||||
platform:
|
||||
architecture: arm64
|
||||
os: linux
|
||||
|
||||
@@ -220,7 +220,7 @@ The following configuration set `Content-Type: application/vnd.android.package-a
|
||||
- `SHOW_USER_EMAIL`: **true**: Whether the email of the user should be shown in the Explore Users page.
|
||||
- `THEMES`: **auto,gitea,arc-green**: All available themes. Allow users select personalized themes.
|
||||
regardless of the value of `DEFAULT_THEME`.
|
||||
- `THEME_COLOR_META_TAG`: **#6cc644**: Value of `theme-color` meta tag, used by Android >= 5.0. An invalid color like "none" or "disable" will have the default style. More info: https://developers.google.com/web/updates/2014/11/Support-for-theme-color-in-Chrome-39-for-Android
|
||||
- `THEME_COLOR_META_TAG`: **\<empty\>**: Value of `theme-color` meta tag, used by some mobile browers for chrome and out-of-viewport areas. Default is unset which uses body color.
|
||||
- `MAX_DISPLAY_FILE_SIZE`: **8388608**: Max size of files to be displayed (default is 8MiB)
|
||||
- `REACTIONS`: All available reactions users can choose on issues/prs and comments
|
||||
Values can be emoji alias (:smile:) or a unicode emoji.
|
||||
@@ -1391,7 +1391,6 @@ although Github don't support this form.
|
||||
|
||||
## Other (`other`)
|
||||
|
||||
- `SHOW_FOOTER_BRANDING`: **false**: Show Gitea branding in the footer.
|
||||
- `SHOW_FOOTER_VERSION`: **true**: Show Gitea and Go version information in the footer.
|
||||
- `SHOW_FOOTER_TEMPLATE_LOAD_TIME`: **true**: Show time of template execution in the footer.
|
||||
- `ENABLE_SITEMAP`: **true**: Generate sitemap.
|
||||
|
||||
@@ -483,5 +483,4 @@ PROXY_HOSTS = *.github.com
|
||||
|
||||
## Other (`other`)
|
||||
|
||||
- `SHOW_FOOTER_BRANDING`: 为真则在页面底部显示Gitea的字样。
|
||||
- `SHOW_FOOTER_VERSION`: 为真则在页面底部显示Gitea的版本。
|
||||
|
||||
@@ -49,6 +49,7 @@ We recommend [Google HTML/CSS Style Guide](https://google.github.io/styleguide/h
|
||||
9. Avoid unnecessary `!important` in CSS, add comments to explain why it's necessary if it can't be avoided.
|
||||
10. Avoid mixing different events in one event listener, prefer to use individual event listeners for every event.
|
||||
11. Custom event names are recommended to use `ce-` prefix.
|
||||
12. Gitea's tailwind-style CSS classes use `gt-` prefix (`gt-relative`), while Gitea's own private framework-level CSS classes use `g-` prefix (`g-modal-confirm`).
|
||||
|
||||
### Accessibility / ARIA
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ module code.gitea.io/gitea
|
||||
go 1.19
|
||||
|
||||
require (
|
||||
code.gitea.io/actions-proto-go v0.2.0
|
||||
code.gitea.io/actions-proto-go v0.2.1
|
||||
code.gitea.io/gitea-vet v0.2.2
|
||||
code.gitea.io/sdk/gitea v0.15.1
|
||||
codeberg.org/gusted/mcaptcha v0.0.0-20220723083913-4f3072e1d570
|
||||
@@ -104,10 +104,11 @@ require (
|
||||
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20220924101305-151362477c87
|
||||
github.com/yuin/goldmark-meta v1.1.0
|
||||
golang.org/x/crypto v0.7.0
|
||||
golang.org/x/image v0.7.0
|
||||
golang.org/x/net v0.8.0
|
||||
golang.org/x/oauth2 v0.6.0
|
||||
golang.org/x/sys v0.6.0
|
||||
golang.org/x/text v0.8.0
|
||||
golang.org/x/text v0.9.0
|
||||
golang.org/x/tools v0.6.0
|
||||
google.golang.org/grpc v1.53.0
|
||||
google.golang.org/protobuf v1.28.1
|
||||
@@ -290,7 +291,7 @@ replace github.com/shurcooL/vfsgen => github.com/lunny/vfsgen v0.0.0-20220105142
|
||||
|
||||
replace github.com/blevesearch/zapx/v15 v15.3.6 => github.com/zeripath/zapx/v15 v15.3.6-alignment-fix
|
||||
|
||||
replace github.com/nektos/act => gitea.com/gitea/act v0.243.3-0.20230407083103-5c4a96bcb797
|
||||
replace github.com/nektos/act => gitea.com/gitea/act v0.243.4
|
||||
|
||||
exclude github.com/gofrs/uuid v3.2.0+incompatible
|
||||
|
||||
|
||||
@@ -40,8 +40,8 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl
|
||||
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
||||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||
cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
|
||||
code.gitea.io/actions-proto-go v0.2.0 h1:nYh9nhhfk67YA4wVNLsCzd//RCvXnljwXClJ33+HPVk=
|
||||
code.gitea.io/actions-proto-go v0.2.0/go.mod h1:00ys5QDo1iHN1tHNvvddAcy2W/g+425hQya1cCSvq9A=
|
||||
code.gitea.io/actions-proto-go v0.2.1 h1:ToMN/8thz2q10TuCq8dL2d8mI+/pWpJcHCvG+TELwa0=
|
||||
code.gitea.io/actions-proto-go v0.2.1/go.mod h1:00ys5QDo1iHN1tHNvvddAcy2W/g+425hQya1cCSvq9A=
|
||||
code.gitea.io/gitea-vet v0.2.1/go.mod h1:zcNbT/aJEmivCAhfmkHOlT645KNOf9W2KnkLgFjGGfE=
|
||||
code.gitea.io/gitea-vet v0.2.2 h1:TEOV/Glf38iGmKzKP0EB++Z5OSL4zGg3RrAvlwaMuvk=
|
||||
code.gitea.io/gitea-vet v0.2.2/go.mod h1:zcNbT/aJEmivCAhfmkHOlT645KNOf9W2KnkLgFjGGfE=
|
||||
@@ -52,8 +52,8 @@ codeberg.org/gusted/mcaptcha v0.0.0-20220723083913-4f3072e1d570/go.mod h1:IIAjsi
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078 h1:cliQ4HHsCo6xi2oWZYKWW4bly/Ory9FuTpFPRxj/mAg=
|
||||
git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078/go.mod h1:g/V2Hjas6Z1UHUp4yIx6bATpNzJ7DYtD0FG3+xARWxs=
|
||||
gitea.com/gitea/act v0.243.3-0.20230407083103-5c4a96bcb797 h1:QdQ+pHxpbIi2qsgZbYVxqYV7trfW3P5M/T4AfpoM7iw=
|
||||
gitea.com/gitea/act v0.243.3-0.20230407083103-5c4a96bcb797/go.mod h1:mabw6AZAiDgxGlK83orWLrNERSPvgBJzEUS3S7u2bHI=
|
||||
gitea.com/gitea/act v0.243.4 h1:MuBHBLCJfpa6mzwwvs4xqQynrSP2RRzpHpWfTV16PmI=
|
||||
gitea.com/gitea/act v0.243.4/go.mod h1:mabw6AZAiDgxGlK83orWLrNERSPvgBJzEUS3S7u2bHI=
|
||||
gitea.com/go-chi/binding v0.0.0-20221013104517-b29891619681 h1:MMSPgnVULVwV9kEBgvyEUhC9v/uviZ55hPJEMjpbNR4=
|
||||
gitea.com/go-chi/binding v0.0.0-20221013104517-b29891619681/go.mod h1:77TZu701zMXWJFvB8gvTbQ92zQ3DQq/H7l5wAEjQRKc=
|
||||
gitea.com/go-chi/cache v0.0.0-20210110083709-82c4c9ce2d5e/go.mod h1:k2V/gPDEtXGjjMGuBJiapffAXTv76H4snSmlJRLUhH0=
|
||||
@@ -1331,6 +1331,8 @@ golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EH
|
||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.7.0 h1:gzS29xtG1J5ybQlv0PuyfE3nmc6R4qB73m6LUUmvFuw=
|
||||
golang.org/x/image v0.7.0/go.mod h1:nd/q4ef1AKKYl/4kft7g+6UyGbdiqWqTP1ZAbRoV7Rg=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
@@ -1415,6 +1417,7 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug
|
||||
golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||
golang.org/x/net v0.0.0-20220906165146-f3363e06e74c/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
|
||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
@@ -1533,6 +1536,7 @@ golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
@@ -1540,6 +1544,7 @@ golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9sn
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@@ -1551,8 +1556,9 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
|
||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package actions
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
)
|
||||
|
||||
// ActionTaskOutput represents an output of ActionTask.
|
||||
// So the outputs are bound to a task, that means when a completed job has been rerun,
|
||||
// the outputs of the job will be reset because the task is new.
|
||||
// It's by design, to avoid the outputs of the old task to be mixed with the new task.
|
||||
type ActionTaskOutput struct {
|
||||
ID int64
|
||||
TaskID int64 `xorm:"INDEX UNIQUE(task_id_output_key)"`
|
||||
OutputKey string `xorm:"VARCHAR(255) UNIQUE(task_id_output_key)"`
|
||||
OutputValue string `xorm:"MEDIUMTEXT"`
|
||||
}
|
||||
|
||||
// FindTaskOutputByTaskID returns the outputs of the task.
|
||||
func FindTaskOutputByTaskID(ctx context.Context, taskID int64) ([]*ActionTaskOutput, error) {
|
||||
var outputs []*ActionTaskOutput
|
||||
return outputs, db.GetEngine(ctx).Where("task_id=?", taskID).Find(&outputs)
|
||||
}
|
||||
|
||||
// FindTaskOutputKeyByTaskID returns the keys of the outputs of the task.
|
||||
func FindTaskOutputKeyByTaskID(ctx context.Context, taskID int64) ([]string, error) {
|
||||
var keys []string
|
||||
return keys, db.GetEngine(ctx).Table(ActionTaskOutput{}).Where("task_id=?", taskID).Cols("output_key").Find(&keys)
|
||||
}
|
||||
|
||||
// InsertTaskOutputIfNotExist inserts a new task output if it does not exist.
|
||||
func InsertTaskOutputIfNotExist(ctx context.Context, taskID int64, key, value string) error {
|
||||
return db.WithTx(ctx, func(ctx context.Context) error {
|
||||
sess := db.GetEngine(ctx)
|
||||
if exist, err := sess.Exist(&ActionTaskOutput{TaskID: taskID, OutputKey: key}); err != nil {
|
||||
return err
|
||||
} else if exist {
|
||||
return nil
|
||||
}
|
||||
_, err := sess.Insert(&ActionTaskOutput{
|
||||
TaskID: taskID,
|
||||
OutputKey: key,
|
||||
OutputValue: value,
|
||||
})
|
||||
return err
|
||||
})
|
||||
}
|
||||
@@ -19,13 +19,16 @@ func TestIterate(t *testing.T) {
|
||||
xe := unittest.GetXORMEngine()
|
||||
assert.NoError(t, xe.Sync(&repo_model.RepoUnit{}))
|
||||
|
||||
var repoCnt int
|
||||
err := db.Iterate(db.DefaultContext, nil, func(ctx context.Context, repo *repo_model.RepoUnit) error {
|
||||
repoCnt++
|
||||
cnt, err := db.GetEngine(db.DefaultContext).Count(&repo_model.RepoUnit{})
|
||||
assert.NoError(t, err)
|
||||
|
||||
var repoUnitCnt int
|
||||
err = db.Iterate(db.DefaultContext, nil, func(ctx context.Context, repo *repo_model.RepoUnit) error {
|
||||
repoUnitCnt++
|
||||
return nil
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 84, repoCnt)
|
||||
assert.EqualValues(t, cnt, repoUnitCnt)
|
||||
|
||||
err = db.Iterate(db.DefaultContext, nil, func(ctx context.Context, repoUnit *repo_model.RepoUnit) error {
|
||||
reopUnit2 := repo_model.RepoUnit{ID: repoUnit.ID}
|
||||
|
||||
@@ -31,15 +31,20 @@ func TestFind(t *testing.T) {
|
||||
xe := unittest.GetXORMEngine()
|
||||
assert.NoError(t, xe.Sync(&repo_model.RepoUnit{}))
|
||||
|
||||
var repoUnitCount int
|
||||
_, err := db.GetEngine(db.DefaultContext).SQL("SELECT COUNT(*) FROM repo_unit").Get(&repoUnitCount)
|
||||
assert.NoError(t, err)
|
||||
assert.NotEmpty(t, repoUnitCount)
|
||||
|
||||
opts := mockListOptions{}
|
||||
var repoUnits []repo_model.RepoUnit
|
||||
err := db.Find(db.DefaultContext, &opts, &repoUnits)
|
||||
err = db.Find(db.DefaultContext, &opts, &repoUnits)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 84, len(repoUnits))
|
||||
assert.Len(t, repoUnits, repoUnitCount)
|
||||
|
||||
cnt, err := db.Count(db.DefaultContext, &opts, new(repo_model.RepoUnit))
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 84, cnt)
|
||||
assert.EqualValues(t, repoUnitCount, cnt)
|
||||
|
||||
repoUnits = make([]repo_model.RepoUnit, 0, 10)
|
||||
newCnt, err := db.FindAndCount(db.DefaultContext, &opts, &repoUnits)
|
||||
|
||||
@@ -12,8 +12,6 @@ import (
|
||||
"code.gitea.io/gitea/models/db"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
func changeDefaultFileBlockSize(n int64) (restore func()) {
|
||||
|
||||
@@ -66,3 +66,45 @@
|
||||
is_prerelease: true
|
||||
is_tag: false
|
||||
created_unix: 946684800
|
||||
|
||||
- id: 6
|
||||
repo_id: 57
|
||||
publisher_id: 2
|
||||
tag_name: "v1.0"
|
||||
lower_tag_name: "v1.0"
|
||||
target: "main"
|
||||
title: "v1.0"
|
||||
sha1: "a8a700e8c644c783ba2c6e742bb81bf91e244bff"
|
||||
num_commits: 3
|
||||
is_draft: false
|
||||
is_prerelease: false
|
||||
is_tag: false
|
||||
created_unix: 946684801
|
||||
|
||||
- id: 7
|
||||
repo_id: 57
|
||||
publisher_id: 2
|
||||
tag_name: "v1.1"
|
||||
lower_tag_name: "v1.1"
|
||||
target: "main"
|
||||
title: "v1.1"
|
||||
sha1: "cef06e48f2642cd0dc9597b4bea09f4b3f74aad6"
|
||||
num_commits: 5
|
||||
is_draft: false
|
||||
is_prerelease: false
|
||||
is_tag: false
|
||||
created_unix: 946684802
|
||||
|
||||
- id: 8
|
||||
repo_id: 57
|
||||
publisher_id: 2
|
||||
tag_name: "v2.0"
|
||||
lower_tag_name: "v2.0"
|
||||
target: "main"
|
||||
title: "v2.0"
|
||||
sha1: "7197b56fdc75b453f47c9110938cb46a303579fd"
|
||||
num_commits: 6
|
||||
is_draft: false
|
||||
is_prerelease: false
|
||||
is_tag: false
|
||||
created_unix: 946684803
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
# See models/unit/unit.go for the meaning of the type
|
||||
-
|
||||
id: 1
|
||||
repo_id: 1
|
||||
@@ -575,3 +576,34 @@
|
||||
repo_id: 56
|
||||
type: 1
|
||||
created_unix: 946684810
|
||||
-
|
||||
id: 85
|
||||
repo_id: 57
|
||||
type: 1
|
||||
created_unix: 946684810
|
||||
-
|
||||
id: 86
|
||||
repo_id: 57
|
||||
type: 2
|
||||
created_unix: 946684810
|
||||
-
|
||||
id: 87
|
||||
repo_id: 57
|
||||
type: 3
|
||||
created_unix: 946684810
|
||||
-
|
||||
id: 88
|
||||
repo_id: 57
|
||||
type: 4
|
||||
created_unix: 946684810
|
||||
-
|
||||
id: 89
|
||||
repo_id: 57
|
||||
type: 5
|
||||
created_unix: 946684810
|
||||
|
||||
-
|
||||
id: 90
|
||||
repo_id: 52
|
||||
type: 1
|
||||
created_unix: 946684810
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
# don't forget to add fixtures in repo_unit.yml
|
||||
-
|
||||
id: 1
|
||||
owner_id: 2
|
||||
@@ -1559,6 +1560,7 @@
|
||||
owner_name: user30
|
||||
lower_name: empty
|
||||
name: empty
|
||||
default_branch: master
|
||||
num_watches: 0
|
||||
num_stars: 0
|
||||
num_forks: 0
|
||||
@@ -1647,3 +1649,16 @@
|
||||
is_private: true
|
||||
status: 0
|
||||
num_issues: 0
|
||||
|
||||
-
|
||||
id: 57
|
||||
owner_id: 2
|
||||
owner_name: user2
|
||||
lower_name: repo-release
|
||||
name: repo-release
|
||||
default_branch: main
|
||||
is_empty: false
|
||||
is_archived: false
|
||||
is_private: false
|
||||
status: 0
|
||||
num_issues: 0
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
num_followers: 2
|
||||
num_following: 1
|
||||
num_stars: 2
|
||||
num_repos: 12
|
||||
num_repos: 13
|
||||
num_teams: 0
|
||||
num_members: 0
|
||||
visibility: 0
|
||||
@@ -1091,7 +1091,7 @@
|
||||
max_repo_creation: -1
|
||||
is_active: true
|
||||
is_admin: false
|
||||
is_restricted: true
|
||||
is_restricted: false
|
||||
allow_git_hook: false
|
||||
allow_import_local: false
|
||||
allow_create_organization: true
|
||||
|
||||
@@ -88,12 +88,12 @@ func TestFindRenamedBranch(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
branch, exist, err := git_model.FindRenamedBranch(db.DefaultContext, 1, "dev")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, true, exist)
|
||||
assert.True(t, exist)
|
||||
assert.Equal(t, "master", branch.To)
|
||||
|
||||
_, exist, err = git_model.FindRenamedBranch(db.DefaultContext, 1, "unknow")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, false, exist)
|
||||
assert.False(t, exist)
|
||||
}
|
||||
|
||||
func TestRenameBranch(t *testing.T) {
|
||||
@@ -115,7 +115,7 @@ func TestRenameBranch(t *testing.T) {
|
||||
return nil
|
||||
}))
|
||||
|
||||
assert.Equal(t, true, _isDefault)
|
||||
assert.True(t, _isDefault)
|
||||
repo1 = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
assert.Equal(t, "main", repo1.DefaultBranch)
|
||||
|
||||
|
||||
+70
-77
@@ -52,84 +52,61 @@ func (err ErrCommentNotExist) Unwrap() error {
|
||||
// CommentType defines whether a comment is just a simple comment, an action (like close) or a reference.
|
||||
type CommentType int
|
||||
|
||||
// define unknown comment type
|
||||
const (
|
||||
CommentTypeUnknown CommentType = -1
|
||||
)
|
||||
// CommentTypeUndefined is used to search for comments of any type
|
||||
const CommentTypeUndefined CommentType = -1
|
||||
|
||||
// Enumerate all the comment types
|
||||
const (
|
||||
// 0 Plain comment, can be associated with a commit (CommitID > 0) and a line (LineNum > 0)
|
||||
CommentTypeComment CommentType = iota
|
||||
CommentTypeReopen // 1
|
||||
CommentTypeClose // 2
|
||||
CommentTypeComment CommentType = iota // 0 Plain comment, can be associated with a commit (CommitID > 0) and a line (LineNum > 0)
|
||||
|
||||
CommentTypeReopen // 1
|
||||
CommentTypeClose // 2
|
||||
|
||||
CommentTypeIssueRef // 3 References.
|
||||
CommentTypeCommitRef // 4 Reference from a commit (not part of a pull request)
|
||||
CommentTypeCommentRef // 5 Reference from a comment
|
||||
CommentTypePullRef // 6 Reference from a pull request
|
||||
|
||||
CommentTypeLabel // 7 Labels changed
|
||||
CommentTypeMilestone // 8 Milestone changed
|
||||
CommentTypeAssignees // 9 Assignees changed
|
||||
CommentTypeChangeTitle // 10 Change Title
|
||||
CommentTypeDeleteBranch // 11 Delete Branch
|
||||
|
||||
CommentTypeStartTracking // 12 Start a stopwatch for time tracking
|
||||
CommentTypeStopTracking // 13 Stop a stopwatch for time tracking
|
||||
CommentTypeAddTimeManual // 14 Add time manual for time tracking
|
||||
CommentTypeCancelTracking // 15 Cancel a stopwatch for time tracking
|
||||
CommentTypeAddedDeadline // 16 Added a due date
|
||||
CommentTypeModifiedDeadline // 17 Modified the due date
|
||||
CommentTypeRemovedDeadline // 18 Removed a due date
|
||||
|
||||
CommentTypeAddDependency // 19 Dependency added
|
||||
CommentTypeRemoveDependency // 20 Dependency removed
|
||||
|
||||
CommentTypeCode // 21 Comment a line of code
|
||||
CommentTypeReview // 22 Reviews a pull request by giving general feedback
|
||||
|
||||
CommentTypeLock // 23 Lock an issue, giving only collaborators access
|
||||
CommentTypeUnlock // 24 Unlocks a previously locked issue
|
||||
|
||||
CommentTypeChangeTargetBranch // 25 Change pull request's target branch
|
||||
|
||||
CommentTypeDeleteTimeManual // 26 Delete time manual for time tracking
|
||||
|
||||
CommentTypeReviewRequest // 27 add or remove Request from one
|
||||
CommentTypeMergePull // 28 merge pull request
|
||||
CommentTypePullRequestPush // 29 push to PR head branch
|
||||
|
||||
CommentTypeProject // 30 Project changed
|
||||
CommentTypeProjectBoard // 31 Project board changed
|
||||
|
||||
CommentTypeDismissReview // 32 Dismiss Review
|
||||
|
||||
CommentTypeChangeIssueRef // 33 Change issue ref
|
||||
|
||||
CommentTypePRScheduledToAutoMerge // 34 pr was scheduled to auto merge when checks succeed
|
||||
CommentTypePRUnScheduledToAutoMerge // 35 pr was un scheduled to auto merge when checks succeed
|
||||
|
||||
// 3 References.
|
||||
CommentTypeIssueRef
|
||||
// 4 Reference from a commit (not part of a pull request)
|
||||
CommentTypeCommitRef
|
||||
// 5 Reference from a comment
|
||||
CommentTypeCommentRef
|
||||
// 6 Reference from a pull request
|
||||
CommentTypePullRef
|
||||
// 7 Labels changed
|
||||
CommentTypeLabel
|
||||
// 8 Milestone changed
|
||||
CommentTypeMilestone
|
||||
// 9 Assignees changed
|
||||
CommentTypeAssignees
|
||||
// 10 Change Title
|
||||
CommentTypeChangeTitle
|
||||
// 11 Delete Branch
|
||||
CommentTypeDeleteBranch
|
||||
// 12 Start a stopwatch for time tracking
|
||||
CommentTypeStartTracking
|
||||
// 13 Stop a stopwatch for time tracking
|
||||
CommentTypeStopTracking
|
||||
// 14 Add time manual for time tracking
|
||||
CommentTypeAddTimeManual
|
||||
// 15 Cancel a stopwatch for time tracking
|
||||
CommentTypeCancelTracking
|
||||
// 16 Added a due date
|
||||
CommentTypeAddedDeadline
|
||||
// 17 Modified the due date
|
||||
CommentTypeModifiedDeadline
|
||||
// 18 Removed a due date
|
||||
CommentTypeRemovedDeadline
|
||||
// 19 Dependency added
|
||||
CommentTypeAddDependency
|
||||
// 20 Dependency removed
|
||||
CommentTypeRemoveDependency
|
||||
// 21 Comment a line of code
|
||||
CommentTypeCode
|
||||
// 22 Reviews a pull request by giving general feedback
|
||||
CommentTypeReview
|
||||
// 23 Lock an issue, giving only collaborators access
|
||||
CommentTypeLock
|
||||
// 24 Unlocks a previously locked issue
|
||||
CommentTypeUnlock
|
||||
// 25 Change pull request's target branch
|
||||
CommentTypeChangeTargetBranch
|
||||
// 26 Delete time manual for time tracking
|
||||
CommentTypeDeleteTimeManual
|
||||
// 27 add or remove Request from one
|
||||
CommentTypeReviewRequest
|
||||
// 28 merge pull request
|
||||
CommentTypeMergePull
|
||||
// 29 push to PR head branch
|
||||
CommentTypePullRequestPush
|
||||
// 30 Project changed
|
||||
CommentTypeProject
|
||||
// 31 Project board changed
|
||||
CommentTypeProjectBoard
|
||||
// 32 Dismiss Review
|
||||
CommentTypeDismissReview
|
||||
// 33 Change issue ref
|
||||
CommentTypeChangeIssueRef
|
||||
// 34 pr was scheduled to auto merge when checks succeed
|
||||
CommentTypePRScheduledToAutoMerge
|
||||
// 35 pr was un scheduled to auto merge when checks succeed
|
||||
CommentTypePRUnScheduledToAutoMerge
|
||||
)
|
||||
|
||||
var commentStrings = []string{
|
||||
@@ -181,7 +158,23 @@ func AsCommentType(typeName string) CommentType {
|
||||
return CommentType(index)
|
||||
}
|
||||
}
|
||||
return CommentTypeUnknown
|
||||
return CommentTypeUndefined
|
||||
}
|
||||
|
||||
func (t CommentType) HasContentSupport() bool {
|
||||
switch t {
|
||||
case CommentTypeComment, CommentTypeCode, CommentTypeReview:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (t CommentType) HasAttachmentSupport() bool {
|
||||
switch t {
|
||||
case CommentTypeComment, CommentTypeCode, CommentTypeReview:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// RoleDescriptor defines comment tag type
|
||||
@@ -1039,7 +1032,7 @@ func (opts *FindCommentsOptions) ToConds() builder.Cond {
|
||||
if opts.Before > 0 {
|
||||
cond = cond.And(builder.Lte{"comment.updated_unix": opts.Before})
|
||||
}
|
||||
if opts.Type != CommentTypeUnknown {
|
||||
if opts.Type != CommentTypeUndefined {
|
||||
cond = cond.And(builder.Eq{"comment.type": opts.Type})
|
||||
}
|
||||
if opts.Line != 0 {
|
||||
|
||||
@@ -56,7 +56,7 @@ func (comments CommentList) getLabelIDs() []int64 {
|
||||
return ids.Values()
|
||||
}
|
||||
|
||||
func (comments CommentList) loadLabels(ctx context.Context) error { //nolint
|
||||
func (comments CommentList) loadLabels(ctx context.Context) error {
|
||||
if len(comments) == 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -415,7 +415,7 @@ func (comments CommentList) getReviewIDs() []int64 {
|
||||
return ids.Values()
|
||||
}
|
||||
|
||||
func (comments CommentList) loadReviews(ctx context.Context) error { //nolint
|
||||
func (comments CommentList) loadReviews(ctx context.Context) error {
|
||||
if len(comments) == 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -453,6 +453,14 @@ func (comments CommentList) loadReviews(ctx context.Context) error { //nolint
|
||||
|
||||
for _, comment := range comments {
|
||||
comment.Review = reviews[comment.ReviewID]
|
||||
|
||||
// If the comment dismisses a review, we need to load the reviewer to show whose review has been dismissed.
|
||||
// Otherwise, the reviewer is the poster of the comment, so we don't need to load it.
|
||||
if comment.Type == CommentTypeDismissReview {
|
||||
if err := comment.Review.LoadReviewer(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -64,8 +64,9 @@ func TestFetchCodeComments(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestAsCommentType(t *testing.T) {
|
||||
assert.Equal(t, issues_model.CommentTypeUnknown, issues_model.AsCommentType(""))
|
||||
assert.Equal(t, issues_model.CommentTypeUnknown, issues_model.AsCommentType("nonsense"))
|
||||
assert.Equal(t, issues_model.CommentType(0), issues_model.CommentTypeComment)
|
||||
assert.Equal(t, issues_model.CommentTypeUndefined, issues_model.AsCommentType(""))
|
||||
assert.Equal(t, issues_model.CommentTypeUndefined, issues_model.AsCommentType("nonsense"))
|
||||
assert.Equal(t, issues_model.CommentTypeComment, issues_model.AsCommentType("comment"))
|
||||
assert.Equal(t, issues_model.CommentTypePRUnScheduledToAutoMerge, issues_model.AsCommentType("pull_cancel_scheduled_merge"))
|
||||
}
|
||||
|
||||
@@ -269,7 +269,7 @@ func (issue *Issue) LoadPullRequest(ctx context.Context) (err error) {
|
||||
}
|
||||
|
||||
func (issue *Issue) loadComments(ctx context.Context) (err error) {
|
||||
return issue.loadCommentsByType(ctx, CommentTypeUnknown)
|
||||
return issue.loadCommentsByType(ctx, CommentTypeUndefined)
|
||||
}
|
||||
|
||||
// LoadDiscussComments loads discuss comments
|
||||
|
||||
@@ -109,11 +109,11 @@ func TestHasUnmergedPullRequestsByHeadInfo(t *testing.T) {
|
||||
|
||||
exist, err := issues_model.HasUnmergedPullRequestsByHeadInfo(db.DefaultContext, 1, "branch2")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, true, exist)
|
||||
assert.True(t, exist)
|
||||
|
||||
exist, err = issues_model.HasUnmergedPullRequestsByHeadInfo(db.DefaultContext, 1, "not_exist_branch")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, false, exist)
|
||||
assert.False(t, exist)
|
||||
}
|
||||
|
||||
func TestGetUnmergedPullRequestsByHeadInfo(t *testing.T) {
|
||||
|
||||
@@ -35,7 +35,7 @@ func TestAddTime(t *testing.T) {
|
||||
assert.Equal(t, int64(3661), tt.Time)
|
||||
|
||||
comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{Type: issues_model.CommentTypeAddTimeManual, PosterID: 3, IssueID: 1})
|
||||
assert.Equal(t, comment.Content, "1 hour 1 minute")
|
||||
assert.Equal(t, "1 hour 1 minute", comment.Content)
|
||||
}
|
||||
|
||||
func TestGetTrackedTimes(t *testing.T) {
|
||||
|
||||
@@ -165,11 +165,6 @@ func (log *TestLogger) Init(config string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Content returns the content accumulated in the content provider
|
||||
func (log *TestLogger) Content() (string, error) {
|
||||
return "", fmt.Errorf("not supported")
|
||||
}
|
||||
|
||||
// Flush when log should be flushed
|
||||
func (log *TestLogger) Flush() {
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright 2022 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
//nolint:forbidigo
|
||||
package base
|
||||
|
||||
import (
|
||||
|
||||
@@ -485,6 +485,8 @@ var migrations = []Migration{
|
||||
NewMigration("Fix incorrect admin team unit access mode", v1_20.FixIncorrectAdminTeamUnitAccessMode),
|
||||
// v253 -> v254
|
||||
NewMigration("Fix ExternalTracker and ExternalWiki accessMode in owner and admin team", v1_20.FixExternalTrackerAndExternalWikiAccessModeInOwnerAndAdminTeam),
|
||||
// v254 -> v255
|
||||
NewMigration("Add ActionTaskOutput table", v1_20.AddActionTaskOutputTable),
|
||||
// to modify later
|
||||
NewMigration("Add size limit on repository", v1_20.AddSizeLimitOnRepo),
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ func RemoveAttachmentMissedRepo(x *xorm.Engine) error {
|
||||
for i := 0; i < len(attachments); i++ {
|
||||
uuid := attachments[i].UUID
|
||||
if err = util.RemoveAll(filepath.Join(setting.Attachment.Path, uuid[0:1], uuid[1:2], uuid)); err != nil {
|
||||
fmt.Printf("Error: %v", err)
|
||||
fmt.Printf("Error: %v", err) //nolint:forbidigo
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,10 +22,10 @@ func FixLanguageStatsToSaveSize(x *xorm.Engine) error {
|
||||
type RepoIndexerType int
|
||||
|
||||
const (
|
||||
// RepoIndexerTypeCode code indexer
|
||||
RepoIndexerTypeCode RepoIndexerType = iota // 0
|
||||
// RepoIndexerTypeStats repository stats indexer
|
||||
RepoIndexerTypeStats // 1
|
||||
// RepoIndexerTypeCode code indexer - 0
|
||||
RepoIndexerTypeCode RepoIndexerType = iota //nolint:unused
|
||||
// RepoIndexerTypeStats repository stats indexer - 1
|
||||
RepoIndexerTypeStats
|
||||
)
|
||||
|
||||
// RepoIndexerStatus see models/repo_indexer.go
|
||||
|
||||
@@ -8,13 +8,13 @@ import (
|
||||
)
|
||||
|
||||
func FixRepoTopics(x *xorm.Engine) error {
|
||||
type Topic struct {
|
||||
type Topic struct { //nolint:unused
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
Name string `xorm:"UNIQUE VARCHAR(25)"`
|
||||
RepoCount int
|
||||
}
|
||||
|
||||
type RepoTopic struct {
|
||||
type RepoTopic struct { //nolint:unused
|
||||
RepoID int64 `xorm:"pk"`
|
||||
TopicID int64 `xorm:"pk"`
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ func ConvertHookTaskTypeToVarcharAndTrim(x *xorm.Engine) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type HookTask struct {
|
||||
type HookTask struct { //nolint:unused
|
||||
Typ string `xorm:"VARCHAR(16) index"`
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ func ConvertHookTaskTypeToVarcharAndTrim(x *xorm.Engine) error {
|
||||
return err
|
||||
}
|
||||
|
||||
type Webhook struct {
|
||||
type Webhook struct { //nolint:unused
|
||||
Type string `xorm:"VARCHAR(16) index"`
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package v1_20 //nolint
|
||||
|
||||
import (
|
||||
"xorm.io/xorm"
|
||||
)
|
||||
|
||||
func AddActionTaskOutputTable(x *xorm.Engine) error {
|
||||
type ActionTaskOutput struct {
|
||||
ID int64
|
||||
TaskID int64 `xorm:"INDEX UNIQUE(task_id_output_key)"`
|
||||
OutputKey string `xorm:"VARCHAR(255) UNIQUE(task_id_output_key)"`
|
||||
OutputValue string `xorm:"MEDIUMTEXT"`
|
||||
}
|
||||
return x.Sync(new(ActionTaskOutput))
|
||||
}
|
||||
+14
-4
@@ -414,10 +414,17 @@ func DeleteTeam(t *organization.Team) error {
|
||||
&organization.TeamUser{OrgID: t.OrgID, TeamID: t.ID},
|
||||
&organization.TeamUnit{TeamID: t.ID},
|
||||
&organization.TeamInvite{TeamID: t.ID},
|
||||
&issues_model.Review{Type: issues_model.ReviewTypeRequest, ReviewerTeamID: t.ID}, // batch delete the binding relationship between team and PR (request review from team)
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, tm := range t.Members {
|
||||
if err := removeInvalidOrgUser(ctx, tm.ID, t.OrgID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Update organization number of teams.
|
||||
if _, err := db.Exec(ctx, "UPDATE `user` SET num_teams=num_teams-1 WHERE id=?", t.OrgID); err != nil {
|
||||
return err
|
||||
@@ -567,16 +574,19 @@ func removeTeamMember(ctx context.Context, team *organization.Team, userID int64
|
||||
}
|
||||
}
|
||||
|
||||
return removeInvalidOrgUser(ctx, userID, team.OrgID)
|
||||
}
|
||||
|
||||
func removeInvalidOrgUser(ctx context.Context, userID, orgID int64) error {
|
||||
// Check if the user is a member of any team in the organization.
|
||||
if count, err := e.Count(&organization.TeamUser{
|
||||
if count, err := db.GetEngine(ctx).Count(&organization.TeamUser{
|
||||
UID: userID,
|
||||
OrgID: team.OrgID,
|
||||
OrgID: orgID,
|
||||
}); err != nil {
|
||||
return err
|
||||
} else if count == 0 {
|
||||
return removeOrgUser(ctx, team.OrgID, userID)
|
||||
return removeOrgUser(ctx, orgID, userID)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -342,11 +342,15 @@ func CreateOrganization(org *Organization, owner *user_model.User) (err error) {
|
||||
// insert units for team
|
||||
units := make([]TeamUnit, 0, len(unit.AllRepoUnitTypes))
|
||||
for _, tp := range unit.AllRepoUnitTypes {
|
||||
up := perm.AccessModeOwner
|
||||
if tp == unit.TypeExternalTracker || tp == unit.TypeExternalWiki {
|
||||
up = perm.AccessModeRead
|
||||
}
|
||||
units = append(units, TeamUnit{
|
||||
OrgID: org.ID,
|
||||
TeamID: t.ID,
|
||||
Type: tp,
|
||||
AccessMode: perm.AccessModeOwner,
|
||||
AccessMode: up,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
+7
-1
@@ -226,6 +226,12 @@ func (repo *Repository) IsBroken() bool {
|
||||
return repo.Status == RepositoryBroken
|
||||
}
|
||||
|
||||
// MarkAsBrokenEmpty marks the repo as broken and empty
|
||||
func (repo *Repository) MarkAsBrokenEmpty() {
|
||||
repo.Status = RepositoryBroken
|
||||
repo.IsEmpty = true
|
||||
}
|
||||
|
||||
// AfterLoad is invoked from XORM after setting the values of all fields of this object.
|
||||
func (repo *Repository) AfterLoad() {
|
||||
repo.NumOpenIssues = repo.NumIssues - repo.NumClosedIssues
|
||||
@@ -769,7 +775,7 @@ func IsRepositoryExist(ctx context.Context, u *user_model.User, repoName string)
|
||||
return false, err
|
||||
}
|
||||
isDir, err := util.IsDir(RepoPath(u.Name, repoName))
|
||||
return has && isDir, err
|
||||
return has || isDir, err
|
||||
}
|
||||
|
||||
// GetTemplateRepo populates repo.TemplateRepo for a generated repository and
|
||||
|
||||
@@ -235,12 +235,12 @@ func TestSearchRepository(t *testing.T) {
|
||||
{
|
||||
name: "AllPublic/PublicRepositoriesOfUserIncludingCollaborative",
|
||||
opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, AllPublic: true, Template: util.OptionalBoolFalse},
|
||||
count: 29,
|
||||
count: 30,
|
||||
},
|
||||
{
|
||||
name: "AllPublic/PublicAndPrivateRepositoriesOfUserIncludingCollaborative",
|
||||
opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, Private: true, AllPublic: true, AllLimited: true, Template: util.OptionalBoolFalse},
|
||||
count: 34,
|
||||
count: 35,
|
||||
},
|
||||
{
|
||||
name: "AllPublic/PublicAndPrivateRepositoriesOfUserIncludingCollaborativeByName",
|
||||
@@ -255,7 +255,7 @@ func TestSearchRepository(t *testing.T) {
|
||||
{
|
||||
name: "AllPublic/PublicRepositoriesOfOrganization",
|
||||
opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 17, AllPublic: true, Collaborate: util.OptionalBoolFalse, Template: util.OptionalBoolFalse},
|
||||
count: 29,
|
||||
count: 30,
|
||||
},
|
||||
{
|
||||
name: "AllTemplates",
|
||||
|
||||
@@ -152,7 +152,7 @@ func init() {
|
||||
Query()
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.EqualValues(t, label.int("NumIssues"), len(issueLabels), "Unexpected number of issue for label id: %d", label.int("ID"))
|
||||
assert.Len(t, issueLabels, label.int("NumIssues"), "Unexpected number of issue for label id: %d", label.int("ID"))
|
||||
|
||||
issueIDs := make([]int, len(issueLabels))
|
||||
for i, issueLabel := range issueLabels {
|
||||
|
||||
+10
-11
@@ -1,6 +1,7 @@
|
||||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
//nolint:forbidigo
|
||||
package unittest
|
||||
|
||||
import (
|
||||
@@ -17,7 +18,7 @@ import (
|
||||
"xorm.io/xorm/schemas"
|
||||
)
|
||||
|
||||
var fixtures *testfixtures.Loader
|
||||
var fixturesLoader *testfixtures.Loader
|
||||
|
||||
// GetXORMEngine gets the XORM engine
|
||||
func GetXORMEngine(engine ...*xorm.Engine) (x *xorm.Engine) {
|
||||
@@ -30,11 +31,11 @@ func GetXORMEngine(engine ...*xorm.Engine) (x *xorm.Engine) {
|
||||
// InitFixtures initialize test fixtures for a test database
|
||||
func InitFixtures(opts FixturesOptions, engine ...*xorm.Engine) (err error) {
|
||||
e := GetXORMEngine(engine...)
|
||||
var testfiles func(*testfixtures.Loader) error
|
||||
var fixtureOptionFiles func(*testfixtures.Loader) error
|
||||
if opts.Dir != "" {
|
||||
testfiles = testfixtures.Directory(opts.Dir)
|
||||
fixtureOptionFiles = testfixtures.Directory(opts.Dir)
|
||||
} else {
|
||||
testfiles = testfixtures.Files(opts.Files...)
|
||||
fixtureOptionFiles = testfixtures.Files(opts.Files...)
|
||||
}
|
||||
dialect := "unknown"
|
||||
switch e.Dialect().URI().DBType {
|
||||
@@ -54,14 +55,14 @@ func InitFixtures(opts FixturesOptions, engine ...*xorm.Engine) (err error) {
|
||||
testfixtures.Database(e.DB().DB),
|
||||
testfixtures.Dialect(dialect),
|
||||
testfixtures.DangerousSkipTestDatabaseCheck(),
|
||||
testfiles,
|
||||
fixtureOptionFiles,
|
||||
}
|
||||
|
||||
if e.Dialect().URI().DBType == schemas.POSTGRES {
|
||||
loaderOptions = append(loaderOptions, testfixtures.SkipResetSequences())
|
||||
}
|
||||
|
||||
fixtures, err = testfixtures.New(loaderOptions...)
|
||||
fixturesLoader, err = testfixtures.New(loaderOptions...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -78,11 +79,9 @@ func InitFixtures(opts FixturesOptions, engine ...*xorm.Engine) (err error) {
|
||||
func LoadFixtures(engine ...*xorm.Engine) error {
|
||||
e := GetXORMEngine(engine...)
|
||||
var err error
|
||||
// Database transaction conflicts could occur and result in ROLLBACK
|
||||
// As a simple workaround, we just retry 20 times.
|
||||
for i := 0; i < 20; i++ {
|
||||
err = fixtures.Load()
|
||||
if err == nil {
|
||||
// (doubt) database transaction conflicts could occur and result in ROLLBACK? just try for a few times.
|
||||
for i := 0; i < 5; i++ {
|
||||
if err = fixturesLoader.Load(); err == nil {
|
||||
break
|
||||
}
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
|
||||
@@ -17,7 +17,7 @@ type Badge struct {
|
||||
}
|
||||
|
||||
// UserBadge represents a user badge
|
||||
type UserBadge struct {
|
||||
type UserBadge struct { //nolint:revive
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
BadgeID int64
|
||||
UserID int64 `xorm:"INDEX"`
|
||||
|
||||
+1
-1
@@ -62,7 +62,7 @@ const (
|
||||
EmailNotificationsOnMention = "onmention"
|
||||
// EmailNotificationsDisabled indicates that the user would not like to be notified via email.
|
||||
EmailNotificationsDisabled = "disabled"
|
||||
// EmailNotificationsEnabled indicates that the user would like to receive all email notifications and your own
|
||||
// EmailNotificationsAndYourOwn indicates that the user would like to receive all email notifications and your own
|
||||
EmailNotificationsAndYourOwn = "andyourown"
|
||||
)
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ package user_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -35,10 +36,10 @@ func TestGetUserEmailsByNames(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
// ignore none active user email
|
||||
assert.Equal(t, []string{"user8@example.com"}, user_model.GetUserEmailsByNames(db.DefaultContext, []string{"user8", "user9"}))
|
||||
assert.Equal(t, []string{"user8@example.com", "user5@example.com"}, user_model.GetUserEmailsByNames(db.DefaultContext, []string{"user8", "user5"}))
|
||||
assert.ElementsMatch(t, []string{"user8@example.com"}, user_model.GetUserEmailsByNames(db.DefaultContext, []string{"user8", "user9"}))
|
||||
assert.ElementsMatch(t, []string{"user8@example.com", "user5@example.com"}, user_model.GetUserEmailsByNames(db.DefaultContext, []string{"user8", "user5"}))
|
||||
|
||||
assert.Equal(t, []string{"user8@example.com"}, user_model.GetUserEmailsByNames(db.DefaultContext, []string{"user8", "user7"}))
|
||||
assert.ElementsMatch(t, []string{"user8@example.com"}, user_model.GetUserEmailsByNames(db.DefaultContext, []string{"user8", "user7"}))
|
||||
}
|
||||
|
||||
func TestCanCreateOrganization(t *testing.T) {
|
||||
@@ -64,9 +65,10 @@ func TestSearchUsers(t *testing.T) {
|
||||
testSuccess := func(opts *user_model.SearchUserOptions, expectedUserOrOrgIDs []int64) {
|
||||
users, _, err := user_model.SearchUsers(opts)
|
||||
assert.NoError(t, err)
|
||||
if assert.Len(t, users, len(expectedUserOrOrgIDs), opts) {
|
||||
cassText := fmt.Sprintf("ids: %v, opts: %v", expectedUserOrOrgIDs, opts)
|
||||
if assert.Len(t, users, len(expectedUserOrOrgIDs), "case: %s", cassText) {
|
||||
for i, expectedID := range expectedUserOrOrgIDs {
|
||||
assert.EqualValues(t, expectedID, users[i].ID)
|
||||
assert.EqualValues(t, expectedID, users[i].ID, "case: %s", cassText)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -118,7 +120,7 @@ func TestSearchUsers(t *testing.T) {
|
||||
[]int64{1})
|
||||
|
||||
testUserSuccess(&user_model.SearchUserOptions{ListOptions: db.ListOptions{Page: 1}, IsRestricted: util.OptionalBoolTrue},
|
||||
[]int64{29, 30})
|
||||
[]int64{29})
|
||||
|
||||
testUserSuccess(&user_model.SearchUserOptions{ListOptions: db.ListOptions{Page: 1}, IsProhibitLogin: util.OptionalBoolTrue},
|
||||
[]int64{30})
|
||||
|
||||
@@ -29,6 +29,14 @@ func init() {
|
||||
}
|
||||
}
|
||||
|
||||
func IsWorkflow(path string) bool {
|
||||
if (!strings.HasSuffix(path, ".yaml")) && (!strings.HasSuffix(path, ".yml")) {
|
||||
return false
|
||||
}
|
||||
|
||||
return strings.HasPrefix(path, ".gitea/workflows") || strings.HasPrefix(path, ".github/workflows")
|
||||
}
|
||||
|
||||
func ListWorkflows(commit *git.Commit) (git.Entries, error) {
|
||||
tree, err := commit.SubTree(".gitea/workflows")
|
||||
if _, ok := err.(git.ErrNotExist); ok {
|
||||
|
||||
@@ -18,6 +18,8 @@ import (
|
||||
|
||||
"github.com/nfnt/resize"
|
||||
"github.com/oliamb/cutter"
|
||||
|
||||
_ "golang.org/x/image/webp" // for processing webp images
|
||||
)
|
||||
|
||||
// AvatarSize returns avatar's size
|
||||
|
||||
@@ -47,7 +47,9 @@ func (e *escapeStreamer) EscapeStatus() *EscapeStatus {
|
||||
// Text tells the next streamer there is a text
|
||||
func (e *escapeStreamer) Text(data string) error {
|
||||
sb := &strings.Builder{}
|
||||
pos, until, next := 0, 0, 0
|
||||
var until int
|
||||
var next int
|
||||
pos := 0
|
||||
if len(data) > len(UTF8BOM) && data[:len(UTF8BOM)] == string(UTF8BOM) {
|
||||
_, _ = sb.WriteString(data[:len(UTF8BOM)])
|
||||
pos = len(UTF8BOM)
|
||||
|
||||
@@ -1,194 +0,0 @@
|
||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||
// Copyright 2019 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package context
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/models/auth"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/web/middleware"
|
||||
)
|
||||
|
||||
// ToggleOptions contains required or check options
|
||||
type ToggleOptions struct {
|
||||
SignInRequired bool
|
||||
SignOutRequired bool
|
||||
AdminRequired bool
|
||||
DisableCSRF bool
|
||||
}
|
||||
|
||||
// Toggle returns toggle options as middleware
|
||||
func Toggle(options *ToggleOptions) func(ctx *Context) {
|
||||
return func(ctx *Context) {
|
||||
// Check prohibit login users.
|
||||
if ctx.IsSigned {
|
||||
if !ctx.Doer.IsActive && setting.Service.RegisterEmailConfirm {
|
||||
ctx.Data["Title"] = ctx.Tr("auth.active_your_account")
|
||||
ctx.HTML(http.StatusOK, "user/auth/activate")
|
||||
return
|
||||
}
|
||||
if !ctx.Doer.IsActive || ctx.Doer.ProhibitLogin {
|
||||
log.Info("Failed authentication attempt for %s from %s", ctx.Doer.Name, ctx.RemoteAddr())
|
||||
ctx.Data["Title"] = ctx.Tr("auth.prohibit_login")
|
||||
ctx.HTML(http.StatusOK, "user/auth/prohibit_login")
|
||||
return
|
||||
}
|
||||
|
||||
if ctx.Doer.MustChangePassword {
|
||||
if ctx.Req.URL.Path != "/user/settings/change_password" {
|
||||
if strings.HasPrefix(ctx.Req.UserAgent(), "git") {
|
||||
ctx.Error(http.StatusUnauthorized, ctx.Tr("auth.must_change_password"))
|
||||
return
|
||||
}
|
||||
ctx.Data["Title"] = ctx.Tr("auth.must_change_password")
|
||||
ctx.Data["ChangePasscodeLink"] = setting.AppSubURL + "/user/change_password"
|
||||
if ctx.Req.URL.Path != "/user/events" {
|
||||
middleware.SetRedirectToCookie(ctx.Resp, setting.AppSubURL+ctx.Req.URL.RequestURI())
|
||||
}
|
||||
ctx.Redirect(setting.AppSubURL + "/user/settings/change_password")
|
||||
return
|
||||
}
|
||||
} else if ctx.Req.URL.Path == "/user/settings/change_password" {
|
||||
// make sure that the form cannot be accessed by users who don't need this
|
||||
ctx.Redirect(setting.AppSubURL + "/")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Redirect to dashboard if user tries to visit any non-login page.
|
||||
if options.SignOutRequired && ctx.IsSigned && ctx.Req.URL.RequestURI() != "/" {
|
||||
ctx.Redirect(setting.AppSubURL + "/")
|
||||
return
|
||||
}
|
||||
|
||||
if !options.SignOutRequired && !options.DisableCSRF && ctx.Req.Method == "POST" {
|
||||
ctx.Csrf.Validate(ctx)
|
||||
if ctx.Written() {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if options.SignInRequired {
|
||||
if !ctx.IsSigned {
|
||||
if ctx.Req.URL.Path != "/user/events" {
|
||||
middleware.SetRedirectToCookie(ctx.Resp, setting.AppSubURL+ctx.Req.URL.RequestURI())
|
||||
}
|
||||
ctx.Redirect(setting.AppSubURL + "/user/login")
|
||||
return
|
||||
} else if !ctx.Doer.IsActive && setting.Service.RegisterEmailConfirm {
|
||||
ctx.Data["Title"] = ctx.Tr("auth.active_your_account")
|
||||
ctx.HTML(http.StatusOK, "user/auth/activate")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Redirect to log in page if auto-signin info is provided and has not signed in.
|
||||
if !options.SignOutRequired && !ctx.IsSigned &&
|
||||
len(ctx.GetSiteCookie(setting.CookieUserName)) > 0 {
|
||||
if ctx.Req.URL.Path != "/user/events" {
|
||||
middleware.SetRedirectToCookie(ctx.Resp, setting.AppSubURL+ctx.Req.URL.RequestURI())
|
||||
}
|
||||
ctx.Redirect(setting.AppSubURL + "/user/login")
|
||||
return
|
||||
}
|
||||
|
||||
if options.AdminRequired {
|
||||
if !ctx.Doer.IsAdmin {
|
||||
ctx.Error(http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
ctx.Data["PageIsAdmin"] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ToggleAPI returns toggle options as middleware
|
||||
func ToggleAPI(options *ToggleOptions) func(ctx *APIContext) {
|
||||
return func(ctx *APIContext) {
|
||||
// Check prohibit login users.
|
||||
if ctx.IsSigned {
|
||||
if !ctx.Doer.IsActive && setting.Service.RegisterEmailConfirm {
|
||||
ctx.Data["Title"] = ctx.Tr("auth.active_your_account")
|
||||
ctx.JSON(http.StatusForbidden, map[string]string{
|
||||
"message": "This account is not activated.",
|
||||
})
|
||||
return
|
||||
}
|
||||
if !ctx.Doer.IsActive || ctx.Doer.ProhibitLogin {
|
||||
log.Info("Failed authentication attempt for %s from %s", ctx.Doer.Name, ctx.RemoteAddr())
|
||||
ctx.Data["Title"] = ctx.Tr("auth.prohibit_login")
|
||||
ctx.JSON(http.StatusForbidden, map[string]string{
|
||||
"message": "This account is prohibited from signing in, please contact your site administrator.",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if ctx.Doer.MustChangePassword {
|
||||
ctx.JSON(http.StatusForbidden, map[string]string{
|
||||
"message": "You must change your password. Change it at: " + setting.AppURL + "/user/change_password",
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Redirect to dashboard if user tries to visit any non-login page.
|
||||
if options.SignOutRequired && ctx.IsSigned && ctx.Req.URL.RequestURI() != "/" {
|
||||
ctx.Redirect(setting.AppSubURL + "/")
|
||||
return
|
||||
}
|
||||
|
||||
if options.SignInRequired {
|
||||
if !ctx.IsSigned {
|
||||
// Restrict API calls with error message.
|
||||
ctx.JSON(http.StatusForbidden, map[string]string{
|
||||
"message": "Only signed in user is allowed to call APIs.",
|
||||
})
|
||||
return
|
||||
} else if !ctx.Doer.IsActive && setting.Service.RegisterEmailConfirm {
|
||||
ctx.Data["Title"] = ctx.Tr("auth.active_your_account")
|
||||
ctx.HTML(http.StatusOK, "user/auth/activate")
|
||||
return
|
||||
}
|
||||
if ctx.IsSigned && ctx.IsBasicAuth {
|
||||
if skip, ok := ctx.Data["SkipLocalTwoFA"]; ok && skip.(bool) {
|
||||
return // Skip 2FA
|
||||
}
|
||||
twofa, err := auth.GetTwoFactorByUID(ctx.Doer.ID)
|
||||
if err != nil {
|
||||
if auth.IsErrTwoFactorNotEnrolled(err) {
|
||||
return // No 2FA enrollment for this user
|
||||
}
|
||||
ctx.InternalServerError(err)
|
||||
return
|
||||
}
|
||||
otpHeader := ctx.Req.Header.Get("X-Gitea-OTP")
|
||||
ok, err := twofa.ValidateTOTP(otpHeader)
|
||||
if err != nil {
|
||||
ctx.InternalServerError(err)
|
||||
return
|
||||
}
|
||||
if !ok {
|
||||
ctx.JSON(http.StatusForbidden, map[string]string{
|
||||
"message": "Only signed in user is allowed to call APIs.",
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if options.AdminRequired {
|
||||
if !ctx.Doer.IsAdmin {
|
||||
ctx.JSON(http.StatusForbidden, map[string]string{
|
||||
"message": "You have no permission to request for this.",
|
||||
})
|
||||
return
|
||||
}
|
||||
ctx.Data["PageIsAdmin"] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -47,7 +47,7 @@ const CookieNameFlash = "gitea_flash"
|
||||
|
||||
// Render represents a template render
|
||||
type Render interface {
|
||||
TemplateLookup(tmpl string) (*template.Template, error)
|
||||
TemplateLookup(tmpl string) (templates.TemplateExecutor, error)
|
||||
HTML(w io.Writer, status int, name string, data interface{}) error
|
||||
}
|
||||
|
||||
@@ -301,7 +301,7 @@ func (ctx *Context) serverErrorInternal(logMsg string, logErr error) {
|
||||
|
||||
// it's safe to show internal error to admin users, and it helps
|
||||
if !setting.IsProd || (ctx.Doer != nil && ctx.Doer.IsAdmin) {
|
||||
ctx.Data["ErrorMsg"] = logErr
|
||||
ctx.Data["ErrorMsg"] = fmt.Sprintf("%s, %s", logMsg, logErr)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -741,8 +741,7 @@ func Contexter(ctx context.Context) func(next http.Handler) http.Handler {
|
||||
|
||||
ctx.Data["ShowRegistrationButton"] = setting.Service.ShowRegistrationButton
|
||||
ctx.Data["ShowMilestonesDashboardPage"] = setting.Service.ShowMilestonesDashboardPage
|
||||
ctx.Data["ShowFooterBranding"] = setting.ShowFooterBranding
|
||||
ctx.Data["ShowFooterVersion"] = setting.ShowFooterVersion
|
||||
ctx.Data["ShowFooterVersion"] = setting.Other.ShowFooterVersion
|
||||
|
||||
ctx.Data["EnableSwagger"] = setting.API.EnableSwagger
|
||||
ctx.Data["EnableOpenIDSignIn"] = setting.Service.EnableOpenIDSignIn
|
||||
|
||||
+25
-16
@@ -184,6 +184,9 @@ func (r *Repository) CanCreateIssueDependencies(user *user_model.User, isPull bo
|
||||
|
||||
// GetCommitsCount returns cached commit count for current view
|
||||
func (r *Repository) GetCommitsCount() (int64, error) {
|
||||
if r.Commit == nil {
|
||||
return 0, nil
|
||||
}
|
||||
var contextName string
|
||||
if r.IsViewBranch {
|
||||
contextName = r.BranchName
|
||||
@@ -449,7 +452,7 @@ func RepoAssignment(ctx *Context) (cancel context.CancelFunc) {
|
||||
userName := ctx.Params(":username")
|
||||
repoName := ctx.Params(":reponame")
|
||||
repoName = strings.TrimSuffix(repoName, ".git")
|
||||
if setting.EnableFeed {
|
||||
if setting.Other.EnableFeed {
|
||||
repoName = strings.TrimSuffix(repoName, ".rss")
|
||||
repoName = strings.TrimSuffix(repoName, ".atom")
|
||||
}
|
||||
@@ -537,7 +540,7 @@ func RepoAssignment(ctx *Context) (cancel context.CancelFunc) {
|
||||
ctx.Data["RepoLink"] = ctx.Repo.RepoLink
|
||||
ctx.Data["RepoRelPath"] = ctx.Repo.Owner.Name + "/" + ctx.Repo.Repository.Name
|
||||
|
||||
if setting.EnableFeed {
|
||||
if setting.Other.EnableFeed {
|
||||
ctx.Data["EnableFeed"] = true
|
||||
ctx.Data["FeedURL"] = ctx.Repo.RepoLink
|
||||
}
|
||||
@@ -642,8 +645,7 @@ func RepoAssignment(ctx *Context) (cancel context.CancelFunc) {
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "repository does not exist") || strings.Contains(err.Error(), "no such file or directory") {
|
||||
log.Error("Repository %-v has a broken repository on the file system: %s Error: %v", ctx.Repo.Repository, ctx.Repo.Repository.RepoPath(), err)
|
||||
ctx.Repo.Repository.Status = repo_model.RepositoryBroken
|
||||
ctx.Repo.Repository.IsEmpty = true
|
||||
ctx.Repo.Repository.MarkAsBrokenEmpty()
|
||||
ctx.Data["BranchName"] = ctx.Repo.Repository.DefaultBranch
|
||||
// Only allow access to base of repo or settings
|
||||
if !isHomeOrSettings {
|
||||
@@ -689,7 +691,7 @@ func RepoAssignment(ctx *Context) (cancel context.CancelFunc) {
|
||||
ctx.Data["BranchesCount"] = len(brs)
|
||||
|
||||
// If not branch selected, try default one.
|
||||
// If default branch doesn't exists, fall back to some other branch.
|
||||
// If default branch doesn't exist, fall back to some other branch.
|
||||
if len(ctx.Repo.BranchName) == 0 {
|
||||
if len(ctx.Repo.Repository.DefaultBranch) > 0 && gitRepo.IsBranchExist(ctx.Repo.Repository.DefaultBranch) {
|
||||
ctx.Repo.BranchName = ctx.Repo.Repository.DefaultBranch
|
||||
@@ -878,6 +880,10 @@ func RepoRefByType(refType RepoRefType, ignoreNotExistErr ...bool) func(*Context
|
||||
return func(ctx *Context) (cancel context.CancelFunc) {
|
||||
// Empty repository does not have reference information.
|
||||
if ctx.Repo.Repository.IsEmpty {
|
||||
// assume the user is viewing the (non-existent) default branch
|
||||
ctx.Repo.IsViewBranch = true
|
||||
ctx.Repo.BranchName = ctx.Repo.Repository.DefaultBranch
|
||||
ctx.Data["TreePath"] = ""
|
||||
return
|
||||
}
|
||||
|
||||
@@ -907,27 +913,30 @@ func RepoRefByType(refType RepoRefType, ignoreNotExistErr ...bool) func(*Context
|
||||
refName = ctx.Repo.Repository.DefaultBranch
|
||||
if !ctx.Repo.GitRepo.IsBranchExist(refName) {
|
||||
brs, _, err := ctx.Repo.GitRepo.GetBranchNames(0, 0)
|
||||
if err != nil {
|
||||
ctx.ServerError("GetBranches", err)
|
||||
return
|
||||
if err == nil && len(brs) != 0 {
|
||||
refName = brs[0]
|
||||
} else if len(brs) == 0 {
|
||||
err = fmt.Errorf("No branches in non-empty repository %s",
|
||||
ctx.Repo.GitRepo.Path)
|
||||
ctx.ServerError("GetBranches", err)
|
||||
return
|
||||
log.Error("No branches in non-empty repository %s", ctx.Repo.GitRepo.Path)
|
||||
ctx.Repo.Repository.MarkAsBrokenEmpty()
|
||||
} else {
|
||||
log.Error("GetBranches error: %v", err)
|
||||
ctx.Repo.Repository.MarkAsBrokenEmpty()
|
||||
}
|
||||
refName = brs[0]
|
||||
}
|
||||
ctx.Repo.RefName = refName
|
||||
ctx.Repo.BranchName = refName
|
||||
ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetBranchCommit(refName)
|
||||
if err != nil {
|
||||
if err == nil {
|
||||
ctx.Repo.CommitID = ctx.Repo.Commit.ID.String()
|
||||
} else if strings.Contains(err.Error(), "fatal: not a git repository") || strings.Contains(err.Error(), "object does not exist") {
|
||||
// if the repository is broken, we can continue to the handler code, to show "Settings -> Delete Repository" for end users
|
||||
log.Error("GetBranchCommit: %v", err)
|
||||
ctx.Repo.Repository.MarkAsBrokenEmpty()
|
||||
} else {
|
||||
ctx.ServerError("GetBranchCommit", err)
|
||||
return
|
||||
}
|
||||
ctx.Repo.CommitID = ctx.Repo.Commit.ID.String()
|
||||
ctx.Repo.IsViewBranch = true
|
||||
|
||||
} else {
|
||||
refName = getRefName(ctx, refType)
|
||||
ctx.Repo.RefName = refName
|
||||
|
||||
@@ -106,7 +106,7 @@ func isWritableDir(path string) error {
|
||||
return err
|
||||
}
|
||||
if err := os.Remove(tmpFile.Name()); err != nil {
|
||||
fmt.Printf("Warning: can't remove temporary file: '%s'\n", tmpFile.Name())
|
||||
fmt.Printf("Warning: can't remove temporary file: '%s'\n", tmpFile.Name()) //nolint:forbidigo
|
||||
}
|
||||
tmpFile.Close()
|
||||
return nil
|
||||
|
||||
+12
-4
@@ -211,10 +211,18 @@ type RunOpts struct {
|
||||
Env []string
|
||||
Timeout time.Duration
|
||||
UseContextTimeout bool
|
||||
Dir string
|
||||
Stdout, Stderr io.Writer
|
||||
Stdin io.Reader
|
||||
PipelineFunc func(context.Context, context.CancelFunc) error
|
||||
|
||||
// Dir is the working dir for the git command, however:
|
||||
// FIXME: this could be incorrect in many cases, for example:
|
||||
// * /some/path/.git
|
||||
// * /some/path/.git/gitea-data/data/repositories/user/repo.git
|
||||
// If "user/repo.git" is invalid/broken, then running git command in it will use "/some/path/.git", and produce unexpected results
|
||||
// The correct approach is to use `--git-dir" global argument
|
||||
Dir string
|
||||
|
||||
Stdout, Stderr io.Writer
|
||||
Stdin io.Reader
|
||||
PipelineFunc func(context.Context, context.CancelFunc) error
|
||||
}
|
||||
|
||||
func commonBaseEnvs() []string {
|
||||
|
||||
+1
-1
@@ -80,7 +80,7 @@ func InitRepository(ctx context.Context, repoPath string, bare bool) error {
|
||||
// IsEmpty Check if repository is empty.
|
||||
func (repo *Repository) IsEmpty() (bool, error) {
|
||||
var errbuf, output strings.Builder
|
||||
if err := NewCommand(repo.Ctx, "show-ref", "--head", "^HEAD$").
|
||||
if err := NewCommand(repo.Ctx).AddOptionFormat("--git-dir=%s", repo.Path).AddArguments("show-ref", "--head", "^HEAD$").
|
||||
Run(&RunOpts{
|
||||
Dir: repo.Path,
|
||||
Stdout: &output,
|
||||
|
||||
@@ -19,7 +19,7 @@ func Test_nulSeparatedAttributeWriter_ReadAttribute(t *testing.T) {
|
||||
|
||||
n, err := wr.Write([]byte(testStr))
|
||||
|
||||
assert.Equal(t, n, len(testStr))
|
||||
assert.Len(t, testStr, n)
|
||||
assert.NoError(t, err)
|
||||
select {
|
||||
case attr := <-wr.ReadAttribute():
|
||||
@@ -32,7 +32,7 @@ func Test_nulSeparatedAttributeWriter_ReadAttribute(t *testing.T) {
|
||||
// Write a second attribute again
|
||||
n, err = wr.Write([]byte(testStr))
|
||||
|
||||
assert.Equal(t, n, len(testStr))
|
||||
assert.Len(t, testStr, n)
|
||||
assert.NoError(t, err)
|
||||
|
||||
select {
|
||||
|
||||
@@ -61,7 +61,7 @@ func OpenRepository(ctx context.Context, repoPath string) (*Repository, error) {
|
||||
}
|
||||
|
||||
repo.batchWriter, repo.batchReader, repo.batchCancel = CatFileBatch(ctx, repoPath)
|
||||
repo.checkWriter, repo.checkReader, repo.checkCancel = CatFileBatchCheck(ctx, repo.Path)
|
||||
repo.checkWriter, repo.checkReader, repo.checkCancel = CatFileBatchCheck(ctx, repoPath)
|
||||
|
||||
return repo, nil
|
||||
}
|
||||
|
||||
@@ -84,6 +84,9 @@ func (repo *Repository) GetCommitByPath(relpath string) (*Commit, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(commits) == 0 {
|
||||
return nil, ErrNotExist{ID: relpath}
|
||||
}
|
||||
return commits[0], nil
|
||||
}
|
||||
|
||||
|
||||
@@ -97,6 +97,6 @@ func TestRepository_CommitsBetweenIDs(t *testing.T) {
|
||||
for i, c := range cases {
|
||||
commits, err := bareRepo1.CommitsBetweenIDs(c.NewID, c.OldID)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, c.ExpectedCommits, len(commits), "case %d", i)
|
||||
assert.Len(t, commits, c.ExpectedCommits, "case %d", i)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ func TestRepository_GetTags(t *testing.T) {
|
||||
return
|
||||
}
|
||||
assert.Len(t, tags, 2)
|
||||
assert.Equal(t, len(tags), total)
|
||||
assert.Len(t, tags, total)
|
||||
assert.EqualValues(t, "signed-tag", tags[0].Name)
|
||||
assert.EqualValues(t, "36f97d9a96457e2bab511db30fe2db03893ebc64", tags[0].ID.String())
|
||||
assert.EqualValues(t, "tag", tags[0].Type)
|
||||
|
||||
@@ -96,7 +96,7 @@ func (g *Manager) start() {
|
||||
run := svc.Run
|
||||
|
||||
//lint:ignore SA1019 We use IsAnInteractiveSession because IsWindowsService has a different permissions profile
|
||||
isAnInteractiveSession, err := svc.IsAnInteractiveSession()
|
||||
isAnInteractiveSession, err := svc.IsAnInteractiveSession() //nolint:staticcheck
|
||||
if err != nil {
|
||||
log.Error("Unable to ascertain if running as an Windows Service: %v", err)
|
||||
return
|
||||
|
||||
@@ -154,7 +154,9 @@ func Init() {
|
||||
log.Trace("IndexerData Process Repo: %d", indexerData.RepoID)
|
||||
|
||||
if err := index(ctx, indexer, indexerData.RepoID); err != nil {
|
||||
log.Error("index: %v", err)
|
||||
if !setting.IsInTesting {
|
||||
log.Error("indexer index error for repo %v: %v", indexerData.RepoID, err)
|
||||
}
|
||||
if indexer.Ping() {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ func testIndexer(name string, t *testing.T, indexer Indexer) {
|
||||
t.Run(kw.Keyword, func(t *testing.T) {
|
||||
total, res, langs, err := indexer.Search(context.TODO(), kw.RepoIDs, "", kw.Keyword, 1, 10, false)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, len(kw.IDs), total)
|
||||
assert.Len(t, kw.IDs, int(total))
|
||||
assert.Len(t, langs, kw.Langs)
|
||||
|
||||
ids := make([]int64, 0, len(res))
|
||||
|
||||
@@ -16,7 +16,6 @@ import (
|
||||
_ "code.gitea.io/gitea/models"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"gopkg.in/ini.v1"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
@@ -27,7 +26,7 @@ func TestMain(m *testing.M) {
|
||||
|
||||
func TestBleveSearchIssues(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
setting.CfgProvider = ini.Empty()
|
||||
setting.CfgProvider = setting.NewEmptyConfigProvider()
|
||||
|
||||
tmpIndexerDir := t.TempDir()
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"code.gitea.io/gitea/modules/graceful"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/process"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
)
|
||||
|
||||
// DBIndexer implements Indexer interface to use database's like search
|
||||
@@ -46,7 +47,7 @@ func (db *DBIndexer) Index(id int64) error {
|
||||
// Get latest commit for default branch
|
||||
commitID, err := gitRepo.GetBranchCommitID(repo.DefaultBranch)
|
||||
if err != nil {
|
||||
if git.IsErrBranchNotExist(err) || git.IsErrNotExist(err) {
|
||||
if git.IsErrBranchNotExist(err) || git.IsErrNotExist(err) || setting.IsInTesting {
|
||||
log.Debug("Unable to get commit ID for default branch %s in %s ... skipping this repository", repo.DefaultBranch, repo.RepoPath())
|
||||
return nil
|
||||
}
|
||||
@@ -62,7 +63,9 @@ func (db *DBIndexer) Index(id int64) error {
|
||||
// Calculate and save language statistics to database
|
||||
stats, err := gitRepo.GetLanguageStats(commitID)
|
||||
if err != nil {
|
||||
log.Error("Unable to get language stats for ID %s for default branch %s in %s. Error: %v", commitID, repo.DefaultBranch, repo.RepoPath(), err)
|
||||
if !setting.IsInTesting {
|
||||
log.Error("Unable to get language stats for ID %s for default branch %s in %s. Error: %v", commitID, repo.DefaultBranch, repo.RepoPath(), err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
err = repo_model.UpdateLanguageStats(repo, commitID, stats)
|
||||
|
||||
@@ -18,7 +18,6 @@ import (
|
||||
_ "code.gitea.io/gitea/models"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"gopkg.in/ini.v1"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
@@ -29,7 +28,7 @@ func TestMain(m *testing.M) {
|
||||
|
||||
func TestRepoStatsIndex(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
setting.CfgProvider = ini.Empty()
|
||||
setting.CfgProvider = setting.NewEmptyConfigProvider()
|
||||
|
||||
setting.LoadQueueSettings()
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"code.gitea.io/gitea/modules/graceful"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/queue"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
)
|
||||
|
||||
// statsQueue represents a queue to handle repository stats updates
|
||||
@@ -20,7 +21,9 @@ func handle(data ...queue.Data) []queue.Data {
|
||||
for _, datum := range data {
|
||||
opts := datum.(int64)
|
||||
if err := indexer.Index(opts); err != nil {
|
||||
log.Error("stats queue indexer.Index(%d) failed: %v", opts, err)
|
||||
if !setting.IsInTesting {
|
||||
log.Error("stats queue indexer.Index(%d) failed: %v", opts, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -162,7 +162,7 @@ func TestHTTPClientDownload(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Equal(t, "download", batchRequest.Operation)
|
||||
assert.Equal(t, 1, len(batchRequest.Objects))
|
||||
assert.Len(t, batchRequest.Objects, 1)
|
||||
assert.Equal(t, p.Oid, batchRequest.Objects[0].Oid)
|
||||
assert.Equal(t, p.Size, batchRequest.Objects[0].Size)
|
||||
|
||||
@@ -269,7 +269,7 @@ func TestHTTPClientUpload(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Equal(t, "upload", batchRequest.Operation)
|
||||
assert.Equal(t, 1, len(batchRequest.Objects))
|
||||
assert.Len(t, batchRequest.Objects, 1)
|
||||
assert.Equal(t, p.Oid, batchRequest.Objects[0].Oid)
|
||||
assert.Equal(t, p.Size, batchRequest.Objects[0].Size)
|
||||
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
// Copyright 2022 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package log
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type bufferWriteCloser struct {
|
||||
mu sync.Mutex
|
||||
buffer bytes.Buffer
|
||||
}
|
||||
|
||||
func (b *bufferWriteCloser) Write(p []byte) (int, error) {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
return b.buffer.Write(p)
|
||||
}
|
||||
|
||||
func (b *bufferWriteCloser) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *bufferWriteCloser) String() string {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
return b.buffer.String()
|
||||
}
|
||||
|
||||
// BufferLogger implements LoggerProvider and writes messages in a buffer.
|
||||
type BufferLogger struct {
|
||||
WriterLogger
|
||||
}
|
||||
|
||||
// NewBufferLogger create BufferLogger returning as LoggerProvider.
|
||||
func NewBufferLogger() LoggerProvider {
|
||||
log := &BufferLogger{}
|
||||
log.NewWriterLogger(&bufferWriteCloser{})
|
||||
return log
|
||||
}
|
||||
|
||||
// Init inits connection writer
|
||||
func (log *BufferLogger) Init(string) error {
|
||||
log.NewWriterLogger(log.out)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Content returns the content accumulated in the content provider
|
||||
func (log *BufferLogger) Content() (string, error) {
|
||||
return log.out.(*bufferWriteCloser).String(), nil
|
||||
}
|
||||
|
||||
// Flush when log should be flushed
|
||||
func (log *BufferLogger) Flush() {
|
||||
}
|
||||
|
||||
// ReleaseReopen does nothing
|
||||
func (log *BufferLogger) ReleaseReopen() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetName returns the default name for this implementation
|
||||
func (log *BufferLogger) GetName() string {
|
||||
return "buffer"
|
||||
}
|
||||
|
||||
func init() {
|
||||
Register("buffer", NewBufferLogger)
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
// Copyright 2022 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package log
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestBufferLogger(t *testing.T) {
|
||||
logger := NewBufferLogger()
|
||||
bufferLogger := logger.(*BufferLogger)
|
||||
assert.NotNil(t, bufferLogger)
|
||||
|
||||
err := logger.Init("")
|
||||
assert.NoError(t, err)
|
||||
|
||||
location, _ := time.LoadLocation("EST")
|
||||
date := time.Date(2019, time.January, 13, 22, 3, 30, 15, location)
|
||||
|
||||
msg := "TEST MSG"
|
||||
event := Event{
|
||||
level: INFO,
|
||||
msg: msg,
|
||||
caller: "CALLER",
|
||||
filename: "FULL/FILENAME",
|
||||
line: 1,
|
||||
time: date,
|
||||
}
|
||||
logger.LogEvent(&event)
|
||||
content, err := bufferLogger.Content()
|
||||
assert.NoError(t, err)
|
||||
assert.Contains(t, content, msg)
|
||||
logger.Close()
|
||||
}
|
||||
|
||||
func TestBufferLoggerContent(t *testing.T) {
|
||||
level := INFO
|
||||
logger := NewLogger(0, "console", "console", fmt.Sprintf(`{"level":"%s"}`, level.String()))
|
||||
|
||||
logger.SetLogger("buffer", "buffer", "{}")
|
||||
defer logger.DelLogger("buffer")
|
||||
|
||||
msg := "A UNIQUE MESSAGE"
|
||||
Error(msg)
|
||||
|
||||
found := false
|
||||
for i := 0; i < 30000; i++ {
|
||||
content, err := logger.GetLoggerProviderContent("buffer")
|
||||
assert.NoError(t, err)
|
||||
if strings.Contains(content, msg) {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
time.Sleep(1 * time.Millisecond)
|
||||
}
|
||||
assert.True(t, found)
|
||||
}
|
||||
@@ -118,11 +118,6 @@ func (log *ConnLogger) Init(jsonconfig string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Content returns the content accumulated in the content provider
|
||||
func (log *ConnLogger) Content() (string, error) {
|
||||
return "", fmt.Errorf("not supported")
|
||||
}
|
||||
|
||||
// Flush does nothing for this implementation
|
||||
func (log *ConnLogger) Flush() {
|
||||
}
|
||||
|
||||
@@ -65,11 +65,6 @@ func (log *ConsoleLogger) Init(config string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Content returns the content accumulated in the content provider
|
||||
func (log *ConsoleLogger) Content() (string, error) {
|
||||
return "", fmt.Errorf("not supported")
|
||||
}
|
||||
|
||||
// Flush when log should be flushed
|
||||
func (log *ConsoleLogger) Flush() {
|
||||
}
|
||||
|
||||
+8
-10
@@ -82,7 +82,7 @@ func (l *ChannelledLog) Start() {
|
||||
l.closeLogger()
|
||||
return
|
||||
}
|
||||
l.loggerProvider.LogEvent(event)
|
||||
l.loggerProvider.LogEvent(event) //nolint:errcheck
|
||||
case _, ok := <-l.flush:
|
||||
if !ok {
|
||||
l.closeLogger()
|
||||
@@ -119,7 +119,7 @@ func (l *ChannelledLog) emptyQueue() bool {
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
l.loggerProvider.LogEvent(event)
|
||||
l.loggerProvider.LogEvent(event) //nolint:errcheck
|
||||
default:
|
||||
return true
|
||||
}
|
||||
@@ -247,12 +247,6 @@ func (m *MultiChannelledLog) GetEventLogger(name string) EventLogger {
|
||||
return m.loggers[name]
|
||||
}
|
||||
|
||||
// GetEventProvider returns a sub logger provider content from this MultiChannelledLog
|
||||
func (m *MultiChannelledLog) GetLoggerProviderContent(name string) (string, error) {
|
||||
channelledLogger := m.GetEventLogger(name).(*ChannelledLog)
|
||||
return channelledLogger.loggerProvider.Content()
|
||||
}
|
||||
|
||||
// GetEventLoggerNames returns a list of names
|
||||
func (m *MultiChannelledLog) GetEventLoggerNames() []string {
|
||||
m.rwmutex.RLock()
|
||||
@@ -351,7 +345,7 @@ func (m *MultiChannelledLog) Start() {
|
||||
for _, logger := range m.loggers {
|
||||
err := logger.LogEvent(event)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
fmt.Println(err) //nolint:forbidigo
|
||||
}
|
||||
}
|
||||
m.rwmutex.RUnlock()
|
||||
@@ -385,7 +379,7 @@ func (m *MultiChannelledLog) emptyQueue() bool {
|
||||
for _, logger := range m.loggers {
|
||||
err := logger.LogEvent(event)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
fmt.Println(err) //nolint:forbidigo
|
||||
}
|
||||
}
|
||||
m.rwmutex.RUnlock()
|
||||
@@ -460,3 +454,7 @@ func (m *MultiChannelledLog) ResetLevel() Level {
|
||||
func (m *MultiChannelledLog) GetName() string {
|
||||
return m.name
|
||||
}
|
||||
|
||||
func (e *Event) GetMsg() string {
|
||||
return e.msg
|
||||
}
|
||||
|
||||
+2
-11
@@ -181,7 +181,7 @@ func (log *FileLogger) DoRotate() error {
|
||||
}
|
||||
|
||||
if log.Compress {
|
||||
go compressOldLogFile(fname, log.CompressionLevel)
|
||||
go compressOldLogFile(fname, log.CompressionLevel) //nolint:errcheck
|
||||
}
|
||||
|
||||
// re-start logger
|
||||
@@ -216,7 +216,7 @@ func compressOldLogFile(fname string, compressionLevel int) error {
|
||||
if err != nil {
|
||||
zw.Close()
|
||||
fw.Close()
|
||||
util.Remove(fname + ".gz")
|
||||
util.Remove(fname + ".gz") //nolint:errcheck
|
||||
return err
|
||||
}
|
||||
reader.Close()
|
||||
@@ -253,15 +253,6 @@ func (log *FileLogger) deleteOldLog() {
|
||||
})
|
||||
}
|
||||
|
||||
// Content returns the content accumulated in the content provider
|
||||
func (log *FileLogger) Content() (string, error) {
|
||||
b, err := os.ReadFile(log.Filename)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(b), nil
|
||||
}
|
||||
|
||||
// Flush flush file logger.
|
||||
// there are no buffering messages in file logger in memory.
|
||||
// flush file means sync file from disk.
|
||||
|
||||
@@ -51,7 +51,7 @@ func TestFileLogger(t *testing.T) {
|
||||
|
||||
fileLogger := NewFileLogger()
|
||||
realFileLogger, ok := fileLogger.(*FileLogger)
|
||||
assert.Equal(t, true, ok)
|
||||
assert.True(t, ok)
|
||||
|
||||
location, _ := time.LoadLocation("EST")
|
||||
|
||||
|
||||
+2
-2
@@ -245,7 +245,7 @@ func Close() {
|
||||
func Log(skip int, level Level, format string, v ...interface{}) {
|
||||
l, ok := NamedLoggers.Load(DEFAULT)
|
||||
if ok {
|
||||
l.Log(skip+1, level, format, v...)
|
||||
l.Log(skip+1, level, format, v...) //nolint:errcheck
|
||||
}
|
||||
}
|
||||
|
||||
@@ -273,7 +273,7 @@ func (l *LoggerAsWriter) Write(p []byte) (int, error) {
|
||||
for _, logger := range l.ourLoggers {
|
||||
// Skip = 3 because this presumes that we have been called by log.Println()
|
||||
// If the caller has used log.Output or the like this will be wrong
|
||||
logger.Log(3, l.level, string(p))
|
||||
logger.Log(3, l.level, string(p)) //nolint:errcheck
|
||||
}
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
+10
-10
@@ -53,7 +53,7 @@ type LevelLoggerLogger struct {
|
||||
|
||||
// Trace records trace log
|
||||
func (l *LevelLoggerLogger) Trace(format string, v ...interface{}) {
|
||||
l.Log(1, TRACE, format, v...)
|
||||
l.Log(1, TRACE, format, v...) //nolint:errcheck
|
||||
}
|
||||
|
||||
// IsTrace returns true if the logger is TRACE
|
||||
@@ -63,7 +63,7 @@ func (l *LevelLoggerLogger) IsTrace() bool {
|
||||
|
||||
// Debug records debug log
|
||||
func (l *LevelLoggerLogger) Debug(format string, v ...interface{}) {
|
||||
l.Log(1, DEBUG, format, v...)
|
||||
l.Log(1, DEBUG, format, v...) //nolint:errcheck
|
||||
}
|
||||
|
||||
// IsDebug returns true if the logger is DEBUG
|
||||
@@ -73,7 +73,7 @@ func (l *LevelLoggerLogger) IsDebug() bool {
|
||||
|
||||
// Info records information log
|
||||
func (l *LevelLoggerLogger) Info(format string, v ...interface{}) {
|
||||
l.Log(1, INFO, format, v...)
|
||||
l.Log(1, INFO, format, v...) //nolint:errcheck
|
||||
}
|
||||
|
||||
// IsInfo returns true if the logger is INFO
|
||||
@@ -83,7 +83,7 @@ func (l *LevelLoggerLogger) IsInfo() bool {
|
||||
|
||||
// Warn records warning log
|
||||
func (l *LevelLoggerLogger) Warn(format string, v ...interface{}) {
|
||||
l.Log(1, WARN, format, v...)
|
||||
l.Log(1, WARN, format, v...) //nolint:errcheck
|
||||
}
|
||||
|
||||
// IsWarn returns true if the logger is WARN
|
||||
@@ -93,12 +93,12 @@ func (l *LevelLoggerLogger) IsWarn() bool {
|
||||
|
||||
// Error records error log
|
||||
func (l *LevelLoggerLogger) Error(format string, v ...interface{}) {
|
||||
l.Log(1, ERROR, format, v...)
|
||||
l.Log(1, ERROR, format, v...) //nolint:errcheck
|
||||
}
|
||||
|
||||
// ErrorWithSkip records error log from "skip" calls back from this function
|
||||
func (l *LevelLoggerLogger) ErrorWithSkip(skip int, format string, v ...interface{}) {
|
||||
l.Log(skip+1, ERROR, format, v...)
|
||||
l.Log(skip+1, ERROR, format, v...) //nolint:errcheck
|
||||
}
|
||||
|
||||
// IsError returns true if the logger is ERROR
|
||||
@@ -108,12 +108,12 @@ func (l *LevelLoggerLogger) IsError() bool {
|
||||
|
||||
// Critical records critical log
|
||||
func (l *LevelLoggerLogger) Critical(format string, v ...interface{}) {
|
||||
l.Log(1, CRITICAL, format, v...)
|
||||
l.Log(1, CRITICAL, format, v...) //nolint:errcheck
|
||||
}
|
||||
|
||||
// CriticalWithSkip records critical log from "skip" calls back from this function
|
||||
func (l *LevelLoggerLogger) CriticalWithSkip(skip int, format string, v ...interface{}) {
|
||||
l.Log(skip+1, CRITICAL, format, v...)
|
||||
l.Log(skip+1, CRITICAL, format, v...) //nolint:errcheck
|
||||
}
|
||||
|
||||
// IsCritical returns true if the logger is CRITICAL
|
||||
@@ -123,14 +123,14 @@ func (l *LevelLoggerLogger) IsCritical() bool {
|
||||
|
||||
// Fatal records fatal log and exit the process
|
||||
func (l *LevelLoggerLogger) Fatal(format string, v ...interface{}) {
|
||||
l.Log(1, FATAL, format, v...)
|
||||
l.Log(1, FATAL, format, v...) //nolint:errcheck
|
||||
l.Close()
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// FatalWithSkip records fatal log from "skip" calls back from this function and exits the process
|
||||
func (l *LevelLoggerLogger) FatalWithSkip(skip int, format string, v ...interface{}) {
|
||||
l.Log(skip+1, FATAL, format, v...)
|
||||
l.Log(skip+1, FATAL, format, v...) //nolint:errcheck
|
||||
l.Close()
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
@@ -99,6 +99,6 @@ func (l *MultiChannelledLogger) SendLog(level Level, caller, filename string, li
|
||||
time: time.Now(),
|
||||
stacktrace: stack,
|
||||
}
|
||||
l.LogEvent(event)
|
||||
l.LogEvent(event) //nolint:errcheck
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ package log
|
||||
// LoggerProvider represents behaviors of a logger provider.
|
||||
type LoggerProvider interface {
|
||||
Init(config string) error
|
||||
Content() (string, error)
|
||||
EventLogger
|
||||
}
|
||||
|
||||
|
||||
@@ -95,11 +95,6 @@ func (log *SMTPLogger) sendMail(p []byte) (int, error) {
|
||||
)
|
||||
}
|
||||
|
||||
// Content returns the content accumulated in the content provider
|
||||
func (log *SMTPLogger) Content() (string, error) {
|
||||
return "", fmt.Errorf("not supported")
|
||||
}
|
||||
|
||||
// Flush when log should be flushed
|
||||
func (log *SMTPLogger) Flush() {
|
||||
}
|
||||
|
||||
@@ -202,7 +202,7 @@ func (logger *WriterLogger) createMsg(buf *[]byte, event *Event) {
|
||||
(&protectedANSIWriter{
|
||||
w: &baw,
|
||||
mode: pawMode,
|
||||
}).Write(msg)
|
||||
}).Write(msg) //nolint:errcheck
|
||||
*buf = baw
|
||||
|
||||
if event.stacktrace != "" && logger.StacktraceLevel <= event.level {
|
||||
@@ -249,7 +249,7 @@ func (logger *WriterLogger) Match(event *Event) bool {
|
||||
(&protectedANSIWriter{
|
||||
w: &baw,
|
||||
mode: removeColor,
|
||||
}).Write([]byte(event.msg))
|
||||
}).Write([]byte(event.msg)) //nolint:errcheck
|
||||
msg = baw
|
||||
return logger.regexp.Match(msg)
|
||||
}
|
||||
|
||||
@@ -593,5 +593,5 @@ func TestIssue18471(t *testing.T) {
|
||||
}, strings.NewReader(data), &res)
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, res.String(), "<a href=\"http://domain/org/repo/compare/783b039...da951ce\" class=\"compare\"><code class=\"nohighlight\">783b039...da951ce</code></a>")
|
||||
assert.Equal(t, "<a href=\"http://domain/org/repo/compare/783b039...da951ce\" class=\"compare\"><code class=\"nohighlight\">783b039...da951ce</code></a>", res.String())
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ func TestParseImageConfig(t *testing.T) {
|
||||
assert.Equal(t, projectURL, metadata.ProjectURL)
|
||||
assert.Equal(t, repositoryURL, metadata.RepositoryURL)
|
||||
assert.Equal(t, documentationURL, metadata.DocumentationURL)
|
||||
assert.Equal(t, []string{"do it 1", "do it 2"}, metadata.ImageLayers)
|
||||
assert.ElementsMatch(t, []string{"do it 1", "do it 2"}, metadata.ImageLayers)
|
||||
assert.Equal(
|
||||
t,
|
||||
map[string]string{
|
||||
|
||||
@@ -70,19 +70,19 @@ func TestPaginator(t *testing.T) {
|
||||
t.Run("Generate pages", func(t *testing.T) {
|
||||
p := New(0, 10, 1, 0)
|
||||
pages := p.Pages()
|
||||
assert.Equal(t, 0, len(pages))
|
||||
assert.Empty(t, pages)
|
||||
})
|
||||
|
||||
t.Run("Only current page", func(t *testing.T) {
|
||||
p := New(0, 10, 1, 1)
|
||||
pages := p.Pages()
|
||||
assert.Equal(t, 1, len(pages))
|
||||
assert.Len(t, pages, 1)
|
||||
assert.Equal(t, 1, pages[0].Num())
|
||||
assert.True(t, pages[0].IsCurrent())
|
||||
|
||||
p = New(1, 10, 1, 1)
|
||||
pages = p.Pages()
|
||||
assert.Equal(t, 1, len(pages))
|
||||
assert.Len(t, pages, 1)
|
||||
assert.Equal(t, 1, pages[0].Num())
|
||||
assert.True(t, pages[0].IsCurrent())
|
||||
})
|
||||
@@ -90,13 +90,13 @@ func TestPaginator(t *testing.T) {
|
||||
t.Run("Total page number is less or equal", func(t *testing.T) {
|
||||
p := New(1, 10, 1, 2)
|
||||
pages := p.Pages()
|
||||
assert.Equal(t, 1, len(pages))
|
||||
assert.Len(t, pages, 1)
|
||||
assert.Equal(t, 1, pages[0].Num())
|
||||
assert.True(t, pages[0].IsCurrent())
|
||||
|
||||
p = New(11, 10, 1, 2)
|
||||
pages = p.Pages()
|
||||
assert.Equal(t, 2, len(pages))
|
||||
assert.Len(t, pages, 2)
|
||||
assert.Equal(t, 1, pages[0].Num())
|
||||
assert.True(t, pages[0].IsCurrent())
|
||||
assert.Equal(t, 2, pages[1].Num())
|
||||
@@ -104,7 +104,7 @@ func TestPaginator(t *testing.T) {
|
||||
|
||||
p = New(11, 10, 2, 2)
|
||||
pages = p.Pages()
|
||||
assert.Equal(t, 2, len(pages))
|
||||
assert.Len(t, pages, 2)
|
||||
assert.Equal(t, 1, pages[0].Num())
|
||||
assert.False(t, pages[0].IsCurrent())
|
||||
assert.Equal(t, 2, pages[1].Num())
|
||||
@@ -112,7 +112,7 @@ func TestPaginator(t *testing.T) {
|
||||
|
||||
p = New(25, 10, 2, 3)
|
||||
pages = p.Pages()
|
||||
assert.Equal(t, 3, len(pages))
|
||||
assert.Len(t, pages, 3)
|
||||
assert.Equal(t, 1, pages[0].Num())
|
||||
assert.False(t, pages[0].IsCurrent())
|
||||
assert.Equal(t, 2, pages[1].Num())
|
||||
@@ -125,7 +125,7 @@ func TestPaginator(t *testing.T) {
|
||||
// ... 2
|
||||
p := New(11, 10, 2, 1)
|
||||
pages := p.Pages()
|
||||
assert.Equal(t, 2, len(pages))
|
||||
assert.Len(t, pages, 2)
|
||||
assert.Equal(t, -1, pages[0].Num())
|
||||
assert.False(t, pages[0].IsCurrent())
|
||||
assert.Equal(t, 2, pages[1].Num())
|
||||
@@ -134,7 +134,7 @@ func TestPaginator(t *testing.T) {
|
||||
// ... 2 3
|
||||
p = New(21, 10, 2, 2)
|
||||
pages = p.Pages()
|
||||
assert.Equal(t, 3, len(pages))
|
||||
assert.Len(t, pages, 3)
|
||||
assert.Equal(t, -1, pages[0].Num())
|
||||
assert.False(t, pages[0].IsCurrent())
|
||||
assert.Equal(t, 2, pages[1].Num())
|
||||
@@ -145,7 +145,7 @@ func TestPaginator(t *testing.T) {
|
||||
// ... 2 3 4
|
||||
p = New(31, 10, 3, 3)
|
||||
pages = p.Pages()
|
||||
assert.Equal(t, 4, len(pages))
|
||||
assert.Len(t, pages, 4)
|
||||
assert.Equal(t, -1, pages[0].Num())
|
||||
assert.False(t, pages[0].IsCurrent())
|
||||
assert.Equal(t, 2, pages[1].Num())
|
||||
@@ -158,7 +158,7 @@ func TestPaginator(t *testing.T) {
|
||||
// ... 3 4 5
|
||||
p = New(41, 10, 4, 3)
|
||||
pages = p.Pages()
|
||||
assert.Equal(t, 4, len(pages))
|
||||
assert.Len(t, pages, 4)
|
||||
assert.Equal(t, -1, pages[0].Num())
|
||||
assert.False(t, pages[0].IsCurrent())
|
||||
assert.Equal(t, 3, pages[1].Num())
|
||||
@@ -171,7 +171,7 @@ func TestPaginator(t *testing.T) {
|
||||
// ... 4 5 6 7 8 9 10
|
||||
p = New(100, 10, 9, 7)
|
||||
pages = p.Pages()
|
||||
assert.Equal(t, 8, len(pages))
|
||||
assert.Len(t, pages, 8)
|
||||
assert.Equal(t, -1, pages[0].Num())
|
||||
assert.False(t, pages[0].IsCurrent())
|
||||
assert.Equal(t, 4, pages[1].Num())
|
||||
@@ -194,7 +194,7 @@ func TestPaginator(t *testing.T) {
|
||||
// 1 ...
|
||||
p := New(21, 10, 1, 1)
|
||||
pages := p.Pages()
|
||||
assert.Equal(t, 2, len(pages))
|
||||
assert.Len(t, pages, 2)
|
||||
assert.Equal(t, 1, pages[0].Num())
|
||||
assert.True(t, pages[0].IsCurrent())
|
||||
assert.Equal(t, -1, pages[1].Num())
|
||||
@@ -203,7 +203,7 @@ func TestPaginator(t *testing.T) {
|
||||
// 1 2 ...
|
||||
p = New(21, 10, 1, 2)
|
||||
pages = p.Pages()
|
||||
assert.Equal(t, 3, len(pages))
|
||||
assert.Len(t, pages, 3)
|
||||
assert.Equal(t, 1, pages[0].Num())
|
||||
assert.True(t, pages[0].IsCurrent())
|
||||
assert.Equal(t, 2, pages[1].Num())
|
||||
@@ -214,7 +214,7 @@ func TestPaginator(t *testing.T) {
|
||||
// 1 2 3 ...
|
||||
p = New(31, 10, 2, 3)
|
||||
pages = p.Pages()
|
||||
assert.Equal(t, 4, len(pages))
|
||||
assert.Len(t, pages, 4)
|
||||
assert.Equal(t, 1, pages[0].Num())
|
||||
assert.False(t, pages[0].IsCurrent())
|
||||
assert.Equal(t, 2, pages[1].Num())
|
||||
@@ -227,7 +227,7 @@ func TestPaginator(t *testing.T) {
|
||||
// 1 2 3 ...
|
||||
p = New(41, 10, 2, 3)
|
||||
pages = p.Pages()
|
||||
assert.Equal(t, 4, len(pages))
|
||||
assert.Len(t, pages, 4)
|
||||
assert.Equal(t, 1, pages[0].Num())
|
||||
assert.False(t, pages[0].IsCurrent())
|
||||
assert.Equal(t, 2, pages[1].Num())
|
||||
@@ -240,7 +240,7 @@ func TestPaginator(t *testing.T) {
|
||||
// 1 2 3 4 5 6 7 ...
|
||||
p = New(100, 10, 1, 7)
|
||||
pages = p.Pages()
|
||||
assert.Equal(t, 8, len(pages))
|
||||
assert.Len(t, pages, 8)
|
||||
assert.Equal(t, 1, pages[0].Num())
|
||||
assert.True(t, pages[0].IsCurrent())
|
||||
assert.Equal(t, 2, pages[1].Num())
|
||||
@@ -261,7 +261,7 @@ func TestPaginator(t *testing.T) {
|
||||
// 1 2 3 4 5 6 7 ...
|
||||
p = New(100, 10, 2, 7)
|
||||
pages = p.Pages()
|
||||
assert.Equal(t, 8, len(pages))
|
||||
assert.Len(t, pages, 8)
|
||||
assert.Equal(t, 1, pages[0].Num())
|
||||
assert.False(t, pages[0].IsCurrent())
|
||||
assert.Equal(t, 2, pages[1].Num())
|
||||
@@ -284,7 +284,7 @@ func TestPaginator(t *testing.T) {
|
||||
// ... 2 3 ...
|
||||
p := New(35, 10, 2, 2)
|
||||
pages := p.Pages()
|
||||
assert.Equal(t, 4, len(pages))
|
||||
assert.Len(t, pages, 4)
|
||||
assert.Equal(t, -1, pages[0].Num())
|
||||
assert.False(t, pages[0].IsCurrent())
|
||||
assert.Equal(t, 2, pages[1].Num())
|
||||
@@ -297,7 +297,7 @@ func TestPaginator(t *testing.T) {
|
||||
// ... 2 3 4 ...
|
||||
p = New(49, 10, 3, 3)
|
||||
pages = p.Pages()
|
||||
assert.Equal(t, 5, len(pages))
|
||||
assert.Len(t, pages, 5)
|
||||
assert.Equal(t, -1, pages[0].Num())
|
||||
assert.False(t, pages[0].IsCurrent())
|
||||
assert.Equal(t, 2, pages[1].Num())
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
package queue
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"sync"
|
||||
"testing"
|
||||
@@ -17,7 +16,6 @@ import (
|
||||
|
||||
func TestPersistableChannelUniqueQueue(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
fmt.Printf("TempDir %s\n", tmpDir)
|
||||
_ = log.NewLogger(1000, "console", "console", `{"level":"warn","stacktracelevel":"NONE","stderr":true}`)
|
||||
|
||||
// Common function to create the Queue
|
||||
@@ -208,7 +206,7 @@ func TestPersistableChannelUniqueQueue(t *testing.T) {
|
||||
|
||||
mapLock.Lock()
|
||||
assert.Equal(t, 101, len(executedInitial[name])+len(executedEmpty[name]))
|
||||
assert.Equal(t, 0, len(hasEmpty[name]))
|
||||
assert.Empty(t, hasEmpty[name])
|
||||
mapLock.Unlock()
|
||||
})
|
||||
close(done)
|
||||
|
||||
@@ -15,9 +15,9 @@ func TestEncryptDecrypt(t *testing.T) {
|
||||
|
||||
hex, _ = EncryptSecret("foo", "baz")
|
||||
str, _ = DecryptSecret("foo", hex)
|
||||
assert.Equal(t, str, "baz")
|
||||
assert.Equal(t, "baz", str)
|
||||
|
||||
hex, _ = EncryptSecret("bar", "baz")
|
||||
str, _ = DecryptSecret("foo", hex)
|
||||
assert.NotEqual(t, str, "baz")
|
||||
assert.NotEqual(t, "baz", str)
|
||||
}
|
||||
|
||||
@@ -4,20 +4,157 @@
|
||||
package setting
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
|
||||
ini "gopkg.in/ini.v1"
|
||||
)
|
||||
|
||||
type ConfigSection interface {
|
||||
Name() string
|
||||
MapTo(interface{}) error
|
||||
HasKey(key string) bool
|
||||
NewKey(name, value string) (*ini.Key, error)
|
||||
Key(key string) *ini.Key
|
||||
Keys() []*ini.Key
|
||||
ChildSections() []*ini.Section
|
||||
}
|
||||
|
||||
// ConfigProvider represents a config provider
|
||||
type ConfigProvider interface {
|
||||
Section(section string) *ini.Section
|
||||
NewSection(name string) (*ini.Section, error)
|
||||
GetSection(name string) (*ini.Section, error)
|
||||
Section(section string) ConfigSection
|
||||
NewSection(name string) (ConfigSection, error)
|
||||
GetSection(name string) (ConfigSection, error)
|
||||
DeleteSection(name string) error
|
||||
Save() error
|
||||
}
|
||||
|
||||
type iniFileConfigProvider struct {
|
||||
*ini.File
|
||||
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
|
||||
func NewEmptyConfigProvider() ConfigProvider {
|
||||
cp, _ := newConfigProviderFromData("")
|
||||
return cp
|
||||
}
|
||||
|
||||
// newConfigProviderFromData this function is only for testing
|
||||
func newConfigProviderFromData(configContent string) (ConfigProvider, error) {
|
||||
var cfg *ini.File
|
||||
var err error
|
||||
if configContent == "" {
|
||||
cfg = ini.Empty()
|
||||
} else {
|
||||
cfg, err = ini.Load(strings.NewReader(configContent))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
cfg.NameMapper = ini.SnackCase
|
||||
return &iniFileConfigProvider{
|
||||
File: cfg,
|
||||
newFile: true,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// newConfigProviderFromFile load configuration from file.
|
||||
// NOTE: do not print any log except error.
|
||||
func newConfigProviderFromFile(customConf string, allowEmpty bool, extraConfig string) (*iniFileConfigProvider, error) {
|
||||
cfg := ini.Empty()
|
||||
newFile := true
|
||||
|
||||
if customConf != "" {
|
||||
isFile, err := util.IsFile(customConf)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to check if %s is a file. Error: %v", customConf, err)
|
||||
}
|
||||
if isFile {
|
||||
if err := cfg.Append(customConf); err != nil {
|
||||
return nil, fmt.Errorf("failed to load custom conf '%s': %v", customConf, err)
|
||||
}
|
||||
newFile = false
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
if extraConfig != "" {
|
||||
if err := cfg.Append([]byte(extraConfig)); err != nil {
|
||||
return nil, fmt.Errorf("unable to append more config: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
cfg.NameMapper = ini.SnackCase
|
||||
return &iniFileConfigProvider{
|
||||
File: cfg,
|
||||
filepath: customConf,
|
||||
newFile: newFile,
|
||||
allowEmpty: allowEmpty,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (p *iniFileConfigProvider) Section(section string) ConfigSection {
|
||||
return p.File.Section(section)
|
||||
}
|
||||
|
||||
func (p *iniFileConfigProvider) NewSection(name string) (ConfigSection, error) {
|
||||
return p.File.NewSection(name)
|
||||
}
|
||||
|
||||
func (p *iniFileConfigProvider) GetSection(name string) (ConfigSection, error) {
|
||||
return p.File.GetSection(name)
|
||||
}
|
||||
|
||||
func (p *iniFileConfigProvider) DeleteSection(name string) error {
|
||||
p.File.DeleteSection(name)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Save save the content into file
|
||||
func (p *iniFileConfigProvider) Save() error {
|
||||
if p.filepath == "" {
|
||||
if !p.allowEmpty {
|
||||
return fmt.Errorf("custom config path must not be empty")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if p.newFile {
|
||||
if err := os.MkdirAll(filepath.Dir(CustomConf), os.ModePerm); err != nil {
|
||||
return fmt.Errorf("failed to create '%s': %v", CustomConf, err)
|
||||
}
|
||||
}
|
||||
if err := p.SaveTo(p.filepath); err != nil {
|
||||
return fmt.Errorf("failed to save '%s': %v", p.filepath, err)
|
||||
}
|
||||
|
||||
// Change permissions to be more restrictive
|
||||
fi, err := os.Stat(CustomConf)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to determine current conf file permissions: %v", err)
|
||||
}
|
||||
|
||||
if fi.Mode().Perm() > 0o600 {
|
||||
if err = os.Chmod(CustomConf, 0o600); err != nil {
|
||||
log.Warn("Failed changing conf file permissions to -rw-------. Consider changing them manually.")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// a file is an implementation ConfigProvider and other implementations are possible, i.e. from docker, k8s, …
|
||||
var _ ConfigProvider = &ini.File{}
|
||||
var _ ConfigProvider = &iniFileConfigProvider{}
|
||||
|
||||
func mustMapSetting(rootCfg ConfigProvider, sectionName string, setting interface{}) {
|
||||
if err := rootCfg.Section(sectionName).MapTo(setting); err != nil {
|
||||
|
||||
@@ -21,9 +21,10 @@ var CORSConfig = struct {
|
||||
Headers []string
|
||||
XFrameOptions string
|
||||
}{
|
||||
Enabled: false,
|
||||
MaxAge: 10 * time.Minute,
|
||||
AllowDomain: []string{"*"},
|
||||
Methods: []string{"GET", "HEAD", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"},
|
||||
Headers: []string{"Content-Type", "User-Agent"},
|
||||
MaxAge: 10 * time.Minute,
|
||||
XFrameOptions: "SAMEORIGIN",
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
ini "gopkg.in/ini.v1"
|
||||
)
|
||||
|
||||
func Test_getCronSettings(t *testing.T) {
|
||||
@@ -23,11 +22,11 @@ func Test_getCronSettings(t *testing.T) {
|
||||
|
||||
iniStr := `
|
||||
[cron.test]
|
||||
Base = true
|
||||
Second = white rabbit
|
||||
Extend = true
|
||||
BASE = true
|
||||
SECOND = white rabbit
|
||||
EXTEND = true
|
||||
`
|
||||
cfg, err := ini.Load([]byte(iniStr))
|
||||
cfg, err := newConfigProviderFromData(iniStr)
|
||||
assert.NoError(t, err)
|
||||
|
||||
extended := &Extended{
|
||||
|
||||
@@ -9,8 +9,6 @@ import (
|
||||
|
||||
"code.gitea.io/gitea/modules/generate"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
|
||||
ini "gopkg.in/ini.v1"
|
||||
)
|
||||
|
||||
// LFS represents the configuration for Git LFS
|
||||
@@ -38,8 +36,7 @@ func loadLFSFrom(rootCfg ConfigProvider) {
|
||||
// DEPRECATED should not be removed because users maybe upgrade from lower version to the latest version
|
||||
// if these are removed, the warning will not be shown
|
||||
deprecatedSetting(rootCfg, "server", "LFS_CONTENT_PATH", "lfs", "PATH", "v1.19.0")
|
||||
lfsSec.Key("PATH").MustString(
|
||||
sec.Key("LFS_CONTENT_PATH").String())
|
||||
lfsSec.Key("PATH").MustString(sec.Key("LFS_CONTENT_PATH").String())
|
||||
|
||||
LFS.Storage = getStorage(rootCfg, "lfs", storageType, lfsSec)
|
||||
|
||||
@@ -62,9 +59,11 @@ func loadLFSFrom(rootCfg ConfigProvider) {
|
||||
}
|
||||
|
||||
// Save secret
|
||||
CreateOrAppendToCustomConf("server.LFS_JWT_SECRET", func(cfg *ini.File) {
|
||||
cfg.Section("server").Key("LFS_JWT_SECRET").SetValue(LFS.JWTSecretBase64)
|
||||
})
|
||||
sec.Key("LFS_JWT_SECRET").SetValue(LFS.JWTSecretBase64)
|
||||
if err := rootCfg.Save(); err != nil {
|
||||
log.Fatal("Error saving JWT Secret for custom config: %v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user