Compare commits

...

52 Commits

Author SHA1 Message Date
techknowlogick
ef8f6d99f1 Fix regression with tag test running (#9941) 2020-01-22 15:49:08 -05:00
John Olheiser
4b688135f9 Changelog 1.11.0-rc2 (#9853)
Signed-off-by: jolheiser <john.olheiser@gmail.com>
Co-authored-by: guillep2k <18600385+guillep2k@users.noreply.github.com>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Antoine GIRARD <sapk@users.noreply.github.com>
Co-authored-by: techknowlogick <techknowlogick@gitea.io>
2020-01-22 14:56:55 -05:00
John Olheiser
e24861a546 Don't convert ellipsis in markdown (#9905) (#9937)
* Don't convert ellipsis

Signed-off-by: jolheiser <john.olheiser@gmail.com>

* Formatting

Co-Authored-By: zeripath <art27@cantab.net>

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Antoine GIRARD <sapk@users.noreply.github.com>
Co-authored-by: zeripath <art27@cantab.net>

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Antoine GIRARD <sapk@users.noreply.github.com>
Co-authored-by: zeripath <art27@cantab.net>
2020-01-22 16:24:04 +00:00
6543
128cc34344 Fixed repo link in generated comment for cross repository dependency (#9863) (#9935)
* fixed link to issue in issue comments after adding/removing a dependency, before links assumed the issue was in the same repository. also changed the format of the displayed issue since the issue will not necessarily be in the same repo

* based on pr comments, changed to use HTMLURL instead of piecing together the issue url, and added an if statement around the issue link display as a nil protection

* only showing repo name in dependency comment if the issue is from another repo

Co-authored-by: Brad Albright <32200834+bhalbright@users.noreply.github.com>
Co-authored-by: Antoine GIRARD <sapk@users.noreply.github.com>
2020-01-22 12:54:40 +02:00
Lauris BH
f82a805478 Check if diff actually contains sections when rendering (#9926) (#9933) 2020-01-22 08:02:57 +00:00
Lunny Xiao
0dced15c1a Fix wrong hint when status checking is running on pull request view (#9886) (#9928)
* Fix wrong hint when status checking is running on pull request view

* fix lint

* fix test

* fix test

* fix wrong tmpl

* fix import

* rename function name
2020-01-22 08:06:11 +02:00
John Olheiser
db9342c854 Fix RocketChat (#9908) (#9921)
* Fix RocketChat??

Signed-off-by: jolheiser <john.olheiser@gmail.com>

* Don't send attachment for repo create/delete

Signed-off-by: jolheiser <john.olheiser@gmail.com>

* Make fmt

Signed-off-by: jolheiser <john.olheiser@gmail.com>

Co-authored-by: Lauris BH <lauris@nix.lv>

Co-authored-by: Lauris BH <lauris@nix.lv>
2020-01-21 17:24:18 -05:00
zeripath
79c1d48532 Do not try to recreate ldap user if they are already created (#9900) (#9919)
* Do not try to recreate ldap user if they are already created

* just remove autoregister

Co-authored-by: techknowlogick <matti@mdranta.net>

Co-authored-by: techknowlogick <matti@mdranta.net>
2020-01-21 21:17:00 +01:00
zeripath
05b9864086 Update queue_redis.go (#9911) 2020-01-21 20:02:25 +08:00
zeripath
ff508c9c9b Add option to prevent LDAP from deactivating everything on empty search (#9879) (#9896)
* Add option to prevent LDAP from deactivating everything on empty search

* Update options/locale/locale_en-US.ini

Co-Authored-By: guillep2k <18600385+guillep2k@users.noreply.github.com>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2020-01-20 21:18:23 +02:00
Lunny Xiao
f96c1a2c79 Fix wrong permissions check when issues/prs shared operations (#9885) (#9889)
* Fix wrong permissions check when issues/prs shared operations

* move redirect to the last of the function

* fix swagger

Co-authored-by: zeripath <art27@cantab.net>
Co-authored-by: Lauris BH <lauris@nix.lv>
2020-01-20 17:59:33 +02:00
6543
ce756ee89f Check user != nil before checking values (#9881) (#9883)
* Check user != nil before checking values

* Handle autoAdmin

Co-authored-by: zeripath <art27@cantab.net>
2020-01-19 22:01:39 -05:00
zeripath
f2e9d4b851 Allow hyphen in language name (#9873) (#9880)
Co-authored-by: techknowlogick <matti@mdranta.net>
2020-01-19 19:23:35 -05:00
zeripath
e878d743f4 Ensure that 2fa is checked on reset-password (#9857) (#9876)
* Ensure that 2fa is checked on reset-password

* Apply suggestions from code review

Co-Authored-By: Lauris BH <lauris@nix.lv>

* Properly manage scratch_code regeneration

Co-authored-by: Lauris BH <lauris@nix.lv>

Co-authored-by: Lauris BH <lauris@nix.lv>
2020-01-19 23:21:21 +00:00
6543
3fa14d89a2 [Backport] CI optimisation & add github token env var (#9875)
* ci: use docker image for golangci-lint (#9737)

* ci: re-ordering Drone CI for optimizing time (#9719)

* ci: try re-ordering for optimizing time

* ci: try re-ordering for optimizing time

* ci: try re-ordering for optimizing time

* ci: try re-ordering for optimizing time

* ci: try re-ordering for optimizing time

* ci: try re-ordering for optimizing time

* ci: try offloading mysql8 to arm64

* Revert "ci: try offloading mysql8 to arm64"

This reverts commit c60de5db1c.

* ci: try offloading pgsql to arm64

* ci: activate ldap on arm64

* ci: test mysql8 in place pgsql arm64

* chore: clean un-needed move

* typo

* ci: revert runnning mysql on arm64

* ci: run compliance on arm

* chore: limit change

* chore: readd maybe need for release fetch-tags

* ci: remove docker-linux-amd64-dry-run

* ci: remove docker-linux-amd64-dry-run

* Revert "ci: remove docker-linux-amd64-dry-run"

This reverts commit 0715f65b11.

Co-authored-by: zeripath <art27@cantab.net>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>

* ci: use new mssql image (#9720)

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>

* ci: run notify on arm64 (#9762)

* ci: run notify on arm64

Free one jobs on amrd64

* Update .drone.yml

* Update .drone.yml

* Update .drone.yml

Based on: https://github.com/appleboy/drone-discord/blob/master/.drone.yml#L339

* improve trigger

Co-authored-by: techknowlogick <matti@mdranta.net>

* ci: move some integration tests on arm64 (#9747)

* tests: configure github remaining limit + read token (#9800)

* ci: configure remaining github limmit

* prepend with github since package is common to all migrations

* add RefreshRate

* Update github.go

* add missing space

* go fmt

* Read env variable GITHUB_READ_TOKEN for token

* Update .drone.yml

* ci: simplify tag/release by always running coverage (#9774)

* ci: simplify tag/release by always running coverage

* use mod and vendor for unit test coverage

* remove not needed lfs for unit test

* use arm drone agent for docs (#9776)

* run translations pipeline on arm server (#9865)

* add git-check to Makefile

Co-authored-by: Antoine GIRARD <sapk@users.noreply.github.com>
Co-authored-by: zeripath <art27@cantab.net>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: techknowlogick <matti@mdranta.net>
2020-01-19 23:21:54 +01:00
zeripath
bcb722daec Make CertFile and KeyFile relative to CustomPath (#9868) (#9874)
* Make CertFile and KeyFile relative to CustomPath

The current code will absolute CertFile and KeyFile against the current working directory. This is quite unexpected for users. This code makes relative paths absolute against the CustomPath.

Fix #4196

* Improve error reporting when reading certificates

* Apply suggestions from code review

Co-Authored-By: guillep2k <18600385+guillep2k@users.noreply.github.com>

Co-authored-by: guillep2k <18600385+guillep2k@users.noreply.github.com>

Co-authored-by: guillep2k <18600385+guillep2k@users.noreply.github.com>
2020-01-19 19:59:30 +00:00
Lunny Xiao
8add1dfacc Fix issues/pulls dependencies problems (#9842) (#9864)
* Fix issues/pulls dependencies problems

* fix swagger and api param name

* fix js
2020-01-19 12:56:57 -05:00
David Svantesson
aa6ed1b7c1 Explicitly refer to PR in squash-merge commit message in case of external tracker (#9844) (#9855)
* Explicitly refer to PR in squash-merge commit message in case of external tracker

* documentation

Co-authored-by: zeripath <art27@cantab.net>

Co-authored-by: zeripath <art27@cantab.net>
2020-01-18 22:28:33 +08:00
6543
95cb921097 fix (#9837) 2020-01-17 23:31:46 -05:00
6543
6730df9e8c Changelog 1.10.3 (#9832) (#9849) 2020-01-17 17:02:30 -05:00
Moritz
b577500a54 Fix markdown anchor links (#9673) (#9840) 2020-01-17 11:49:50 -05:00
Lunny Xiao
fe46185407 Fix download file wrong content-type (#9825) (#9834)
* Fix download file wrong content-type

* change the error text to be more precise

* fix test

Co-authored-by: Lauris BH <lauris@nix.lv>
2020-01-17 15:11:20 +01:00
Lunny Xiao
69a2a29c33 Fix wrong identify poster on a migrated pull request when submi… (#9827) (#9830) 2020-01-17 13:38:11 +01:00
Lunny Xiao
f766719895 fix dump non-exist log directory (#9818) (#9819) 2020-01-17 13:02:41 +08:00
Lunny Xiao
e2ddc42377 Fix compare (#9808) (#9814)
Co-authored-by: techknowlogick <matti@mdranta.net>

Co-authored-by: techknowlogick <matti@mdranta.net>
2020-01-17 10:08:28 +08:00
John Olheiser
3521177a34 Fix push-to-create (#9772) (#9797)
* Fix push-to-create

Signed-off-by: jolheiser <john.olheiser@gmail.com>

* Check URL path and service

Signed-off-by: jolheiser <john.olheiser@gmail.com>

* Send dummy payload on receive-pack GET

Signed-off-by: jolheiser <john.olheiser@gmail.com>

* The space was actually a NUL byte

Signed-off-by: jolheiser <john.olheiser@gmail.com>

* Use real bare repo instead of manufactured payload

Signed-off-by: jolheiser <john.olheiser@gmail.com>

Co-authored-by: zeripath <art27@cantab.net>
2020-01-16 07:40:37 +02:00
Lunny Xiao
c8bb0ecf52 Fix missing msteam webhook on organization (#9781) (#9794) 2020-01-16 03:09:47 +00:00
zeripath
dbe6136348 Fix missing unlock in uniquequeue (#9791) 2020-01-16 01:09:31 +01:00
6543
6d1f7e90cf Fix (#9761) Korean locales (#9780)
* backport korean 20-20-01-15 | fix #9761

* update state 14:43:10 UTC
2020-01-15 11:28:44 -05:00
David Svantesson
42663a687c Fix add team on collaborator page when same name as organization (#9778) 2020-01-15 14:18:18 +01:00
6543
73c90c26d4 Backport Locales [2020-01-14] (#9773)
* backport state of 2020-01-14

* Apply suggestions from code review

Co-Authored-By: 6543 <6543@obermui.de>

Co-authored-by: zeripath <art27@cantab.net>
2020-01-15 07:03:38 +00:00
John Olheiser
c579ad92b5 Fix SimpleMDE quote reply (#9757) (#9768)
Signed-off-by: jolheiser <john.olheiser@gmail.com>

Co-authored-by: zeripath <art27@cantab.net>

Co-authored-by: zeripath <art27@cantab.net>
Co-authored-by: Antoine GIRARD <sapk@users.noreply.github.com>
2020-01-15 03:23:55 +01:00
6543
602c5da953 Fix #9752 (#9769) (#9775)
Co-authored-by: zeripath <art27@cantab.net>
2020-01-15 01:41:28 +01:00
6543
1980e59ac2 Fix milestones page (#9771)
Signed-off-by: jolheiser <john.olheiser@gmail.com>

Co-authored-by: John Olheiser <42128690+jolheiser@users.noreply.github.com>
2020-01-14 23:33:12 +01:00
Lunny Xiao
28508792ba Fix missing updated time on migrated issues and comments (#9744) (#9764)
* Fix missing updated time on migrated issues and comments

* Fix testing and missing updated on migrating pullrequest

Co-authored-by: Antoine GIRARD <sapk@users.noreply.github.com>

Co-authored-by: Antoine GIRARD <sapk@users.noreply.github.com>
2020-01-14 17:55:03 +01:00
silverwind
3e23dad075 fix webpack polyfills (#9735) (#9738)
webpack polyfills did not work because useBuiltIns: 'entry' expects a
explicit core-js import. Changed it to 'usage' which does not require
these explicit imports and polyfills based on browserslist.

As a result, the built index.js now went from 128kB to 192kB.

Ref: https://babeljs.io/docs/en/babel-preset-env#usebuiltins
2020-01-12 17:43:16 -05:00
zeripath
b13b9d3dbd Move Errored PRs out of StatusChecking (#9675) (#9726)
* Move Errored PRs out of StatusChecking (#9675)

* Set Errored PRs out of StatusChecking

* Ensure that api status is correctly set too

* Update models/pull.go

Co-Authored-By: John Olheiser <42128690+jolheiser@users.noreply.github.com>

Co-authored-by: John Olheiser <42128690+jolheiser@users.noreply.github.com>

* Update services/pull/check.go

Co-authored-by: John Olheiser <42128690+jolheiser@users.noreply.github.com>
2020-01-12 20:52:40 +01:00
zeripath
4072f28e60 Make hook status printing configurable with delay (#9641) (#9725)
* Delay printing hook statuses until after 1 second

* Move to a 5s delay, wrapped writer structure and add config

* Update cmd/hook.go

* Apply suggestions from code review

* Update cmd/hook.go

Co-authored-by: Antoine GIRARD <sapk@users.noreply.github.com>

Co-authored-by: Antoine GIRARD <sapk@users.noreply.github.com>
2020-01-12 18:02:36 +00:00
6543
dbeef6bb02 [BugFix] [API] ​/repos​/issues​/search (#9698) (#9724)
* fix

* fix options

* add TEST

Co-authored-by: Antoine GIRARD <sapk@users.noreply.github.com>

Co-authored-by: Antoine GIRARD <sapk@users.noreply.github.com>
2020-01-12 10:20:49 +00:00
silverwind
fec35440db silence fomantic error regarding tabs (#9713) (#9718)
Fomantic expects all tabs to have a target element with content as
defined by the data-tab attribute. All our usage of the tab module seems
to use <a> element tabs that link to new pages so these content elements
are never present and fomantic complains about that in the console with
an "Activated tab cannot be found" error. This silences that error.
2020-01-11 23:20:33 -05:00
zeripath
f8ea50cc7a Remove unused lock (#9710) 2020-01-11 19:06:39 +00:00
zeripath
0e53a16cca Missed q.lock.Unlock() will cause panic (#9706) 2020-01-11 17:05:24 +00:00
zeripath
7eaba6ba8a Never allow an empty password to validate (#9682) (#9683)
* Restore IsPasswordSet previous value

* Update models/user.go

Co-authored-by: Lauris BH <lauris@nix.lv>
2020-01-11 16:27:03 +02:00
guillep2k
ff16099c6d Don't attempt to close issue if already closed (#9699) 2020-01-11 01:42:11 -05:00
John Olheiser
a516a7ba0f Load milestone in API PR list (#9671) (#9700) 2020-01-10 22:58:03 -05:00
silverwind
11bce6fd3d eliminate horizontal scroll caused by footer (#9674)
Co-authored-by: zeripath <art27@cantab.net>
2020-01-10 08:45:59 +08:00
techknowlogick
3fb906dc02 remove google font call (#9668) (#9681) 2020-01-09 16:40:57 -05:00
zeripath
3a00a690c9 Prevent redirect to Host (#9678) (#9679) 2020-01-09 16:37:37 -05:00
John Olheiser
a2b7cc1bb1 Fix nil reference in repo generation (#9660) (#9666)
* Fix nil reference

Signed-off-by: jolheiser <john.olheiser@gmail.com>

* Tighten

Signed-off-by: jolheiser <john.olheiser@gmail.com>
2020-01-09 16:50:21 +00:00
John Olheiser
04a77b1f42 Add HTML URL to API Issues (#9654) (#9661)
* Add HTML URL to API Issues

Signed-off-by: jolheiser <john.olheiser@gmail.com>

* Swagger

Signed-off-by: jolheiser <john.olheiser@gmail.com>

Co-authored-by: Lauris BH <lauris@nix.lv>

Co-authored-by: Lauris BH <lauris@nix.lv>
2020-01-09 08:07:21 +02:00
John Olheiser
f523372d07 Add PR review webhook to Telegram (#9653) (#9655)
Signed-off-by: jolheiser <john.olheiser@gmail.com>

Co-authored-by: Antoine GIRARD <sapk@users.noreply.github.com>

Co-authored-by: Antoine GIRARD <sapk@users.noreply.github.com>
2020-01-08 21:42:28 +02:00
6543
e39c238ef4 fix #9648 (#9652) 2020-01-08 17:32:25 +01:00
99 changed files with 1576 additions and 630 deletions

View File

@@ -1,44 +1,44 @@
repo: go-gitea/gitea repo: go-gitea/gitea
groups: groups:
- -
name: BREAKING name: BREAKING
labels: labels:
- kind/breaking - kind/breaking
- -
name: FEATURE name: FEATURE
labels: labels:
- kind/feature - kind/feature
-
name: SECURITY
labels:
- kind/security
- -
name: BUGFIXES name: BUGFIXES
labels: labels:
- kind/bug - kind/bug
- -
name: ENHANCEMENT name: ENHANCEMENT
labels: labels:
- kind/enhancement - kind/enhancement
- kind/refactor - kind/refactor
- kind/ui - kind/ui
- -
name: SECURITY
labels:
- kind/security
-
name: TESTING name: TESTING
labels: labels:
- kind/testing - kind/testing
- -
name: TRANSLATION name: TRANSLATION
labels: labels:
- kind/translation - kind/translation
- -
name: BUILD name: BUILD
labels: labels:
- kind/build - kind/build
- kind/lint - kind/lint
- -
name: DOCS name: DOCS
labels: labels:
- kind/docs - kind/docs
- -
name: MISC name: MISC
default: true default: true

View File

@@ -1,6 +1,61 @@
--- ---
kind: pipeline kind: pipeline
name: testing name: compliance
platform:
os: linux
arch: arm64
workspace:
base: /go
path: src/code.gitea.io/gitea
steps:
- name: pre-build
pull: always
image: node:10 # this step is kept at the lowest version of node that we support
commands:
- make css
- make js
- name: build-without-gcc
pull: always
image: golang:1.11 # this step is kept as the lowest version of golang that we support
environment:
GO111MODULE: on
GOPROXY: off
commands:
- go build -mod=vendor -o gitea_no_gcc # test if build succeeds without the sqlite tag
- name: build-linux-386
pull: always
image: golang:1.13
environment:
GO111MODULE: on
GOPROXY: off
GOOS: linux
GOARCH: 386
commands:
- go build -mod=vendor -o gitea_linux_386 # test if compatible with 32 bit
- name: check
pull: always
image: golang:1.13
commands:
- make clean
- make golangci-lint
- make revive
- make swagger-check
- make swagger-validate
- make test-vendor
environment:
GOPROXY: https://goproxy.cn # proxy.golang.org is blocked in China, this proxy is not
GOSUMDB: sum.golang.org
TAGS: bindata sqlite sqlite_unlock_notify
---
kind: pipeline
name: testing-amd64
platform: platform:
os: linux os: linux
@@ -25,15 +80,9 @@ services:
MYSQL_ALLOW_EMPTY_PASSWORD: yes MYSQL_ALLOW_EMPTY_PASSWORD: yes
MYSQL_DATABASE: testgitea MYSQL_DATABASE: testgitea
- name: pgsql
pull: default
image: postgres:9.5
environment:
POSTGRES_DB: test
- name: mssql - name: mssql
pull: default pull: default
image: microsoft/mssql-server-linux:latest image: mcr.microsoft.com/mssql/server:latest
environment: environment:
ACCEPT_EULA: Y ACCEPT_EULA: Y
MSSQL_PID: Standard MSSQL_PID: Standard
@@ -54,52 +103,23 @@ steps:
exclude: exclude:
- pull_request - pull_request
- name: pre-build
pull: always
image: node:10 # this step is kept at the lowest version of node that we support
commands:
- make css
- make js
- name: build-without-gcc
pull: always
image: golang:1.11 # this step is kept as the lowest version of golang that we support
environment:
GO111MODULE: on
GOPROXY: off
commands:
- curl -sL https://deb.nodesource.com/setup_12.x | bash - && apt -y install nodejs
- go build -mod=vendor -o gitea_no_gcc # test if build succeeds without the sqlite tag
- name: build-linux-386
pull: always
image: golang:1.13
environment:
GO111MODULE: on
GOPROXY: off
GOOS: linux
GOARCH: 386
commands:
- curl -sL https://deb.nodesource.com/setup_12.x | bash - && apt -y install nodejs
- go build -mod=vendor -o gitea_linux_386 # test if compatible with 32 bit
- name: build - name: build
pull: always pull: always
image: golang:1.13 image: golang:1.13
commands: commands:
- curl -sL https://deb.nodesource.com/setup_12.x | bash - && apt -y install nodejs - curl -sL https://deb.nodesource.com/setup_12.x | bash - && apt -y install nodejs
- make clean
- make golangci-lint
- make revive
- make swagger-check
- make swagger-validate
- make test-vendor
- make build - make build
environment: environment:
GOPROXY: https://goproxy.cn # proxy.golang.org is blocked in China, this proxy is not GOPROXY: https://goproxy.cn # proxy.golang.org is blocked in China, this proxy is not
GOSUMDB: sum.golang.org GOSUMDB: sum.golang.org
TAGS: bindata sqlite sqlite_unlock_notify TAGS: bindata sqlite sqlite_unlock_notify
- name: tag-pre-condition
pull: always
image: alpine/git
commands:
- git update-ref refs/heads/tag_test ${DRONE_COMMIT_SHA}
- name: unit-test - name: unit-test
pull: always pull: always
image: golang:1.13 image: golang:1.13
@@ -108,70 +128,8 @@ steps:
environment: environment:
GOPROXY: off GOPROXY: off
TAGS: bindata sqlite sqlite_unlock_notify TAGS: bindata sqlite sqlite_unlock_notify
depends_on: GITHUB_READ_TOKEN:
- build from_secret: github_read_token
when:
branch:
- master
event:
- push
- pull_request
- name: release-test
pull: always
image: golang:1.13
commands:
- make test
environment:
GOPROXY: off
TAGS: bindata sqlite sqlite_unlock_notify
depends_on:
- build
when:
branch:
- "release/*"
event:
- push
- pull_request
- name: tag-pre-condition
pull: always
image: alpine/git
commands:
- git update-ref refs/heads/tag_test ${DRONE_COMMIT_SHA}
depends_on:
- build
when:
event:
- tag
- name: tag-test
pull: always
image: golang:1.13
commands:
- make test
environment:
GOPROXY: off
TAGS: bindata
depends_on:
- tag-pre-condition
when:
event:
- tag
- name: test-sqlite
pull: always
image: golang:1.13
commands:
- "curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash"
- apt-get install -y git-lfs
- timeout -s ABRT 20m make test-sqlite-migration
- timeout -s ABRT 20m make test-sqlite
environment:
GOPROXY: off
TAGS: bindata
depends_on:
- build
- name: test-mysql - name: test-mysql
pull: always pull: always
@@ -187,30 +145,6 @@ steps:
TEST_LDAP: 1 TEST_LDAP: 1
depends_on: depends_on:
- build - build
when:
branch:
- master
event:
- push
- pull_request
- name: tag-test-mysql
pull: always
image: golang:1.13
commands:
- "curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash"
- apt-get install -y git-lfs
- timeout -s ABRT 20m make test-mysql-migration
- timeout -s ABRT 20m make test-mysql
environment:
GOPROXY: off
TAGS: bindata
TEST_LDAP: 1
depends_on:
- build
when:
event:
- tag
- name: test-mysql8 - name: test-mysql8
pull: always pull: always
@@ -227,21 +161,6 @@ steps:
depends_on: depends_on:
- build - build
- name: test-pgsql
pull: always
image: golang:1.13
commands:
- "curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash"
- apt-get install -y git-lfs
- timeout -s ABRT 20m make test-pgsql-migration
- timeout -s ABRT 20m make test-pgsql
environment:
GOPROXY: off
TAGS: bindata
TEST_LDAP: 1
depends_on:
- build
- name: test-mssql - name: test-mssql
pull: always pull: always
image: golang:1.13 image: golang:1.13
@@ -293,13 +212,89 @@ steps:
- push - push
- pull_request - pull_request
---
kind: pipeline
name: testing-arm64
platform:
os: linux
arch: arm64
workspace:
base: /go
path: src/code.gitea.io/gitea
services:
- name: pgsql
pull: default
image: postgres:9.5
environment:
POSTGRES_DB: test
- name: ldap
pull: default
image: gitea/test-openldap:latest
steps:
- name: fetch-tags
pull: default
image: docker:git
commands:
- git fetch --tags --force
when:
event:
exclude:
- pull_request
- name: build
pull: always
image: golang:1.13
commands:
- curl -sL https://deb.nodesource.com/setup_12.x | bash - && apt -y install nodejs
- make build
environment:
GOPROXY: https://goproxy.cn # proxy.golang.org is blocked in China, this proxy is not
GOSUMDB: sum.golang.org
TAGS: bindata sqlite sqlite_unlock_notify
- name: test-sqlite
pull: always
image: golang:1.13
commands:
- "curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash"
- apt-get install -y git-lfs
- timeout -s ABRT 20m make test-sqlite-migration
- timeout -s ABRT 20m make test-sqlite
environment:
GOPROXY: off
TAGS: bindata
depends_on:
- build
- name: test-pgsql
pull: always
image: golang:1.13
commands:
- "curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash"
- apt-get install -y git-lfs
- timeout -s ABRT 20m make test-pgsql-migration
- timeout -s ABRT 20m make test-pgsql
environment:
GOPROXY: off
TAGS: bindata
TEST_LDAP: 1
depends_on:
- build
--- ---
kind: pipeline kind: pipeline
name: translations name: translations
platform: platform:
os: linux os: linux
arch: amd64 arch: arm64
workspace: workspace:
base: /go base: /go
@@ -378,7 +373,8 @@ trigger:
- push - push
depends_on: depends_on:
- testing - testing-amd64
- testing-arm64
- translations - translations
steps: steps:
@@ -476,7 +472,8 @@ trigger:
- tag - tag
depends_on: depends_on:
- testing - testing-arm64
- testing-amd64
steps: steps:
- name: fetch-tags - name: fetch-tags
@@ -545,17 +542,14 @@ name: docs
platform: platform:
os: linux os: linux
arch: amd64 arch: arm64
workspace:
base: /go
path: src/code.gitea.io/gitea
steps: steps:
- name: build-docs - name: build-docs
pull: always pull: always
image: webhippie/hugo:latest image: plugins/hugo:latest
commands: commands:
- apk add --no-cache make bash curl
- cd docs - cd docs
- make trans-copy - make trans-copy
- make clean - make clean
@@ -563,7 +557,7 @@ steps:
- name: publish-docs - name: publish-docs
pull: always pull: always
image: lucap/drone-netlify:latest image: techknowlogick/drone-netlify:latest
settings: settings:
path: docs/public/ path: docs/public/
site_id: d2260bae-7861-4c02-8646-8f6440b12672 site_id: d2260bae-7861-4c02-8646-8f6440b12672
@@ -578,7 +572,7 @@ steps:
--- ---
kind: pipeline kind: pipeline
name: docker-linux-amd64 name: docker-linux-amd64-release
platform: platform:
os: linux os: linux
@@ -589,13 +583,13 @@ workspace:
path: src/code.gitea.io/gitea path: src/code.gitea.io/gitea
depends_on: depends_on:
- testing - testing-amd64
- testing-arm64
trigger: trigger:
ref: ref:
- refs/heads/master - refs/heads/master
- "refs/tags/**" - "refs/tags/**"
- "refs/pull/**"
steps: steps:
- name: fetch-tags - name: fetch-tags
@@ -603,23 +597,6 @@ steps:
image: docker:git image: docker:git
commands: commands:
- git fetch --tags --force - git fetch --tags --force
when:
event:
exclude:
- pull_request
- name: dryrun
pull: always
image: plugins/docker:linux-amd64
settings:
dry_run: true
repo: gitea/gitea
tags: linux-amd64
build_args:
- GOPROXY=off
when:
event:
- pull_request
- name: publish - name: publish
pull: always pull: always
@@ -641,7 +618,7 @@ steps:
--- ---
kind: pipeline kind: pipeline
name: docker-linux-arm64 name: docker-linux-arm64-dry-run
platform: platform:
os: linux os: linux
@@ -652,25 +629,13 @@ workspace:
path: src/code.gitea.io/gitea path: src/code.gitea.io/gitea
depends_on: depends_on:
- testing - compliance
trigger: trigger:
ref: ref:
- refs/heads/master
- "refs/tags/**"
- "refs/pull/**" - "refs/pull/**"
steps: steps:
- name: fetch-tags
pull: default
image: docker:git
commands:
- git fetch --tags --force
when:
event:
exclude:
- pull_request
- name: dryrun - name: dryrun
pull: always pull: always
image: plugins/docker:linux-arm64 image: plugins/docker:linux-arm64
@@ -684,6 +649,33 @@ steps:
event: event:
- pull_request - pull_request
---
kind: pipeline
name: docker-linux-arm64-release
platform:
os: linux
arch: arm64
workspace:
base: /go
path: src/code.gitea.io/gitea
depends_on:
- testing-amd64
- testing-arm64
trigger:
ref:
- refs/heads/master
- "refs/tags/**"
steps:
- name: fetch-tags
pull: default
image: docker:git
commands:
- git fetch --tags --force
- name: publish - name: publish
pull: always pull: always
image: plugins/docker:linux-arm64 image: plugins/docker:linux-arm64
@@ -729,45 +721,49 @@ trigger:
- "refs/tags/**" - "refs/tags/**"
depends_on: depends_on:
- docker-linux-amd64 - docker-linux-amd64-release
- docker-linux-arm64 - docker-linux-arm64-release
--- ---
kind: pipeline kind: pipeline
name: notify name: notifications
platform: platform:
os: linux os: linux
arch: amd64 arch: arm64
workspace:
base: /go
path: src/code.gitea.io/gitea
clone: clone:
disable: true disable: true
when: trigger:
branch:
- master
- "release/*"
event:
- push
- tag
status: status:
- success - success
- failure - failure
depends_on: depends_on:
- testing - testing-amd64
- testing-arm64
- translations - translations
- release-version - release-version
- release-master - release-master
- docker-linux-amd64 - docker-linux-amd64-release
- docker-linux-arm64 - docker-linux-arm64-release
- docker-manifest - docker-manifest
- docs - docs
steps: steps:
- name: discord - name: discord
pull: always pull: always
image: appleboy/drone-discord:1.0.0 image: appleboy/drone-discord:1.2.4
environment: settings:
DISCORD_WEBHOOK_ID: message: "{{#success build.status}} ✅ Build #{{build.number}} of `{{repo.name}}` succeeded.\n\n📝 Commit by {{commit.author}} on `{{commit.branch}}`:\n``` {{commit.message}} ```\n\n🌐 {{ build.link }} {{else}} ❌ Build #{{build.number}} of `{{repo.name}}` failed.\n\n📝 Commit by {{commit.author}} on `{{commit.branch}}`:\n``` {{commit.message}} ```\n\n🌐 {{ build.link }} {{/success}}\n"
webhook_id:
from_secret: discord_webhook_id from_secret: discord_webhook_id
DISCORD_WEBHOOK_TOKEN: webhook_token:
from_secret: discord_webhook_token from_secret: discord_webhook_token

View File

@@ -4,6 +4,62 @@ This changelog goes through all the changes that have been made in each release
without substantial changes to our git log; to see the highlights of what has without substantial changes to our git log; to see the highlights of what has
been added to each release, please refer to the [blog](https://blog.gitea.io). been added to each release, please refer to the [blog](https://blog.gitea.io).
## [1.11.0-RC2](https://github.com/go-gitea/gitea/releases/tag/v1.11.0-rc2) - 2020-01-18
* BREAKING
* Make CertFile and KeyFile relative to CustomPath (#9868) (#9874)
* SECURITY
* Never allow an empty password to validate (#9682) (#9683)
* Prevent redirect to Host (#9678) (#9679)
* BUGFIXES
* Don't convert ellipsis in markdown (#9905) (#9937)
* Fixed repo link in generated comment for cross repository dependency (#9863) (#9935)
* Check if diff actually contains sections when rendering (#9926) (#9933)
* Fix wrong hint when status checking is running on pull request view (#9886) (#9928)
* Fix RocketChat (#9908) (#9921)
* Do not try to recreate ldap user if they are already created (#9900) (#9919)
* Create terminated channel in queue_redis (#9910) (#9911)
* Prevent empty LDAP search result from deactivating all users (#9879) (#9896)
* Fix wrong permissions check when issues/prs shared operations (#9885) (#9889)
* Check user != nil before checking values (#9881) (#9883)
* Allow hyphen in language name (#9873) (#9880)
* Ensure that 2fa is checked on reset-password (#9857) (#9876)
* Fix issues/pulls dependencies problems (#9842) (#9864)
* Explicitly refer to PR in squash-merge commit message in case of external tracker (#9844) (#9855)
* Fix markdown anchor links (#9673) (#9840)
* Allow assignee on Pull Creation when Issue Unit is deactivated (#9836) (#9837)
* Fix download file wrong content-type (#9825) (#9834)
* Fix wrong poster identity on a migrated pull request when submit review (#9827) (#9830)
* Fix database dump when log directory is missing (#9818) (#9819)
* Fix compare (#9808) (#9814)
* Fix push-to-create (#9772) (#9797)
* Fix missing msteam webhook on organization (#9781) (#9794)
* Fix missing unlock in uniquequeue (#9790) (#9791)
* Fix add team on collaborator page when same name as organization (#9778)
* DeleteRepoFile incorrectly handles Delete to new branch (#9769) (#9775)
* Fix milestones page (#9771)
* Fix SimpleMDE quote reply (#9757) (#9768)
* Fix missing updated time on migrated issues and comments (#9744) (#9764)
* Move Errored PRs out of StatusChecking (#9675) (#9726)
* Make hook status printing configurable with delay (#9641) (#9725)
* Fix /repos/issues/search (#9698) (#9724)
* Silence fomantic error regarding tabs (#9713) (#9718)
* Remove unused lock (#9709) (#9710)
* Remove q.lock.Unlock() in setInternal to prevent panic (#9705) (#9706)
* Load milestone in API PR list (#9671) (#9700)
* Don't attempt to close issue if already closed (#9696) (#9699)
* Remove google font call (#9668) (#9681)
* Eliminate horizontal scroll caused by footer (#9674)
* Fix nil reference in repo generation (#9660) (#9666)
* Add HTML URL to API Issues (#9654) (#9661)
* Add PR review webhook to Telegram (#9653) (#9655)
* Use filepath.IsAbs instead of path.IsAbs (#9651) (#9652)
* TRANSLATION
* Fix Korean locales (#9761) (#9780)
* BUILD
* Fix webpack polyfills (#9735) (#9738)
* MISC
* Backport Locales [2020-01-14] (#9773)
## [1.11.0-RC1](https://github.com/go-gitea/gitea/releases/tag/v1.11.0-rc1) - 2020-01-07 ## [1.11.0-RC1](https://github.com/go-gitea/gitea/releases/tag/v1.11.0-rc1) - 2020-01-07
* BREAKING * BREAKING
* Remove unused endpoints (#9538) * Remove unused endpoints (#9538)
@@ -384,6 +440,24 @@ been added to each release, please refer to the [blog](https://blog.gitea.io).
* Update CodeMirror to version 5.49.0 (#8381) * Update CodeMirror to version 5.49.0 (#8381)
* Wiki editor: enable side-by-side button (#7242) * Wiki editor: enable side-by-side button (#7242)
## [1.10.3](https://github.com/go-gitea/gitea/releases/tag/v1.10.3) - 2020-01-17
* SECURITY
* Hide credentials when submitting migration (#9102) (#9704)
* Never allow an empty password to validate (#9682) (#9684)
* Prevent redirect to Host (#9678) (#9680)
* Hide public repos owned by private orgs (#9609) (#9616)
* BUGFIXES
* Allow assignee on Pull Creation when Issue Unit is deactivated (#9836) (#9838)
* Fix download file wrong content-type (#9825) (#9835)
* Fix wrong identify poster on a migrated pull request when submit review (#9827) (#9831)
* Fix dump non-exist log directory (#9818) (#9820)
* Fix compare (#9808) (#9815)
* Fix missing msteam webhook on organization (#9781) (#9795)
* Fix add team on collaborator page when same name as organization (#9783)
* Fix cache problem on dashboard (#9358) (#9703)
* Send tag create and push webhook when release created on UI (#8671) (#9702)
* Branches not at ref commit ID should not be listed as Merged (#9614) (#9639)
## [1.10.2](https://github.com/go-gitea/gitea/releases/tag/v1.10.2) - 2020-01-02 ## [1.10.2](https://github.com/go-gitea/gitea/releases/tag/v1.10.2) - 2020-01-02
* BUGFIXES * BUGFIXES
* Allow only specific Columns to be updated on Issue via API (#9539) (#9580) * Allow only specific Columns to be updated on Issue via API (#9539) (#9580)
@@ -1483,13 +1557,13 @@ been added to each release, please refer to the [blog](https://blog.gitea.io).
* BUGFIXES * BUGFIXES
* Allow resend of confirmation email when logged in (#6482) (#6487) * Allow resend of confirmation email when logged in (#6482) (#6487)
## [1.7.5](https://github.com/go-gitea/gitea/releases/tag/v1.7.5) - 2019-03-27 ## [1.7.5](https://github.com/go-gitea/gitea/releases/tag/v1.7.5) - 2019-03-27
* BUGFIXES * BUGFIXES
* Fix unitTypeCode not being used in accessLevelUnit (#6419) (#6423) * Fix unitTypeCode not being used in accessLevelUnit (#6419) (#6423)
* Fix bug where manifest.json was being requested without cookies and continuously creating new sessions (#6372) (#6383) * Fix bug where manifest.json was being requested without cookies and continuously creating new sessions (#6372) (#6383)
* Fix ParsePatch function to work with quoted diff --git strings (#6323) (#6332) * Fix ParsePatch function to work with quoted diff --git strings (#6323) (#6332)
## [1.7.4](https://github.com/go-gitea/gitea/releases/tag/v1.7.4) - 2019-03-12 ## [1.7.4](https://github.com/go-gitea/gitea/releases/tag/v1.7.4) - 2019-03-12
* SECURITY * SECURITY
* Fix potential XSS vulnerability in repository description. (#6306) (#6308) * Fix potential XSS vulnerability in repository description. (#6306) (#6308)
* BUGFIXES * BUGFIXES

View File

@@ -119,6 +119,13 @@ go-check:
exit 1; \ exit 1; \
fi fi
.PHONY: git-check
git-check:
@if git lfs >/dev/null 2>&1 ; then : ; else \
echo "Gitea requires git with lfs support to run tests." ; \
exit 1; \
fi
.PHONY: node-check .PHONY: node-check
node-check: node-check:
$(eval NODE_VERSION := $(shell printf "%03d%03d%03d" $(shell node -v | grep -Eo '[0-9]+\.?[0-9]+?\.?[0-9]?' | tr '.' ' ');)) $(eval NODE_VERSION := $(shell printf "%03d%03d%03d" $(shell node -v | grep -Eo '[0-9]+\.?[0-9]+?\.?[0-9]?' | tr '.' ' ');))
@@ -233,7 +240,7 @@ coverage:
.PHONY: unit-test-coverage .PHONY: unit-test-coverage
unit-test-coverage: unit-test-coverage:
$(GO) test -tags='sqlite sqlite_unlock_notify' -cover -coverprofile coverage.out $(PACKAGES) && echo "\n==>\033[32m Ok\033[m\n" || exit 1 GO111MODULE=on $(GO) test -mod=vendor -tags='sqlite sqlite_unlock_notify' -cover -coverprofile coverage.out $(PACKAGES) && echo "\n==>\033[32m Ok\033[m\n" || exit 1
.PHONY: vendor .PHONY: vendor
vendor: vendor:
@@ -376,7 +383,7 @@ integrations.mssql.test: $(GO_SOURCES)
integrations.sqlite.test: $(GO_SOURCES) integrations.sqlite.test: $(GO_SOURCES)
GO111MODULE=on $(GO) test -mod=vendor -c code.gitea.io/gitea/integrations -o integrations.sqlite.test -tags 'sqlite sqlite_unlock_notify' GO111MODULE=on $(GO) test -mod=vendor -c code.gitea.io/gitea/integrations -o integrations.sqlite.test -tags 'sqlite sqlite_unlock_notify'
integrations.cover.test: $(GO_SOURCES) integrations.cover.test: git-check $(GO_SOURCES)
GO111MODULE=on $(GO) test -mod=vendor -c code.gitea.io/gitea/integrations -coverpkg $(shell echo $(PACKAGES) | tr ' ' ',') -o integrations.cover.test GO111MODULE=on $(GO) test -mod=vendor -c code.gitea.io/gitea/integrations -coverpkg $(shell echo $(PACKAGES) | tr ' ' ',') -o integrations.cover.test
.PHONY: migrations.mysql.test .PHONY: migrations.mysql.test

View File

@@ -61,6 +61,10 @@ var (
Name: "admin-filter", Name: "admin-filter",
Usage: "An LDAP filter specifying if a user should be given administrator privileges.", Usage: "An LDAP filter specifying if a user should be given administrator privileges.",
}, },
cli.BoolFlag{
Name: "allow-deactivate-all",
Usage: "Allow empty search results to deactivate all users.",
},
cli.StringFlag{ cli.StringFlag{
Name: "username-attribute", Name: "username-attribute",
Usage: "The attribute of the users LDAP record containing the user name.", Usage: "The attribute of the users LDAP record containing the user name.",
@@ -231,6 +235,9 @@ func parseLdapConfig(c *cli.Context, config *models.LDAPConfig) error {
if c.IsSet("admin-filter") { if c.IsSet("admin-filter") {
config.Source.AdminFilter = c.String("admin-filter") config.Source.AdminFilter = c.String("admin-filter")
} }
if c.IsSet("allow-deactivate-all") {
config.Source.AllowDeactivateAll = c.Bool("allow-deactivate-all")
}
return nil return nil
} }

View File

@@ -151,8 +151,10 @@ func runDump(ctx *cli.Context) error {
} }
} }
if err := z.AddDir("log", setting.LogRootPath); err != nil { if com.IsExist(setting.LogRootPath) {
fatal("Failed to include log: %v", err) if err := z.AddDir("log", setting.LogRootPath); err != nil {
fatal("Failed to include log: %v", err)
}
} }
if err = z.Close(); err != nil { if err = z.Close(); err != nil {

View File

@@ -8,10 +8,12 @@ import (
"bufio" "bufio"
"bytes" "bytes"
"fmt" "fmt"
"io"
"net/http" "net/http"
"os" "os"
"strconv" "strconv"
"strings" "strings"
"time"
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/git"
@@ -58,6 +60,85 @@ var (
} }
) )
type delayWriter struct {
internal io.Writer
buf *bytes.Buffer
timer *time.Timer
}
func newDelayWriter(internal io.Writer, delay time.Duration) *delayWriter {
timer := time.NewTimer(delay)
return &delayWriter{
internal: internal,
buf: &bytes.Buffer{},
timer: timer,
}
}
func (d *delayWriter) Write(p []byte) (n int, err error) {
if d.buf != nil {
select {
case <-d.timer.C:
_, err := d.internal.Write(d.buf.Bytes())
if err != nil {
return 0, err
}
d.buf = nil
return d.internal.Write(p)
default:
return d.buf.Write(p)
}
}
return d.internal.Write(p)
}
func (d *delayWriter) WriteString(s string) (n int, err error) {
if d.buf != nil {
select {
case <-d.timer.C:
_, err := d.internal.Write(d.buf.Bytes())
if err != nil {
return 0, err
}
d.buf = nil
return d.internal.Write([]byte(s))
default:
return d.buf.WriteString(s)
}
}
return d.internal.Write([]byte(s))
}
func (d *delayWriter) Close() error {
if d == nil {
return nil
}
stopped := d.timer.Stop()
if stopped {
return nil
}
select {
case <-d.timer.C:
default:
}
if d.buf == nil {
return nil
}
_, err := d.internal.Write(d.buf.Bytes())
d.buf = nil
return err
}
type nilWriter struct{}
func (n *nilWriter) Write(p []byte) (int, error) {
return len(p), nil
}
func (n *nilWriter) WriteString(s string) (int, error) {
return len(s), nil
}
func runHookPreReceive(c *cli.Context) error { func runHookPreReceive(c *cli.Context) error {
if os.Getenv(models.EnvIsInternal) == "true" { if os.Getenv(models.EnvIsInternal) == "true" {
return nil return nil
@@ -101,6 +182,18 @@ Gitea or set your environment appropriately.`, "")
total := 0 total := 0
lastline := 0 lastline := 0
var out io.Writer
out = &nilWriter{}
if setting.Git.VerbosePush {
if setting.Git.VerbosePushDelay > 0 {
dWriter := newDelayWriter(os.Stdout, setting.Git.VerbosePushDelay)
defer dWriter.Close()
out = dWriter
} else {
out = os.Stdout
}
}
for scanner.Scan() { for scanner.Scan() {
// TODO: support news feeds for wiki // TODO: support news feeds for wiki
if isWiki { if isWiki {
@@ -124,12 +217,10 @@ Gitea or set your environment appropriately.`, "")
newCommitIDs[count] = newCommitID newCommitIDs[count] = newCommitID
refFullNames[count] = refFullName refFullNames[count] = refFullName
count++ count++
fmt.Fprintf(os.Stdout, "*") fmt.Fprintf(out, "*")
os.Stdout.Sync()
if count >= hookBatchSize { if count >= hookBatchSize {
fmt.Fprintf(os.Stdout, " Checking %d branches\n", count) fmt.Fprintf(out, " Checking %d branches\n", count)
os.Stdout.Sync()
hookOptions.OldCommitIDs = oldCommitIDs hookOptions.OldCommitIDs = oldCommitIDs
hookOptions.NewCommitIDs = newCommitIDs hookOptions.NewCommitIDs = newCommitIDs
@@ -147,12 +238,10 @@ Gitea or set your environment appropriately.`, "")
lastline = 0 lastline = 0
} }
} else { } else {
fmt.Fprintf(os.Stdout, ".") fmt.Fprintf(out, ".")
os.Stdout.Sync()
} }
if lastline >= hookBatchSize { if lastline >= hookBatchSize {
fmt.Fprintf(os.Stdout, "\n") fmt.Fprintf(out, "\n")
os.Stdout.Sync()
lastline = 0 lastline = 0
} }
} }
@@ -162,8 +251,7 @@ Gitea or set your environment appropriately.`, "")
hookOptions.NewCommitIDs = newCommitIDs[:count] hookOptions.NewCommitIDs = newCommitIDs[:count]
hookOptions.RefFullNames = refFullNames[:count] hookOptions.RefFullNames = refFullNames[:count]
fmt.Fprintf(os.Stdout, " Checking %d branches\n", count) fmt.Fprintf(out, " Checking %d branches\n", count)
os.Stdout.Sync()
statusCode, msg := private.HookPreReceive(username, reponame, hookOptions) statusCode, msg := private.HookPreReceive(username, reponame, hookOptions)
switch statusCode { switch statusCode {
@@ -173,14 +261,11 @@ Gitea or set your environment appropriately.`, "")
fail(msg, "") fail(msg, "")
} }
} else if lastline > 0 { } else if lastline > 0 {
fmt.Fprintf(os.Stdout, "\n") fmt.Fprintf(out, "\n")
os.Stdout.Sync()
lastline = 0 lastline = 0
} }
fmt.Fprintf(os.Stdout, "Checked %d references in total\n", total) fmt.Fprintf(out, "Checked %d references in total\n", total)
os.Stdout.Sync()
return nil return nil
} }
@@ -206,6 +291,19 @@ Gitea or set your environment appropriately.`, "")
} }
} }
var out io.Writer
var dWriter *delayWriter
out = &nilWriter{}
if setting.Git.VerbosePush {
if setting.Git.VerbosePushDelay > 0 {
dWriter = newDelayWriter(os.Stdout, setting.Git.VerbosePushDelay)
defer dWriter.Close()
out = dWriter
} else {
out = os.Stdout
}
}
// the environment setted on serv command // the environment setted on serv command
repoUser := os.Getenv(models.EnvRepoUsername) repoUser := os.Getenv(models.EnvRepoUsername)
isWiki := (os.Getenv(models.EnvRepoIsWiki) == "true") isWiki := (os.Getenv(models.EnvRepoIsWiki) == "true")
@@ -241,7 +339,7 @@ Gitea or set your environment appropriately.`, "")
continue continue
} }
fmt.Fprintf(os.Stdout, ".") fmt.Fprintf(out, ".")
oldCommitIDs[count] = string(fields[0]) oldCommitIDs[count] = string(fields[0])
newCommitIDs[count] = string(fields[1]) newCommitIDs[count] = string(fields[1])
refFullNames[count] = string(fields[2]) refFullNames[count] = string(fields[2])
@@ -250,16 +348,15 @@ Gitea or set your environment appropriately.`, "")
} }
count++ count++
total++ total++
os.Stdout.Sync()
if count >= hookBatchSize { if count >= hookBatchSize {
fmt.Fprintf(os.Stdout, " Processing %d references\n", count) fmt.Fprintf(out, " Processing %d references\n", count)
os.Stdout.Sync()
hookOptions.OldCommitIDs = oldCommitIDs hookOptions.OldCommitIDs = oldCommitIDs
hookOptions.NewCommitIDs = newCommitIDs hookOptions.NewCommitIDs = newCommitIDs
hookOptions.RefFullNames = refFullNames hookOptions.RefFullNames = refFullNames
resp, err := private.HookPostReceive(repoUser, repoName, hookOptions) resp, err := private.HookPostReceive(repoUser, repoName, hookOptions)
if resp == nil { if resp == nil {
_ = dWriter.Close()
hookPrintResults(results) hookPrintResults(results)
fail("Internal Server Error", err) fail("Internal Server Error", err)
} }
@@ -277,9 +374,9 @@ Gitea or set your environment appropriately.`, "")
fail("Internal Server Error", "SetDefaultBranch failed with Error: %v", err) fail("Internal Server Error", "SetDefaultBranch failed with Error: %v", err)
} }
} }
fmt.Fprintf(os.Stdout, "Processed %d references in total\n", total) fmt.Fprintf(out, "Processed %d references in total\n", total)
os.Stdout.Sync()
_ = dWriter.Close()
hookPrintResults(results) hookPrintResults(results)
return nil return nil
} }
@@ -288,19 +385,18 @@ Gitea or set your environment appropriately.`, "")
hookOptions.NewCommitIDs = newCommitIDs[:count] hookOptions.NewCommitIDs = newCommitIDs[:count]
hookOptions.RefFullNames = refFullNames[:count] hookOptions.RefFullNames = refFullNames[:count]
fmt.Fprintf(os.Stdout, " Processing %d references\n", count) fmt.Fprintf(out, " Processing %d references\n", count)
os.Stdout.Sync()
resp, err := private.HookPostReceive(repoUser, repoName, hookOptions) resp, err := private.HookPostReceive(repoUser, repoName, hookOptions)
if resp == nil { if resp == nil {
_ = dWriter.Close()
hookPrintResults(results) hookPrintResults(results)
fail("Internal Server Error", err) fail("Internal Server Error", err)
} }
wasEmpty = wasEmpty || resp.RepoWasEmpty wasEmpty = wasEmpty || resp.RepoWasEmpty
results = append(results, resp.Results...) results = append(results, resp.Results...)
fmt.Fprintf(os.Stdout, "Processed %d references in total\n", total) fmt.Fprintf(out, "Processed %d references in total\n", total)
os.Stdout.Sync()
if wasEmpty && masterPushed { if wasEmpty && masterPushed {
// We need to tell the repo to reset the default branch to master // We need to tell the repo to reset the default branch to master
@@ -309,7 +405,7 @@ Gitea or set your environment appropriately.`, "")
fail("Internal Server Error", "SetDefaultBranch failed with Error: %v", err) fail("Internal Server Error", "SetDefaultBranch failed with Error: %v", err)
} }
} }
_ = dWriter.Close()
hookPrintResults(results) hookPrintResults(results)
return nil return nil

View File

@@ -275,8 +275,9 @@ DISABLE_ROUTER_LOG = false
; not forget to export the private key): ; not forget to export the private key):
; $ openssl pkcs12 -in cert.pfx -out cert.pem -nokeys ; $ openssl pkcs12 -in cert.pfx -out cert.pem -nokeys
; $ openssl pkcs12 -in cert.pfx -out key.pem -nocerts -nodes ; $ openssl pkcs12 -in cert.pfx -out key.pem -nocerts -nodes
CERT_FILE = custom/https/cert.pem ; Paths are relative to CUSTOM_PATH
KEY_FILE = custom/https/key.pem CERT_FILE = https/cert.pem
KEY_FILE = https/key.pem
; Root directory containing templates and static files. ; Root directory containing templates and static files.
; default is the path where Gitea is executed ; default is the path where Gitea is executed
STATIC_ROOT_PATH = STATIC_ROOT_PATH =

View File

@@ -181,8 +181,8 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`.
- `SSH_LISTEN_PORT`: **%(SSH\_PORT)s**: Port for the built-in SSH server. - `SSH_LISTEN_PORT`: **%(SSH\_PORT)s**: Port for the built-in SSH server.
- `OFFLINE_MODE`: **false**: Disables use of CDN for static files and Gravatar for profile pictures. - `OFFLINE_MODE`: **false**: Disables use of CDN for static files and Gravatar for profile pictures.
- `DISABLE_ROUTER_LOG`: **false**: Mute printing of the router log. - `DISABLE_ROUTER_LOG`: **false**: Mute printing of the router log.
- `CERT_FILE`: **custom/https/cert.pem**: Cert file path used for HTTPS. - `CERT_FILE`: **https/cert.pem**: Cert file path used for HTTPS. From 1.11 paths are relative to `CUSTOM_PATH`.
- `KEY_FILE`: **custom/https/key.pem**: Key file path used for HTTPS. - `KEY_FILE`: **https/key.pem**: Key file path used for HTTPS. From 1.11 paths are relative to `CUSTOM_PATH`.
- `STATIC_ROOT_PATH`: **./**: Upper level of template and static files path. - `STATIC_ROOT_PATH`: **./**: Upper level of template and static files path.
- `STATIC_CACHE_TIME`: **6h**: Web browser cache time for static resources on `custom/`, `public/` and all uploaded avatars. - `STATIC_CACHE_TIME`: **6h**: Web browser cache time for static resources on `custom/`, `public/` and all uploaded avatars.
- `ENABLE_GZIP`: **false**: Enables application-level GZIP support. - `ENABLE_GZIP`: **false**: Enables application-level GZIP support.
@@ -522,6 +522,8 @@ NB: You must `REDIRECT_MACARON_LOG` and have `DISABLE_ROUTER_LOG` set to `false`
- `MAX_GIT_DIFF_FILES`: **100**: Max number of files shown in diff view. - `MAX_GIT_DIFF_FILES`: **100**: Max number of files shown in diff view.
- `GC_ARGS`: **\<empty\>**: Arguments for command `git gc`, e.g. `--aggressive --auto`. See more on http://git-scm.com/docs/git-gc/ - `GC_ARGS`: **\<empty\>**: Arguments for command `git gc`, e.g. `--aggressive --auto`. See more on http://git-scm.com/docs/git-gc/
- `ENABLE_AUTO_GIT_WIRE_PROTOCOL`: **true**: If use git wire protocol version 2 when git version >= 2.18, default is true, set to false when you always want git wire protocol version 1 - `ENABLE_AUTO_GIT_WIRE_PROTOCOL`: **true**: If use git wire protocol version 2 when git version >= 2.18, default is true, set to false when you always want git wire protocol version 1
- `VERBOSE_PUSH`: **true**: Print status information about pushes as they are being processed.
- `VERBOSE_PUSH_DELAY`: **5s**: Only print verbose information if push takes longer than this delay.
## Git - Timeout settings (`git.timeout`) ## Git - Timeout settings (`git.timeout`)
- `DEFAUlT`: **360**: Git operations default timeout seconds. - `DEFAUlT`: **360**: Git operations default timeout seconds.

View File

@@ -136,7 +136,8 @@ the `!` marker to identify pull requests. For example:
> This is pull request [!1234](#), and links to a pull request in Gitea. > This is pull request [!1234](#), and links to a pull request in Gitea.
The `!` and `#` can be used interchangeably for issues and pull request _except_ The `!` and `#` can be used interchangeably for issues and pull request _except_
for this case, where a distinction is required. for this case, where a distinction is required. If the repository uses external
tracker, commit message for squash merge will use `!` as reference by default.
## Issues and Pull Requests References Summary ## Issues and Pull Requests References Summary

View File

@@ -7,6 +7,7 @@ package integrations
import ( import (
"fmt" "fmt"
"net/http" "net/http"
"net/url"
"testing" "testing"
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
@@ -120,3 +121,47 @@ func TestAPIEditIssue(t *testing.T) {
assert.Equal(t, body, issueAfter.Content) assert.Equal(t, body, issueAfter.Content)
assert.Equal(t, title, issueAfter.Title) assert.Equal(t, title, issueAfter.Title)
} }
func TestAPISearchIssue(t *testing.T) {
defer prepareTestEnv(t)()
session := loginUser(t, "user2")
token := getTokenForLoggedInUser(t, session)
link, _ := url.Parse("/api/v1/repos/issues/search")
req := NewRequest(t, "GET", link.String())
resp := session.MakeRequest(t, req, http.StatusOK)
var apiIssues []*api.Issue
DecodeJSON(t, resp, &apiIssues)
assert.Len(t, apiIssues, 8)
query := url.Values{}
query.Add("token", token)
link.RawQuery = query.Encode()
req = NewRequest(t, "GET", link.String())
resp = session.MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &apiIssues)
assert.Len(t, apiIssues, 8)
query.Add("state", "closed")
link.RawQuery = query.Encode()
req = NewRequest(t, "GET", link.String())
resp = session.MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &apiIssues)
assert.Len(t, apiIssues, 2)
query.Set("state", "all")
link.RawQuery = query.Encode()
req = NewRequest(t, "GET", link.String())
resp = session.MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &apiIssues)
assert.Len(t, apiIssues, 10) //there are more but 10 is page item limit
query.Add("page", "2")
link.RawQuery = query.Encode()
req = NewRequest(t, "GET", link.String())
resp = session.MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &apiIssues)
assert.Len(t, apiIssues, 0)
}

View File

@@ -11,7 +11,6 @@ import (
"strings" "strings"
"testing" "testing"
"code.gitea.io/gitea/models"
api "code.gitea.io/gitea/modules/structs" api "code.gitea.io/gitea/modules/structs"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@@ -48,20 +47,20 @@ func TestPullCreate_CommitStatus(t *testing.T) {
commitID := path.Base(commitURL) commitID := path.Base(commitURL)
statusList := []models.CommitStatusState{ statusList := []api.CommitStatusState{
models.CommitStatusPending, api.CommitStatusPending,
models.CommitStatusError, api.CommitStatusError,
models.CommitStatusFailure, api.CommitStatusFailure,
models.CommitStatusWarning, api.CommitStatusWarning,
models.CommitStatusSuccess, api.CommitStatusSuccess,
} }
statesIcons := map[models.CommitStatusState]string{ statesIcons := map[api.CommitStatusState]string{
models.CommitStatusPending: "circle icon yellow", api.CommitStatusPending: "circle icon yellow",
models.CommitStatusSuccess: "check icon green", api.CommitStatusSuccess: "check icon green",
models.CommitStatusError: "warning icon red", api.CommitStatusError: "warning icon red",
models.CommitStatusFailure: "remove icon red", api.CommitStatusFailure: "remove icon red",
models.CommitStatusWarning: "warning sign icon yellow", api.CommitStatusWarning: "warning sign icon yellow",
} }
// Update commit status, and check if icon is updated as well // Update commit status, and check if icon is updated as well

View File

@@ -19,52 +19,19 @@ import (
"xorm.io/xorm" "xorm.io/xorm"
) )
// CommitStatusState holds the state of a Status
// It can be "pending", "success", "error", "failure", and "warning"
type CommitStatusState string
// IsWorseThan returns true if this State is worse than the given State
func (css CommitStatusState) IsWorseThan(css2 CommitStatusState) bool {
switch css {
case CommitStatusError:
return true
case CommitStatusFailure:
return css2 != CommitStatusError
case CommitStatusWarning:
return css2 != CommitStatusError && css2 != CommitStatusFailure
case CommitStatusSuccess:
return css2 != CommitStatusError && css2 != CommitStatusFailure && css2 != CommitStatusWarning
default:
return css2 != CommitStatusError && css2 != CommitStatusFailure && css2 != CommitStatusWarning && css2 != CommitStatusSuccess
}
}
const (
// CommitStatusPending is for when the Status is Pending
CommitStatusPending CommitStatusState = "pending"
// CommitStatusSuccess is for when the Status is Success
CommitStatusSuccess CommitStatusState = "success"
// CommitStatusError is for when the Status is Error
CommitStatusError CommitStatusState = "error"
// CommitStatusFailure is for when the Status is Failure
CommitStatusFailure CommitStatusState = "failure"
// CommitStatusWarning is for when the Status is Warning
CommitStatusWarning CommitStatusState = "warning"
)
// CommitStatus holds a single Status of a single Commit // CommitStatus holds a single Status of a single Commit
type CommitStatus struct { type CommitStatus struct {
ID int64 `xorm:"pk autoincr"` ID int64 `xorm:"pk autoincr"`
Index int64 `xorm:"INDEX UNIQUE(repo_sha_index)"` Index int64 `xorm:"INDEX UNIQUE(repo_sha_index)"`
RepoID int64 `xorm:"INDEX UNIQUE(repo_sha_index)"` RepoID int64 `xorm:"INDEX UNIQUE(repo_sha_index)"`
Repo *Repository `xorm:"-"` Repo *Repository `xorm:"-"`
State CommitStatusState `xorm:"VARCHAR(7) NOT NULL"` State api.CommitStatusState `xorm:"VARCHAR(7) NOT NULL"`
SHA string `xorm:"VARCHAR(64) NOT NULL INDEX UNIQUE(repo_sha_index)"` SHA string `xorm:"VARCHAR(64) NOT NULL INDEX UNIQUE(repo_sha_index)"`
TargetURL string `xorm:"TEXT"` TargetURL string `xorm:"TEXT"`
Description string `xorm:"TEXT"` Description string `xorm:"TEXT"`
ContextHash string `xorm:"char(40) index"` ContextHash string `xorm:"char(40) index"`
Context string `xorm:"TEXT"` Context string `xorm:"TEXT"`
Creator *User `xorm:"-"` Creator *User `xorm:"-"`
CreatorID int64 CreatorID int64
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
@@ -118,9 +85,9 @@ func (status *CommitStatus) APIFormat() *api.Status {
// CalcCommitStatus returns commit status state via some status, the commit statues should order by id desc // CalcCommitStatus returns commit status state via some status, the commit statues should order by id desc
func CalcCommitStatus(statuses []*CommitStatus) *CommitStatus { func CalcCommitStatus(statuses []*CommitStatus) *CommitStatus {
var lastStatus *CommitStatus var lastStatus *CommitStatus
var state CommitStatusState var state api.CommitStatusState
for _, status := range statuses { for _, status := range statuses {
if status.State.IsWorseThan(state) { if status.State.NoBetterThan(state) {
state = status.State state = status.State
lastStatus = status lastStatus = status
} }

View File

@@ -7,6 +7,7 @@ package models
import ( import (
"testing" "testing"
"code.gitea.io/gitea/modules/structs"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@@ -23,22 +24,22 @@ func TestGetCommitStatuses(t *testing.T) {
assert.Len(t, statuses, 5) assert.Len(t, statuses, 5)
assert.Equal(t, "ci/awesomeness", statuses[0].Context) assert.Equal(t, "ci/awesomeness", statuses[0].Context)
assert.Equal(t, CommitStatusPending, statuses[0].State) assert.Equal(t, structs.CommitStatusPending, statuses[0].State)
assert.Equal(t, "https://try.gitea.io/api/v1/repos/user2/repo1/statuses/1234123412341234123412341234123412341234", statuses[0].APIURL()) assert.Equal(t, "https://try.gitea.io/api/v1/repos/user2/repo1/statuses/1234123412341234123412341234123412341234", statuses[0].APIURL())
assert.Equal(t, "cov/awesomeness", statuses[1].Context) assert.Equal(t, "cov/awesomeness", statuses[1].Context)
assert.Equal(t, CommitStatusWarning, statuses[1].State) assert.Equal(t, structs.CommitStatusWarning, statuses[1].State)
assert.Equal(t, "https://try.gitea.io/api/v1/repos/user2/repo1/statuses/1234123412341234123412341234123412341234", statuses[1].APIURL()) assert.Equal(t, "https://try.gitea.io/api/v1/repos/user2/repo1/statuses/1234123412341234123412341234123412341234", statuses[1].APIURL())
assert.Equal(t, "cov/awesomeness", statuses[2].Context) assert.Equal(t, "cov/awesomeness", statuses[2].Context)
assert.Equal(t, CommitStatusSuccess, statuses[2].State) assert.Equal(t, structs.CommitStatusSuccess, statuses[2].State)
assert.Equal(t, "https://try.gitea.io/api/v1/repos/user2/repo1/statuses/1234123412341234123412341234123412341234", statuses[2].APIURL()) assert.Equal(t, "https://try.gitea.io/api/v1/repos/user2/repo1/statuses/1234123412341234123412341234123412341234", statuses[2].APIURL())
assert.Equal(t, "ci/awesomeness", statuses[3].Context) assert.Equal(t, "ci/awesomeness", statuses[3].Context)
assert.Equal(t, CommitStatusFailure, statuses[3].State) assert.Equal(t, structs.CommitStatusFailure, statuses[3].State)
assert.Equal(t, "https://try.gitea.io/api/v1/repos/user2/repo1/statuses/1234123412341234123412341234123412341234", statuses[3].APIURL()) assert.Equal(t, "https://try.gitea.io/api/v1/repos/user2/repo1/statuses/1234123412341234123412341234123412341234", statuses[3].APIURL())
assert.Equal(t, "deploy/awesomeness", statuses[4].Context) assert.Equal(t, "deploy/awesomeness", statuses[4].Context)
assert.Equal(t, CommitStatusError, statuses[4].State) assert.Equal(t, structs.CommitStatusError, statuses[4].State)
assert.Equal(t, "https://try.gitea.io/api/v1/repos/user2/repo1/statuses/1234123412341234123412341234123412341234", statuses[4].APIURL()) assert.Equal(t, "https://try.gitea.io/api/v1/repos/user2/repo1/statuses/1234123412341234123412341234123412341234", statuses[4].APIURL())
} }

View File

@@ -381,6 +381,7 @@ func (issue *Issue) apiFormat(e Engine) *api.Issue {
apiIssue := &api.Issue{ apiIssue := &api.Issue{
ID: issue.ID, ID: issue.ID,
URL: issue.APIURL(), URL: issue.APIURL(),
HTMLURL: issue.HTMLURL(),
Index: issue.Index, Index: issue.Index,
Poster: issue.Poster.APIFormat(), Poster: issue.Poster.APIFormat(),
Title: issue.Title, Title: issue.Title,
@@ -402,11 +403,12 @@ func (issue *Issue) apiFormat(e Engine) *api.Issue {
apiIssue.Closed = issue.ClosedUnix.AsTimePtr() apiIssue.Closed = issue.ClosedUnix.AsTimePtr()
} }
issue.loadMilestone(e)
if issue.Milestone != nil { if issue.Milestone != nil {
apiIssue.Milestone = issue.Milestone.APIFormat() apiIssue.Milestone = issue.Milestone.APIFormat()
} }
issue.loadAssignees(e)
issue.loadAssignees(e)
if len(issue.Assignees) > 0 { if len(issue.Assignees) > 0 {
for _, assignee := range issue.Assignees { for _, assignee := range issue.Assignees {
apiIssue.Assignees = append(apiIssue.Assignees, assignee.APIFormat()) apiIssue.Assignees = append(apiIssue.Assignees, assignee.APIFormat())
@@ -436,7 +438,7 @@ func (issue *Issue) HashTag() string {
// IsPoster returns true if given user by ID is the poster. // IsPoster returns true if given user by ID is the poster.
func (issue *Issue) IsPoster(uid int64) bool { func (issue *Issue) IsPoster(uid int64) bool {
return issue.PosterID == uid return issue.OriginalAuthorID == 0 && issue.PosterID == uid
} }
func (issue *Issue) hasLabel(e Engine, labelID int64) bool { func (issue *Issue) hasLabel(e Engine, labelID int64) bool {

View File

@@ -376,6 +376,11 @@ func (comments CommentList) loadDependentIssues(e Engine) error {
for _, comment := range comments { for _, comment := range comments {
if comment.DependentIssue == nil { if comment.DependentIssue == nil {
comment.DependentIssue = issues[comment.DependentIssueID] comment.DependentIssue = issues[comment.DependentIssueID]
if comment.DependentIssue != nil {
if err := comment.DependentIssue.loadRepo(e); err != nil {
return err
}
}
} }
} }
return nil return nil

View File

@@ -461,7 +461,7 @@ var (
// LoginViaLDAP queries if login/password is valid against the LDAP directory pool, // LoginViaLDAP queries if login/password is valid against the LDAP directory pool,
// and create a local user if success when enabled. // and create a local user if success when enabled.
func LoginViaLDAP(user *User, login, password string, source *LoginSource, autoRegister bool) (*User, error) { func LoginViaLDAP(user *User, login, password string, source *LoginSource) (*User, error) {
sr := source.Cfg.(*LDAPConfig).SearchEntry(login, password, source.Type == LoginDLDAP) sr := source.Cfg.(*LDAPConfig).SearchEntry(login, password, source.Type == LoginDLDAP)
if sr == nil { if sr == nil {
// User not in LDAP, do nothing // User not in LDAP, do nothing
@@ -473,17 +473,25 @@ func LoginViaLDAP(user *User, login, password string, source *LoginSource, autoR
// Update User admin flag if exist // Update User admin flag if exist
if isExist, err := IsUserExist(0, sr.Username); err != nil { if isExist, err := IsUserExist(0, sr.Username); err != nil {
return nil, err return nil, err
} else if isExist && } else if isExist {
!user.ProhibitLogin && len(source.LDAP().AdminFilter) > 0 && user.IsAdmin != sr.IsAdmin { if user == nil {
// Change existing admin flag only if AdminFilter option is set user, err = GetUserByName(sr.Username)
user.IsAdmin = sr.IsAdmin if err != nil {
err = UpdateUserCols(user, "is_admin") return nil, err
if err != nil { }
return nil, err }
if user != nil &&
!user.ProhibitLogin && len(source.LDAP().AdminFilter) > 0 && user.IsAdmin != sr.IsAdmin {
// Change existing admin flag only if AdminFilter option is set
user.IsAdmin = sr.IsAdmin
err = UpdateUserCols(user, "is_admin")
if err != nil {
return nil, err
}
} }
} }
if !autoRegister { if user != nil {
if isAttributeSSHPublicKeySet && synchronizeLdapSSHPublicKeys(user, source, sr.SSHPublicKey) { if isAttributeSSHPublicKeySet && synchronizeLdapSSHPublicKeys(user, source, sr.SSHPublicKey) {
return user, RewriteAllPublicKeys() return user, RewriteAllPublicKeys()
} }
@@ -594,7 +602,7 @@ func SMTPAuth(a smtp.Auth, cfg *SMTPConfig) error {
// LoginViaSMTP queries if login/password is valid against the SMTP, // LoginViaSMTP queries if login/password is valid against the SMTP,
// and create a local user if success when enabled. // and create a local user if success when enabled.
func LoginViaSMTP(user *User, login, password string, sourceID int64, cfg *SMTPConfig, autoRegister bool) (*User, error) { func LoginViaSMTP(user *User, login, password string, sourceID int64, cfg *SMTPConfig) (*User, error) {
// Verify allowed domains. // Verify allowed domains.
if len(cfg.AllowedDomains) > 0 { if len(cfg.AllowedDomains) > 0 {
idx := strings.Index(login, "@") idx := strings.Index(login, "@")
@@ -625,7 +633,7 @@ func LoginViaSMTP(user *User, login, password string, sourceID int64, cfg *SMTPC
return nil, err return nil, err
} }
if !autoRegister { if user != nil {
return user, nil return user, nil
} }
@@ -657,7 +665,7 @@ func LoginViaSMTP(user *User, login, password string, sourceID int64, cfg *SMTPC
// LoginViaPAM queries if login/password is valid against the PAM, // LoginViaPAM queries if login/password is valid against the PAM,
// and create a local user if success when enabled. // and create a local user if success when enabled.
func LoginViaPAM(user *User, login, password string, sourceID int64, cfg *PAMConfig, autoRegister bool) (*User, error) { func LoginViaPAM(user *User, login, password string, sourceID int64, cfg *PAMConfig) (*User, error) {
if err := pam.Auth(cfg.ServiceName, login, password); err != nil { if err := pam.Auth(cfg.ServiceName, login, password); err != nil {
if strings.Contains(err.Error(), "Authentication failure") { if strings.Contains(err.Error(), "Authentication failure") {
return nil, ErrUserNotExist{0, login, 0} return nil, ErrUserNotExist{0, login, 0}
@@ -665,7 +673,7 @@ func LoginViaPAM(user *User, login, password string, sourceID int64, cfg *PAMCon
return nil, err return nil, err
} }
if !autoRegister { if user != nil {
return user, nil return user, nil
} }
@@ -683,7 +691,7 @@ func LoginViaPAM(user *User, login, password string, sourceID int64, cfg *PAMCon
} }
// ExternalUserLogin attempts a login using external source types. // ExternalUserLogin attempts a login using external source types.
func ExternalUserLogin(user *User, login, password string, source *LoginSource, autoRegister bool) (*User, error) { func ExternalUserLogin(user *User, login, password string, source *LoginSource) (*User, error) {
if !source.IsActived { if !source.IsActived {
return nil, ErrLoginSourceNotActived return nil, ErrLoginSourceNotActived
} }
@@ -691,11 +699,11 @@ func ExternalUserLogin(user *User, login, password string, source *LoginSource,
var err error var err error
switch source.Type { switch source.Type {
case LoginLDAP, LoginDLDAP: case LoginLDAP, LoginDLDAP:
user, err = LoginViaLDAP(user, login, password, source, autoRegister) user, err = LoginViaLDAP(user, login, password, source)
case LoginSMTP: case LoginSMTP:
user, err = LoginViaSMTP(user, login, password, source.ID, source.Cfg.(*SMTPConfig), autoRegister) user, err = LoginViaSMTP(user, login, password, source.ID, source.Cfg.(*SMTPConfig))
case LoginPAM: case LoginPAM:
user, err = LoginViaPAM(user, login, password, source.ID, source.Cfg.(*PAMConfig), autoRegister) user, err = LoginViaPAM(user, login, password, source.ID, source.Cfg.(*PAMConfig))
default: default:
return nil, ErrUnsupportedLoginType return nil, ErrUnsupportedLoginType
} }
@@ -775,7 +783,7 @@ func UserSignIn(username, password string) (*User, error) {
return nil, ErrLoginSourceNotExist{user.LoginSource} return nil, ErrLoginSourceNotExist{user.LoginSource}
} }
return ExternalUserLogin(user, user.LoginName, password, &source, false) return ExternalUserLogin(user, user.LoginName, password, &source)
} }
} }
@@ -789,7 +797,7 @@ func UserSignIn(username, password string) (*User, error) {
// don't try to authenticate against OAuth2 and SSPI sources here // don't try to authenticate against OAuth2 and SSPI sources here
continue continue
} }
authUser, err := ExternalUserLogin(nil, username, password, source, true) authUser, err := ExternalUserLogin(nil, username, password, source)
if err == nil { if err == nil {
return authUser, nil return authUser, nil
} }

View File

@@ -35,6 +35,7 @@ const (
PullRequestStatusChecking PullRequestStatusChecking
PullRequestStatusMergeable PullRequestStatusMergeable
PullRequestStatusManuallyMerged PullRequestStatusManuallyMerged
PullRequestStatusError
) )
// PullRequest represents relation between pull request and repositories. // PullRequest represents relation between pull request and repositories.
@@ -384,6 +385,13 @@ func (pr *PullRequest) GetDefaultSquashMessage() string {
log.Error("LoadIssue: %v", err) log.Error("LoadIssue: %v", err)
return "" return ""
} }
if err := pr.LoadBaseRepo(); err != nil {
log.Error("LoadBaseRepo: %v", err)
return ""
}
if pr.BaseRepo.UnitEnabled(UnitTypeExternalTracker) {
return fmt.Sprintf("%s (!%d)", pr.Issue.Title, pr.Issue.Index)
}
return fmt.Sprintf("%s (#%d)", pr.Issue.Title, pr.Issue.Index) return fmt.Sprintf("%s (#%d)", pr.Issue.Title, pr.Issue.Index)
} }
@@ -513,7 +521,7 @@ func (pr *PullRequest) apiFormat(e Engine) *api.PullRequest {
} }
if pr.Status != PullRequestStatusChecking { if pr.Status != PullRequestStatusChecking {
mergeable := pr.Status != PullRequestStatusConflict && !pr.IsWorkInProgress() mergeable := !(pr.Status == PullRequestStatusConflict || pr.Status == PullRequestStatusError) && !pr.IsWorkInProgress()
apiPullRequest.Mergeable = mergeable apiPullRequest.Mergeable = mergeable
} }
if pr.HasMerged { if pr.HasMerged {

View File

@@ -124,41 +124,43 @@ func generateRepoCommit(e Engine, repo, templateRepo, generateRepo *Repository,
return fmt.Errorf("checkGiteaTemplate: %v", err) return fmt.Errorf("checkGiteaTemplate: %v", err)
} }
if err := os.Remove(gt.Path); err != nil { if gt != nil {
return fmt.Errorf("remove .giteatemplate: %v", err) if err := os.Remove(gt.Path); err != nil {
} return fmt.Errorf("remove .giteatemplate: %v", err)
}
// Avoid walking tree if there are no globs // Avoid walking tree if there are no globs
if len(gt.Globs()) > 0 { if len(gt.Globs()) > 0 {
tmpDirSlash := strings.TrimSuffix(filepath.ToSlash(tmpDir), "/") + "/" tmpDirSlash := strings.TrimSuffix(filepath.ToSlash(tmpDir), "/") + "/"
if err := filepath.Walk(tmpDirSlash, func(path string, info os.FileInfo, walkErr error) error { if err := filepath.Walk(tmpDirSlash, func(path string, info os.FileInfo, walkErr error) error {
if walkErr != nil { if walkErr != nil {
return walkErr return walkErr
}
if info.IsDir() {
return nil
}
base := strings.TrimPrefix(filepath.ToSlash(path), tmpDirSlash)
for _, g := range gt.Globs() {
if g.Match(base) {
content, err := ioutil.ReadFile(path)
if err != nil {
return err
}
if err := ioutil.WriteFile(path,
[]byte(generateExpansion(string(content), templateRepo, generateRepo)),
0644); err != nil {
return err
}
break
} }
if info.IsDir() {
return nil
}
base := strings.TrimPrefix(filepath.ToSlash(path), tmpDirSlash)
for _, g := range gt.Globs() {
if g.Match(base) {
content, err := ioutil.ReadFile(path)
if err != nil {
return err
}
if err := ioutil.WriteFile(path,
[]byte(generateExpansion(string(content), templateRepo, generateRepo)),
0644); err != nil {
return err
}
break
}
}
return nil
}); err != nil {
return err
} }
return nil
}); err != nil {
return err
} }
} }

View File

@@ -503,7 +503,7 @@ func (u *User) ValidatePassword(passwd string) bool {
// IsPasswordSet checks if the password is set or left empty // IsPasswordSet checks if the password is set or left empty
func (u *User) IsPasswordSet() bool { func (u *User) IsPasswordSet() bool {
return len(u.Passwd) > 0 return !u.ValidatePassword("")
} }
// UploadAvatar saves custom avatar for user. // UploadAvatar saves custom avatar for user.
@@ -1760,6 +1760,15 @@ func SyncExternalUsers(ctx context.Context) {
continue continue
} }
if len(sr) == 0 {
if !s.LDAP().AllowDeactivateAll {
log.Error("LDAP search found no entries but did not report an error. Refusing to deactivate all users")
continue
} else {
log.Warn("LDAP search found no entries but did not report an error. All users will be deactivated as per settings")
}
}
for _, su := range sr { for _, su := range sr {
select { select {
case <-ctx.Done(): case <-ctx.Done():

View File

@@ -30,6 +30,7 @@ type AuthenticationForm struct {
SearchPageSize int SearchPageSize int
Filter string Filter string
AdminFilter string AdminFilter string
AllowDeactivateAll bool
IsActive bool IsActive bool
IsSyncEnabled bool IsSyncEnabled bool
SMTPAuth string SMTPAuth string

View File

@@ -47,6 +47,7 @@ type Source struct {
Filter string // Query filter to validate entry Filter string // Query filter to validate entry
AdminFilter string // Query filter to check if user is admin AdminFilter string // Query filter to check if user is admin
Enabled bool // if this source is disabled Enabled bool // if this source is disabled
AllowDeactivateAll bool // Allow an empty search response to deactivate all users from this source
} }
// SearchResult : user data // SearchResult : user data

View File

@@ -1,4 +1,5 @@
// Copyright 2014 The Gogs Authors. All rights reserved. // Copyright 2014 The Gogs Authors. All rights reserved.
// Copyright 2020 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style // Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
@@ -122,7 +123,7 @@ func (ctx *Context) RedirectToFirst(location ...string) {
} }
u, err := url.Parse(loc) u, err := url.Parse(loc)
if err != nil || (u.Scheme != "" && !strings.HasPrefix(strings.ToLower(loc), strings.ToLower(setting.AppURL))) { if err != nil || ((u.Scheme != "" || u.Host != "") && !strings.HasPrefix(strings.ToLower(loc), strings.ToLower(setting.AppURL))) {
continue continue
} }

View File

@@ -91,12 +91,12 @@ func (r *Repository) CanUseTimetracker(issue *models.Issue, user *models.User) b
// 2. Is the user a contributor, admin, poster or assignee and do the repository policies require this? // 2. Is the user a contributor, admin, poster or assignee and do the repository policies require this?
isAssigned, _ := models.IsUserAssignedToIssue(issue, user) isAssigned, _ := models.IsUserAssignedToIssue(issue, user)
return r.Repository.IsTimetrackerEnabled() && (!r.Repository.AllowOnlyContributorsToTrackTime() || return r.Repository.IsTimetrackerEnabled() && (!r.Repository.AllowOnlyContributorsToTrackTime() ||
r.Permission.CanWrite(models.UnitTypeIssues) || issue.IsPoster(user.ID) || isAssigned) r.Permission.CanWriteIssuesOrPulls(issue.IsPull) || issue.IsPoster(user.ID) || isAssigned)
} }
// CanCreateIssueDependencies returns whether or not a user can create dependencies. // CanCreateIssueDependencies returns whether or not a user can create dependencies.
func (r *Repository) CanCreateIssueDependencies(user *models.User) bool { func (r *Repository) CanCreateIssueDependencies(user *models.User, isPull bool) bool {
return r.Permission.CanWrite(models.UnitTypeIssues) && r.Repository.IsDependenciesEnabled() return r.Repository.IsDependenciesEnabled() && r.Permission.CanWriteIssuesOrPulls(isPull)
} }
// GetCommitsCount returns cached commit count for current view // GetCommitsCount returns cached commit count for current view

View File

@@ -7,6 +7,7 @@ package graceful
import ( import (
"crypto/tls" "crypto/tls"
"io/ioutil"
"net" "net"
"os" "os"
"strings" "strings"
@@ -99,12 +100,25 @@ func (srv *Server) ListenAndServeTLS(certFile, keyFile string, serve ServeFuncti
} }
config.Certificates = make([]tls.Certificate, 1) config.Certificates = make([]tls.Certificate, 1)
var err error
config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile) certPEMBlock, err := ioutil.ReadFile(certFile)
if err != nil { if err != nil {
log.Error("Failed to load https cert file %s for %s:%s: %v", certFile, srv.network, srv.address, err) log.Error("Failed to load https cert file %s for %s:%s: %v", certFile, srv.network, srv.address, err)
return err return err
} }
keyPEMBlock, err := ioutil.ReadFile(keyFile)
if err != nil {
log.Error("Failed to load https key file %s for %s:%s: %v", keyFile, srv.network, srv.address, err)
return err
}
config.Certificates[0], err = tls.X509KeyPair(certPEMBlock, keyPEMBlock)
if err != nil {
log.Error("Failed to create certificate from cert file %s and key file %s for %s:%s: %v", certFile, keyFile, srv.network, srv.address, err)
return err
}
return srv.ListenAndServeTLSConfig(config, serve) return srv.ListenAndServeTLSConfig(config, serve)
} }

View File

@@ -79,6 +79,9 @@ func (g *GiteaASTTransformer) Transform(node *ast.Document, reader text.Reader,
} }
link = []byte(giteautil.URLJoin(pc.Get(urlPrefixKey).(string), lnk)) link = []byte(giteautil.URLJoin(pc.Get(urlPrefixKey).(string), lnk))
} }
if len(link) > 0 && link[0] == '#' {
link = []byte("#user-content-" + string(link)[1:])
}
v.Destination = link v.Destination = link
} }
return ast.WalkContinue, nil return ast.WalkContinue, nil

View File

@@ -48,8 +48,9 @@ func RenderRaw(body []byte, urlPrefix string, wikiMarkdown bool) []byte {
common.FootnoteExtension, common.FootnoteExtension,
extension.NewTypographer( extension.NewTypographer(
extension.WithTypographicSubstitutions(extension.TypographicSubstitutions{ extension.WithTypographicSubstitutions(extension.TypographicSubstitutions{
extension.EnDash: nil, extension.EnDash: nil,
extension.EmDash: nil, extension.EmDash: nil,
extension.Ellipsis: nil,
}), }),
), ),
), ),

View File

@@ -38,7 +38,7 @@ func NewSanitizer() {
func ReplaceSanitizer() { func ReplaceSanitizer() {
sanitizer.policy = bluemonday.UGCPolicy() sanitizer.policy = bluemonday.UGCPolicy()
// We only want to allow HighlightJS specific classes for code blocks // We only want to allow HighlightJS specific classes for code blocks
sanitizer.policy.AllowAttrs("class").Matching(regexp.MustCompile(`^language-\w+$`)).OnElements("code") sanitizer.policy.AllowAttrs("class").Matching(regexp.MustCompile(`^language-[\w-]+$`)).OnElements("code")
// Checkboxes // Checkboxes
sanitizer.policy.AllowAttrs("type").Matching(regexp.MustCompile(`^checkbox$`)).OnElements("input") sanitizer.policy.AllowAttrs("type").Matching(regexp.MustCompile(`^checkbox$`)).OnElements("input")

View File

@@ -14,6 +14,7 @@ type Comment struct {
PosterName string PosterName string
PosterEmail string PosterEmail string
Created time.Time Created time.Time
Updated time.Time
Content string Content string
Reactions *Reactions Reactions *Reactions
} }

View File

@@ -19,6 +19,7 @@ type Issue struct {
State string // closed, open State string // closed, open
IsLocked bool IsLocked bool
Created time.Time Created time.Time
Updated time.Time
Closed *time.Time Closed *time.Time
Labels []*Label Labels []*Label
Reactions *Reactions Reactions *Reactions

View File

@@ -21,6 +21,7 @@ type PullRequest struct {
Milestone string Milestone string
State string State string
Created time.Time Created time.Time
Updated time.Time
Closed *time.Time Closed *time.Time
Labels []*Label Labels []*Label
PatchURL string PatchURL string

View File

@@ -332,6 +332,7 @@ func (g *GiteaLocalUploader) CreateIssues(issues ...*base.Issue) error {
MilestoneID: milestoneID, MilestoneID: milestoneID,
Labels: labels, Labels: labels,
CreatedUnix: timeutil.TimeStamp(issue.Created.Unix()), CreatedUnix: timeutil.TimeStamp(issue.Created.Unix()),
UpdatedUnix: timeutil.TimeStamp(issue.Updated.Unix()),
} }
userid, ok := g.userMap[issue.PosterID] userid, ok := g.userMap[issue.PosterID]
@@ -406,6 +407,7 @@ func (g *GiteaLocalUploader) CreateComments(comments ...*base.Comment) error {
Type: models.CommentTypeComment, Type: models.CommentTypeComment,
Content: comment.Content, Content: comment.Content,
CreatedUnix: timeutil.TimeStamp(comment.Created.Unix()), CreatedUnix: timeutil.TimeStamp(comment.Created.Unix()),
UpdatedUnix: timeutil.TimeStamp(comment.Updated.Unix()),
} }
if userid > 0 { if userid > 0 {
@@ -574,6 +576,7 @@ func (g *GiteaLocalUploader) newPullRequest(pr *base.PullRequest) (*models.PullR
IsLocked: pr.IsLocked, IsLocked: pr.IsLocked,
Labels: labels, Labels: labels,
CreatedUnix: timeutil.TimeStamp(pr.Created.Unix()), CreatedUnix: timeutil.TimeStamp(pr.Created.Unix()),
UpdatedUnix: timeutil.TimeStamp(pr.Updated.Unix()),
} }
userid, ok := g.userMap[pr.PosterID] userid, ok := g.userMap[pr.PosterID]

View File

@@ -24,6 +24,8 @@ import (
var ( var (
_ base.Downloader = &GithubDownloaderV3{} _ base.Downloader = &GithubDownloaderV3{}
_ base.DownloaderFactory = &GithubDownloaderV3Factory{} _ base.DownloaderFactory = &GithubDownloaderV3Factory{}
// GithubLimitRateRemaining limit to wait for new rate to apply
GithubLimitRateRemaining = 0
) )
func init() { func init() {
@@ -115,7 +117,7 @@ func (g *GithubDownloaderV3) SetContext(ctx context.Context) {
} }
func (g *GithubDownloaderV3) sleep() { func (g *GithubDownloaderV3) sleep() {
for g.rate != nil && g.rate.Remaining <= 0 { for g.rate != nil && g.rate.Remaining <= GithubLimitRateRemaining {
timer := time.NewTimer(time.Until(g.rate.Reset.Time)) timer := time.NewTimer(time.Until(g.rate.Reset.Time))
select { select {
case <-g.ctx.Done(): case <-g.ctx.Done():
@@ -124,15 +126,24 @@ func (g *GithubDownloaderV3) sleep() {
case <-timer.C: case <-timer.C:
} }
rates, _, err := g.client.RateLimits(g.ctx) err := g.RefreshRate()
if err != nil { if err != nil {
log.Error("g.client.RateLimits: %s", err) log.Error("g.client.RateLimits: %s", err)
} }
g.rate = rates.GetCore()
} }
} }
// RefreshRate update the current rate (doesn't count in rate limit)
func (g *GithubDownloaderV3) RefreshRate() error {
rates, _, err := g.client.RateLimits(g.ctx)
if err != nil {
return err
}
g.rate = rates.GetCore()
return nil
}
// GetRepoInfo returns a repository information // GetRepoInfo returns a repository information
func (g *GithubDownloaderV3) GetRepoInfo() (*base.Repository, error) { func (g *GithubDownloaderV3) GetRepoInfo() (*base.Repository, error) {
g.sleep() g.sleep()
@@ -385,6 +396,7 @@ func (g *GithubDownloaderV3) GetIssues(page, perPage int) ([]*base.Issue, bool,
Milestone: milestone, Milestone: milestone,
State: *issue.State, State: *issue.State,
Created: *issue.CreatedAt, Created: *issue.CreatedAt,
Updated: *issue.UpdatedAt,
Labels: labels, Labels: labels,
Reactions: reactions, Reactions: reactions,
Closed: issue.ClosedAt, Closed: issue.ClosedAt,
@@ -428,6 +440,7 @@ func (g *GithubDownloaderV3) GetComments(issueNumber int64) ([]*base.Comment, er
PosterEmail: email, PosterEmail: email,
Content: *comment.Body, Content: *comment.Body,
Created: *comment.CreatedAt, Created: *comment.CreatedAt,
Updated: *comment.UpdatedAt,
Reactions: reactions, Reactions: reactions,
}) })
} }
@@ -523,6 +536,7 @@ func (g *GithubDownloaderV3) GetPullRequests(page, perPage int) ([]*base.PullReq
Milestone: milestone, Milestone: milestone,
State: *pr.State, State: *pr.State,
Created: *pr.CreatedAt, Created: *pr.CreatedAt,
Updated: *pr.UpdatedAt,
Closed: pr.ClosedAt, Closed: pr.ClosedAt,
Labels: labels, Labels: labels,
Merged: merged, Merged: merged,

View File

@@ -6,6 +6,7 @@
package migrations package migrations
import ( import (
"os"
"testing" "testing"
"time" "time"
@@ -62,7 +63,11 @@ func assertLabelEqual(t *testing.T, name, color, description string, label *base
} }
func TestGitHubDownloadRepo(t *testing.T) { func TestGitHubDownloadRepo(t *testing.T) {
downloader := NewGithubDownloaderV3("", "", "go-gitea", "test_repo") GithubLimitRateRemaining = 3 //Wait at 3 remaining since we could have 3 CI in //
downloader := NewGithubDownloaderV3(os.Getenv("GITHUB_READ_TOKEN"), "", "go-gitea", "test_repo")
err := downloader.RefreshRate()
assert.NoError(t, err)
repo, err := downloader.GetRepoInfo() repo, err := downloader.GetRepoInfo()
assert.NoError(t, err) assert.NoError(t, err)
assert.EqualValues(t, &base.Repository{ assert.EqualValues(t, &base.Repository{
@@ -157,6 +162,7 @@ func TestGitHubDownloadRepo(t *testing.T) {
PosterName: "guillep2k", PosterName: "guillep2k",
State: "closed", State: "closed",
Created: time.Date(2019, 11, 9, 17, 0, 29, 0, time.UTC), Created: time.Date(2019, 11, 9, 17, 0, 29, 0, time.UTC),
Updated: time.Date(2019, 11, 12, 20, 29, 53, 0, time.UTC),
Labels: []*base.Label{ Labels: []*base.Label{
{ {
Name: "bug", Name: "bug",
@@ -189,6 +195,7 @@ func TestGitHubDownloadRepo(t *testing.T) {
PosterName: "mrsdizzie", PosterName: "mrsdizzie",
State: "closed", State: "closed",
Created: time.Date(2019, 11, 12, 21, 0, 6, 0, time.UTC), Created: time.Date(2019, 11, 12, 21, 0, 6, 0, time.UTC),
Updated: time.Date(2019, 11, 12, 22, 7, 14, 0, time.UTC),
Labels: []*base.Label{ Labels: []*base.Label{
{ {
Name: "duplicate", Name: "duplicate",
@@ -219,6 +226,7 @@ func TestGitHubDownloadRepo(t *testing.T) {
PosterID: 1669571, PosterID: 1669571,
PosterName: "mrsdizzie", PosterName: "mrsdizzie",
Created: time.Date(2019, 11, 12, 21, 0, 13, 0, time.UTC), Created: time.Date(2019, 11, 12, 21, 0, 13, 0, time.UTC),
Updated: time.Date(2019, 11, 12, 21, 0, 13, 0, time.UTC),
Content: "This is a comment", Content: "This is a comment",
Reactions: &base.Reactions{ Reactions: &base.Reactions{
TotalCount: 1, TotalCount: 1,
@@ -235,6 +243,7 @@ func TestGitHubDownloadRepo(t *testing.T) {
PosterID: 1669571, PosterID: 1669571,
PosterName: "mrsdizzie", PosterName: "mrsdizzie",
Created: time.Date(2019, 11, 12, 22, 7, 14, 0, time.UTC), Created: time.Date(2019, 11, 12, 22, 7, 14, 0, time.UTC),
Updated: time.Date(2019, 11, 12, 22, 7, 14, 0, time.UTC),
Content: "A second comment", Content: "A second comment",
Reactions: &base.Reactions{ Reactions: &base.Reactions{
TotalCount: 0, TotalCount: 0,
@@ -266,6 +275,7 @@ func TestGitHubDownloadRepo(t *testing.T) {
PosterName: "mrsdizzie", PosterName: "mrsdizzie",
State: "closed", State: "closed",
Created: time.Date(2019, 11, 12, 21, 21, 43, 0, time.UTC), Created: time.Date(2019, 11, 12, 21, 21, 43, 0, time.UTC),
Updated: time.Date(2019, 11, 12, 21, 39, 28, 0, time.UTC),
Labels: []*base.Label{ Labels: []*base.Label{
{ {
Name: "documentation", Name: "documentation",
@@ -302,6 +312,7 @@ func TestGitHubDownloadRepo(t *testing.T) {
PosterName: "mrsdizzie", PosterName: "mrsdizzie",
State: "open", State: "open",
Created: time.Date(2019, 11, 12, 21, 54, 18, 0, time.UTC), Created: time.Date(2019, 11, 12, 21, 54, 18, 0, time.UTC),
Updated: time.Date(2020, 1, 4, 11, 30, 1, 0, time.UTC),
Labels: []*base.Label{ Labels: []*base.Label{
{ {
Name: "bug", Name: "bug",

View File

@@ -6,6 +6,7 @@ package queue
import ( import (
"context" "context"
"sync"
"time" "time"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
@@ -33,6 +34,7 @@ type PersistableChannelQueueConfiguration struct {
type PersistableChannelQueue struct { type PersistableChannelQueue struct {
*ChannelQueue *ChannelQueue
delayedStarter delayedStarter
lock sync.Mutex
closed chan struct{} closed chan struct{}
} }

View File

@@ -84,11 +84,12 @@ func NewRedisQueue(handle HandlerFunc, cfg, exemplar interface{}) (Queue, error)
boostWorkers: config.BoostWorkers, boostWorkers: config.BoostWorkers,
maxNumberOfWorkers: config.MaxWorkers, maxNumberOfWorkers: config.MaxWorkers,
}, },
queueName: config.QueueName, queueName: config.QueueName,
exemplar: exemplar, exemplar: exemplar,
closed: make(chan struct{}), closed: make(chan struct{}),
workers: config.Workers, terminated: make(chan struct{}),
name: config.Name, workers: config.Workers,
name: config.Name,
} }
if len(dbs) == 0 { if len(dbs) == 0 {
return nil, errors.New("no redis host specified") return nil, errors.New("no redis host specified")

View File

@@ -28,7 +28,6 @@ type WrappedQueueConfiguration struct {
} }
type delayedStarter struct { type delayedStarter struct {
lock sync.Mutex
internal Queue internal Queue
underlying Type underlying Type
cfg interface{} cfg interface{}
@@ -62,7 +61,6 @@ func (q *delayedStarter) setInternal(atShutdown func(context.Context, func()), h
queue, err := NewQueue(q.underlying, handle, q.cfg, exemplar) queue, err := NewQueue(q.underlying, handle, q.cfg, exemplar)
if err == nil { if err == nil {
q.internal = queue q.internal = queue
q.lock.Unlock()
break break
} }
if err.Error() != "resource temporarily unavailable" { if err.Error() != "resource temporarily unavailable" {
@@ -90,6 +88,7 @@ func (q *delayedStarter) setInternal(atShutdown func(context.Context, func()), h
// WrappedQueue wraps a delayed starting queue // WrappedQueue wraps a delayed starting queue
type WrappedQueue struct { type WrappedQueue struct {
delayedStarter delayedStarter
lock sync.Mutex
handle HandlerFunc handle HandlerFunc
exemplar interface{} exemplar interface{}
channel chan Data channel chan Data

View File

@@ -103,8 +103,8 @@ func UpdateIssuesCommit(doer *models.User, repo *models.Repository, commits []*m
refMarked[key] = true refMarked[key] = true
// FIXME: this kind of condition is all over the code, it should be consolidated in a single place // FIXME: this kind of condition is all over the code, it should be consolidated in a single place
canclose := perm.IsAdmin() || perm.IsOwner() || perm.CanWrite(models.UnitTypeIssues) || refIssue.PosterID == doer.ID canclose := perm.IsAdmin() || perm.IsOwner() || perm.CanWriteIssuesOrPulls(refIssue.IsPull) || refIssue.PosterID == doer.ID
cancomment := canclose || perm.CanRead(models.UnitTypeIssues) cancomment := canclose || perm.CanReadIssuesOrPulls(refIssue.IsPull)
// Don't proceed if the user can't comment // Don't proceed if the user can't comment
if !cancomment { if !cancomment {
@@ -137,9 +137,11 @@ func UpdateIssuesCommit(doer *models.User, repo *models.Repository, commits []*m
continue continue
} }
} }
close := (ref.Action == references.XRefActionCloses)
if err := changeIssueStatus(refRepo, refIssue, doer, ref.Action == references.XRefActionCloses); err != nil { if close != refIssue.IsClosed {
return err if err := changeIssueStatus(refRepo, refIssue, doer, close); err != nil {
return err
}
} }
} }
} }

View File

@@ -46,7 +46,7 @@ func DeleteRepoFile(repo *models.Repository, doer *models.User, opts *DeleteRepo
// If we aren't branching to a new branch, make sure user can commit to the given branch // If we aren't branching to a new branch, make sure user can commit to the given branch
if opts.NewBranch != opts.OldBranch { if opts.NewBranch != opts.OldBranch {
newBranch, err := repo.GetBranch(opts.NewBranch) newBranch, err := repo.GetBranch(opts.NewBranch)
if git.IsErrNotExist(err) { if err != nil && !git.IsErrBranchNotExist(err) {
return nil, err return nil, err
} }
if newBranch != nil { if newBranch != nil {

View File

@@ -21,6 +21,8 @@ var (
MaxGitDiffLines int MaxGitDiffLines int
MaxGitDiffLineCharacters int MaxGitDiffLineCharacters int
MaxGitDiffFiles int MaxGitDiffFiles int
VerbosePush bool
VerbosePushDelay time.Duration
GCArgs []string `ini:"GC_ARGS" delim:" "` GCArgs []string `ini:"GC_ARGS" delim:" "`
EnableAutoGitWireProtocol bool EnableAutoGitWireProtocol bool
Timeout struct { Timeout struct {
@@ -36,6 +38,8 @@ var (
MaxGitDiffLines: 1000, MaxGitDiffLines: 1000,
MaxGitDiffLineCharacters: 5000, MaxGitDiffLineCharacters: 5000,
MaxGitDiffFiles: 100, MaxGitDiffFiles: 100,
VerbosePush: true,
VerbosePushDelay: 5 * time.Second,
GCArgs: []string{}, GCArgs: []string{},
EnableAutoGitWireProtocol: true, EnableAutoGitWireProtocol: true,
Timeout: struct { Timeout: struct {

View File

@@ -7,6 +7,7 @@ package setting
import ( import (
"fmt" "fmt"
"path" "path"
"path/filepath"
"strconv" "strconv"
"strings" "strings"
"time" "time"
@@ -44,7 +45,7 @@ func GetQueueSettings(name string) QueueSettings {
q := QueueSettings{} q := QueueSettings{}
sec := Cfg.Section("queue." + name) sec := Cfg.Section("queue." + name)
// DataDir is not directly inheritable // DataDir is not directly inheritable
q.DataDir = path.Join(Queue.DataDir, name) q.DataDir = filepath.Join(Queue.DataDir, name)
// QueueName is not directly inheritable either // QueueName is not directly inheritable either
q.QueueName = name + Queue.QueueName q.QueueName = name + Queue.QueueName
for _, key := range sec.Keys() { for _, key := range sec.Keys() {
@@ -55,8 +56,8 @@ func GetQueueSettings(name string) QueueSettings {
q.QueueName = key.MustString(q.QueueName) q.QueueName = key.MustString(q.QueueName)
} }
} }
if !path.IsAbs(q.DataDir) { if !filepath.IsAbs(q.DataDir) {
q.DataDir = path.Join(AppDataPath, q.DataDir) q.DataDir = filepath.Join(AppDataPath, q.DataDir)
} }
sec.Key("DATADIR").SetValue(q.DataDir) sec.Key("DATADIR").SetValue(q.DataDir)
// The rest are... // The rest are...
@@ -82,8 +83,8 @@ func GetQueueSettings(name string) QueueSettings {
func NewQueueService() { func NewQueueService() {
sec := Cfg.Section("queue") sec := Cfg.Section("queue")
Queue.DataDir = sec.Key("DATADIR").MustString("queues/") Queue.DataDir = sec.Key("DATADIR").MustString("queues/")
if !path.IsAbs(Queue.DataDir) { if !filepath.IsAbs(Queue.DataDir) {
Queue.DataDir = path.Join(AppDataPath, Queue.DataDir) Queue.DataDir = filepath.Join(AppDataPath, Queue.DataDir)
} }
Queue.Length = sec.Key("LENGTH").MustInt(20) Queue.Length = sec.Key("LENGTH").MustInt(20)
Queue.BatchLength = sec.Key("BATCH_LENGTH").MustInt(20) Queue.BatchLength = sec.Key("BATCH_LENGTH").MustInt(20)

View File

@@ -554,6 +554,12 @@ func NewContext() {
Protocol = HTTPS Protocol = HTTPS
CertFile = sec.Key("CERT_FILE").String() CertFile = sec.Key("CERT_FILE").String()
KeyFile = sec.Key("KEY_FILE").String() KeyFile = sec.Key("KEY_FILE").String()
if !filepath.IsAbs(CertFile) && len(CertFile) > 0 {
CertFile = filepath.Join(CustomPath, CertFile)
}
if !filepath.IsAbs(KeyFile) && len(KeyFile) > 0 {
KeyFile = filepath.Join(CustomPath, KeyFile)
}
case "fcgi": case "fcgi":
Protocol = FCGI Protocol = FCGI
case "fcgi+unix": case "fcgi+unix":

View File

@@ -3,6 +3,7 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package structs // import "code.gitea.io/gitea/modules/structs" package structs // import "code.gitea.io/gitea/modules/structs"
import ( import (
"time" "time"
) )

View File

@@ -0,0 +1,63 @@
// Copyright 2020 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package structs
// CommitStatusState holds the state of a Status
// It can be "pending", "success", "error", "failure", and "warning"
type CommitStatusState string
const (
// CommitStatusPending is for when the Status is Pending
CommitStatusPending CommitStatusState = "pending"
// CommitStatusSuccess is for when the Status is Success
CommitStatusSuccess CommitStatusState = "success"
// CommitStatusError is for when the Status is Error
CommitStatusError CommitStatusState = "error"
// CommitStatusFailure is for when the Status is Failure
CommitStatusFailure CommitStatusState = "failure"
// CommitStatusWarning is for when the Status is Warning
CommitStatusWarning CommitStatusState = "warning"
)
// NoBetterThan returns true if this State is no better than the given State
func (css CommitStatusState) NoBetterThan(css2 CommitStatusState) bool {
switch css {
case CommitStatusError:
return true
case CommitStatusFailure:
return css2 != CommitStatusError
case CommitStatusWarning:
return css2 != CommitStatusError && css2 != CommitStatusFailure
case CommitStatusPending:
return css2 != CommitStatusError && css2 != CommitStatusFailure && css2 != CommitStatusWarning
default:
return css2 != CommitStatusError && css2 != CommitStatusFailure && css2 != CommitStatusWarning && css2 != CommitStatusPending
}
}
// IsPending represents if commit status state is pending
func (css CommitStatusState) IsPending() bool {
return css == CommitStatusPending
}
// IsSuccess represents if commit status state is success
func (css CommitStatusState) IsSuccess() bool {
return css == CommitStatusSuccess
}
// IsError represents if commit status state is error
func (css CommitStatusState) IsError() bool {
return css == CommitStatusError
}
// IsFailure represents if commit status state is failure
func (css CommitStatusState) IsFailure() bool {
return css == CommitStatusFailure
}
// IsWarning represents if commit status state is warning
func (css CommitStatusState) IsWarning() bool {
return css == CommitStatusWarning
}

View File

@@ -38,6 +38,7 @@ type RepositoryMeta struct {
type Issue struct { type Issue struct {
ID int64 `json:"id"` ID int64 `json:"id"`
URL string `json:"url"` URL string `json:"url"`
HTMLURL string `json:"html_url"`
Index int64 `json:"number"` Index int64 `json:"number"`
Poster *User `json:"user"` Poster *User `json:"user"`
OriginalAuthor string `json:"original_author"` OriginalAuthor string `json:"original_author"`

View File

@@ -82,6 +82,7 @@ func (q *UniqueQueue) AddFunc(id interface{}, fn func()) {
idStr := com.ToStr(id) idStr := com.ToStr(id)
q.table.lock.Lock() q.table.lock.Lock()
if _, ok := q.table.pool[idStr]; ok { if _, ok := q.table.pool[idStr]; ok {
q.table.lock.Unlock()
return return
} }
q.table.pool[idStr] = struct{}{} q.table.pool[idStr] = struct{}{}

View File

@@ -142,7 +142,7 @@ func getDingtalkIssuesPayload(p *api.IssuePayload) (*DingtalkPayload, error) {
Title: issueTitle, Title: issueTitle,
HideAvatar: "0", HideAvatar: "0",
SingleTitle: "view issue", SingleTitle: "view issue",
SingleURL: p.Issue.URL, SingleURL: p.Issue.HTMLURL,
}, },
}, nil }, nil
} }

View File

@@ -236,7 +236,7 @@ func getDiscordIssuesPayload(p *api.IssuePayload, meta *DiscordMeta) (*DiscordPa
{ {
Title: text, Title: text,
Description: attachmentText, Description: attachmentText,
URL: p.Issue.URL, URL: p.Issue.HTMLURL,
Color: color, Color: color,
Author: DiscordEmbedAuthor{ Author: DiscordEmbedAuthor{
Name: p.Sender.UserName, Name: p.Sender.UserName,

View File

@@ -299,7 +299,7 @@ func getMSTeamsIssuesPayload(p *api.IssuePayload) (*MSTeamsPayload, error) {
Targets: []MSTeamsActionTarget{ Targets: []MSTeamsActionTarget{
{ {
Os: "default", Os: "default",
URI: p.Issue.URL, URI: p.Issue.HTMLURL,
}, },
}, },
}, },

View File

@@ -158,7 +158,7 @@ func getSlackIssuesPayload(p *api.IssuePayload, slack *SlackMeta) (*SlackPayload
pl.Attachments = []SlackAttachment{{ pl.Attachments = []SlackAttachment{{
Color: fmt.Sprintf("%x", color), Color: fmt.Sprintf("%x", color),
Title: issueTitle, Title: issueTitle,
TitleLink: p.Issue.URL, TitleLink: p.Issue.HTMLURL,
Text: attachmentText, Text: attachmentText,
}} }}
} }
@@ -232,8 +232,10 @@ func getSlackPushPayload(p *api.PushPayload, slack *SlackMeta) (*SlackPayload, e
Username: slack.Username, Username: slack.Username,
IconURL: slack.IconURL, IconURL: slack.IconURL,
Attachments: []SlackAttachment{{ Attachments: []SlackAttachment{{
Color: slack.Color, Color: slack.Color,
Text: attachmentText, Title: p.Repo.HTMLURL,
TitleLink: p.Repo.HTMLURL,
Text: attachmentText,
}}, }},
}, nil }, nil
} }
@@ -289,12 +291,11 @@ func getSlackPullRequestApprovalPayload(p *api.PullRequestPayload, slack *SlackM
func getSlackRepositoryPayload(p *api.RepositoryPayload, slack *SlackMeta) (*SlackPayload, error) { func getSlackRepositoryPayload(p *api.RepositoryPayload, slack *SlackMeta) (*SlackPayload, error) {
senderLink := SlackLinkFormatter(setting.AppURL+p.Sender.UserName, p.Sender.UserName) senderLink := SlackLinkFormatter(setting.AppURL+p.Sender.UserName, p.Sender.UserName)
repoLink := SlackLinkFormatter(p.Repository.HTMLURL, p.Repository.FullName) repoLink := SlackLinkFormatter(p.Repository.HTMLURL, p.Repository.FullName)
var text, title, attachmentText string var text string
switch p.Action { switch p.Action {
case api.HookRepoCreated: case api.HookRepoCreated:
text = fmt.Sprintf("[%s] Repository created by %s", repoLink, senderLink) text = fmt.Sprintf("[%s] Repository created by %s", repoLink, senderLink)
title = p.Repository.HTMLURL
case api.HookRepoDeleted: case api.HookRepoDeleted:
text = fmt.Sprintf("[%s] Repository deleted by %s", repoLink, senderLink) text = fmt.Sprintf("[%s] Repository deleted by %s", repoLink, senderLink)
} }
@@ -304,12 +305,6 @@ func getSlackRepositoryPayload(p *api.RepositoryPayload, slack *SlackMeta) (*Sla
Text: text, Text: text,
Username: slack.Username, Username: slack.Username,
IconURL: slack.IconURL, IconURL: slack.IconURL,
Attachments: []SlackAttachment{{
Color: slack.Color,
Title: title,
TitleLink: title,
Text: attachmentText,
}},
}, nil }, nil
} }

View File

@@ -148,6 +148,25 @@ func getTelegramPullRequestPayload(p *api.PullRequestPayload) (*TelegramPayload,
}, nil }, nil
} }
func getTelegramPullRequestApprovalPayload(p *api.PullRequestPayload, event models.HookEventType) (*TelegramPayload, error) {
var text, attachmentText string
switch p.Action {
case api.HookIssueSynchronized:
action, err := parseHookPullRequestEventType(event)
if err != nil {
return nil, err
}
text = fmt.Sprintf("[%s] Pull request review %s: #%d %s", p.Repository.FullName, action, p.Index, p.PullRequest.Title)
attachmentText = p.Review.Content
}
return &TelegramPayload{
Message: text + "\n" + attachmentText,
}, nil
}
func getTelegramRepositoryPayload(p *api.RepositoryPayload) (*TelegramPayload, error) { func getTelegramRepositoryPayload(p *api.RepositoryPayload) (*TelegramPayload, error) {
var title string var title string
switch p.Action { switch p.Action {
@@ -192,6 +211,8 @@ func GetTelegramPayload(p api.Payloader, event models.HookEventType, meta string
return getTelegramPushPayload(p.(*api.PushPayload)) return getTelegramPushPayload(p.(*api.PushPayload))
case models.HookEventPullRequest: case models.HookEventPullRequest:
return getTelegramPullRequestPayload(p.(*api.PullRequestPayload)) return getTelegramPullRequestPayload(p.(*api.PullRequestPayload))
case models.HookEventPullRequestRejected, models.HookEventPullRequestApproved, models.HookEventPullRequestComment:
return getTelegramPullRequestApprovalPayload(p.(*api.PullRequestPayload), event)
case models.HookEventRepository: case models.HookEventRepository:
return getTelegramRepositoryPayload(p.(*api.RepositoryPayload)) return getTelegramRepositoryPayload(p.(*api.RepositoryPayload))
case models.HookEventRelease: case models.HookEventRelease:

View File

@@ -2035,4 +2035,3 @@ error.probable_bad_default_signature=VAROVÁNÍ! Ačkoli výchozí klíč má to
[units] [units]
error.no_unit_allowed_repo=Nejste oprávněni přistupovat k žádné části tohoto repozitáře. error.no_unit_allowed_repo=Nejste oprávněni přistupovat k žádné části tohoto repozitáře.
error.unit_not_allowed=Nejste oprávněni přistupovat k této části repozitáře. error.unit_not_allowed=Nejste oprávněni přistupovat k této části repozitáře.

View File

@@ -606,7 +606,7 @@ clone_helper=Benötigst du Hilfe beim Klonen? Öffne die <a target="_blank" rel=
fork_repo=Repository forken fork_repo=Repository forken
fork_from=Fork von fork_from=Fork von
fork_visibility_helper=Die Sichtbarkeit eines geforkten Repositorys kann nicht geändert werden. fork_visibility_helper=Die Sichtbarkeit eines geforkten Repositorys kann nicht geändert werden.
use_template=Verwende dieses Template use_template=Dieses Template verwenden
generate_repo=Repository erstellen generate_repo=Repository erstellen
generate_from=Erstelle aus generate_from=Erstelle aus
repo_desc=Beschreibung repo_desc=Beschreibung
@@ -1062,6 +1062,8 @@ pulls.no_merge_desc=Dieser Pull-Request kann nicht gemerged werden, da keine Mer
pulls.no_merge_helper=Aktiviere Mergeoptionen in den Repositoryeinstellungen oder merge den Pull-Request manuell. pulls.no_merge_helper=Aktiviere Mergeoptionen in den Repositoryeinstellungen oder merge den Pull-Request manuell.
pulls.no_merge_wip=Dieser Pull Request kann nicht zusammengeführt werden, da er als Work In Progress gekennzeichnet ist. pulls.no_merge_wip=Dieser Pull Request kann nicht zusammengeführt werden, da er als Work In Progress gekennzeichnet ist.
pulls.no_merge_status_check=Dieser Pull-Request kann nicht zusammengeführt werden, da nicht alle erforderlichen Statusprüfungen erfolgreich waren. pulls.no_merge_status_check=Dieser Pull-Request kann nicht zusammengeführt werden, da nicht alle erforderlichen Statusprüfungen erfolgreich waren.
pulls.no_merge_not_ready=Dieser Pull-Request kann nicht zusammengeführt werden, überprüfe den Reviewstatus und die Statusprüfungen.
pulls.no_merge_access=Du bist nicht berechtigt, diesen Pull-Request zu Mergen.
pulls.merge_pull_request=Pull-Request zusammenführen pulls.merge_pull_request=Pull-Request zusammenführen
pulls.rebase_merge_pull_request=Rebase und Mergen pulls.rebase_merge_pull_request=Rebase und Mergen
pulls.rebase_merge_commit_pull_request=Rebasen und Mergen (--no-ff) pulls.rebase_merge_commit_pull_request=Rebasen und Mergen (--no-ff)
@@ -1412,6 +1414,8 @@ settings.protect_approvals_whitelist_enabled=Freigaben auf Benutzer oder Teams a
settings.protect_approvals_whitelist_enabled_desc=Nur Bewertungen von Benutzern auf der Whitelist oder Teams zählen zu den erforderlichen Genehmigungen. Gibt es keine Whitelist, so zählen Reviews von jedem mit Schreibzugriff zu den erforderlichen Genehmigungen. settings.protect_approvals_whitelist_enabled_desc=Nur Bewertungen von Benutzern auf der Whitelist oder Teams zählen zu den erforderlichen Genehmigungen. Gibt es keine Whitelist, so zählen Reviews von jedem mit Schreibzugriff zu den erforderlichen Genehmigungen.
settings.protect_approvals_whitelist_users=Freigeschaltete Reviewer: settings.protect_approvals_whitelist_users=Freigeschaltete Reviewer:
settings.protect_approvals_whitelist_teams=Freigeschaltete Teams: settings.protect_approvals_whitelist_teams=Freigeschaltete Teams:
settings.dismiss_stale_approvals=Entferne alte Genehmigungen
settings.dismiss_stale_approvals_desc=Wenn neue Commits gepusht werden, die den Inhalt des Pull-Requests ändern, werden alte Genehmigungen entfernt.
settings.add_protected_branch=Schutz aktivieren settings.add_protected_branch=Schutz aktivieren
settings.delete_protected_branch=Schutz deaktivieren settings.delete_protected_branch=Schutz deaktivieren
settings.update_protect_branch_success=Branch-Schutz für den Branch „%s“ wurde geändert. settings.update_protect_branch_success=Branch-Schutz für den Branch „%s“ wurde geändert.
@@ -1747,6 +1751,7 @@ users.new_account=Benutzerkonto erstellen
users.name=Benutzername users.name=Benutzername
users.activated=Aktiviert users.activated=Aktiviert
users.admin=Administrator users.admin=Administrator
users.restricted=Eingeschränkt
users.repos=Repositories users.repos=Repositories
users.created=Registriert am users.created=Registriert am
users.last_login=Letzte Anmeldung users.last_login=Letzte Anmeldung
@@ -1765,6 +1770,7 @@ users.max_repo_creation_desc=(Gib -1 ein, um das globale Standardlimit zu verwen
users.is_activated=Account ist aktiviert users.is_activated=Account ist aktiviert
users.prohibit_login=Anmelden deaktivieren users.prohibit_login=Anmelden deaktivieren
users.is_admin=Ist Administrator users.is_admin=Ist Administrator
users.is_restricted=Ist eingeschränkt
users.allow_git_hook=Darf „Git Hooks“ erstellen users.allow_git_hook=Darf „Git Hooks“ erstellen
users.allow_import_local=Darf lokale Repositories importieren users.allow_import_local=Darf lokale Repositories importieren
users.allow_create_organization=Darf Organisationen erstellen users.allow_create_organization=Darf Organisationen erstellen
@@ -2025,8 +2031,47 @@ monitor.execute_time=Ausführungszeit
monitor.process.cancel=Prozess abbrechen monitor.process.cancel=Prozess abbrechen
monitor.process.cancel_desc=Abbrechen eines Prozesses kann Datenverlust verursachen monitor.process.cancel_desc=Abbrechen eines Prozesses kann Datenverlust verursachen
monitor.process.cancel_notices=Abbrechen: <strong>%s</strong>? monitor.process.cancel_notices=Abbrechen: <strong>%s</strong>?
monitor.queues=Warteschlangen
monitor.queue=Warteschlange: %s
monitor.queue.name=Name
monitor.queue.type=Typ
monitor.queue.numberworkers=Anzahl der Worker
monitor.queue.maxnumberworkers=Maximale Anzahl der Worker
monitor.queue.review=Konfiguration überprüfen
monitor.queue.review_add=Worker hinzufügen/prüfen
monitor.queue.configuration=Erstkonfiguration
monitor.queue.nopool.title=Kein Worker-Pool
monitor.queue.nopool.desc=Diese Warteschlange umgibt andere Warteschlangen und hat selbst keinen Worker-Pool.
monitor.queue.wrapped.desc=Eine Wrapped Queue umfasst eine langsame Start-Warteschlange und puffert die in der Warteschlange stehenden Aufträge in einem Kanal. Sie besitzt selbst keinen Worker-Pool.
monitor.queue.persistable-channel.desc=Ein persistierender Channel umfasst zwei Warteschlangen, eine Channel-Warteschlange mit einem eigenen Worker-Pool und eine Level-Warteschlange für persistente Anfragen aus früheren Shutdowns. Er hat selbst keinen Worker-Pool.
monitor.queue.pool.timeout=Timeout
monitor.queue.pool.addworkers.title=Worker hinzufügen
monitor.queue.pool.addworkers.submit=Worker hinzufügen
monitor.queue.pool.addworkers.numberworkers.placeholder=Anzahl der Worker
monitor.queue.pool.addworkers.timeout.placeholder=Setze auf 0 für keinen Timeout
monitor.queue.pool.addworkers.musttimeoutduration=Timeout muss eine Golang-Dauer sein, z. B. 5m oder 0
monitor.queue.settings.title=Pool-Einstellungen
monitor.queue.settings.desc=Pools wachsen dynamisch mit einem Boost als Reaktion auf die Blockierung ihrer Workerwarteschlangen. Diese Änderungen wirken sich nicht auf die aktuellen Worker Gruppen aus.
monitor.queue.settings.timeout=Timeout verlängern
monitor.queue.settings.timeout.placeholder=Derzeit %[1]v
monitor.queue.settings.timeout.error=Timeout muss eine Golang-Dauer sein, z.B. 5m oder 0
monitor.queue.settings.numberworkers=Anzahl der Worker erhöhen
monitor.queue.settings.numberworkers.placeholder=Derzeit %[1]v
monitor.queue.settings.maxnumberworkers.placeholder=Derzeit %[1]v
monitor.queue.settings.maxnumberworkers.error=Die Anzahl der Worker muss eine Zahl sein
monitor.queue.settings.submit=Einstellungen aktualisieren
monitor.queue.settings.changed=Einstellungen aktualisiert
monitor.queue.settings.blocktimeout=Aktuelle Block-Timeout
monitor.queue.settings.blocktimeout.value=%[1]v
monitor.queue.pool.none=Diese Warteschlange hat keinen Pool
monitor.queue.pool.added=Workergruppe hinzugefügt
monitor.queue.pool.workers.title=Aktive Workergruppen
monitor.queue.pool.workers.none=Keine Workergruppen.
monitor.queue.pool.cancel=Workergruppen herunterfahren
monitor.queue.pool.cancelling=Workergruppe fährt herunter
monitor.queue.pool.cancel_notices=Diese Gruppe von %s Workern herunterfahren?
notices.system_notice_list=Systemmitteilungen notices.system_notice_list=Systemmitteilungen
notices.view_detail_header=Meldungsdetails ansehen notices.view_detail_header=Meldungsdetails ansehen
@@ -2120,4 +2165,3 @@ error.probable_bad_default_signature=WARNHINWEIS! Obwohl der Standardschlüssel
[units] [units]
error.no_unit_allowed_repo=Du hast keine Berechtigung, um auf irgendeinen Bereich dieses Repositories zuzugreifen. error.no_unit_allowed_repo=Du hast keine Berechtigung, um auf irgendeinen Bereich dieses Repositories zuzugreifen.
error.unit_not_allowed=Du hast keine Berechtigung, um auf diesen Repository-Bereich zuzugreifen. error.unit_not_allowed=Du hast keine Berechtigung, um auf diesen Repository-Bereich zuzugreifen.

View File

@@ -1063,6 +1063,8 @@ pulls.no_merge_desc = This pull request cannot be merged because all repository
pulls.no_merge_helper = Enable merge options in the repository settings or merge the pull request manually. pulls.no_merge_helper = Enable merge options in the repository settings or merge the pull request manually.
pulls.no_merge_wip = This pull request can not be merged because it is marked as being a work in progress. pulls.no_merge_wip = This pull request can not be merged because it is marked as being a work in progress.
pulls.no_merge_status_check = This pull request cannot be merged because not all required status checkes are successful. pulls.no_merge_status_check = This pull request cannot be merged because not all required status checkes are successful.
pulls.no_merge_not_ready = This pull request is not ready to be merged, check review status and status checks.
pulls.no_merge_access = You are not authorized to merge this pull request.
pulls.merge_pull_request = Merge Pull Request pulls.merge_pull_request = Merge Pull Request
pulls.rebase_merge_pull_request = Rebase and Merge pulls.rebase_merge_pull_request = Rebase and Merge
pulls.rebase_merge_commit_pull_request = Rebase and Merge (--no-ff) pulls.rebase_merge_commit_pull_request = Rebase and Merge (--no-ff)
@@ -1413,6 +1415,8 @@ settings.protect_approvals_whitelist_enabled = Restrict approvals to whitelisted
settings.protect_approvals_whitelist_enabled_desc = Only reviews from whitelisted users or teams will count to the required approvals. Without approval whitelist, reviews from anyone with write access count to the required approvals. settings.protect_approvals_whitelist_enabled_desc = Only reviews from whitelisted users or teams will count to the required approvals. Without approval whitelist, reviews from anyone with write access count to the required approvals.
settings.protect_approvals_whitelist_users = Whitelisted reviewers: settings.protect_approvals_whitelist_users = Whitelisted reviewers:
settings.protect_approvals_whitelist_teams = Whitelisted teams for reviews: settings.protect_approvals_whitelist_teams = Whitelisted teams for reviews:
settings.dismiss_stale_approvals = Dismiss stale approvals
settings.dismiss_stale_approvals_desc = When new commits that change the content of the pull request are pushed to the branch, old approvals will be dismissed.
settings.add_protected_branch = Enable protection settings.add_protected_branch = Enable protection
settings.delete_protected_branch = Disable protection settings.delete_protected_branch = Disable protection
settings.update_protect_branch_success = Branch protection for branch '%s' has been updated. settings.update_protect_branch_success = Branch protection for branch '%s' has been updated.
@@ -1748,6 +1752,7 @@ users.new_account = Create User Account
users.name = Username users.name = Username
users.activated = Activated users.activated = Activated
users.admin = Admin users.admin = Admin
users.restricted = Restricted
users.repos = Repos users.repos = Repos
users.created = Created users.created = Created
users.last_login = Last Sign-In users.last_login = Last Sign-In
@@ -1766,6 +1771,7 @@ users.max_repo_creation_desc = (Enter -1 to use the global default limit.)
users.is_activated = User Account Is Activated users.is_activated = User Account Is Activated
users.prohibit_login = Disable Sign-In users.prohibit_login = Disable Sign-In
users.is_admin = Is Administrator users.is_admin = Is Administrator
users.is_restricted = Is Restricted
users.allow_git_hook = May Create Git Hooks users.allow_git_hook = May Create Git Hooks
users.allow_import_local = May Import Local Repositories users.allow_import_local = May Import Local Repositories
users.allow_create_organization = May Create Organizations users.allow_create_organization = May Create Organizations
@@ -1820,6 +1826,7 @@ auths.attribute_surname = Surname Attribute
auths.attribute_mail = Email Attribute auths.attribute_mail = Email Attribute
auths.attribute_ssh_public_key = Public SSH Key Attribute auths.attribute_ssh_public_key = Public SSH Key Attribute
auths.attributes_in_bind = Fetch Attributes in Bind DN Context auths.attributes_in_bind = Fetch Attributes in Bind DN Context
auths.allow_deactivate_all = Allow an empty search result to deactivate all users
auths.use_paged_search = Use Paged Search auths.use_paged_search = Use Paged Search
auths.search_page_size = Page Size auths.search_page_size = Page Size
auths.filter = User Filter auths.filter = User Filter

View File

@@ -2109,4 +2109,3 @@ error.probable_bad_default_signature=¡ADVERTENCIA! ¡La clave por defecto tiene
[units] [units]
error.no_unit_allowed_repo=No tiene permisos para acceder a ninguna sección de este repositorio. error.no_unit_allowed_repo=No tiene permisos para acceder a ninguna sección de este repositorio.
error.unit_not_allowed=No tiene permisos para acceder a esta sección del repositorio. error.unit_not_allowed=No tiene permisos para acceder a esta sección del repositorio.

View File

@@ -2120,4 +2120,3 @@ error.probable_bad_default_signature=هشدار! اگرچه اینجا یک کل
[units] [units]
error.no_unit_allowed_repo=شما اجازه دسترسی به هیچ قسمت از این مخزن را ندارید. error.no_unit_allowed_repo=شما اجازه دسترسی به هیچ قسمت از این مخزن را ندارید.
error.unit_not_allowed=شما اجازه دسترسی به این قسمت مخزن را ندارید. error.unit_not_allowed=شما اجازه دسترسی به این قسمت مخزن را ندارید.

View File

@@ -2096,4 +2096,3 @@ error.probable_bad_default_signature=AVERTISSEMENT ! Bien que la clé par défau
[units] [units]
error.no_unit_allowed_repo=Vous n'êtes pas autorisé à accéder à n'importe quelle section de ce dépôt. error.no_unit_allowed_repo=Vous n'êtes pas autorisé à accéder à n'importe quelle section de ce dépôt.
error.unit_not_allowed=Vous n'êtes pas autorisé à accéder à cette section du dépôt. error.unit_not_allowed=Vous n'êtes pas autorisé à accéder à cette section du dépôt.

View File

@@ -10,6 +10,7 @@ link_account=Tautan Akun
register=Daftar register=Daftar
website=Situs Web website=Situs Web
version=Versi version=Versi
powered_by=Diberdayakan oleh %s
page=Halaman page=Halaman
template=Contoh template=Contoh
language=Bahasa language=Bahasa
@@ -29,8 +30,16 @@ twofa_scratch=Kode Awal Dua Faktor
passcode=Kode Akses passcode=Kode Akses
u2f_insert_key=Masukkan kunci keamanan anda u2f_insert_key=Masukkan kunci keamanan anda
u2f_sign_in=Tekan tombol pada kunci keamanan anda. Jika kunci keamanan anda tidak memiliki tombol, masukkan kembali.
u2f_press_button=Silahkan tekan tombol pada kunci keamanan anda… u2f_press_button=Silahkan tekan tombol pada kunci keamanan anda…
u2f_use_twofa=Menggunakan kode dua faktor dari telepon anda u2f_use_twofa=Menggunakan kode dua faktor dari telepon anda
u2f_error=Tidak dapat membaca kunci keamanan Anda.
u2f_unsupported_browser=Browser Anda tidak mendukung kunci keamanan U2F.
u2f_error_1=Terdapat kesalahan yang tidak diketahui. Mohon coba lagi.
u2f_error_2=Pastikan menggunakan URL yang benar dan terenkripsi (https://).
u2f_error_3=Server tidak bisa memproses permintaan anda.
u2f_error_4=Kunci keamanan tidak diperbolehkan untuk permintaan ini. Pastikan bahwa kunci ini belum terdaftar sebelumnya.
u2f_error_5=Waktu habis sebelum kunci Anda dapat dibaca. Mohon muat ulang halaman ini dan coba lagi.
u2f_reload=Muat Ulang u2f_reload=Muat Ulang
repository=Repositori repository=Repositori
@@ -58,25 +67,51 @@ forks=Garpu
activities=Aktivitas activities=Aktivitas
pull_requests=Tarik Permintaan pull_requests=Tarik Permintaan
issues=Masalah issues=Masalah
milestones=Tonggak
cancel=Batal cancel=Batal
add=Tambah
add_all=Tambah Semua
remove=Buang
remove_all=Buang Semua
write=Tulis
preview=Pratinjau
loading=Memuat…
[startpage] [startpage]
app_desc=Sebuah layanan hosting Git sendiri yang tanpa kesulitan
install=Mudah dipasang
install_desc=Cukup <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/install-from-binary/">jalankan program biner</a> yang sesuai dengan sistem operasi Anda. Atau jalankan Gitea dengan <a target="_blank" rel="noopener noreferrer" href="https://github.com/go-gitea/gitea/tree/master/docker">Docker</a> atau <a target="_blank" rel="noopener noreferrer" href="https://github.com/alvaroaleman/ansible-gitea/blob/master/Vagrantfile">Vagrant</a>, atau install dari <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/install-from-package/">paket</a>.
platform=Lintas platform
platform_desc=Gitea bisa digunakan di mana <a target="_blank" rel="noopener noreferrer" href="http://golang.org/">Go</a> bisa dijalankan: Windows, macOS, Linux, ARM, dll. Silahkan pilih yang Anda suka!
lightweight=Ringan
lightweight_desc=Gitea hanya membutuhkan persyaratan minimal dan bisa berjalan pada Raspberry Pi yang murah. Bisa menghemat listrik!
license=Sumber Terbuka
license_desc="Go get" (Dapatkan kode sumber dari) <a target="_blank" rel="noopener noreferrer" href="https://code.gitea.io/gitea">code.gitea.io/gitea</a>! Mari bergabung dengan <a target="_blank" rel="noopener noreferrer" href="https://github.com/go-gitea/gitea">berkontribusi</a> untuk membuat proyek ini lebih baik. Jangan malu untuk menjadi kontributor!
[install] [install]
install=Pemasangan install=Pemasangan
title=Konfigurasi Awal title=Konfigurasi Awal
docker_helper=Jika Anda menjalankan Gitea di dalam Docker, baca <a target="_blank" rel="noopener" href="%s">dokumentasi </a> sebelum mengubah pengaturan.
requite_db_desc=Gitea memerlukan MySQL, PostgreSQL, MSSQL atau SQLite3.
db_title=Pengaturan Basis Data db_title=Pengaturan Basis Data
db_type=Tipe Basis Data db_type=Tipe Basis Data
host=Host host=Host
user=Nama Pengguna user=Nama Pengguna
password=Kata Sandi password=Kata Sandi
db_name=Nama Basis Data db_name=Nama Basis Data
db_helper=Untuk pengguna MySQL: Mohon gunakan mesin penyimpanan InnoDB, dan jika Anda menggunakan enkoding "utf8mb4", versi InnoDB Anda harus diatas 5.6.
ssl_mode=SSL ssl_mode=SSL
charset=Jenis karakter
path=Jalur path=Jalur
sqlite_helper=Jalur berkas untuk basis data SQLite3 atau TiDB.<br>Masukkan path absolut jika anda menjalankan Gitea sebagai layanan.
err_empty_db_path=Jalur basis data SQLite3 tidak boleh kosong.
no_admin_and_disable_registration=Anda tidak dapat menonaktifkan pendaftaran tanpa membuat akun admin. no_admin_and_disable_registration=Anda tidak dapat menonaktifkan pendaftaran tanpa membuat akun admin.
err_empty_admin_password=Sandi administrator tidak boleh kosong. err_empty_admin_password=Sandi administrator tidak boleh kosong.
err_empty_admin_email=Email administrator tidak boleh kosong.
err_admin_name_is_reserved=Nama pengguna Administrator tidak valid, nama tersebut dicadangkan
err_admin_name_is_invalid=Nama Administrator tidak valid.
general_title=Pengaturan Umum general_title=Pengaturan Umum
app_name=Judul Situs app_name=Judul Situs
@@ -111,13 +146,20 @@ server_service_title=Server dan Pengaturan Layanan Pihak Ketiga
offline_mode=Aktifkan Mode Lokal offline_mode=Aktifkan Mode Lokal
offline_mode_popup=Non-aktifkan jaringan pengiriman konten dari pihak ketiga dan layani semua sumber daya secara lokal. offline_mode_popup=Non-aktifkan jaringan pengiriman konten dari pihak ketiga dan layani semua sumber daya secara lokal.
disable_gravatar=Non-aktifkan Gravatar disable_gravatar=Non-aktifkan Gravatar
federated_avatar_lookup=Aktifkan Avatar Terfederasi
federated_avatar_lookup_popup=Mengaktifkan pencarian avatar federasi menggunakan Libravatar. federated_avatar_lookup_popup=Mengaktifkan pencarian avatar federasi menggunakan Libravatar.
disable_registration=Matikan Swa-pendaftaran
disable_registration_popup=Nonaktifkan pendaftaran oleh pengguna. Hanya admin yang dapat membuat akun pengguna baru.
allow_only_external_registration_popup=Perbolehkan Pendaftaran Hanya Melalui Layanan External
openid_signin=Aktifkan Login OpenID openid_signin=Aktifkan Login OpenID
openid_signin_popup=Aktifkan masuk pengguna lewat OpenID.
openid_signup=Aktifkan Pendaftaran OpenID openid_signup=Aktifkan Pendaftaran OpenID
openid_signup_popup=Aktifkan pendaftaran berdasarkan OpenID. openid_signup_popup=Aktifkan pendaftaran berdasarkan OpenID.
enable_captcha=Aktifkan CAPTCHA enable_captcha=Aktifkan CAPTCHA
enable_captcha_popup=Membutukan CAPTCHA untuk pendaftaran. enable_captcha_popup=Membutukan CAPTCHA untuk pendaftaran.
require_sign_in_view=Anda Harus Login untuk Melihat Halaman require_sign_in_view=Anda Harus Login untuk Melihat Halaman
require_sign_in_view_popup=Batasi akses halaman hanya pada pengguna yang masuk. Pengunjung hanya dapat melihat halaman masuk dan pendaftaran.
admin_setting_desc=Akun administrator tidak wajib dibuat. Pengguna yang pertama kali mendaftar akan secara otomatis menjadi administrator.
admin_title=Pengaturan Akun Admin admin_title=Pengaturan Akun Admin
admin_name=Nama Pengguna Admin admin_name=Nama Pengguna Admin
admin_password=Kata sandi admin_password=Kata sandi
@@ -127,7 +169,15 @@ install_btn_confirm=Memasang Gitea
test_git_failed=Tidak dapat menguji perintah 'git': %v test_git_failed=Tidak dapat menguji perintah 'git': %v
sqlite3_not_available=Gitea versi ini tidak mendukung SQLite3, Silahkan untuh versi biner resmi dari %s (bukan versi 'gobuild'). sqlite3_not_available=Gitea versi ini tidak mendukung SQLite3, Silahkan untuh versi biner resmi dari %s (bukan versi 'gobuild').
invalid_db_setting=Pengaturan basis data tidak valid: %v invalid_db_setting=Pengaturan basis data tidak valid: %v
invalid_repo_path=Lokasi folder repositori tidak valid: %v
run_user_not_match=Nama pengguna 'run as' bukanlah nama pengguna saat ini: %s -> %s
save_config_failed=Gagal menyimpan konfigurasi: %v save_config_failed=Gagal menyimpan konfigurasi: %v
invalid_admin_setting=Pengaturan akun administrator tidak valid: %v
install_success=Selamat datang! Terimakasih telah memilih Gitea. Selamat bersenang-senang dan hati-hati!
invalid_log_root_path=Jalur folder log tidak valid: %v
default_keep_email_private=Sembunyikan Alamat Email secara Asali
default_keep_email_private_popup=Sembunyikan alamat email pengguna baru secara asali.
default_allow_create_organization_popup=Perbolehkan pengguna baru untuk membuat organisasi.
[home] [home]
uname_holder=Nama Pengguna atau Alamat Surel uname_holder=Nama Pengguna atau Alamat Surel
@@ -161,36 +211,50 @@ social_register_helper_msg=Sudah memiliki akun? Hubungkan sekarang!
remember_me=Ingat Saya remember_me=Ingat Saya
forgot_password_title=Lupa Kata Sandi forgot_password_title=Lupa Kata Sandi
forgot_password=Lupa kata sandi? forgot_password=Lupa kata sandi?
sign_up_now=Butuh akun? Daftar sekarang.
sign_up_successful=Akun berhasil dibuat.
confirmation_mail_sent_prompt=Surel konfirmasi baru telah dikirim ke <b>%s</b>. Silakan periksa kotak masuk anda dalam %s ke depan untuk menyelesaikan proses pendaftaran. confirmation_mail_sent_prompt=Surel konfirmasi baru telah dikirim ke <b>%s</b>. Silakan periksa kotak masuk anda dalam %s ke depan untuk menyelesaikan proses pendaftaran.
active_your_account=Aktifkan Akun Anda active_your_account=Aktifkan Akun Anda
account_activated=Akun telah diaktifkan
prohibit_login_desc=Akun Anda tidak diperbolehkan untuk masuk, silakan hubungi admin situs.
has_unconfirmed_mail=Hai %s, anda memiliki sebuah alamat surel yang belum dikonfirmasi (<b>%s</b>). Jika anda belum menerima surel konfirmasi atau perlu untuk mengirim ulang yang baru, silakan klik pada tombol di bawah. has_unconfirmed_mail=Hai %s, anda memiliki sebuah alamat surel yang belum dikonfirmasi (<b>%s</b>). Jika anda belum menerima surel konfirmasi atau perlu untuk mengirim ulang yang baru, silakan klik pada tombol di bawah.
resend_mail=Klik di sini untuk mengirim ulang surel aktivasi anda resend_mail=Klik di sini untuk mengirim ulang surel aktivasi anda
email_not_associate=Alamat surel tidak terhubung dengan akun apapun. email_not_associate=Alamat surel tidak terhubung dengan akun apapun.
send_reset_mail=Kirim Surel Pemulihan Akun
reset_password=Pemulihan Akun
password_too_short=Panjang kata sandi tidak boleh kurang dari %d karakter.
verify=Verifikasi verify=Verifikasi
scratch_code=Kode coretan scratch_code=Kode coretan
use_scratch_code=Gunakan kode coretan use_scratch_code=Gunakan kode coretan
twofa_scratch_used=Anda telah menggunakan kode coretan anda. Anda telah dialihkan ke halaman pengaturan dua-faktor jadi anda boleh menghapus pendaftaran perangkat anda atau menghasilkan kode coretan yang baru. twofa_scratch_used=Anda telah menggunakan kode coretan anda. Anda telah dialihkan ke halaman pengaturan dua-faktor jadi anda boleh menghapus pendaftaran perangkat anda atau menghasilkan kode coretan yang baru.
twofa_passcode_incorrect=Kata sandi Anda salah. Jika Anda salah tempatkan perangkat Anda, gunakan kode gosok Anda untuk masuk.
twofa_scratch_token_incorrect=Kode coretan anda tidak tepat. twofa_scratch_token_incorrect=Kode coretan anda tidak tepat.
login_openid=OpenID login_openid=OpenID
openid_connect_submit=Sambungkan openid_connect_submit=Sambungkan
openid_connect_title=Sambungkan ke akun yang sudah ada openid_connect_title=Sambungkan ke akun yang sudah ada
openid_register_title=Buat akun baru openid_register_title=Buat akun baru
openid_signin_desc=Masukkan URI OpenID Anda. Misalnya: https://anne.me, bob.openid.org.cn, atau gnusocial.net/carry.
email_domain_blacklisted=Anda tidak dapat mendaftar dengan alamat email.
authorize_application=Izinkan aplikasi
[mail] [mail]
activate_account=Silakan aktifkan akun anda activate_account=Silakan aktifkan akun anda
activate_email=Verifikasi alamat surel anda activate_email=Verifikasi alamat surel anda
reset_password=Pulihkan akun Anda
register_success=Pendaftaran berhasil register_success=Pendaftaran berhasil
register_notify=Selamat Datang di Gitea register_notify=Selamat Datang di Gitea
[modal] [modal]
yes=Ya yes=Ya
no=Tidak no=Tidak
modify=Perbarui
[form] [form]
UserName=Nama Pengguna UserName=Nama Pengguna
RepoName=Nama repositori RepoName=Nama repositori
Email=Alamat surel Email=Alamat surel
Password=Kata Sandi Password=Kata Sandi
Retype=Ketik Ulang Kata Sandi
SSHTitle=Nama kunci SSH SSHTitle=Nama kunci SSH
HttpsUrl=HTTPS URL HttpsUrl=HTTPS URL
PayloadUrl=Muatan URL PayloadUrl=Muatan URL
@@ -205,6 +269,7 @@ CommitChoice=Pilihan Commit
TreeName=Jalur berkas TreeName=Jalur berkas
Content=Konten Content=Konten
SSPISeparatorReplacement=Pemisah
require_error=` tidak boleh kosong.` require_error=` tidak boleh kosong.`
size_error=` harus berukuran %s.` size_error=` harus berukuran %s.`
@@ -214,53 +279,100 @@ email_error=` bukan alamat surel yang valid. `
url_error=` bukan URL yang valid.` url_error=` bukan URL yang valid.`
include_error=` harus mengandung substring '%s'.` include_error=` harus mengandung substring '%s'.`
unknown_error=Kesalahan yang tidak diketahui: unknown_error=Kesalahan yang tidak diketahui:
lang_select_error=Pilih bahasa dari daftar.
email_been_used=Alamat email sudah digunakan.
openid_been_used=Alamat OpenID '%s' sudah digunakan.
username_password_incorrect=Nama pengguna atau sandi salah.
password_complexity=Kata sandi tidak memenuhi persyaratan kerumitan:
password_lowercase_one=Sekurang-kurangnya satu karakter kecil
password_uppercase_one=Sekurang-kurangnya satu karakter besar
password_digit_one=Sekurang-kurangnya satu angka
password_special_one=Sekurang-kurangnya satu karater khusus (tanda baca, kurung, kutip, dll.)
enterred_invalid_repo_name=Nama repositori yang Anda masukkan salah.
enterred_invalid_owner_name=Nama pemilik baru salah.
enterred_invalid_password=Kata sandi yang Anda masukkan salah.
user_not_exist=Pengguna tidak ada. user_not_exist=Pengguna tidak ada.
team_not_exist=Tim tidak ada.
last_org_owner=Anda tidak dapat menghapus pengguna terakhir dari tim pemilik. Harus ada setidaknya satu pemilik dalam tim yang diberikan.
cannot_add_org_to_team=Sebuah organisasi tidak dapat ditambahkan sebagai anggota tim.
invalid_ssh_key=Tidak dapat memverifikasi kunci SSH Anda: %s
invalid_gpg_key=Tidak dapat memverifikasi kunci GPG Anda: %s
unable_verify_ssh_key=Tidak dapat memverifikasi kunci SSH; periksa kembali bila ada kesalahan.
auth_failed=Otentikasi gagal: %v auth_failed=Otentikasi gagal: %v
still_own_repo=Akun anda memiliki satu atau lebih repositori, pindahkan atau transfer terlebih dahulu.
still_has_org=Akun Anda adalah anggota dari satu atau lebih organisasi, tinggalkan terlebih dahulu.
org_still_own_repo=Organisasi ini masih memiliki satu atau lebih repositori; hapus atau transfer terlebih dahulu.
target_branch_not_exist=Target cabang tidak ada. target_branch_not_exist=Target cabang tidak ada.
[user] [user]
change_avatar=Ganti avatar anda…
join_on=Telah bergabung di join_on=Telah bergabung di
repositories=Repositori repositories=Repositori
activity=Aktivitas Publik activity=Aktivitas Publik
followers=Pengikut followers=Pengikut
starred=Repositori Terbintang
following=Mengikuti following=Mengikuti
follow=Ikuti follow=Ikuti
unfollow=Berhenti Mengikuti unfollow=Berhenti Mengikuti
heatmap.loading=Memuat Peta Panas…
user_bio=Biografi
form.name_reserved=Nama pengguna '%s' dicadangkan. form.name_reserved=Nama pengguna '%s' dicadangkan.
form.name_pattern_not_allowed=Pola '%s' tidak diperbolehkan dalam nama pengguna.
[settings] [settings]
profile=Profil profile=Profil
account=Akun
password=Kata Sandi password=Kata Sandi
security=Keamanan security=Keamanan
avatar=Avatar avatar=Avatar
ssh_gpg_keys=Kunci SSH / GPG ssh_gpg_keys=Kunci SSH / GPG
social=Akun Sosial social=Akun Sosial
applications=Aplikasi
orgs=Kelola organisasi
repos=Repositori repos=Repositori
delete=Hapus Akun delete=Hapus Akun
twofa=Otentikasi Dua-Faktor twofa=Otentikasi Dua-Faktor
account_link=Akun Tertaut
organization=Organisasi
uid=Uid uid=Uid
u2f=Kunci keamanan
public_profile=Profil Publik public_profile=Profil Publik
profile_desc=Alamat email Anda akan digunakan untuk notifikasi dan operasi lainnya.
password_username_disabled=Pengguna non-lokal tidak diizinkan untuk mengubah nama pengguna mereka. Silakan hubungi administrator sistem anda untuk lebih lanjut.
full_name=Nama Lengkap full_name=Nama Lengkap
website=Situs Web website=Situs Web
location=Lokasi location=Lokasi
update_theme=Perbarui Tema
update_profile=Perbarui Profil update_profile=Perbarui Profil
update_profile_success=Profil anda telah diperbarui. update_profile_success=Profil anda telah diperbarui.
change_username=Nama pengguna Anda telah diganti.
change_username_prompt=Catatan: Perubahan nama pengguna juga mengubah URL akun Anda.
continue=Lanjutkan continue=Lanjutkan
cancel=Batalkan cancel=Batalkan
language=Bahasa
ui=Tema
lookup_avatar_by_mail=Cari Avatar melalui Alamat Email
federated_avatar_lookup=Aktifkan Pencarian Avatar Representasi federated_avatar_lookup=Aktifkan Pencarian Avatar Representasi
enable_custom_avatar=Gunakan Avatar Pilihan enable_custom_avatar=Gunakan Avatar Pilihan
choose_new_avatar=Pilih avatar baru choose_new_avatar=Pilih avatar baru
update_avatar=Perbarui Avatar
delete_current_avatar=Hapus Avatar Saat Ini delete_current_avatar=Hapus Avatar Saat Ini
uploaded_avatar_not_a_image=Berkas yang diunggah bukanlah gambar.
uploaded_avatar_is_too_big=Berkas yang diunggah melebihi ukuran maksimum.
update_avatar_success=Avatar Anda telah diperbarui.
change_password=Perbarui kata sandi
old_password=Kata Sandi Saat Ini old_password=Kata Sandi Saat Ini
new_password=Kata Sandi Baru new_password=Kata Sandi Baru
retype_new_password=Ketik Ulang Kata Sandi Baru
password_incorrect=Kata sandi saat ini salah.
emails=Alamat Surel emails=Alamat Surel
email_desc=Alamat surel utama anda akan digunakan untuk notifikasi dan operasi lainnya. email_desc=Alamat surel utama anda akan digunakan untuk notifikasi dan operasi lainnya.
@@ -318,6 +430,7 @@ confirm_delete_account=Konfirmasi Penghapusan
owner=Pemilik owner=Pemilik
repo_name=Nama Repositori repo_name=Nama Repositori
visibility=Jarak pandang visibility=Jarak pandang
clone_helper=Butuh bantuan kloning? Kunjungi <a target="_blank" rel="noopener noreferrer" href="%s">Bantuan</a>.
fork_repo=Cabang Gudang penyimpanan fork_repo=Cabang Gudang penyimpanan
fork_from=Cabang Dari fork_from=Cabang Dari
repo_desc=Deskripsi repo_desc=Deskripsi
@@ -508,6 +621,7 @@ pulls.new=Permintaan Tarik Baru
pulls.filter_branch=Penyaringan cabang pulls.filter_branch=Penyaringan cabang
pulls.no_results=Hasil tidak ditemukan. pulls.no_results=Hasil tidak ditemukan.
pulls.create=Buat Permintaan Tarik pulls.create=Buat Permintaan Tarik
pulls.title_desc=ingin menggabungkan komit %[1]d dari <code>%[2]s</code> menuju <code id="branch_target">%[3]s</code>
pulls.merged_title_desc=commit %[1]d telah digabungkan dari <code>%[2]s</code> menjadi <code>%[3]s</code> %[4]s pulls.merged_title_desc=commit %[1]d telah digabungkan dari <code>%[2]s</code> menjadi <code>%[3]s</code> %[4]s
pulls.tab_conversation=Percakapan pulls.tab_conversation=Percakapan
pulls.tab_commits=Melakukan pulls.tab_commits=Melakukan
@@ -625,6 +739,7 @@ settings.webhook.request=Permintaan
settings.webhook.response=Tanggapan settings.webhook.response=Tanggapan
settings.webhook.headers=Tajuk settings.webhook.headers=Tajuk
settings.webhook.body=Tubuh settings.webhook.body=Tubuh
settings.githooks_desc=Kaitan Git diberdayakan oleh Git itu sendiri. Anda bisa menyunting berkas kaitan di bawah untuk mempersiapkan operasi kustom.
settings.githook_edit_desc=Jika hook tidak aktif, konten sampel akan dipaparkan. Meninggalkan konten dengan nilai kosong akan menonaktifkan hook ini. settings.githook_edit_desc=Jika hook tidak aktif, konten sampel akan dipaparkan. Meninggalkan konten dengan nilai kosong akan menonaktifkan hook ini.
settings.githook_name=Nama Hook settings.githook_name=Nama Hook
settings.githook_content=Konten Hook settings.githook_content=Konten Hook

View File

@@ -1062,6 +1062,8 @@ pulls.no_merge_desc=リポジトリのマージオプションがすべて無効
pulls.no_merge_helper=リポジトリ設定でマージを有効にするか、手動でマージしてください。 pulls.no_merge_helper=リポジトリ設定でマージを有効にするか、手動でマージしてください。
pulls.no_merge_wip=このプルリクエストはWork in Progressとマークされているため、マージすることはできません。 pulls.no_merge_wip=このプルリクエストはWork in Progressとマークされているため、マージすることはできません。
pulls.no_merge_status_check=すべての必要なステータスチェックが成功していないため、このプルリクエストはマージできません。 pulls.no_merge_status_check=すべての必要なステータスチェックが成功していないため、このプルリクエストはマージできません。
pulls.no_merge_not_ready=このプルリクエストはマージする準備ができていません。 レビュー状況とステータスチェックを確認してください。
pulls.no_merge_access=このプルリクエストをマージする権限がありません。
pulls.merge_pull_request=プルリクエストをマージ pulls.merge_pull_request=プルリクエストをマージ
pulls.rebase_merge_pull_request=リベースしてマージ pulls.rebase_merge_pull_request=リベースしてマージ
pulls.rebase_merge_commit_pull_request=リベースしてマージ(--no-ff) pulls.rebase_merge_commit_pull_request=リベースしてマージ(--no-ff)
@@ -1412,6 +1414,8 @@ settings.protect_approvals_whitelist_enabled=ホワイトリストに登録し
settings.protect_approvals_whitelist_enabled_desc=ホワイトリストに登録したユーザーやチームによるレビューのみを、必要な承認とみなします。 承認のホワイトリストが無い場合は、書き込み権限がある人によるレビューを必要な承認とみなします。 settings.protect_approvals_whitelist_enabled_desc=ホワイトリストに登録したユーザーやチームによるレビューのみを、必要な承認とみなします。 承認のホワイトリストが無い場合は、書き込み権限がある人によるレビューを必要な承認とみなします。
settings.protect_approvals_whitelist_users=ホワイトリストに含めるレビューア: settings.protect_approvals_whitelist_users=ホワイトリストに含めるレビューア:
settings.protect_approvals_whitelist_teams=ホワイトリストに含めるレビューチーム: settings.protect_approvals_whitelist_teams=ホワイトリストに含めるレビューチーム:
settings.dismiss_stale_approvals=古くなった承認を取り消す
settings.dismiss_stale_approvals_desc=プルリクエストの内容を変える新たなコミットがブランチにプッシュされた場合、以前の承認を取り消します。
settings.add_protected_branch=保護を有効にする settings.add_protected_branch=保護を有効にする
settings.delete_protected_branch=保護を無効にする settings.delete_protected_branch=保護を無効にする
settings.update_protect_branch_success=ブランチ '%s' の保護を更新しました。 settings.update_protect_branch_success=ブランチ '%s' の保護を更新しました。
@@ -1747,6 +1751,7 @@ users.new_account=ユーザーアカウントを作成
users.name=ユーザー名 users.name=ユーザー名
users.activated=アクティベート済み users.activated=アクティベート済み
users.admin=管理者 users.admin=管理者
users.restricted=制限あり
users.repos=リポジトリ users.repos=リポジトリ
users.created=作成日 users.created=作成日
users.last_login=前回のサインイン users.last_login=前回のサインイン
@@ -1765,6 +1770,7 @@ users.max_repo_creation_desc=( -1を設定するとデフォルトの制限が
users.is_activated=ユーザーアカウントはアクティベート済み users.is_activated=ユーザーアカウントはアクティベート済み
users.prohibit_login=サインイン無効 users.prohibit_login=サインイン無効
users.is_admin=管理者 users.is_admin=管理者
users.is_restricted=制限あり
users.allow_git_hook=Gitフックを作成可 users.allow_git_hook=Gitフックを作成可
users.allow_import_local=ローカルリポジトリをインポート可 users.allow_import_local=ローカルリポジトリをインポート可
users.allow_create_organization=組織を作成可 users.allow_create_organization=組織を作成可
@@ -2025,8 +2031,54 @@ monitor.execute_time=実行時間
monitor.process.cancel=処理をキャンセル monitor.process.cancel=処理をキャンセル
monitor.process.cancel_desc=処理をキャンセルするとデータが失われる可能性があります monitor.process.cancel_desc=処理をキャンセルするとデータが失われる可能性があります
monitor.process.cancel_notices=キャンセル: <strong>%s</strong>? monitor.process.cancel_notices=キャンセル: <strong>%s</strong>?
monitor.queues=キュー
monitor.queue=キュー: %s
monitor.queue.name=キュー名
monitor.queue.type=種類
monitor.queue.exemplar=要素の型
monitor.queue.numberworkers=ワーカー数
monitor.queue.maxnumberworkers=ワーカー数上限
monitor.queue.review=設定確認
monitor.queue.review_add=確認/ワーカー追加
monitor.queue.configuration=初期設定
monitor.queue.nopool.title=ワーカープールはありません
monitor.queue.nopool.desc=このキューは他のキューをラップし、これ自体にはワーカープールがありません。
monitor.queue.wrapped.desc=wrappedキューは、すぐに開始されないキューをラップし、入ってきたリクエストをチャンネルにバッファリングします。 これ自体にはワーカープールがありません。
monitor.queue.persistable-channel.desc=persistable-channelキューは二つのキューをラップします。 一つはchannelキューで、自分のワーカープールを持ちます。もう一つはlevelキューで、前回のシャットダウンからリクエストを引き継ぐためのものです。 これ自体にはワーカープールがありません。
monitor.queue.pool.timeout=タイムアウト
monitor.queue.pool.addworkers.title=ワーカーの追加
monitor.queue.pool.addworkers.submit=ワーカーを追加
monitor.queue.pool.addworkers.desc=このプールに、タイムアウト付きまたはタイムアウト無しでワーカーを追加します。 タイムアウトを指定した場合は、タイムアウト後にそれらのワーカーがこのプールから取り除かれます。
monitor.queue.pool.addworkers.numberworkers.placeholder=ワーカー数
monitor.queue.pool.addworkers.timeout.placeholder=0でタイムアウト無し
monitor.queue.pool.addworkers.mustnumbergreaterzero=追加するワーカー数は1以上にしてください
monitor.queue.pool.addworkers.musttimeoutduration=タイムアウトは 、Go言語の時間差表記(例 5m)、または0にしてください
monitor.queue.settings.title=プール設定
monitor.queue.settings.desc=ワーカーへのキューのブロックが発生すると、それに応じてプール数がブースト分ずつ動的に増えます。 これらの変更は現在のワーカーグループには影響しません。
monitor.queue.settings.timeout=ブースト分のタイムアウト
monitor.queue.settings.timeout.placeholder=現在の設定 %[1]v
monitor.queue.settings.timeout.error=タイムアウトは 、Go言語の時間差表記(例 5m)、または0にしてください
monitor.queue.settings.numberworkers=ブースト分のワーカー数
monitor.queue.settings.numberworkers.placeholder=現在の設定 %[1]d
monitor.queue.settings.numberworkers.error=追加するワーカー数はゼロ以上にしてください
monitor.queue.settings.maxnumberworkers=ワーカー数上限
monitor.queue.settings.maxnumberworkers.placeholder=現在の設定 %[1]d
monitor.queue.settings.maxnumberworkers.error=ワーカー数上限は数値にしてください
monitor.queue.settings.submit=設定を更新
monitor.queue.settings.changed=設定を更新しました
monitor.queue.settings.blocktimeout=現在のブロックタイムアウト
monitor.queue.settings.blocktimeout.value=%[1]v
monitor.queue.pool.none=このキューにはプールがありません
monitor.queue.pool.added=ワーカーグループを追加しました
monitor.queue.pool.max_changed=ワーカー数の上限を変更しました
monitor.queue.pool.workers.title=アクティブなワーカーグループ
monitor.queue.pool.workers.none=ワーカーグループはありません。
monitor.queue.pool.cancel=ワーカーグループのシャットダウン
monitor.queue.pool.cancelling=ワーカーグループをシャットダウンしています
monitor.queue.pool.cancel_notices=このワーカー数 %s のグループをシャットダウンしますか?
monitor.queue.pool.cancel_desc=キューをワーカーグループ無しのままにすると、リクエストがブロックし続ける原因となります。
notices.system_notice_list=システム通知 notices.system_notice_list=システム通知
notices.view_detail_header=通知の詳細を表示 notices.view_detail_header=通知の詳細を表示
@@ -2120,4 +2172,3 @@ error.probable_bad_default_signature=警告! これはデフォルト鍵のIDで
[units] [units]
error.no_unit_allowed_repo=このリポジトリのどのセクションにもアクセスが許可されていません。 error.no_unit_allowed_repo=このリポジトリのどのセクションにもアクセスが許可されていません。
error.unit_not_allowed=このセクションへのアクセスが許可されていません。 error.unit_not_allowed=このセクションへのアクセスが許可されていません。

View File

@@ -3,9 +3,9 @@ dashboard=대시보드
explore=탐색 explore=탐색
help=도움말 help=도움말
sign_in=로그인 sign_in=로그인
sign_in_with=냐후 ㅑㅜ 쨔소 sign_in_with=다음을 통해 로그인
sign_out=로그아웃 sign_out=로그아웃
sign_up=ㄲㄷ햔ㅅㄷㄱ sign_up=가입하기
link_account=계정 연결 link_account=계정 연결
register=가입하기 register=가입하기
website=웹 사이트 website=웹 사이트
@@ -14,18 +14,18 @@ page=페이지
template=템플릿 template=템플릿
language=언어 language=언어
notifications=알림 notifications=알림
create_new=ㅊㄱㄷㅁㅅㄷ... create_new=생성하기
user_profile_and_more=ㅖ개랴ㅣㄷ 뭉 ㄴㄷㅅ샤ㅜㅎㄴ... user_profile_and_more=프로파일 및 설정
signed_in_as=다음 사용자로 로그인됨 signed_in_as=다음 사용자로 로그인됨
enable_javascript=쏘ㅑㄴ ㅈ듀냣ㄷ 재간 ㅠㄷㅅㅅㄷㄱ 쟈소 ㅓㅁㅍㅁㄴㅊ갸ㅔㅅ. enable_javascript=이 웹사이트는 자바스크립트 활성화가 필요합니다.
username=사용자명 username=사용자명
email=뜨먀ㅣ ㅁㅇㅇㄱㄷㄴㄴ email=이메일 주소
password=비밀번호 password=비밀번호
re_type=ㄲㄷ-쑈ㅔㄷ ㅖㅁㄴㄴ잭ㅇ re_type=비밀번호 재입력
captcha=ㅊ몠촘 captcha=보안 문자
twofa=ㅆ재-ㄻㅊ색 며소두샻ㅁ샤ㅐㅜ twofa=2단계 인증
twofa_scratch=ㅆ재-ㄻㅊ색 ㄴㅊㄱㅁㅅ초 챙ㄷ twofa_scratch=2단계 일회성 코드
passcode=인증코드 passcode=인증코드
u2f_insert_key=보안 키를 입력해주세요. u2f_insert_key=보안 키를 입력해주세요.
@@ -50,12 +50,12 @@ new_mirror=새로운 미러
new_fork=새 저장소 포크 new_fork=새 저장소 포크
new_org=새로운 조직 new_org=새로운 조직
manage_org=조직 관리 manage_org=조직 관리
admin_panel=냣ㄷ ㅁ으ㅑㅜㅑㄴㅅㄱㅁ샤ㅐㅜ admin_panel=사이트 관리
account_settings=계정 설정 account_settings=계정 설정
settings=설정 settings=설정
your_profile=ㅖ개랴ㅣㄷ your_profile=프로필
your_starred=ㄴㅅㅁㄱㄱㄷㅇ your_starred=즐겨찾기
your_settings=ㄴㄷㅅ샤ㅜㅎㄴ your_settings=설정
all=전체 all=전체
sources=소스 sources=소스
@@ -66,71 +66,75 @@ forks=포크
activities=활동 activities=활동
pull_requests=풀 리퀘스트 pull_requests=풀 리퀘스트
issues=이슈들 issues=이슈들
milestones=마일스톤
cancel=취소 cancel=취소
add=추가
write=쓰기 write=쓰기
preview=미리보기 preview=미리보기
loading=불러오는 중... loading=불러오는 중...
[startpage] [startpage]
app_desc=편리한 설치형 Git 서비스
license=오픈 소스
[install] [install]
install=설치 install=설치
title=ㅑㅜㅑ샤미 채ㅜ랴혁ㅁ샤ㅐㅜ title=초기 설정
docker_helper=Gitea를 Docker에서 실행하려면 설정 전에 이 <a target="_blank" rel="noopener noreferrer" href="%s">문서</a>를 읽어보세요. docker_helper=Gitea를 Docker에서 실행하려면 설정 전에 이 <a target="_blank" rel="noopener noreferrer" href="%s">문서</a>를 읽어보세요.
requite_db_desc=Gitea를 실행하려면 MySQL, PostgreSQL, MSSQL 또는 SQLite3 중 하나가 필요합니다. requite_db_desc=Gitea를 실행하려면 MySQL, PostgreSQL, MSSQL 또는 SQLite3 중 하나가 필요합니다.
db_title=데이터베이스 설정 db_title=데이터베이스 설정
db_type=데이터베이스 유형 db_type=데이터베이스 유형
host=호스트 host=호스트
user=ㅕㄴㄷ구믇 user=이름
password=비밀번호 password=비밀번호
db_name=데이터베이스 이름 db_name=데이터베이스 이름
ssl_mode=ㄴ니 ssl_mode=SSL
charset=문자셋 charset=문자셋
path=경로 path=경로
sqlite_helper=SQLite3 데이터베이스에 대한 파일 경로입니다.<br>Gitea를 서비스로 구동할 경우, 절대 경로를 입력해주십시오. sqlite_helper=SQLite3 데이터베이스에 대한 파일 경로입니다.<br>Gitea를 서비스로 구동할 경우, 절대 경로를 입력해주십시오.
err_empty_db_path=SQLite3 데이터베이스 경로는 필수 입력 값입니다. err_empty_db_path=SQLite3 데이터베이스 경로는 필수 입력 값입니다.
no_admin_and_disable_registration=ㅛㅐㅕ ㅊ무ㅜㅐㅅ 얀뮤ㅣㄷ ㅕㄴㄷㄱ ㄴ딜-ㄱㄷ햔ㅅㄱㅁ샤ㅐㅜ 쟈쇄ㅕㅅ ㅊㄱㄷㅁ샤ㅜㅎ 무 ㅁ으ㅑㅜㅑㄴㅅㄱㅁ색 ㅁㅊ채ㅕㅜㅅ. no_admin_and_disable_registration=관리자 계정을 만들지 않고 등록을 비활성화할 수 없습니다.
err_empty_admin_password=쏟 ㅁ으ㅑㅜㅑㄴㅅㄱㅁ색 ㅔㅁㄴㄴ잭ㅇ ㅊ무ㅜㅐㅅ ㅠㄷ 드ㅔ쇼. err_empty_admin_password=관리자 비밀번호는 비어 있을 수 없습니다.
err_empty_admin_email=관리자 이메일은 비어 있을 수 없습니다. err_empty_admin_email=관리자 이메일은 비어 있을 수 없습니다.
err_admin_name_is_reserved=관리자 사용자 이름이 올바르지 않습니다, 제한된 사용자 이름입니다 err_admin_name_is_reserved=관리자 사용자 이름이 올바르지 않습니다, 제한된 사용자 이름입니다
err_admin_name_is_invalid=관리자 사용자 이름이 올바르지 않습니다 err_admin_name_is_invalid=관리자 사용자 이름이 올바르지 않습니다
general_title=ㅎ둗ㄱ미 ㄴㄷㅅ샤ㅜㅎㄴ general_title=기본설정
app_name=냣ㄷ 쌰싣 app_name=사이트 제목
app_name_helper=ㅛㅐㅕ ㅊ무 둣ㄷㄱ ㅛㅐㅕㄱ 채ㅡㅔ무ㅛ ㅜ믇 ㅗㄷㄱㄷ. app_name_helper=회사이름을 넣으세요.
repo_path=저장소 최상위 경로 repo_path=저장소 최상위 경로
repo_path_helper=ㄲ드ㅐㅅㄷ 햣 ㄱ데ㅐ냐새갿ㄴ 쟈ㅣㅣ ㅠㄷ ㄴㅁㅍㄷㅇ 새 소ㅑㄴ 약ㄷㅊ새교. repo_path_helper=Git 원격 저장소는 이 디렉터리에 저장 됩니다.
lfs_path=햣 ㅣㄹㄴ 깨ㅐㅅ ㅖㅁ소 lfs_path=Git LFS 루트 경로
lfs_path_helper=랴ㅣㄷㄴ ㅅㄱㅁ찯ㅇ ㅠㅛ 햣 ㅣㄹㄴ 쟈ㅣㅣ ㅠㄷ ㄴ색ㄷㅇ ㅑㅜ 소ㅑㄴ 약ㄷㅊ새교. ㅣㄷㅁㅍㄷ 드ㅔ쇼 새 얀뮤ㅣㄷ. lfs_path_helper=Git LFS에 저장된 파일들은 이 디렉토리에 저장됩니다. LFS를 사용하지 않는다면 빈칸으로 남겨주세요.
run_user=껴ㅜ ㅁㄴ ㅕㄴㄷ구믇 run_user=실행 사용자명
run_user_helper=뚯ㄷㄱ 솓 ㅐㅔㄷㄱㅁ샤ㅜㅎ 뇬ㅅ드 ㅕㄴㄷ구믇 솜ㅅ 햣ㄷㅁ 겨ㅜㄴ ㅁㄴ. ㅜㅐㅅㄷ 솜ㅅ 소ㅑㄴ ㅕㄴㄷㄱ ㅡㅕㄴㅅ ㅗㅁㅍㄷ ㅁㅊㅊㄷㄴㄴ 새 솓 ㄱ데ㅐ냐새교 개ㅐㅅ ㅔㅁ소. run_user_helper=Gitea 를 실행할 시스템 사용자명을 넣으세요. 시스템 사용자는 레포지토리 루트 경로에 대한 권한이 필요합니다.
domain=ㄴ노 ㄴㄷㄱㅍㄷㄱ 애ㅡ먀ㅜ domain=SSH 서버 도메인
domain_helper=애ㅡ먀ㅜ ㅐㄱ ㅙㄴㅅ ㅁㅇㅇㄱㄷㄴㄴ 랙 노ㅗ 치ㅐㅜㄷ ㅕ낀. domain_helper=SSH clone URL 에 대한 도메인 또는 호스트 주소
ssh_port=ㄴ노 ㄴㄷㄱㅍㄷㄱ ㅖㅐㄳ ssh_port=ㄴ노 ㄴㄷㄱㅍㄷㄱ ㅖㅐㄳ
ssh_port_helper=ㅖㅐㄳ ㅜㅕㅡㅠㄷㄱ ㅛㅐㅕㄱ 노ㅗ ㄴㄷㄱㅍㄷㄱ ㅣㅑㄴㅅ둔 ㅐㅜ. ㅣㄷㅁㅍㄷ 드ㅔ쇼 새 얀뮤ㅣㄷ. ssh_port_helper=SSH 서버가 실행되고 있는 포트를 입력하세요. 비워둘 경우 SSH를 사용하지 않습니다.
http_port=햣ㄷㅁ ㅗㅆ쎄 ㅣㅑㄴㅅ두 ㅖㅐㄳ http_port=Gitea HTTP 수신 포트
http_port_helper=ㅖㅐㄳ ㅜㅕㅡㅠㄷㄱ 솓 햣ㄷㅁㄴ ㅈ듀 ㄴㄷㄱㅍㄷㄱ 쟈ㅣㅣ ㅣㅑㄴㅅ두 ㅐㅜ. http_port_helper=Gitea 웹서버가 수신할 포트 번호
app_url=햣ㄷㅁ ㅠㅁㄴㄷ ㅕ끼 app_url=Gitea 기본 URL
app_url_helper=ㅠㅁㄴㄷ ㅁㅇㅇㄱㄷㄴㄴ 랙 ㅗㅆ쎼(ㄴ) 치ㅐㅜㄷ ㅕ낀 뭉 드먀ㅣ ㅜㅐ샤럋ㅁ샤ㅐㅜㄴ. app_url_helper=HTTP(S) clone URL 및 이메일 알림 기본 주소
log_root_path=로그 경로 log_root_path=로그 경로
log_root_path_helper=ㅣㅐㅎ 랴ㅣㄷㄴ 쟈ㅣㅣ ㅠㄷ ㅈ걋ㅅ두 새 소ㅑㄴ 약ㄷㅊ새교. log_root_path_helper=로그파일은 이 디렉토리에 저장됩니다.
optional_title=추가설정 optional_title=추가설정
email_title=뜨먀ㅣ ㄴㄷㅅ샤ㅜㅎㄴ email_title=이메일 설정
smtp_host=SMTP 호스트 smtp_host=SMTP 호스트
smtp_from=ㄴ둥 뜨먀ㅣ ㅁㄴ smtp_from=이메일 발신인
smtp_from_helper=뜨먀ㅣ ㅁㅇㅇㄱㄷㄴㄴ 햣ㄷㅁ 쟈ㅣㅣ ㅕㄴㄷ. 뚯ㄷㄱ ㅁ ㅔㅣ먀ㅜ 드먀ㅣ ㅁㅇㅇㄱㄷㄴㄴ ㅐㄱ ㅕㄴㄷ 솓 "ㅜ믇" <드먀ㅣ@ㄷㅌ므ㅔㅣㄷ.kr> 래금ㅅ. smtp_from_helper=Gitea 가 사용할 이메일 주소. 이메일 주소 또는 "이름" <email@example.com> 형식으로 입력하세요.
mailer_user=느쎼 ㅕㄴㄷ구믇 mailer_user=SMTP 사용자이름
mailer_password=느쎼 ㅖㅁㄴㄴ잭ㅇ mailer_password=SMTP 비밀번호
register_confirm=ㄲㄷ벼ㅑㄱㄷ 뜨먀ㅣ 채ㅜ랴금샤ㅐㅜ 새 ㄲㄷ햔ㅅㄷㄱ register_confirm=가입시 이메일 확인 필수
mail_notify=뚜뮤ㅣㄷ 뜨먀ㅣ ㅜㅐ샤럋ㅁ샤ㅐㅜㄴ mail_notify=이메일 알림 켜기
server_service_title=ㄴㄷㄱㅍㄷㄱ 뭉 쏘ㅑㄱㅇ-ㅖㅁㄱ쇼 ㄴㄷㄱ퍛ㄷ ㄴㄷㅅ샤ㅜㅎㄴ server_service_title=서버 및 기타 서비스 설정
offline_mode=뚜뮤ㅣㄷ ㅣㅐㅊ미 ㅡㅐㅇㄷ offline_mode=로컬 모드 켜기
offline_mode_popup=얀뮤ㅣㄷ 소ㅑㄱㅇ-ㅔㅁㄱ쇼 채ㅜㅅ둣 ㅇ디ㅑㅍㄷ교 ㅜㄷㅅ재간 뭉 ㄴㄷㄱㅍㄷ 미ㅣ ㄱㄷ내ㅕㄱㅊㄷㄴ ㅣㅐㅊ미ㅣㅛ. offline_mode_popup=타사 콘텐츠 전송 네트워크를 사용하지 않도록 설정하고 모든 리소스를 로컬로 제공하십시오.
disable_gravatar=얀뮤ㅣㄷ ㅎㄱㅁㅍㅍㅁㅅㅁㄱ disable_gravatar=Gravatar 사용안함
disable_gravatar_popup=얀뮤ㅣㄷ ㅎㄱㅁㅍㅁㅅㅁㄱ 뭉 소ㅑㄱㅇ-ㅔㅁㄱ쇼 ㅁㅍㅁㄴㅅㅁㄱ 내ㅕㄱㅊㄷㄴ. ㅁ ㅇㄷㄹ며ㅣㅅ ㅁㅍㅁㅅㅁㄱ 쟈ㅣㅣ ㅠㄷ ㅕㄴㄷㅇ ㅕㅟㄷㄴㄴ ㅁ ㅕㄴㄷㄱ ㅣㅐㅊ미ㅣㅛ ㅕㅔㅣㅐㅁㅇㄴ 무 ㅁㅍㅁㅅㅁㄱ. disable_gravatar_popup=Gravatar 및 타사 아바타 소스를 사용하지 않도록 설정합니다. 사용자가 로컬로 아바타를 업로드하지 않는 한 기본 아바타가 사용됩니다.
federated_avatar_lookup=아바타 연동 사용여부 federated_avatar_lookup=아바타 연동 사용여부
federated_avatar_lookup_popup=libravatar 기반 오픈소스 서비스 사용 목적으로 연합 아바타 조회를 허용하기 federated_avatar_lookup_popup=libravatar 기반 오픈소스 서비스 사용 목적으로 연합 아바타 조회를 허용하기
disable_registration=사용자 등록 비활성화 disable_registration=사용자 등록 비활성화
@@ -509,6 +513,8 @@ confirm_delete_account=삭제 승인
delete_account_title=사용자 계정 삭제 delete_account_title=사용자 계정 삭제
delete_account_desc=이 계정을 정말로 삭제하시겠습니까? delete_account_desc=이 계정을 정말로 삭제하시겠습니까?
email_notifications.enable=이메일 알림 켜기
email_notifications.disable=이메일 알림 끄기
[repo] [repo]
owner=소유자 owner=소유자
@@ -879,6 +885,7 @@ milestones.filter_sort.most_complete=완료율이 높은 순
milestones.filter_sort.most_issues=이슈 많은 순 milestones.filter_sort.most_issues=이슈 많은 순
milestones.filter_sort.least_issues=이슈 적은 순 milestones.filter_sort.least_issues=이슈 적은 순
ext_wiki=외부 위키 ext_wiki=외부 위키
ext_wiki.desc=외부 위키에 연결하기. ext_wiki.desc=외부 위키에 연결하기.
@@ -960,6 +967,8 @@ settings.basic_settings=기본 설정
settings.mirror_settings=미러 설정 settings.mirror_settings=미러 설정
settings.sync_mirror=지금 동기화 settings.sync_mirror=지금 동기화
settings.mirror_sync_in_progress=미러 동기화 진행중입니다. 잠시 후 다시 확인해주십시오. settings.mirror_sync_in_progress=미러 동기화 진행중입니다. 잠시 후 다시 확인해주십시오.
settings.email_notifications.enable=이메일 알림 켜기
settings.email_notifications.disable=이메일 알림 끄기
settings.site=웹 사이트 settings.site=웹 사이트
settings.update_settings=설정 저장 settings.update_settings=설정 저장
settings.advanced_settings=고급 설정 settings.advanced_settings=고급 설정
@@ -1080,6 +1089,8 @@ settings.protected_branch_can_push_yes=푸시할 수 있습니다.
settings.protected_branch_can_push_no=푸시할 수 없습니다. settings.protected_branch_can_push_no=푸시할 수 없습니다.
settings.branch_protection='<b>%s</b>' 브랜치 보호 settings.branch_protection='<b>%s</b>' 브랜치 보호
settings.protect_this_branch=브랜치 보호 활성화 settings.protect_this_branch=브랜치 보호 활성화
settings.protect_disable_push=푸시 끄기
settings.protect_enable_push=푸시 켜기
settings.protect_whitelist_search_users=사용자 찾기... settings.protect_whitelist_search_users=사용자 찾기...
settings.protect_whitelist_search_teams=팀 찾기... settings.protect_whitelist_search_teams=팀 찾기...
settings.protect_merge_whitelist_committers=머지 화이트리스트 활성화 settings.protect_merge_whitelist_committers=머지 화이트리스트 활성화
@@ -1511,6 +1522,7 @@ monitor.process=실행중인 프로세스들
monitor.desc=설명 monitor.desc=설명
monitor.start=시작 시간 monitor.start=시작 시간
monitor.execute_time=실행 시간 monitor.execute_time=실행 시간
monitor.queue.configuration=초기 설정

View File

@@ -1596,7 +1596,7 @@ settings.full_name=Pilns vārds, uzvārds
settings.website=Mājas lapa settings.website=Mājas lapa
settings.location=Atrašanās vieta settings.location=Atrašanās vieta
settings.permission=Tiesības settings.permission=Tiesības
settings.repoadminchangeteam=Repozitorija administrators var pievienot vain noņemt piekļuvi komandām settings.repoadminchangeteam=Repozitorija administrators var pievienot vai noņemt piekļuvi komandām
settings.visibility=Redzamība settings.visibility=Redzamība
settings.visibility.public=Publiska settings.visibility.public=Publiska
settings.visibility.limited=Ierobežota (redzama tikai autorizētiem lietotājiem) settings.visibility.limited=Ierobežota (redzama tikai autorizētiem lietotājiem)
@@ -2025,8 +2025,54 @@ monitor.execute_time=Izpildes laiks
monitor.process.cancel=Atcelt procesu monitor.process.cancel=Atcelt procesu
monitor.process.cancel_desc=Procesa atcelšana var radīt datu zaudējumus monitor.process.cancel_desc=Procesa atcelšana var radīt datu zaudējumus
monitor.process.cancel_notices=Atcelt: <strong>%s</strong>? monitor.process.cancel_notices=Atcelt: <strong>%s</strong>?
monitor.queues=Rindas
monitor.queue=Rinda: %s
monitor.queue.name=Nosaukums
monitor.queue.type=Veids
monitor.queue.exemplar=Eksemplāra veids
monitor.queue.numberworkers=Strādņu skaits
monitor.queue.maxnumberworkers=Maksimālais strādņu skaits
monitor.queue.review=Pārbaudīt konfigurāciju
monitor.queue.review_add=Pārbaudīt/Pievienot strādņus
monitor.queue.configuration=Sākotnējā konfigurācija
monitor.queue.nopool.title=Nav strādņu pūla
monitor.queue.nopool.desc=Šī rinda apvieno citas rindas un tai nav strādņu pūla.
monitor.queue.wrapped.desc=Apvienojošā rinda apvieno lēni startējošās rindas, uzkrājot sarindotos pieprasījumus kanālā. Tai nav strādņu pūla.
monitor.queue.persistable-channel.desc=Patstāvīgas kanāli apvieno divas rindas, kanāla rindu, kurai ir savs strādņu pūls un līmeņu rindu patstāvīgajiem pieprasījumiem no iepriekšejām izslēgšanām. Tai nav strādņu pūla.
monitor.queue.pool.timeout=Noildze
monitor.queue.pool.addworkers.title=Pievienot strādņus
monitor.queue.pool.addworkers.submit=Pievienot
monitor.queue.pool.addworkers.desc=Pievienot strādņus šim pūlam ar vai bez noildzes. Ja uzstādīsies noildzi, tad šie strādņi tiks noņemti no pūla, kad noildze būs iestājusies.
monitor.queue.pool.addworkers.numberworkers.placeholder=Strādņu skaits
monitor.queue.pool.addworkers.timeout.placeholder=Norādiet 0, lai nebūtu noildzes
monitor.queue.pool.addworkers.mustnumbergreaterzero=Strādņu skaitam, ko pievienot, ir jābūt lielākam par nulli
monitor.queue.pool.addworkers.musttimeoutduration=Noildzei ir jābūt norādītai kā ilgumam, piemēram, 5m vai 0
monitor.queue.settings.title=Pūla iestatījumi
monitor.queue.settings.desc=Pūli var dinamiski augt un paildzinātu atbildi uz strādņu rindas bloķēšanu. Šis izmaiņas ietekmēs pašreizējās strādņu grupas.
monitor.queue.settings.timeout=Pagarināt noildzi
monitor.queue.settings.timeout.placeholder=Pašalaik %[1]v
monitor.queue.settings.timeout.error=Noildzei ir jābūt norādītai kā ilgumam, piemēram, 5m vai 0
monitor.queue.settings.numberworkers=Palielināt strādņu skaitu
monitor.queue.settings.numberworkers.placeholder=Pašalaik %[1]d
monitor.queue.settings.numberworkers.error=Strādņu skaitam ir jābūt lielākam vai vienādam ar nulli
monitor.queue.settings.maxnumberworkers=Maksimālais strādņu skaits
monitor.queue.settings.maxnumberworkers.placeholder=Pašalaik %[1]d
monitor.queue.settings.maxnumberworkers.error=Maksimālajam strādņu skaitam ir jābūt skaitlim
monitor.queue.settings.submit=Saglabāt iestatījumus
monitor.queue.settings.changed=Iestatījumi saglabāti
monitor.queue.settings.blocktimeout=Pašreizējās grupas noildze
monitor.queue.settings.blocktimeout.value=%[1]v
monitor.queue.pool.none=Rindai nav pūla
monitor.queue.pool.added=Strādņu grupa pievienota
monitor.queue.pool.max_changed=Maksimālais strādņu skaits mainīts
monitor.queue.pool.workers.title=Aktīvās strādņu grupas
monitor.queue.pool.workers.none=Nav strādņu grupu.
monitor.queue.pool.cancel=Izslēgt strādņu grupu
monitor.queue.pool.cancelling=Strādņu grupa tiek izslēgta
monitor.queue.pool.cancel_notices=Izslēgt šo grupu ar %s strādņiem?
monitor.queue.pool.cancel_desc=Atstājot rindu bez nevienas strādņu grupas, var radīt pieprasījumu bloķēšanos.
notices.system_notice_list=Sistēmas paziņojumi notices.system_notice_list=Sistēmas paziņojumi
notices.view_detail_header=Skatīt paziņojuma detaļas notices.view_detail_header=Skatīt paziņojuma detaļas
@@ -2120,4 +2166,3 @@ error.probable_bad_default_signature=BRĪDINĀJUMS! Lai arī šai atslēgai ir n
[units] [units]
error.no_unit_allowed_repo=Jums nav tiesību aplūkot nevienu šī repozitorija sadaļu. error.no_unit_allowed_repo=Jums nav tiesību aplūkot nevienu šī repozitorija sadaļu.
error.unit_not_allowed=Jums nav tiesību piekļūt šai repozitorija sadaļai. error.unit_not_allowed=Jums nav tiesību piekļūt šai repozitorija sadaļai.

View File

@@ -2100,4 +2100,3 @@ error.probable_bad_default_signature=OSTRZEŻENIE! Pomimo, że domyślny klucz p
[units] [units]
error.no_unit_allowed_repo=Nie masz uprawnień do żadnej sekcji tego repozytorium. error.no_unit_allowed_repo=Nie masz uprawnień do żadnej sekcji tego repozytorium.
error.unit_not_allowed=Nie masz uprawnień do tej sekcji repozytorium. error.unit_not_allowed=Nie masz uprawnień do tej sekcji repozytorium.

View File

@@ -1062,6 +1062,8 @@ pulls.no_merge_desc=O merge deste pull request não pode ser aplicado porque tod
pulls.no_merge_helper=Habilite as opções de merge nas configurações do repositório ou faça o merge do pull request manualmente. pulls.no_merge_helper=Habilite as opções de merge nas configurações do repositório ou faça o merge do pull request manualmente.
pulls.no_merge_wip=O merge deste pull request não pode ser aplicado porque está marcado como um trabalho em andamento. pulls.no_merge_wip=O merge deste pull request não pode ser aplicado porque está marcado como um trabalho em andamento.
pulls.no_merge_status_check=Este pull request não pode ter seu merge aplicado porque nem todas as verificações de status necessárias foram bem sucedidas. pulls.no_merge_status_check=Este pull request não pode ter seu merge aplicado porque nem todas as verificações de status necessárias foram bem sucedidas.
pulls.no_merge_not_ready=Este pull request não está pronto para ser realizado o merge, verifique o status da revisão e as verificações de status.
pulls.no_merge_access=Você não está autorizado para realizar o merge deste pull request.
pulls.merge_pull_request=Aplicar merge do pull request pulls.merge_pull_request=Aplicar merge do pull request
pulls.rebase_merge_pull_request=Aplicar Rebase e Merge pulls.rebase_merge_pull_request=Aplicar Rebase e Merge
pulls.rebase_merge_commit_pull_request=Aplicar Rebase e Merge (--no-ff) pulls.rebase_merge_commit_pull_request=Aplicar Rebase e Merge (--no-ff)
@@ -1412,6 +1414,8 @@ settings.protect_approvals_whitelist_enabled=Restringir aprovações a usuários
settings.protect_approvals_whitelist_enabled_desc=Somente as avaliações de usuários ou equipes da lista permitida serão contadas com as aprovações necessárias. Sem aprovação da lista permitida, as revisões de qualquer pessoa com acesso de escrita contam para as aprovações necessárias. settings.protect_approvals_whitelist_enabled_desc=Somente as avaliações de usuários ou equipes da lista permitida serão contadas com as aprovações necessárias. Sem aprovação da lista permitida, as revisões de qualquer pessoa com acesso de escrita contam para as aprovações necessárias.
settings.protect_approvals_whitelist_users=Usuários com permissão de revisão: settings.protect_approvals_whitelist_users=Usuários com permissão de revisão:
settings.protect_approvals_whitelist_teams=Equipes com permissão de revisão: settings.protect_approvals_whitelist_teams=Equipes com permissão de revisão:
settings.dismiss_stale_approvals=Descartar aprovações obsoletas
settings.dismiss_stale_approvals_desc=Quando novos commits que mudam o conteúdo do pull request são enviados para o branch, as antigas aprovações serão descartadas.
settings.add_protected_branch=Habilitar proteção settings.add_protected_branch=Habilitar proteção
settings.delete_protected_branch=Desabilitar proteção settings.delete_protected_branch=Desabilitar proteção
settings.update_protect_branch_success=Proteção do branch '%s' foi atualizada. settings.update_protect_branch_success=Proteção do branch '%s' foi atualizada.
@@ -1747,6 +1751,7 @@ users.new_account=Criar conta de usuário
users.name=Nome de usuário users.name=Nome de usuário
users.activated=Ativado users.activated=Ativado
users.admin=Administrador users.admin=Administrador
users.restricted=Restrito
users.repos=Repositórios users.repos=Repositórios
users.created=Criado users.created=Criado
users.last_login=Último acesso users.last_login=Último acesso
@@ -1765,6 +1770,7 @@ users.max_repo_creation_desc=(Use -1 para usar o limite padrão global.)
users.is_activated=Conta de usuário está ativada users.is_activated=Conta de usuário está ativada
users.prohibit_login=Desabilitar acesso users.prohibit_login=Desabilitar acesso
users.is_admin=É administrador users.is_admin=É administrador
users.is_restricted=Está restrito
users.allow_git_hook=Pode criar hooks Git users.allow_git_hook=Pode criar hooks Git
users.allow_import_local=Pode importar repositórios locais users.allow_import_local=Pode importar repositórios locais
users.allow_create_organization=Pode criar organizações users.allow_create_organization=Pode criar organizações
@@ -2166,4 +2172,3 @@ error.probable_bad_default_signature=AVISO! Embora a chave padrão tenha este ID
[units] [units]
error.no_unit_allowed_repo=Você não tem permissão para acessar nenhuma seção deste repositório. error.no_unit_allowed_repo=Você não tem permissão para acessar nenhuma seção deste repositório.
error.unit_not_allowed=Você não tem permissão para acessar esta seção do repositório. error.unit_not_allowed=Você não tem permissão para acessar esta seção do repositório.

View File

@@ -2113,4 +2113,3 @@ error.probable_bad_default_signature=UYARI! Varsayılan anahtarın bu kimliği o
[units] [units]
error.no_unit_allowed_repo=Bu deponun hiçbir bölümüne erişme izniniz yok. error.no_unit_allowed_repo=Bu deponun hiçbir bölümüne erişme izniniz yok.
error.unit_not_allowed=Bu depo bölümüne erişme izniniz yok. error.unit_not_allowed=Bu depo bölümüne erişme izniniz yok.

View File

@@ -2115,4 +2115,3 @@ error.probable_bad_default_signature=УВАГА! Хоча типовий клю
[units] [units]
error.no_unit_allowed_repo=У вас немає доступу до жодного розділу цього репозитория. error.no_unit_allowed_repo=У вас немає доступу до жодного розділу цього репозитория.
error.unit_not_allowed=У вас немає доступу до жодного розділу цього репозитория. error.unit_not_allowed=У вас немає доступу до жодного розділу цього репозитория.

View File

@@ -2166,4 +2166,3 @@ error.probable_bad_default_signature=警告虽然默认密钥拥有此ID
[units] [units]
error.no_unit_allowed_repo=您没有被允许访问此仓库的任何单元。 error.no_unit_allowed_repo=您没有被允许访问此仓库的任何单元。
error.unit_not_allowed=您没有权限访问此仓库单元 error.unit_not_allowed=您没有权限访问此仓库单元

View File

@@ -8,7 +8,6 @@
* http://opensource.org/licenses/MIT * http://opensource.org/licenses/MIT
* *
*/ */
@import url('https://fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic&subset=latin&display=swap');
/*! /*!
* # Fomantic-UI - Reset * # Fomantic-UI - Reset
* http://github.com/fomantic/Fomantic-UI/ * http://github.com/fomantic/Fomantic-UI/

View File

@@ -7,8 +7,7 @@
* Released under the MIT license * Released under the MIT license
* http://opensource.org/licenses/MIT * http://opensource.org/licenses/MIT
* *
*/ *//*!
@import url(https://fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic&subset=latin&display=swap);/*!
* # Fomantic-UI - Reset * # Fomantic-UI - Reset
* http://github.com/fomantic/Fomantic-UI/ * http://github.com/fomantic/Fomantic-UI/
* *

View File

@@ -130,6 +130,7 @@ func parseLDAPConfig(form auth.AuthenticationForm) *models.LDAPConfig {
SearchPageSize: pageSize, SearchPageSize: pageSize,
Filter: form.Filter, Filter: form.Filter,
AdminFilter: form.AdminFilter, AdminFilter: form.AdminFilter,
AllowDeactivateAll: form.AllowDeactivateAll,
Enabled: true, Enabled: true,
}, },
} }

View File

@@ -51,6 +51,10 @@ func SearchIssues(ctx *context.APIContext) {
// description: repository to prioritize in the results // description: repository to prioritize in the results
// type: integer // type: integer
// format: int64 // format: int64
// - name: type
// in: query
// description: filter by type (issues / pulls) if set
// type: string
// responses: // responses:
// "200": // "200":
// "$ref": "#/responses/IssueList" // "$ref": "#/responses/IssueList"
@@ -67,20 +71,24 @@ func SearchIssues(ctx *context.APIContext) {
// find repos user can access (for issue search) // find repos user can access (for issue search)
repoIDs := make([]int64, 0) repoIDs := make([]int64, 0)
opts := &models.SearchRepoOptions{
PageSize: 15,
Private: false,
AllPublic: true,
TopicOnly: false,
Collaborate: util.OptionalBoolNone,
UserIsAdmin: ctx.IsUserSiteAdmin(),
OrderBy: models.SearchOrderByRecentUpdated,
}
if ctx.IsSigned {
opts.Private = true
opts.AllLimited = true
opts.UserID = ctx.User.ID
}
issueCount := 0 issueCount := 0
for page := 1; ; page++ { for page := 1; ; page++ {
repos, count, err := models.SearchRepositoryByName(&models.SearchRepoOptions{ opts.Page = page
Page: page, repos, count, err := models.SearchRepositoryByName(opts)
PageSize: 15,
Private: true,
Keyword: "",
OwnerID: ctx.User.ID,
TopicOnly: false,
Collaborate: util.OptionalBoolNone,
UserIsAdmin: ctx.IsUserSiteAdmin(),
UserID: ctx.User.ID,
OrderBy: models.SearchOrderByRecentUpdated,
})
if err != nil { if err != nil {
ctx.Error(http.StatusInternalServerError, "SearchRepositoryByName", err) ctx.Error(http.StatusInternalServerError, "SearchRepositoryByName", err)
return return
@@ -125,6 +133,16 @@ func SearchIssues(ctx *context.APIContext) {
} }
} }
var isPull util.OptionalBool
switch ctx.Query("type") {
case "pulls":
isPull = util.OptionalBoolTrue
case "issues":
isPull = util.OptionalBoolFalse
default:
isPull = util.OptionalBoolNone
}
// Only fetch the issues if we either don't have a keyword or the search returned issues // Only fetch the issues if we either don't have a keyword or the search returned issues
// This would otherwise return all issues if no issues were found by the search. // This would otherwise return all issues if no issues were found by the search.
if len(keyword) == 0 || len(issueIDs) > 0 || len(labelIDs) > 0 { if len(keyword) == 0 || len(issueIDs) > 0 || len(labelIDs) > 0 {
@@ -137,6 +155,7 @@ func SearchIssues(ctx *context.APIContext) {
LabelIDs: labelIDs, LabelIDs: labelIDs,
SortType: "priorityrepo", SortType: "priorityrepo",
PriorityRepoID: ctx.QueryInt64("priority_repo_id"), PriorityRepoID: ctx.QueryInt64("priority_repo_id"),
IsPull: isPull,
}) })
} }
@@ -188,6 +207,10 @@ func ListIssues(ctx *context.APIContext) {
// in: query // in: query
// description: search string // description: search string
// type: string // type: string
// - name: type
// in: query
// description: filter by type (issues / pulls) if set
// type: string
// responses: // responses:
// "200": // "200":
// "$ref": "#/responses/IssueList" // "$ref": "#/responses/IssueList"
@@ -223,6 +246,16 @@ func ListIssues(ctx *context.APIContext) {
} }
} }
var isPull util.OptionalBool
switch ctx.Query("type") {
case "pulls":
isPull = util.OptionalBoolTrue
case "issues":
isPull = util.OptionalBoolFalse
default:
isPull = util.OptionalBoolNone
}
// Only fetch the issues if we either don't have a keyword or the search returned issues // Only fetch the issues if we either don't have a keyword or the search returned issues
// This would otherwise return all issues if no issues were found by the search. // This would otherwise return all issues if no issues were found by the search.
if len(keyword) == 0 || len(issueIDs) > 0 || len(labelIDs) > 0 { if len(keyword) == 0 || len(issueIDs) > 0 || len(labelIDs) > 0 {
@@ -233,6 +266,7 @@ func ListIssues(ctx *context.APIContext) {
IsClosed: isClosed, IsClosed: isClosed,
IssueIDs: issueIDs, IssueIDs: issueIDs,
LabelIDs: labelIDs, LabelIDs: labelIDs,
IsPull: isPull,
}) })
} }
@@ -457,6 +491,7 @@ func EditIssue(ctx *context.APIContext, form api.EditIssueOption) {
return return
} }
issue.Repo = ctx.Repo.Repository issue.Repo = ctx.Repo.Repository
canWrite := ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull)
err = issue.LoadAttributes() err = issue.LoadAttributes()
if err != nil { if err != nil {
@@ -464,7 +499,7 @@ func EditIssue(ctx *context.APIContext, form api.EditIssueOption) {
return return
} }
if !issue.IsPoster(ctx.User.ID) && !ctx.Repo.CanWrite(models.UnitTypeIssues) { if !issue.IsPoster(ctx.User.ID) && !canWrite {
ctx.Status(http.StatusForbidden) ctx.Status(http.StatusForbidden)
return return
} }
@@ -477,7 +512,7 @@ func EditIssue(ctx *context.APIContext, form api.EditIssueOption) {
} }
// Update or remove the deadline, only if set and allowed // Update or remove the deadline, only if set and allowed
if (form.Deadline != nil || form.RemoveDeadline != nil) && ctx.Repo.CanWrite(models.UnitTypeIssues) { if (form.Deadline != nil || form.RemoveDeadline != nil) && canWrite {
var deadlineUnix timeutil.TimeStamp var deadlineUnix timeutil.TimeStamp
if (form.RemoveDeadline == nil || !*form.RemoveDeadline) && !form.Deadline.IsZero() { if (form.RemoveDeadline == nil || !*form.RemoveDeadline) && !form.Deadline.IsZero() {
@@ -501,7 +536,7 @@ func EditIssue(ctx *context.APIContext, form api.EditIssueOption) {
// Pass one or more user logins to replace the set of assignees on this Issue. // Pass one or more user logins to replace the set of assignees on this Issue.
// Send an empty array ([]) to clear all assignees from the Issue. // Send an empty array ([]) to clear all assignees from the Issue.
if ctx.Repo.CanWrite(models.UnitTypeIssues) && (form.Assignees != nil || form.Assignee != nil) { if canWrite && (form.Assignees != nil || form.Assignee != nil) {
oneAssignee := "" oneAssignee := ""
if form.Assignee != nil { if form.Assignee != nil {
oneAssignee = *form.Assignee oneAssignee = *form.Assignee
@@ -514,7 +549,7 @@ func EditIssue(ctx *context.APIContext, form api.EditIssueOption) {
} }
} }
if ctx.Repo.CanWrite(models.UnitTypeIssues) && form.Milestone != nil && if canWrite && form.Milestone != nil &&
issue.MilestoneID != *form.Milestone { issue.MilestoneID != *form.Milestone {
oldMilestoneID := issue.MilestoneID oldMilestoneID := issue.MilestoneID
issue.MilestoneID = *form.Milestone issue.MilestoneID = *form.Milestone
@@ -600,7 +635,7 @@ func UpdateIssueDeadline(ctx *context.APIContext, form api.EditDeadlineOption) {
return return
} }
if !ctx.Repo.CanWrite(models.UnitTypeIssues) { if !ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull) {
ctx.Error(http.StatusForbidden, "", "Not repo writer") ctx.Error(http.StatusForbidden, "", "Not repo writer")
return return
} }

View File

@@ -190,7 +190,7 @@ func CreateIssueComment(ctx *context.APIContext, form api.CreateIssueCommentOpti
return return
} }
if issue.IsLocked && !ctx.Repo.CanWrite(models.UnitTypeIssues) && !ctx.User.IsAdmin { if issue.IsLocked && !ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull) && !ctx.User.IsAdmin {
ctx.Error(http.StatusForbidden, "CreateIssueComment", errors.New(ctx.Tr("repo.issues.comment_on_locked"))) ctx.Error(http.StatusForbidden, "CreateIssueComment", errors.New(ctx.Tr("repo.issues.comment_on_locked")))
return return
} }

View File

@@ -179,7 +179,7 @@ func changeIssueCommentReaction(ctx *context.APIContext, form api.EditReactionOp
ctx.Error(http.StatusInternalServerError, "comment.LoadIssue() failed", err) ctx.Error(http.StatusInternalServerError, "comment.LoadIssue() failed", err)
} }
if comment.Issue.IsLocked && !ctx.Repo.CanWrite(models.UnitTypeIssues) { if comment.Issue.IsLocked && !ctx.Repo.CanWriteIssuesOrPulls(comment.Issue.IsPull) {
ctx.Error(http.StatusForbidden, "ChangeIssueCommentReaction", errors.New("no permission to change reaction")) ctx.Error(http.StatusForbidden, "ChangeIssueCommentReaction", errors.New("no permission to change reaction"))
return return
} }
@@ -380,7 +380,7 @@ func changeIssueReaction(ctx *context.APIContext, form api.EditReactionOption, i
return return
} }
if issue.IsLocked && !ctx.Repo.CanWrite(models.UnitTypeIssues) { if issue.IsLocked && !ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull) {
ctx.Error(http.StatusForbidden, "ChangeIssueCommentReaction", errors.New("no permission to change reaction")) ctx.Error(http.StatusForbidden, "ChangeIssueCommentReaction", errors.New("no permission to change reaction"))
return return
} }

View File

@@ -170,7 +170,7 @@ func prepareIssueStopwatch(ctx *context.APIContext, shouldExist bool) (*models.I
return nil, err return nil, err
} }
if !ctx.Repo.CanWrite(models.UnitTypeIssues) { if !ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull) {
ctx.Status(http.StatusForbidden) ctx.Status(http.StatusForbidden)
return nil, err return nil, err
} }

View File

@@ -53,7 +53,7 @@ func NewCommitStatus(ctx *context.APIContext, form api.CreateStatusOption) {
return return
} }
status := &models.CommitStatus{ status := &models.CommitStatus{
State: models.CommitStatusState(form.State), State: api.CommitStatusState(form.State),
TargetURL: form.TargetURL, TargetURL: form.TargetURL,
Description: form.Description, Description: form.Description,
Context: form.Context, Context: form.Context,
@@ -220,13 +220,13 @@ func getCommitStatuses(ctx *context.APIContext, sha string) {
} }
type combinedCommitStatus struct { type combinedCommitStatus struct {
State models.CommitStatusState `json:"state"` State api.CommitStatusState `json:"state"`
SHA string `json:"sha"` SHA string `json:"sha"`
TotalCount int `json:"total_count"` TotalCount int `json:"total_count"`
Statuses []*api.Status `json:"statuses"` Statuses []*api.Status `json:"statuses"`
Repo *api.Repository `json:"repository"` Repo *api.Repository `json:"repository"`
CommitURL string `json:"commit_url"` CommitURL string `json:"commit_url"`
URL string `json:"url"` URL string `json:"url"`
} }
// GetCombinedCommitStatusByRef returns the combined status for any given commit hash // GetCombinedCommitStatusByRef returns the combined status for any given commit hash
@@ -293,7 +293,7 @@ func GetCombinedCommitStatusByRef(ctx *context.APIContext) {
retStatus.Statuses = make([]*api.Status, 0, len(statuses)) retStatus.Statuses = make([]*api.Status, 0, len(statuses))
for _, status := range statuses { for _, status := range statuses {
retStatus.Statuses = append(retStatus.Statuses, status.APIFormat()) retStatus.Statuses = append(retStatus.Statuses, status.APIFormat())
if status.State.IsWorseThan(retStatus.State) { if status.State.NoBetterThan(retStatus.State) {
retStatus.State = status.State retStatus.State = status.State
} }
} }

View File

@@ -157,12 +157,12 @@ func ParseCompareInfo(ctx *context.Context) (*models.User, *models.Repository, *
ctx.ServerError("OpenRepository", err) ctx.ServerError("OpenRepository", err)
return nil, nil, nil, nil, "", "" return nil, nil, nil, nil, "", ""
} }
defer headGitRepo.Close()
} }
// user should have permission to read baseRepo's codes and pulls, NOT headRepo's // user should have permission to read baseRepo's codes and pulls, NOT headRepo's
permBase, err := models.GetUserRepoPermission(baseRepo, ctx.User) permBase, err := models.GetUserRepoPermission(baseRepo, ctx.User)
if err != nil { if err != nil {
headGitRepo.Close()
ctx.ServerError("GetUserRepoPermission", err) ctx.ServerError("GetUserRepoPermission", err)
return nil, nil, nil, nil, "", "" return nil, nil, nil, nil, "", ""
} }
@@ -173,42 +173,40 @@ func ParseCompareInfo(ctx *context.Context) (*models.User, *models.Repository, *
baseRepo, baseRepo,
permBase) permBase)
} }
headGitRepo.Close()
ctx.NotFound("ParseCompareInfo", nil) ctx.NotFound("ParseCompareInfo", nil)
return nil, nil, nil, nil, "", "" return nil, nil, nil, nil, "", ""
} }
// user should have permission to read headrepo's codes if !isSameRepo {
permHead, err := models.GetUserRepoPermission(headRepo, ctx.User) // user should have permission to read headrepo's codes
if err != nil { permHead, err := models.GetUserRepoPermission(headRepo, ctx.User)
headGitRepo.Close() if err != nil {
ctx.ServerError("GetUserRepoPermission", err) ctx.ServerError("GetUserRepoPermission", err)
return nil, nil, nil, nil, "", "" return nil, nil, nil, nil, "", ""
} }
if !permHead.CanRead(models.UnitTypeCode) { if !permHead.CanRead(models.UnitTypeCode) {
if log.IsTrace() { if log.IsTrace() {
log.Trace("Permission Denied: User: %-v cannot read code in Repo: %-v\nUser in headRepo has Permissions: %-+v", log.Trace("Permission Denied: User: %-v cannot read code in Repo: %-v\nUser in headRepo has Permissions: %-+v",
ctx.User, ctx.User,
headRepo, headRepo,
permHead) permHead)
}
ctx.NotFound("ParseCompareInfo", nil)
return nil, nil, nil, nil, "", ""
} }
headGitRepo.Close()
ctx.NotFound("ParseCompareInfo", nil)
return nil, nil, nil, nil, "", ""
} }
// Check if head branch is valid. // Check if head branch is valid.
headIsCommit := ctx.Repo.GitRepo.IsCommitExist(headBranch) headIsCommit := headGitRepo.IsCommitExist(headBranch)
headIsBranch := headGitRepo.IsBranchExist(headBranch) headIsBranch := headGitRepo.IsBranchExist(headBranch)
headIsTag := headGitRepo.IsTagExist(headBranch) headIsTag := headGitRepo.IsTagExist(headBranch)
if !headIsCommit && !headIsBranch && !headIsTag { if !headIsCommit && !headIsBranch && !headIsTag {
// Check if headBranch is short sha commit hash // Check if headBranch is short sha commit hash
if headCommit, _ := ctx.Repo.GitRepo.GetCommit(headBranch); headCommit != nil { if headCommit, _ := headGitRepo.GetCommit(headBranch); headCommit != nil {
headBranch = headCommit.ID.String() headBranch = headCommit.ID.String()
ctx.Data["HeadBranch"] = headBranch ctx.Data["HeadBranch"] = headBranch
headIsCommit = true headIsCommit = true
} else { } else {
headGitRepo.Close()
ctx.NotFound("IsRefExist", nil) ctx.NotFound("IsRefExist", nil)
return nil, nil, nil, nil, "", "" return nil, nil, nil, nil, "", ""
} }
@@ -229,14 +227,12 @@ func ParseCompareInfo(ctx *context.Context) (*models.User, *models.Repository, *
baseRepo, baseRepo,
permBase) permBase)
} }
headGitRepo.Close()
ctx.NotFound("ParseCompareInfo", nil) ctx.NotFound("ParseCompareInfo", nil)
return nil, nil, nil, nil, "", "" return nil, nil, nil, nil, "", ""
} }
compareInfo, err := headGitRepo.GetCompareInfo(models.RepoPath(baseRepo.Owner.Name, baseRepo.Name), baseBranch, headBranch) compareInfo, err := headGitRepo.GetCompareInfo(baseRepo.RepoPath(), baseBranch, headBranch)
if err != nil { if err != nil {
headGitRepo.Close()
ctx.ServerError("GetCompareInfo", err) ctx.ServerError("GetCompareInfo", err)
return nil, nil, nil, nil, "", "" return nil, nil, nil, nil, "", ""
} }
@@ -385,7 +381,8 @@ func CompareDiff(ctx *context.Context) {
} }
defer headGitRepo.Close() defer headGitRepo.Close()
if err := parseBaseRepoInfo(ctx, headRepo); err != nil { var err error
if err = parseBaseRepoInfo(ctx, headRepo); err != nil {
ctx.ServerError("parseBaseRepoInfo", err) ctx.ServerError("parseBaseRepoInfo", err)
return return
} }
@@ -418,7 +415,7 @@ func CompareDiff(ctx *context.Context) {
if !nothingToCompare { if !nothingToCompare {
// Setup information for new form. // Setup information for new form.
RetrieveRepoMetas(ctx, ctx.Repo.Repository) RetrieveRepoMetas(ctx, ctx.Repo.Repository, true)
if ctx.Written() { if ctx.Written() {
return return
} }
@@ -427,6 +424,11 @@ func CompareDiff(ctx *context.Context) {
beforeCommitID := ctx.Data["BeforeCommitID"].(string) beforeCommitID := ctx.Data["BeforeCommitID"].(string)
afterCommitID := ctx.Data["AfterCommitID"].(string) afterCommitID := ctx.Data["AfterCommitID"].(string)
if ctx.Data["Assignees"], err = ctx.Repo.Repository.GetAssignees(); err != nil {
ctx.ServerError("GetAssignees", err)
return
}
ctx.Data["Title"] = "Comparing " + base.ShortSha(beforeCommitID) + "..." + base.ShortSha(afterCommitID) ctx.Data["Title"] = "Comparing " + base.ShortSha(beforeCommitID) + "..." + base.ShortSha(afterCommitID)
ctx.Data["IsRepoToolbarCommits"] = true ctx.Data["IsRepoToolbarCommits"] = true

View File

@@ -12,6 +12,7 @@ import (
"strings" "strings"
"code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/charset"
"code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/lfs" "code.gitea.io/gitea/modules/lfs"
@@ -33,7 +34,12 @@ func ServeData(ctx *context.Context, name string, reader io.Reader) error {
name = strings.Replace(name, ",", " ", -1) name = strings.Replace(name, ",", " ", -1)
if base.IsTextFile(buf) || ctx.QueryBool("render") { if base.IsTextFile(buf) || ctx.QueryBool("render") {
ctx.Resp.Header().Set("Content-Type", "text/plain; charset=utf-8") cs, err := charset.DetectEncoding(buf)
if err != nil {
log.Error("Detect raw file %s charset failed: %v, using by default utf-8", name, err)
cs = "utf-8"
}
ctx.Resp.Header().Set("Content-Type", "text/plain; charset="+strings.ToLower(cs))
} else if base.IsImageFile(buf) || base.IsPDFFile(buf) { } else if base.IsImageFile(buf) || base.IsPDFFile(buf) {
ctx.Resp.Header().Set("Content-Disposition", fmt.Sprintf(`inline; filename="%s"`, name)) ctx.Resp.Header().Set("Content-Disposition", fmt.Sprintf(`inline; filename="%s"`, name))
} else { } else {

View File

@@ -10,6 +10,7 @@ import (
"compress/gzip" "compress/gzip"
gocontext "context" gocontext "context"
"fmt" "fmt"
"io/ioutil"
"net/http" "net/http"
"os" "os"
"os/exec" "os/exec"
@@ -17,6 +18,7 @@ import (
"regexp" "regexp"
"strconv" "strconv"
"strings" "strings"
"sync"
"time" "time"
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
@@ -65,11 +67,12 @@ func HTTP(ctx *context.Context) {
return return
} }
var isPull bool var isPull, receivePack bool
service := ctx.Query("service") service := ctx.Query("service")
if service == "git-receive-pack" || if service == "git-receive-pack" ||
strings.HasSuffix(ctx.Req.URL.Path, "git-receive-pack") { strings.HasSuffix(ctx.Req.URL.Path, "git-receive-pack") {
isPull = false isPull = false
receivePack = true
} else if service == "git-upload-pack" || } else if service == "git-upload-pack" ||
strings.HasSuffix(ctx.Req.URL.Path, "git-upload-pack") { strings.HasSuffix(ctx.Req.URL.Path, "git-upload-pack") {
isPull = true isPull = true
@@ -282,6 +285,11 @@ func HTTP(ctx *context.Context) {
} }
if !repoExist { if !repoExist {
if !receivePack {
ctx.HandleText(http.StatusNotFound, "Repository not found")
return
}
if owner.IsOrganization() && !setting.Repository.EnablePushCreateOrg { if owner.IsOrganization() && !setting.Repository.EnablePushCreateOrg {
ctx.HandleText(http.StatusForbidden, "Push to create is not enabled for organizations.") ctx.HandleText(http.StatusForbidden, "Push to create is not enabled for organizations.")
return return
@@ -290,6 +298,13 @@ func HTTP(ctx *context.Context) {
ctx.HandleText(http.StatusForbidden, "Push to create is not enabled for users.") ctx.HandleText(http.StatusForbidden, "Push to create is not enabled for users.")
return return
} }
// Return dummy payload if GET receive-pack
if ctx.Req.Method == http.MethodGet {
dummyInfoRefs(ctx)
return
}
repo, err = repo_service.PushCreateRepo(authUser, owner, reponame) repo, err = repo_service.PushCreateRepo(authUser, owner, reponame)
if err != nil { if err != nil {
log.Error("pushCreateRepo: %v", err) log.Error("pushCreateRepo: %v", err)
@@ -352,6 +367,48 @@ func HTTP(ctx *context.Context) {
ctx.NotFound("Smart Git HTTP", nil) ctx.NotFound("Smart Git HTTP", nil)
} }
var (
infoRefsCache []byte
infoRefsOnce sync.Once
)
func dummyInfoRefs(ctx *context.Context) {
infoRefsOnce.Do(func() {
tmpDir, err := ioutil.TempDir(os.TempDir(), "gitea-info-refs-cache")
if err != nil {
log.Error("Failed to create temp dir for git-receive-pack cache: %v", err)
return
}
defer func() {
if err := os.RemoveAll(tmpDir); err != nil {
log.Error("RemoveAll: %v", err)
}
}()
if err := git.InitRepository(tmpDir, true); err != nil {
log.Error("Failed to init bare repo for git-receive-pack cache: %v", err)
return
}
refs, err := git.NewCommand("receive-pack", "--stateless-rpc", "--advertise-refs", ".").RunInDirBytes(tmpDir)
if err != nil {
log.Error(fmt.Sprintf("%v - %s", err, string(refs)))
}
log.Debug("populating infoRefsCache: \n%s", string(refs))
infoRefsCache = refs
})
ctx.Header().Set("Expires", "Fri, 01 Jan 1980 00:00:00 GMT")
ctx.Header().Set("Pragma", "no-cache")
ctx.Header().Set("Cache-Control", "no-cache, max-age=0, must-revalidate")
ctx.Header().Set("Content-Type", "application/x-git-receive-pack-advertisement")
_, _ = ctx.Write(packetWrite("# service=git-receive-pack\n"))
_, _ = ctx.Write([]byte("0000"))
_, _ = ctx.Write(infoRefsCache)
}
type serviceConfig struct { type serviceConfig struct {
UploadPack bool UploadPack bool
ReceivePack bool ReceivePack bool

View File

@@ -63,13 +63,12 @@ var (
// If locked and user has permissions to write to the repository, // If locked and user has permissions to write to the repository,
// then the comment is allowed, else it is blocked // then the comment is allowed, else it is blocked
func MustAllowUserComment(ctx *context.Context) { func MustAllowUserComment(ctx *context.Context) {
issue := GetActionIssue(ctx) issue := GetActionIssue(ctx)
if ctx.Written() { if ctx.Written() {
return return
} }
if issue.IsLocked && !ctx.Repo.CanWrite(models.UnitTypeIssues) && !ctx.User.IsAdmin { if issue.IsLocked && !ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull) && !ctx.User.IsAdmin {
ctx.Flash.Error(ctx.Tr("repo.issues.comment_on_locked")) ctx.Flash.Error(ctx.Tr("repo.issues.comment_on_locked"))
ctx.Redirect(issue.HTMLURL()) ctx.Redirect(issue.HTMLURL())
return return
@@ -348,8 +347,8 @@ func RetrieveRepoMilestonesAndAssignees(ctx *context.Context, repo *models.Repos
} }
// RetrieveRepoMetas find all the meta information of a repository // RetrieveRepoMetas find all the meta information of a repository
func RetrieveRepoMetas(ctx *context.Context, repo *models.Repository) []*models.Label { func RetrieveRepoMetas(ctx *context.Context, repo *models.Repository, isPull bool) []*models.Label {
if !ctx.Repo.CanWrite(models.UnitTypeIssues) { if !ctx.Repo.CanWriteIssuesOrPulls(isPull) {
return nil return nil
} }
@@ -373,7 +372,7 @@ func RetrieveRepoMetas(ctx *context.Context, repo *models.Repository) []*models.
ctx.Data["Branches"] = brs ctx.Data["Branches"] = brs
// Contains true if the user can create issue dependencies // Contains true if the user can create issue dependencies
ctx.Data["CanCreateIssueDependencies"] = ctx.Repo.CanCreateIssueDependencies(ctx.User) ctx.Data["CanCreateIssueDependencies"] = ctx.Repo.CanCreateIssueDependencies(ctx.User, isPull)
return labels return labels
} }
@@ -443,7 +442,7 @@ func NewIssue(ctx *context.Context) {
setTemplateIfExists(ctx, issueTemplateKey, IssueTemplateCandidates) setTemplateIfExists(ctx, issueTemplateKey, IssueTemplateCandidates)
renderAttachmentSettings(ctx) renderAttachmentSettings(ctx)
RetrieveRepoMetas(ctx, ctx.Repo.Repository) RetrieveRepoMetas(ctx, ctx.Repo.Repository, false)
if ctx.Written() { if ctx.Written() {
return return
} }
@@ -458,7 +457,7 @@ func ValidateRepoMetas(ctx *context.Context, form auth.CreateIssueForm, isPull b
err error err error
) )
labels := RetrieveRepoMetas(ctx, ctx.Repo.Repository) labels := RetrieveRepoMetas(ctx, ctx.Repo.Repository, isPull)
if ctx.Written() { if ctx.Written() {
return nil, nil, 0 return nil, nil, 0
} }
@@ -670,6 +669,14 @@ func ViewIssue(ctx *context.Context) {
ctx.Data["PageIsIssueList"] = true ctx.Data["PageIsIssueList"] = true
} }
if issue.IsPull && !ctx.Repo.CanRead(models.UnitTypeIssues) {
ctx.Data["IssueType"] = "pulls"
} else if !issue.IsPull && !ctx.Repo.CanRead(models.UnitTypePullRequests) {
ctx.Data["IssueType"] = "issues"
} else {
ctx.Data["IssueType"] = "all"
}
ctx.Data["RequireHighlightJS"] = true ctx.Data["RequireHighlightJS"] = true
ctx.Data["RequireDropzone"] = true ctx.Data["RequireDropzone"] = true
ctx.Data["RequireTribute"] = true ctx.Data["RequireTribute"] = true
@@ -807,7 +814,7 @@ func ViewIssue(ctx *context.Context) {
} }
// Check if the user can use the dependencies // Check if the user can use the dependencies
ctx.Data["CanCreateIssueDependencies"] = ctx.Repo.CanCreateIssueDependencies(ctx.User) ctx.Data["CanCreateIssueDependencies"] = ctx.Repo.CanCreateIssueDependencies(ctx.User, issue.IsPull)
// check if dependencies can be created across repositories // check if dependencies can be created across repositories
ctx.Data["AllowCrossRepositoryDependencies"] = setting.Service.AllowCrossRepositoryDependencies ctx.Data["AllowCrossRepositoryDependencies"] = setting.Service.AllowCrossRepositoryDependencies
@@ -998,7 +1005,6 @@ func ViewIssue(ctx *context.Context) {
ctx.Data["IsIssuePoster"] = ctx.IsSigned && issue.IsPoster(ctx.User.ID) ctx.Data["IsIssuePoster"] = ctx.IsSigned && issue.IsPoster(ctx.User.ID)
ctx.Data["IsIssueWriter"] = ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull) ctx.Data["IsIssueWriter"] = ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull)
ctx.Data["IsRepoAdmin"] = ctx.IsSigned && (ctx.Repo.IsAdmin() || ctx.User.IsAdmin) ctx.Data["IsRepoAdmin"] = ctx.IsSigned && (ctx.Repo.IsAdmin() || ctx.User.IsAdmin)
ctx.Data["IsRepoIssuesWriter"] = ctx.IsSigned && (ctx.Repo.CanWrite(models.UnitTypeIssues) || ctx.User.IsAdmin)
ctx.Data["LockReasons"] = setting.Repository.Issue.LockReasons ctx.Data["LockReasons"] = setting.Repository.Issue.LockReasons
ctx.HTML(200, tplIssueView) ctx.HTML(200, tplIssueView)
} }
@@ -1259,9 +1265,10 @@ func NewComment(ctx *context.Context, form auth.CreateCommentForm) {
} }
ctx.Error(403) ctx.Error(403)
return
} }
if issue.IsLocked && !ctx.Repo.CanWrite(models.UnitTypeIssues) && !ctx.User.IsAdmin { if issue.IsLocked && !ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull) && !ctx.User.IsAdmin {
ctx.Flash.Error(ctx.Tr("repo.issues.comment_on_locked")) ctx.Flash.Error(ctx.Tr("repo.issues.comment_on_locked"))
ctx.Redirect(issue.HTMLURL(), http.StatusSeeOther) ctx.Redirect(issue.HTMLURL(), http.StatusSeeOther)
return return

View File

@@ -14,14 +14,6 @@ import (
// AddDependency adds new dependencies // AddDependency adds new dependencies
func AddDependency(ctx *context.Context) { func AddDependency(ctx *context.Context) {
// Check if the Repo is allowed to have dependencies
if !ctx.Repo.CanCreateIssueDependencies(ctx.User) {
ctx.Error(http.StatusForbidden, "CanCreateIssueDependencies")
return
}
depID := ctx.QueryInt64("newDependency")
issueIndex := ctx.ParamsInt64("index") issueIndex := ctx.ParamsInt64("index")
issue, err := models.GetIssueByIndex(ctx.Repo.Repository.ID, issueIndex) issue, err := models.GetIssueByIndex(ctx.Repo.Repository.ID, issueIndex)
if err != nil { if err != nil {
@@ -29,6 +21,14 @@ func AddDependency(ctx *context.Context) {
return return
} }
// Check if the Repo is allowed to have dependencies
if !ctx.Repo.CanCreateIssueDependencies(ctx.User, issue.IsPull) {
ctx.Error(http.StatusForbidden, "CanCreateIssueDependencies")
return
}
depID := ctx.QueryInt64("newDependency")
if err = issue.LoadRepo(); err != nil { if err = issue.LoadRepo(); err != nil {
ctx.ServerError("LoadRepo", err) ctx.ServerError("LoadRepo", err)
return return
@@ -73,14 +73,6 @@ func AddDependency(ctx *context.Context) {
// RemoveDependency removes the dependency // RemoveDependency removes the dependency
func RemoveDependency(ctx *context.Context) { func RemoveDependency(ctx *context.Context) {
// Check if the Repo is allowed to have dependencies
if !ctx.Repo.CanCreateIssueDependencies(ctx.User) {
ctx.Error(http.StatusForbidden, "CanCreateIssueDependencies")
return
}
depID := ctx.QueryInt64("removeDependencyID")
issueIndex := ctx.ParamsInt64("index") issueIndex := ctx.ParamsInt64("index")
issue, err := models.GetIssueByIndex(ctx.Repo.Repository.ID, issueIndex) issue, err := models.GetIssueByIndex(ctx.Repo.Repository.ID, issueIndex)
if err != nil { if err != nil {
@@ -88,14 +80,19 @@ func RemoveDependency(ctx *context.Context) {
return return
} }
// Check if the Repo is allowed to have dependencies
if !ctx.Repo.CanCreateIssueDependencies(ctx.User, issue.IsPull) {
ctx.Error(http.StatusForbidden, "CanCreateIssueDependencies")
return
}
depID := ctx.QueryInt64("removeDependencyID")
if err = issue.LoadRepo(); err != nil { if err = issue.LoadRepo(); err != nil {
ctx.ServerError("LoadRepo", err) ctx.ServerError("LoadRepo", err)
return return
} }
// Redirect
ctx.Redirect(issue.HTMLURL(), http.StatusSeeOther)
// Dependency Type // Dependency Type
depTypeStr := ctx.Req.PostForm.Get("dependencyType") depTypeStr := ctx.Req.PostForm.Get("dependencyType")
@@ -126,4 +123,7 @@ func RemoveDependency(ctx *context.Context) {
ctx.ServerError("RemoveIssueDependency", err) ctx.ServerError("RemoveIssueDependency", err)
return return
} }
// Redirect
ctx.Redirect(issue.HTMLURL(), http.StatusSeeOther)
} }

View File

@@ -403,7 +403,9 @@ func PrepareViewPullInfo(ctx *context.Context, issue *models.Issue) *git.Compare
} }
return false return false
} }
ctx.Data["IsRequiredStatusCheckSuccess"] = pull_service.IsCommitStatusContextSuccess(commitStatuses, pull.ProtectedBranch.StatusCheckContexts) state := pull_service.MergeRequiredContextsCommitStatus(commitStatuses, pull.ProtectedBranch.StatusCheckContexts)
ctx.Data["RequiredStatusCheckState"] = state
ctx.Data["IsRequiredStatusCheckSuccess"] = state.IsSuccess()
} }
ctx.Data["HeadBranchMovedOn"] = headBranchSha != sha ctx.Data["HeadBranchMovedOn"] = headBranchSha != sha

View File

@@ -81,7 +81,7 @@ func SubmitReview(ctx *context.Context, form auth.SubmitReviewForm) {
// can not approve/reject your own PR // can not approve/reject your own PR
case models.ReviewTypeApprove, models.ReviewTypeReject: case models.ReviewTypeApprove, models.ReviewTypeReject:
if issue.Poster.ID == ctx.User.ID { if issue.IsPoster(ctx.User.ID) {
var translated string var translated string
if reviewType == models.ReviewTypeApprove { if reviewType == models.ReviewTypeApprove {
translated = ctx.Tr("repo.issues.review.self.approval") translated = ctx.Tr("repo.issues.review.self.approval")

View File

@@ -581,7 +581,7 @@ func AddTeamPost(ctx *context.Context) {
} }
name := utils.RemoveUsernameParameterSuffix(strings.ToLower(ctx.Query("team"))) name := utils.RemoveUsernameParameterSuffix(strings.ToLower(ctx.Query("team")))
if len(name) == 0 || ctx.Repo.Owner.LowerName == name { if len(name) == 0 {
ctx.Redirect(ctx.Repo.RepoLink + "/settings/collaboration") ctx.Redirect(ctx.Repo.RepoLink + "/settings/collaboration")
return return
} }

View File

@@ -455,7 +455,7 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Post("/discord/:id", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksEditPost) m.Post("/discord/:id", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksEditPost)
m.Post("/dingtalk/:id", bindIgnErr(auth.NewDingtalkHookForm{}), repo.DingtalkHooksEditPost) m.Post("/dingtalk/:id", bindIgnErr(auth.NewDingtalkHookForm{}), repo.DingtalkHooksEditPost)
m.Post("/telegram/:id", bindIgnErr(auth.NewTelegramHookForm{}), repo.TelegramHooksEditPost) m.Post("/telegram/:id", bindIgnErr(auth.NewTelegramHookForm{}), repo.TelegramHooksEditPost)
m.Post("/msteams/:id", bindIgnErr(auth.NewMSTeamsHookForm{}), repo.MSTeamsHooksNewPost) m.Post("/msteams/:id", bindIgnErr(auth.NewMSTeamsHookForm{}), repo.MSTeamsHooksEditPost)
}) })
m.Group("/auths", func() { m.Group("/auths", func() {
@@ -503,19 +503,13 @@ func RegisterRoutes(m *macaron.Macaron) {
reqRepoReleaseWriter := context.RequireRepoWriter(models.UnitTypeReleases) reqRepoReleaseWriter := context.RequireRepoWriter(models.UnitTypeReleases)
reqRepoReleaseReader := context.RequireRepoReader(models.UnitTypeReleases) reqRepoReleaseReader := context.RequireRepoReader(models.UnitTypeReleases)
reqRepoWikiWriter := context.RequireRepoWriter(models.UnitTypeWiki) reqRepoWikiWriter := context.RequireRepoWriter(models.UnitTypeWiki)
reqRepoIssueWriter := context.RequireRepoWriter(models.UnitTypeIssues)
reqRepoIssueReader := context.RequireRepoReader(models.UnitTypeIssues) reqRepoIssueReader := context.RequireRepoReader(models.UnitTypeIssues)
reqRepoPullsWriter := context.RequireRepoWriter(models.UnitTypePullRequests) reqRepoPullsWriter := context.RequireRepoWriter(models.UnitTypePullRequests)
reqRepoPullsReader := context.RequireRepoReader(models.UnitTypePullRequests) reqRepoPullsReader := context.RequireRepoReader(models.UnitTypePullRequests)
reqRepoIssuesOrPullsWriter := context.RequireRepoWriterOr(models.UnitTypeIssues, models.UnitTypePullRequests) reqRepoIssuesOrPullsWriter := context.RequireRepoWriterOr(models.UnitTypeIssues, models.UnitTypePullRequests)
reqRepoIssuesOrPullsReader := context.RequireRepoReaderOr(models.UnitTypeIssues, models.UnitTypePullRequests) reqRepoIssuesOrPullsReader := context.RequireRepoReaderOr(models.UnitTypeIssues, models.UnitTypePullRequests)
reqRepoIssueWriter := func(ctx *context.Context) {
if !ctx.Repo.CanWrite(models.UnitTypeIssues) {
ctx.Error(403)
return
}
}
// ***** START: Organization ***** // ***** START: Organization *****
m.Group("/org", func() { m.Group("/org", func() {
m.Group("", func() { m.Group("", func() {
@@ -563,6 +557,7 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Post("/discord/new", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksNewPost) m.Post("/discord/new", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksNewPost)
m.Post("/dingtalk/new", bindIgnErr(auth.NewDingtalkHookForm{}), repo.DingtalkHooksNewPost) m.Post("/dingtalk/new", bindIgnErr(auth.NewDingtalkHookForm{}), repo.DingtalkHooksNewPost)
m.Post("/telegram/new", bindIgnErr(auth.NewTelegramHookForm{}), repo.TelegramHooksNewPost) m.Post("/telegram/new", bindIgnErr(auth.NewTelegramHookForm{}), repo.TelegramHooksNewPost)
m.Post("/msteams/new", bindIgnErr(auth.NewMSTeamsHookForm{}), repo.MSTeamsHooksNewPost)
m.Get("/:id", repo.WebHooksEdit) m.Get("/:id", repo.WebHooksEdit)
m.Post("/gitea/:id", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksEditPost) m.Post("/gitea/:id", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksEditPost)
m.Post("/gogs/:id", bindIgnErr(auth.NewGogshookForm{}), repo.GogsHooksEditPost) m.Post("/gogs/:id", bindIgnErr(auth.NewGogshookForm{}), repo.GogsHooksEditPost)
@@ -570,6 +565,7 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Post("/discord/:id", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksEditPost) m.Post("/discord/:id", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksEditPost)
m.Post("/dingtalk/:id", bindIgnErr(auth.NewDingtalkHookForm{}), repo.DingtalkHooksEditPost) m.Post("/dingtalk/:id", bindIgnErr(auth.NewDingtalkHookForm{}), repo.DingtalkHooksEditPost)
m.Post("/telegram/:id", bindIgnErr(auth.NewTelegramHookForm{}), repo.TelegramHooksEditPost) m.Post("/telegram/:id", bindIgnErr(auth.NewTelegramHookForm{}), repo.TelegramHooksEditPost)
m.Post("/msteams/:id", bindIgnErr(auth.NewMSTeamsHookForm{}), repo.MSTeamsHooksEditPost)
}) })
m.Route("/delete", "GET,POST", org.SettingsDelete) m.Route("/delete", "GET,POST", org.SettingsDelete)

View File

@@ -1284,7 +1284,7 @@ func ForgotPasswdPost(ctx *context.Context) {
ctx.HTML(200, tplForgotPassword) ctx.HTML(200, tplForgotPassword)
} }
func commonResetPassword(ctx *context.Context) *models.User { func commonResetPassword(ctx *context.Context) (*models.User, *models.TwoFactor) {
code := ctx.Query("code") code := ctx.Query("code")
ctx.Data["Title"] = ctx.Tr("auth.reset_password") ctx.Data["Title"] = ctx.Tr("auth.reset_password")
@@ -1296,14 +1296,25 @@ func commonResetPassword(ctx *context.Context) *models.User {
if len(code) == 0 { if len(code) == 0 {
ctx.Flash.Error(ctx.Tr("auth.invalid_code")) ctx.Flash.Error(ctx.Tr("auth.invalid_code"))
return nil return nil, nil
} }
// Fail early, don't frustrate the user // Fail early, don't frustrate the user
u := models.VerifyUserActiveCode(code) u := models.VerifyUserActiveCode(code)
if u == nil { if u == nil {
ctx.Flash.Error(ctx.Tr("auth.invalid_code")) ctx.Flash.Error(ctx.Tr("auth.invalid_code"))
return nil return nil, nil
}
twofa, err := models.GetTwoFactorByUID(u.ID)
if err != nil {
if !models.IsErrTwoFactorNotEnrolled(err) {
ctx.Error(http.StatusInternalServerError, "CommonResetPassword", err.Error())
return nil, nil
}
} else {
ctx.Data["has_two_factor"] = true
ctx.Data["scratch_code"] = ctx.QueryBool("scratch_code")
} }
// Show the user that they are affecting the account that they intended to // Show the user that they are affecting the account that they intended to
@@ -1311,10 +1322,10 @@ func commonResetPassword(ctx *context.Context) *models.User {
if nil != ctx.User && u.ID != ctx.User.ID { if nil != ctx.User && u.ID != ctx.User.ID {
ctx.Flash.Error(ctx.Tr("auth.reset_password_wrong_user", ctx.User.Email, u.Email)) ctx.Flash.Error(ctx.Tr("auth.reset_password_wrong_user", ctx.User.Email, u.Email))
return nil return nil, nil
} }
return u return u, twofa
} }
// ResetPasswd render the account recovery page // ResetPasswd render the account recovery page
@@ -1322,13 +1333,19 @@ func ResetPasswd(ctx *context.Context) {
ctx.Data["IsResetForm"] = true ctx.Data["IsResetForm"] = true
commonResetPassword(ctx) commonResetPassword(ctx)
if ctx.Written() {
return
}
ctx.HTML(200, tplResetPassword) ctx.HTML(200, tplResetPassword)
} }
// ResetPasswdPost response from account recovery request // ResetPasswdPost response from account recovery request
func ResetPasswdPost(ctx *context.Context) { func ResetPasswdPost(ctx *context.Context) {
u := commonResetPassword(ctx) u, twofa := commonResetPassword(ctx)
if ctx.Written() {
return
}
if u == nil { if u == nil {
// Flash error has been set // Flash error has been set
@@ -1350,6 +1367,39 @@ func ResetPasswdPost(ctx *context.Context) {
return return
} }
// Handle two-factor
regenerateScratchToken := false
if twofa != nil {
if ctx.QueryBool("scratch_code") {
if !twofa.VerifyScratchToken(ctx.Query("token")) {
ctx.Data["IsResetForm"] = true
ctx.Data["Err_Token"] = true
ctx.RenderWithErr(ctx.Tr("auth.twofa_scratch_token_incorrect"), tplResetPassword, nil)
return
}
regenerateScratchToken = true
} else {
passcode := ctx.Query("passcode")
ok, err := twofa.ValidateTOTP(passcode)
if err != nil {
ctx.Error(http.StatusInternalServerError, "ValidateTOTP", err.Error())
return
}
if !ok || twofa.LastUsedPasscode == passcode {
ctx.Data["IsResetForm"] = true
ctx.Data["Err_Passcode"] = true
ctx.RenderWithErr(ctx.Tr("auth.twofa_passcode_incorrect"), tplResetPassword, nil)
return
}
twofa.LastUsedPasscode = passcode
if err = models.UpdateTwoFactor(twofa); err != nil {
ctx.ServerError("ResetPasswdPost: UpdateTwoFactor", err)
return
}
}
}
var err error var err error
if u.Rands, err = models.GetUserSalt(); err != nil { if u.Rands, err = models.GetUserSalt(); err != nil {
ctx.ServerError("UpdateUser", err) ctx.ServerError("UpdateUser", err)
@@ -1359,7 +1409,6 @@ func ResetPasswdPost(ctx *context.Context) {
ctx.ServerError("UpdateUser", err) ctx.ServerError("UpdateUser", err)
return return
} }
u.HashPassword(passwd) u.HashPassword(passwd)
u.MustChangePassword = false u.MustChangePassword = false
if err := models.UpdateUserCols(u, "must_change_password", "passwd", "rands", "salt"); err != nil { if err := models.UpdateUserCols(u, "must_change_password", "passwd", "rands", "salt"); err != nil {
@@ -1368,9 +1417,27 @@ func ResetPasswdPost(ctx *context.Context) {
} }
log.Trace("User password reset: %s", u.Name) log.Trace("User password reset: %s", u.Name)
ctx.Data["IsResetFailed"] = true ctx.Data["IsResetFailed"] = true
remember := len(ctx.Query("remember")) != 0 remember := len(ctx.Query("remember")) != 0
if regenerateScratchToken {
// Invalidate the scratch token.
_, err = twofa.GenerateScratchToken()
if err != nil {
ctx.ServerError("UserSignIn", err)
return
}
if err = models.UpdateTwoFactor(twofa); err != nil {
ctx.ServerError("UserSignIn", err)
return
}
handleSignInFull(ctx, u, remember, false)
ctx.Flash.Info(ctx.Tr("auth.twofa_scratch_used"))
ctx.Redirect(setting.AppSubURL + "/user/settings/security")
return
}
handleSignInFull(ctx, u, remember, true) handleSignInFull(ctx, u, remember, true)
} }

View File

@@ -344,7 +344,7 @@ func (diffFile *DiffFile) GetHighlightClass() string {
// GetTailSection creates a fake DiffLineSection if the last section is not the end of the file // GetTailSection creates a fake DiffLineSection if the last section is not the end of the file
func (diffFile *DiffFile) GetTailSection(gitRepo *git.Repository, leftCommitID, rightCommitID string) *DiffSection { func (diffFile *DiffFile) GetTailSection(gitRepo *git.Repository, leftCommitID, rightCommitID string) *DiffSection {
if diffFile.Type != DiffFileChange || diffFile.IsBin || diffFile.IsLFSFile { if len(diffFile.Sections) == 0 || diffFile.Type != DiffFileChange || diffFile.IsBin || diffFile.IsLFSFile {
return nil return nil
} }
leftCommit, err := gitRepo.GetCommit(leftCommitID) leftCommit, err := gitRepo.GetCommit(leftCommitID)

View File

@@ -194,10 +194,16 @@ func TestPullRequests(ctx context.Context) {
if err != nil { if err != nil {
log.Error("GetPullRequestByID[%s]: %v", prID, err) log.Error("GetPullRequestByID[%s]: %v", prID, err)
continue continue
} else if pr.Status != models.PullRequestStatusChecking {
continue
} else if manuallyMerged(pr) { } else if manuallyMerged(pr) {
continue continue
} else if err = TestPatch(pr); err != nil { } else if err = TestPatch(pr); err != nil {
log.Error("testPatch[%d]: %v", pr.ID, err) log.Error("testPatch[%d]: %v", pr.ID, err)
pr.Status = models.PullRequestStatusError
if err := pr.UpdateCols("status"); err != nil {
log.Error("Unable to update status of pr %d: %v", pr.ID, err)
}
continue continue
} }
checkAndUpdateStatus(pr) checkAndUpdateStatus(pr)

View File

@@ -8,15 +8,47 @@ package pull
import ( import (
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/structs"
"github.com/pkg/errors" "github.com/pkg/errors"
) )
// MergeRequiredContextsCommitStatus returns a commit status state for given required contexts
func MergeRequiredContextsCommitStatus(commitStatuses []*models.CommitStatus, requiredContexts []string) structs.CommitStatusState {
if len(requiredContexts) == 0 {
status := models.CalcCommitStatus(commitStatuses)
if status != nil {
return status.State
}
return structs.CommitStatusSuccess
}
var returnedStatus = structs.CommitStatusPending
for _, ctx := range requiredContexts {
var targetStatus structs.CommitStatusState
for _, commitStatus := range commitStatuses {
if commitStatus.Context == ctx {
targetStatus = commitStatus.State
break
}
}
if targetStatus == "" {
targetStatus = structs.CommitStatusPending
}
if targetStatus.NoBetterThan(returnedStatus) {
returnedStatus = targetStatus
}
}
return returnedStatus
}
// IsCommitStatusContextSuccess returns true if all required status check contexts succeed. // IsCommitStatusContextSuccess returns true if all required status check contexts succeed.
func IsCommitStatusContextSuccess(commitStatuses []*models.CommitStatus, requiredContexts []string) bool { func IsCommitStatusContextSuccess(commitStatuses []*models.CommitStatus, requiredContexts []string) bool {
// If no specific context is required, require that last commit status is a success // If no specific context is required, require that last commit status is a success
if len(requiredContexts) == 0 { if len(requiredContexts) == 0 {
status := models.CalcCommitStatus(commitStatuses) status := models.CalcCommitStatus(commitStatuses)
if status == nil || status.State != models.CommitStatusSuccess { if status == nil || status.State != structs.CommitStatusSuccess {
return false return false
} }
return true return true
@@ -26,7 +58,7 @@ func IsCommitStatusContextSuccess(commitStatuses []*models.CommitStatus, require
var found bool var found bool
for _, commitStatus := range commitStatuses { for _, commitStatus := range commitStatuses {
if commitStatus.Context == ctx { if commitStatus.Context == ctx {
if commitStatus.State != models.CommitStatusSuccess { if commitStatus.State != structs.CommitStatusSuccess {
return false return false
} }
@@ -50,30 +82,39 @@ func IsPullCommitStatusPass(pr *models.PullRequest) (bool, error) {
return true, nil return true, nil
} }
state, err := GetPullRequestCommitStatusState(pr)
if err != nil {
return false, err
}
return state.IsSuccess(), nil
}
// GetPullRequestCommitStatusState returns pull request merged commit status state
func GetPullRequestCommitStatusState(pr *models.PullRequest) (structs.CommitStatusState, error) {
// check if all required status checks are successful // check if all required status checks are successful
headGitRepo, err := git.OpenRepository(pr.HeadRepo.RepoPath()) headGitRepo, err := git.OpenRepository(pr.HeadRepo.RepoPath())
if err != nil { if err != nil {
return false, errors.Wrap(err, "OpenRepository") return "", errors.Wrap(err, "OpenRepository")
} }
defer headGitRepo.Close() defer headGitRepo.Close()
if !headGitRepo.IsBranchExist(pr.HeadBranch) { if !headGitRepo.IsBranchExist(pr.HeadBranch) {
return false, errors.New("Head branch does not exist, can not merge") return "", errors.New("Head branch does not exist, can not merge")
} }
sha, err := headGitRepo.GetBranchCommitID(pr.HeadBranch) sha, err := headGitRepo.GetBranchCommitID(pr.HeadBranch)
if err != nil { if err != nil {
return false, errors.Wrap(err, "GetBranchCommitID") return "", errors.Wrap(err, "GetBranchCommitID")
} }
if err := pr.LoadBaseRepo(); err != nil { if err := pr.LoadBaseRepo(); err != nil {
return false, errors.Wrap(err, "LoadBaseRepo") return "", errors.Wrap(err, "LoadBaseRepo")
} }
commitStatuses, err := models.GetLatestCommitStatus(pr.BaseRepo, sha, 0) commitStatuses, err := models.GetLatestCommitStatus(pr.BaseRepo, sha, 0)
if err != nil { if err != nil {
return false, errors.Wrap(err, "GetLatestCommitStatus") return "", errors.Wrap(err, "GetLatestCommitStatus")
} }
return IsCommitStatusContextSuccess(commitStatuses, pr.ProtectedBranch.StatusCheckContexts), nil return MergeRequiredContextsCommitStatus(commitStatuses, pr.ProtectedBranch.StatusCheckContexts), nil
} }

View File

@@ -374,8 +374,10 @@ func Merge(pr *models.PullRequest, doer *models.User, baseGitRepo *git.Repositor
return err return err
} }
close := (ref.RefAction == references.XRefActionCloses) close := (ref.RefAction == references.XRefActionCloses)
if err = issue_service.ChangeStatus(ref.Issue, doer, close); err != nil { if close != ref.Issue.IsClosed {
return err if err = issue_service.ChangeStatus(ref.Issue, doer, close); err != nil {
return err
}
} }
} }

View File

@@ -112,6 +112,12 @@
</div> </div>
</div> </div>
{{end}} {{end}}
<div class="inline field">
<div class="ui checkbox">
<label for="allow_deactivate_all"><strong>{{.i18n.Tr "admin.auths.allow_deactivate_all"}}</strong></label>
<input id="allow_deactivate_all" name="allow_deactivate_all" type="checkbox" {{if $cfg.AllowDeactivateAll}}checked{{end}}>
</div>
</div>
{{end}} {{end}}
<!-- SMTP --> <!-- SMTP -->

View File

@@ -66,7 +66,7 @@
{{ template "repo/issue/view_content/pull". }} {{ template "repo/issue/view_content/pull". }}
{{end}} {{end}}
{{if .IsSigned}} {{if .IsSigned}}
{{ if and (or .IsRepoAdmin .IsRepoIssuesWriter (or (not .Issue.IsLocked))) (not .Repository.IsArchived) }} {{ if and (or .IsRepoAdmin .IsIssueWriter (or (not .Issue.IsLocked))) (not .Repository.IsArchived) }}
<div class="comment form"> <div class="comment form">
<a class="avatar" href="{{.SignedUser.HomeLink}}"> <a class="avatar" href="{{.SignedUser.HomeLink}}">
<img src="{{.SignedUser.RelAvatarLink}}"> <img src="{{.SignedUser.RelAvatarLink}}">

View File

@@ -277,10 +277,20 @@
<span class="text grey"> <span class="text grey">
{{$.i18n.Tr "repo.issues.dependency.added_dependency" .Poster.HomeLink (.Poster.GetDisplayName|Escape) $createdStr | Safe}} {{$.i18n.Tr "repo.issues.dependency.added_dependency" .Poster.HomeLink (.Poster.GetDisplayName|Escape) $createdStr | Safe}}
</span> </span>
<div class="detail"> {{if .DependentIssue}}
<span class="octicon octicon-plus"></span> <div class="detail">
<span class="text grey"><a href="{{$.RepoLink}}/issues/{{.DependentIssue.Index}}">#{{.DependentIssue.Index}} {{.DependentIssue.Title}}</a></span> <span class="octicon octicon-plus"></span>
</div> <span class="text grey">
<a href="{{.DependentIssue.HTMLURL}}">
{{if eq .DependentIssue.RepoID .Issue.RepoID}}
#{{.DependentIssue.Index}} {{.DependentIssue.Title}}
{{else}}
{{.DependentIssue.Repo.FullName}}#{{.DependentIssue.Index}} - {{.DependentIssue.Title}}
{{end}}
</a>
</span>
</div>
{{end}}
</div> </div>
{{else if eq .Type 20}} {{else if eq .Type 20}}
<div class="event" id="{{.HashTag}}"> <div class="event" id="{{.HashTag}}">
@@ -291,10 +301,20 @@
<span class="text grey"> <span class="text grey">
{{$.i18n.Tr "repo.issues.dependency.removed_dependency" .Poster.HomeLink (.Poster.GetDisplayName|Escape) $createdStr | Safe}} {{$.i18n.Tr "repo.issues.dependency.removed_dependency" .Poster.HomeLink (.Poster.GetDisplayName|Escape) $createdStr | Safe}}
</span> </span>
<div class="detail"> {{if .DependentIssue}}
<span class="text grey octicon octicon-trashcan"></span> <div class="detail">
<span class="text grey"><a href="{{$.RepoLink}}/issues/{{.DependentIssue.Index}}">#{{.DependentIssue.Index}} {{.DependentIssue.Title}}</a></span> <span class="text grey octicon octicon-trashcan"></span>
</div> <span class="text grey">
<a href="{{.DependentIssue.HTMLURL}}">
{{if eq .DependentIssue.RepoID .Issue.RepoID}}
#{{.DependentIssue.Index}} {{.DependentIssue.Title}}
{{else}}
{{.DependentIssue.Repo.FullName}}#{{.DependentIssue.Index}} - {{.DependentIssue.Title}}
{{end}}
</a>
</span>
</div>
{{end}}
</div> </div>
{{else if eq .Type 22}} {{else if eq .Type 22}}
<div class="event" id="{{.HashTag}}"> <div class="event" id="{{.HashTag}}">

View File

@@ -42,7 +42,8 @@
{{else if .IsPullRequestBroken}}red {{else if .IsPullRequestBroken}}red
{{else if .IsBlockedByApprovals}}red {{else if .IsBlockedByApprovals}}red
{{else if .IsBlockedByRejection}}red {{else if .IsBlockedByRejection}}red
{{else if and .EnableStatusCheck (not .IsRequiredStatusCheckSuccess)}}red {{else if and .EnableStatusCheck (or .RequiredStatusCheckState.IsFailure .RequiredStatusCheckState.IsError)}}red
{{else if and .EnableStatusCheck (or .RequiredStatusCheckState.IsPending .RequiredStatusCheckState.IsWarning)}}yellow
{{else if .Issue.PullRequest.IsChecking}}yellow {{else if .Issue.PullRequest.IsChecking}}yellow
{{else if .Issue.PullRequest.CanAutoMerge}}green {{else if .Issue.PullRequest.CanAutoMerge}}green
{{else}}red{{end}}"><span class="mega-octicon octicon-git-merge"></span></a> {{else}}red{{end}}"><span class="mega-octicon octicon-git-merge"></span></a>
@@ -117,7 +118,7 @@
{{$.i18n.Tr "repo.pulls.required_status_check_failed"}} {{$.i18n.Tr "repo.pulls.required_status_check_failed"}}
</div> </div>
{{else if .Issue.PullRequest.CanAutoMerge}} {{else if .Issue.PullRequest.CanAutoMerge}}
{{if and .EnableStatusCheck (not .IsRequiredStatusCheckSuccess)}} {{if and .EnableStatusCheck (or .RequiredStatusCheckState.IsError .RequiredStatusCheckState.IsFailure)}}
<div class="item text red"> <div class="item text red">
<span class="octicon octicon-x"></span> <span class="octicon octicon-x"></span>
{{$.i18n.Tr "repo.pulls.required_status_check_failed"}} {{$.i18n.Tr "repo.pulls.required_status_check_failed"}}

View File

@@ -428,6 +428,7 @@
<input type="hidden" id="repolink" value="{{$.RepoRelPath}}"> <input type="hidden" id="repolink" value="{{$.RepoRelPath}}">
<input type="hidden" id="repoId" value="{{.Repository.ID}}"> <input type="hidden" id="repoId" value="{{.Repository.ID}}">
<input type="hidden" id="crossRepoSearch" value="{{.AllowCrossRepositoryDependencies}}"> <input type="hidden" id="crossRepoSearch" value="{{.AllowCrossRepositoryDependencies}}">
<input type="hidden" id="type" value="{{.IssueType}}">
<!-- I know, there is probably a better way to do this --> <!-- I know, there is probably a better way to do this -->
<input type="hidden" id="issueIndex" value="{{.Issue.Index}}"/> <input type="hidden" id="issueIndex" value="{{.Issue.Index}}"/>

View File

@@ -1173,6 +1173,12 @@
"description": "repository to prioritize in the results", "description": "repository to prioritize in the results",
"name": "priority_repo_id", "name": "priority_repo_id",
"in": "query" "in": "query"
},
{
"type": "string",
"description": "filter by type (issues / pulls) if set",
"name": "type",
"in": "query"
} }
], ],
"responses": { "responses": {
@@ -2903,6 +2909,12 @@
"description": "search string", "description": "search string",
"name": "q", "name": "q",
"in": "query" "in": "query"
},
{
"type": "string",
"description": "filter by type (issues / pulls) if set",
"name": "type",
"in": "query"
} }
], ],
"responses": { "responses": {
@@ -10179,6 +10191,10 @@
"format": "date-time", "format": "date-time",
"x-go-name": "Deadline" "x-go-name": "Deadline"
}, },
"html_url": {
"type": "string",
"x-go-name": "HTMLURL"
},
"id": { "id": {
"type": "integer", "type": "integer",
"format": "int64", "format": "int64",

View File

@@ -18,7 +18,7 @@
{{end}} {{end}}
{{if .IsResetForm}} {{if .IsResetForm}}
<div class="required inline field {{if .Err_Password}}error{{end}}"> <div class="required inline field {{if .Err_Password}}error{{end}}">
<label for="password">{{.i18n.Tr "password"}}</label> <label for="password">{{.i18n.Tr "settings.new_password"}}</label>
<input id="password" name="password" type="password" value="{{.password}}" autocomplete="off" autofocus required> <input id="password" name="password" type="password" value="{{.password}}" autocomplete="off" autofocus required>
</div> </div>
{{if not .user_signed_in}} {{if not .user_signed_in}}
@@ -30,10 +30,31 @@
</div> </div>
</div> </div>
{{end}} {{end}}
{{if .has_two_factor}}
<h4 class="ui dividing header">
{{.i18n.Tr "twofa"}}
</h4>
<div class="ui warning visible message">{{.i18n.Tr "settings.twofa_is_enrolled" | Str2html }}</div>
{{if .scratch_code}}
<div class="required inline field {{if .Err_Token}}error{{end}}">
<label for="token">{{.i18n.Tr "auth.scratch_code"}}</label>
<input id="token" name="token" type="text" autocomplete="off" autofocus required>
</div>
<input type="hidden" name="scratch_code" value="true">
{{else}}
<div class="required inline field {{if .Err_Passcode}}error{{end}}">
<label for="passcode">{{.i18n.Tr "passcode"}}</label>
<input id="passcode" name="passcode" type="number" autocomplete="off" autofocus required>
</div>
{{end}}
{{end}}
<div class="ui divider"></div> <div class="ui divider"></div>
<div class="inline field"> <div class="inline field">
<label></label> <label></label>
<button class="ui blue button">{{.i18n.Tr "auth.reset_password_helper"}}</button> <button class="ui blue button">{{.i18n.Tr "auth.reset_password_helper"}}</button>
{{if and .has_two_factor (not .scratch_code)}}
<a href="{{.Link}}?code={{.Code}}&amp;scratch_code=true">{{.i18n.Tr "auth.use_scratch_code" | Str2html}}</a>
{{end}}
</div> </div>
{{else}} {{else}}
<p class="center">{{.i18n.Tr "auth.invalid_code"}}</p> <p class="center">{{.i18n.Tr "auth.invalid_code"}}</p>

View File

@@ -65,7 +65,7 @@
<div class="milestone list"> <div class="milestone list">
{{range .Milestones}} {{range .Milestones}}
<li class="item"> <li class="item">
<div class="ui label">{{if not $.RepoIDs}}{{.Repo.FullName}}{{end}}</div> <div class="ui label">{{.Repo.FullName}}</div>
<i class="octicon octicon-milestone"></i> <a href="{{.Repo.Link }}/milestone/{{.ID}}">{{.Name}}</a> <i class="octicon octicon-milestone"></i> <a href="{{.Repo.Link }}/milestone/{{.ID}}">{{.Name}}</a>
<div class="ui right green progress" data-percent="{{.Completeness}}"> <div class="ui right green progress" data-percent="{{.Completeness}}">
<div class="bar" {{if not .Completeness}}style="background-color: transparent"{{end}}> <div class="bar" {{if not .Completeness}}style="background-color: transparent"{{end}}>

View File

@@ -22,6 +22,9 @@ if (typeof (Dropzone) !== 'undefined') {
Dropzone.autoDiscover = false; Dropzone.autoDiscover = false;
} }
// Silence fomantic's error logging when tabs are used without a target content element
$.fn.tab.settings.silent = true;
function initCommentPreviewTab($form) { function initCommentPreviewTab($form) {
const $tabMenu = $form.find('.tabular.menu'); const $tabMenu = $form.find('.tabular.menu');
$tabMenu.find('.item').tab(); $tabMenu.find('.item').tab();
@@ -320,12 +323,14 @@ function initSimpleMDEImagePaste(simplemde, files) {
}); });
} }
let autoSimpleMDE;
function initCommentForm() { function initCommentForm() {
if ($('.comment.form').length === 0) { if ($('.comment.form').length === 0) {
return; return;
} }
setCommentSimpleMDE($('.comment.form textarea:not(.review-textarea)')); autoSimpleMDE = setCommentSimpleMDE($('.comment.form textarea:not(.review-textarea)'));
initBranchSelector(); initBranchSelector();
initCommentPreviewTab($('.comment.form')); initCommentPreviewTab($('.comment.form'));
initImagePaste($('.comment.form textarea')); initImagePaste($('.comment.form textarea'));
@@ -823,25 +828,27 @@ function initRepository() {
$('.quote-reply').click(function (event) { $('.quote-reply').click(function (event) {
$(this).closest('.dropdown').find('.menu').toggle('visible'); $(this).closest('.dropdown').find('.menu').toggle('visible');
const target = $(this).data('target'); const target = $(this).data('target');
const quote = $(`#comment-${target}`).text().replace(/\n/g, '\n> ');
const content = `> ${quote}\n\n`;
let $content; let $content;
if ($(this).hasClass('quote-reply-diff')) { if ($(this).hasClass('quote-reply-diff')) {
const $parent = $(this).closest('.comment-code-cloud'); const $parent = $(this).closest('.comment-code-cloud');
$parent.find('button.comment-form-reply').click(); $parent.find('button.comment-form-reply').click();
$content = $parent.find('[name="content"]'); $content = $parent.find('[name="content"]');
} else { if ($content.val() !== '') {
$content = $('#content'); $content.val(`${$content.val()}\n\n${content}`);
} else {
$content.val(`${content}`);
}
$content.focus();
} else if (autoSimpleMDE !== null) {
if (autoSimpleMDE.value() !== '') {
autoSimpleMDE.value(`${autoSimpleMDE.value()}\n\n${content}`);
} else {
autoSimpleMDE.value(`${content}`);
}
} }
const quote = $(`#comment-${target}`).text().replace(/\n/g, '\n> ');
const content = `> ${quote}\n\n`;
if ($content.val() !== '') {
$content.val(`${$content.val()}\n\n${content}`);
} else {
$content.val(`${content}`);
}
$content.focus();
event.preventDefault(); event.preventDefault();
}); });
@@ -3448,9 +3455,10 @@ function initIssueList() {
const repolink = $('#repolink').val(); const repolink = $('#repolink').val();
const repoId = $('#repoId').val(); const repoId = $('#repoId').val();
const crossRepoSearch = $('#crossRepoSearch').val(); const crossRepoSearch = $('#crossRepoSearch').val();
let issueSearchUrl = `${suburl}/api/v1/repos/${repolink}/issues?q={query}`; const tp = $('#type').val();
let issueSearchUrl = `${suburl}/api/v1/repos/${repolink}/issues?q={query}&type=${tp}`;
if (crossRepoSearch === 'true') { if (crossRepoSearch === 'true') {
issueSearchUrl = `${suburl}/api/v1/repos/issues/search?q={query}&priority_repo_id=${repoId}`; issueSearchUrl = `${suburl}/api/v1/repos/issues/search?q={query}&priority_repo_id=${repoId}&type=${tp}`;
} }
$('#new-dependency-drop-list') $('#new-dependency-drop-list')
.dropdown({ .dropdown({

View File

@@ -774,6 +774,7 @@ footer {
.container { .container {
width: 100vw !important; width: 100vw !important;
padding: 0 0.5rem; padding: 0 0.5rem;
max-width: calc(100vw - 1rem) !important;
.fa { .fa {
width: 16px; width: 16px;

View File

@@ -36,7 +36,7 @@ module.exports = {
[ [
'@babel/preset-env', '@babel/preset-env',
{ {
useBuiltIns: 'entry', useBuiltIns: 'usage',
corejs: 3, corejs: 3,
} }
] ]