mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-11-03 08:02:36 +09:00 
			
		
		
		
	Compare commits
	
		
			76 Commits
		
	
	
		
			v1.20.0-de
			...
			v1.11.0
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					9169b39458 | ||
| 
						 | 
					80eb50655a | ||
| 
						 | 
					b16c555541 | ||
| 
						 | 
					b5b44364e3 | ||
| 
						 | 
					6af58022c8 | ||
| 
						 | 
					e48b460a0a | ||
| 
						 | 
					2cd2614eaa | ||
| 
						 | 
					0129e76ef5 | ||
| 
						 | 
					6896dad675 | ||
| 
						 | 
					1ed4323005 | ||
| 
						 | 
					049af0d3d0 | ||
| 
						 | 
					f5727d83dd | ||
| 
						 | 
					912ce27421 | ||
| 
						 | 
					b3549bb5ec | ||
| 
						 | 
					491cbeca67 | ||
| 
						 | 
					895d92ffe5 | ||
| 
						 | 
					4b11f967bd | ||
| 
						 | 
					1e73dd2446 | ||
| 
						 | 
					315026c2c5 | ||
| 
						 | 
					16dfd9ffbe | ||
| 
						 | 
					16f7b43903 | ||
| 
						 | 
					043febdbc9 | ||
| 
						 | 
					60f91d56f0 | ||
| 
						 | 
					16fc15ae6a | ||
| 
						 | 
					ef8f6d99f1 | ||
| 
						 | 
					4b688135f9 | ||
| 
						 | 
					e24861a546 | ||
| 
						 | 
					128cc34344 | ||
| 
						 | 
					f82a805478 | ||
| 
						 | 
					0dced15c1a | ||
| 
						 | 
					db9342c854 | ||
| 
						 | 
					79c1d48532 | ||
| 
						 | 
					05b9864086 | ||
| 
						 | 
					ff508c9c9b | ||
| 
						 | 
					f96c1a2c79 | ||
| 
						 | 
					ce756ee89f | ||
| 
						 | 
					f2e9d4b851 | ||
| 
						 | 
					e878d743f4 | ||
| 
						 | 
					3fa14d89a2 | ||
| 
						 | 
					bcb722daec | ||
| 
						 | 
					8add1dfacc | ||
| 
						 | 
					aa6ed1b7c1 | ||
| 
						 | 
					95cb921097 | ||
| 
						 | 
					6730df9e8c | ||
| 
						 | 
					b577500a54 | ||
| 
						 | 
					fe46185407 | ||
| 
						 | 
					69a2a29c33 | ||
| 
						 | 
					f766719895 | ||
| 
						 | 
					e2ddc42377 | ||
| 
						 | 
					3521177a34 | ||
| 
						 | 
					c8bb0ecf52 | ||
| 
						 | 
					dbe6136348 | ||
| 
						 | 
					6d1f7e90cf | ||
| 
						 | 
					42663a687c | ||
| 
						 | 
					73c90c26d4 | ||
| 
						 | 
					c579ad92b5 | ||
| 
						 | 
					602c5da953 | ||
| 
						 | 
					1980e59ac2 | ||
| 
						 | 
					28508792ba | ||
| 
						 | 
					3e23dad075 | ||
| 
						 | 
					b13b9d3dbd | ||
| 
						 | 
					4072f28e60 | ||
| 
						 | 
					dbeef6bb02 | ||
| 
						 | 
					fec35440db | ||
| 
						 | 
					f8ea50cc7a | ||
| 
						 | 
					0e53a16cca | ||
| 
						 | 
					7eaba6ba8a | ||
| 
						 | 
					ff16099c6d | ||
| 
						 | 
					a516a7ba0f | ||
| 
						 | 
					11bce6fd3d | ||
| 
						 | 
					3fb906dc02 | ||
| 
						 | 
					3a00a690c9 | ||
| 
						 | 
					a2b7cc1bb1 | ||
| 
						 | 
					04a77b1f42 | ||
| 
						 | 
					f523372d07 | ||
| 
						 | 
					e39c238ef4 | 
@@ -1,44 +1,57 @@
 | 
				
			|||||||
 | 
					# The full repository name
 | 
				
			||||||
repo: go-gitea/gitea
 | 
					repo: go-gitea/gitea
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Service type (gitea or github)
 | 
				
			||||||
 | 
					service: github
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Base URL for Gitea instance if using gitea service type (optional)
 | 
				
			||||||
 | 
					# Default: https://gitea.com
 | 
				
			||||||
 | 
					base-url:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Changelog groups and which labeled PRs to add to each group
 | 
				
			||||||
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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# regex indicating which labels to skip for the changelog
 | 
				
			||||||
 | 
					skip-labels: skip-changelog|backport\/.+
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										408
									
								
								.drone.yml
									
									
									
									
									
								
							
							
						
						
									
										408
									
								
								.drone.yml
									
									
									
									
									
								
							@@ -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
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										107
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										107
									
								
								CHANGELOG.md
									
									
									
									
									
								
							@@ -4,13 +4,22 @@ 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-RC1](https://github.com/go-gitea/gitea/releases/tag/v1.11.0-rc1) - 2020-01-07
 | 
					## [1.11.0](https://github.com/go-gitea/gitea/releases/tag/v1.11.0) - 2020-02-10
 | 
				
			||||||
* BREAKING
 | 
					* BREAKING
 | 
				
			||||||
 | 
					  * Fix followers and following tabs in profile (#10202) (#10203)
 | 
				
			||||||
 | 
					  * Make CertFile and KeyFile relative to CustomPath (#9868) (#9874)
 | 
				
			||||||
  * Remove unused endpoints (#9538)
 | 
					  * Remove unused endpoints (#9538)
 | 
				
			||||||
  * Prefix all user-generated IDs in markup (#9477)
 | 
					  * Prefix all user-generated IDs in markup (#9477)
 | 
				
			||||||
  * Enforce Gitea environment for pushes (#8982)
 | 
					  * Enforce Gitea environment for pushes (#8982)
 | 
				
			||||||
  * Hide some user information via API if user have no enough permission (#8655)
 | 
					  * Hide some user information via API if user have not enough permissions (#8655)
 | 
				
			||||||
  * Move startpage/homepage translation to crowdin (#8596)
 | 
					  * Move startpage/homepage translation to crowdin (#8596)
 | 
				
			||||||
 | 
					* SECURITY
 | 
				
			||||||
 | 
					  * Never allow an empty password to validate (#9682) (#9683)
 | 
				
			||||||
 | 
					  * Prevent redirect to Host (#9678) (#9679)
 | 
				
			||||||
 | 
					  * Swagger hide search field (#9554)
 | 
				
			||||||
 | 
					  * Add "search" to reserved usernames (#9063)
 | 
				
			||||||
 | 
					  * Switch to fomantic-ui (#9374)
 | 
				
			||||||
 | 
					  * Only serve attachments when linked to issue/release and if accessible by user (#9340)
 | 
				
			||||||
* FEATURES
 | 
					* FEATURES
 | 
				
			||||||
  * Webhooks should only show sender if it makes sense (#9601)
 | 
					  * Webhooks should only show sender if it makes sense (#9601)
 | 
				
			||||||
  * Provide Default messages for merges (#9393)
 | 
					  * Provide Default messages for merges (#9393)
 | 
				
			||||||
@@ -44,6 +53,68 @@ been added to each release, please refer to the [blog](https://blog.gitea.io).
 | 
				
			|||||||
  * Sign merges, CRUD, Wiki and Repository initialisation with gpg key (#7631)
 | 
					  * Sign merges, CRUD, Wiki and Repository initialisation with gpg key (#7631)
 | 
				
			||||||
  * Add basic repository lfs management (#7199)
 | 
					  * Add basic repository lfs management (#7199)
 | 
				
			||||||
* BUGFIXES
 | 
					* BUGFIXES
 | 
				
			||||||
 | 
					  * Fix code-expansion arc-green theme bug (#10180) (#10185)
 | 
				
			||||||
 | 
					  * Prevent double wait-group decrement (#10170) (#10175)
 | 
				
			||||||
 | 
					  * Allow emoji on review head comments (#10159) (#10174)
 | 
				
			||||||
 | 
					  * Fix issue/pull link (#10158) (#10173)
 | 
				
			||||||
 | 
					  * Fix push-create SSH bugs (#10145) (#10151)
 | 
				
			||||||
 | 
					  * Prevent DeleteUser API abuse (#10125) (#10128)
 | 
				
			||||||
 | 
					  * Fix issues/pulls dashboard paging error (#10114) (#10115)
 | 
				
			||||||
 | 
					  * Add button to revert SimpleMDE to plain textarea (#10099) (#10102)
 | 
				
			||||||
 | 
					  * Fix branch page pull request title and link error (#10092) (#10097)
 | 
				
			||||||
 | 
					  * Fix PR API: Only try to get HeadBranch if HeadRepo exist (#10029) (#10088)
 | 
				
			||||||
 | 
					  * Update topics repo count when deleting repository (#10051) (#10081)
 | 
				
			||||||
 | 
					  * Show pull icon on pull requests (#10061) (#10062)
 | 
				
			||||||
 | 
					  * Fix milestone API state parameter unhandled (#10049) (#10052)
 | 
				
			||||||
 | 
					  * Move to using a temporary repo for pushing new PRs (#10009) (#10042)
 | 
				
			||||||
 | 
					  * Fix wiki raw view on sub path (#10002) (#10040)
 | 
				
			||||||
 | 
					  * Ensure that feeds are appropriately restricted (#10018) (#10019)
 | 
				
			||||||
 | 
					  * Sanitize credentials in mirror form (#9975) (#9991)
 | 
				
			||||||
 | 
					  * Close related pull requests when deleting head repository or head branch (#9927) (#9974)
 | 
				
			||||||
 | 
					  * Switch to use -f instead of -F for sendmail (#9961) (#9970)
 | 
				
			||||||
 | 
					  * Fix file rename/copy not supported by indexer (#9965) (#9967)
 | 
				
			||||||
 | 
					  * Fix repo indexer not updating upon push (#9957) (#9963)
 | 
				
			||||||
 | 
					  * 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)
 | 
				
			||||||
 | 
					  * 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)
 | 
				
			||||||
  * Disable remove button on repository teams when have access to all (#9640)
 | 
					  * Disable remove button on repository teams when have access to all (#9640)
 | 
				
			||||||
  * Clean up old references on branch delete (#9614)
 | 
					  * Clean up old references on branch delete (#9614)
 | 
				
			||||||
  * Hide public repos owned by private orgs (#9609)
 | 
					  * Hide public repos owned by private orgs (#9609)
 | 
				
			||||||
@@ -175,6 +246,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.io).
 | 
				
			|||||||
  * Fix migrate mirror 500 bug (#8526)
 | 
					  * Fix migrate mirror 500 bug (#8526)
 | 
				
			||||||
  * Fix password complexity regex for special characters (on master) (#8525)
 | 
					  * Fix password complexity regex for special characters (on master) (#8525)
 | 
				
			||||||
* ENHANCEMENTS
 | 
					* ENHANCEMENTS
 | 
				
			||||||
 | 
					  * Explicitly refer to PR in squash-merge commit message in case of external tracker (#9844) (#9855)
 | 
				
			||||||
  * Add a /user/login landing page option (#9622)
 | 
					  * Add a /user/login landing page option (#9622)
 | 
				
			||||||
  * Some more e-mail notification fixes (#9596)
 | 
					  * Some more e-mail notification fixes (#9596)
 | 
				
			||||||
  * Add branch protection option to block merge on requested changes. (#9592)
 | 
					  * Add branch protection option to block merge on requested changes. (#9592)
 | 
				
			||||||
@@ -291,12 +363,6 @@ been added to each release, please refer to the [blog](https://blog.gitea.io).
 | 
				
			|||||||
  * wiki - add 'write' 'preview' buttons to wiki edit like in issues (#7241)
 | 
					  * wiki - add 'write' 'preview' buttons to wiki edit like in issues (#7241)
 | 
				
			||||||
  * Change target branch for pull request (#6488)
 | 
					  * Change target branch for pull request (#6488)
 | 
				
			||||||
  * Display PR commits and diffs using base repo rather than forked (#3648)
 | 
					  * Display PR commits and diffs using base repo rather than forked (#3648)
 | 
				
			||||||
* SECURITY
 | 
					 | 
				
			||||||
  * Swagger hide search field (#9554)
 | 
					 | 
				
			||||||
  * Add "search" to reserved usernames (#9063)
 | 
					 | 
				
			||||||
  * Switch to fomantic-ui (#9374)
 | 
					 | 
				
			||||||
  * Only serve attachments when linked to issue/release and if accessible by user (#9340)
 | 
					 | 
				
			||||||
  * Hide credentials when submitting migration through API (#9102)
 | 
					 | 
				
			||||||
* TESTING
 | 
					* TESTING
 | 
				
			||||||
  * Add debug option to serv to help debug problems (#9492)
 | 
					  * Add debug option to serv to help debug problems (#9492)
 | 
				
			||||||
  * Fix the intermittent TestGPGGit failures (#9360)
 | 
					  * Fix the intermittent TestGPGGit failures (#9360)
 | 
				
			||||||
@@ -310,10 +376,12 @@ been added to each release, please refer to the [blog](https://blog.gitea.io).
 | 
				
			|||||||
  * Update Github Migration Tests (#8893) (#8938)
 | 
					  * Update Github Migration Tests (#8893) (#8938)
 | 
				
			||||||
  * Update heatmap fixtures to restore tests (#8615)
 | 
					  * Update heatmap fixtures to restore tests (#8615)
 | 
				
			||||||
* TRANSLATION
 | 
					* TRANSLATION
 | 
				
			||||||
 | 
					  * Fix Korean locales (#9761) (#9780)
 | 
				
			||||||
  * Fix placeholders in the error message (#9060)
 | 
					  * Fix placeholders in the error message (#9060)
 | 
				
			||||||
  * Fix spelling of admin.users.max_repo_creation (#8934)
 | 
					  * Fix spelling of admin.users.max_repo_creation (#8934)
 | 
				
			||||||
  * Improve german translation of homepage (#8549)
 | 
					  * Improve german translation of homepage (#8549)
 | 
				
			||||||
* BUILD
 | 
					* BUILD
 | 
				
			||||||
 | 
					  * Fix webpack polyfills (#9735) (#9738)
 | 
				
			||||||
  * Update gitea.com/macaron to 1.4.0 (#9608)
 | 
					  * Update gitea.com/macaron to 1.4.0 (#9608)
 | 
				
			||||||
  * Upgrade lato fonts to v16. (#9498)
 | 
					  * Upgrade lato fonts to v16. (#9498)
 | 
				
			||||||
  * Update alpine to 3.11 (#9440)
 | 
					  * Update alpine to 3.11 (#9440)
 | 
				
			||||||
@@ -344,6 +412,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.io).
 | 
				
			|||||||
  * Update the provided gitea.service to mention socket activation (#8531)
 | 
					  * Update the provided gitea.service to mention socket activation (#8531)
 | 
				
			||||||
  * Doc added how to setup email (#8520)
 | 
					  * Doc added how to setup email (#8520)
 | 
				
			||||||
* MISC
 | 
					* MISC
 | 
				
			||||||
 | 
					  * Backport Locales [2020-01-14] (#9773)
 | 
				
			||||||
  * Add translatable Powered by Gitea text in footer (#9600)
 | 
					  * Add translatable Powered by Gitea text in footer (#9600)
 | 
				
			||||||
  * Add contrib/environment-to-ini (#9519)
 | 
					  * Add contrib/environment-to-ini (#9519)
 | 
				
			||||||
  * Remove unnecessary loading of settings in update hook (#9496)
 | 
					  * Remove unnecessary loading of settings in update hook (#9496)
 | 
				
			||||||
@@ -384,6 +453,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 +1570,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
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										11
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								Makefile
									
									
									
									
									
								
							@@ -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
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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 user’s LDAP record containing the user name.",
 | 
								Usage: "The attribute of the user’s 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
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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 {
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										148
									
								
								cmd/hook.go
									
									
									
									
									
								
							
							
						
						
									
										148
									
								
								cmd/hook.go
									
									
									
									
									
								
							@@ -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
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,6 +12,7 @@ import (
 | 
				
			|||||||
	"net/url"
 | 
						"net/url"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"os/exec"
 | 
						"os/exec"
 | 
				
			||||||
 | 
						"regexp"
 | 
				
			||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
@@ -72,6 +73,7 @@ var (
 | 
				
			|||||||
		"git-receive-pack":   models.AccessModeWrite,
 | 
							"git-receive-pack":   models.AccessModeWrite,
 | 
				
			||||||
		lfsAuthenticateVerb:  models.AccessModeNone,
 | 
							lfsAuthenticateVerb:  models.AccessModeNone,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						alphaDashDotPattern = regexp.MustCompile(`[^\w-\.]`)
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func fail(userMessage, logMessage string, args ...interface{}) {
 | 
					func fail(userMessage, logMessage string, args ...interface{}) {
 | 
				
			||||||
@@ -147,6 +149,10 @@ func runServ(c *cli.Context) error {
 | 
				
			|||||||
	username := strings.ToLower(rr[0])
 | 
						username := strings.ToLower(rr[0])
 | 
				
			||||||
	reponame := strings.ToLower(strings.TrimSuffix(rr[1], ".git"))
 | 
						reponame := strings.ToLower(strings.TrimSuffix(rr[1], ".git"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if alphaDashDotPattern.MatchString(reponame) {
 | 
				
			||||||
 | 
							fail("Invalid repo name", "Invalid repo name: %s", reponame)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if setting.EnablePprof || c.Bool("enable-pprof") {
 | 
						if setting.EnablePprof || c.Bool("enable-pprof") {
 | 
				
			||||||
		if err := os.MkdirAll(setting.PprofDataPath, os.ModePerm); err != nil {
 | 
							if err := os.MkdirAll(setting.PprofDataPath, os.ModePerm); err != nil {
 | 
				
			||||||
			fail("Error while trying to create PPROF_DATA_PATH", "Error while trying to create PPROF_DATA_PATH: %v", err)
 | 
								fail("Error while trying to create PPROF_DATA_PATH", "Error while trying to create PPROF_DATA_PATH: %v", err)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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 =
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,7 +18,7 @@ params:
 | 
				
			|||||||
  description: Git with a cup of tea
 | 
					  description: Git with a cup of tea
 | 
				
			||||||
  author: The Gitea Authors
 | 
					  author: The Gitea Authors
 | 
				
			||||||
  website: https://docs.gitea.io
 | 
					  website: https://docs.gitea.io
 | 
				
			||||||
  version: 1.10.2
 | 
					  version: 1.11.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
outputs:
 | 
					outputs:
 | 
				
			||||||
  home:
 | 
					  home:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										47
									
								
								integrations/api_issue_milestone_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								integrations/api_issue_milestone_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,47 @@
 | 
				
			|||||||
 | 
					// 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 integrations
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"net/http"
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/models"
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/structs"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/stretchr/testify/assert"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestAPIIssuesMilestone(t *testing.T) {
 | 
				
			||||||
 | 
						defer prepareTestEnv(t)()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						milestone := models.AssertExistsAndLoadBean(t, &models.Milestone{ID: 1}).(*models.Milestone)
 | 
				
			||||||
 | 
						repo := models.AssertExistsAndLoadBean(t, &models.Repository{ID: milestone.RepoID}).(*models.Repository)
 | 
				
			||||||
 | 
						owner := models.AssertExistsAndLoadBean(t, &models.User{ID: repo.OwnerID}).(*models.User)
 | 
				
			||||||
 | 
						assert.Equal(t, int64(1), int64(milestone.NumIssues))
 | 
				
			||||||
 | 
						assert.Equal(t, structs.StateOpen, milestone.State())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						session := loginUser(t, owner.Name)
 | 
				
			||||||
 | 
						token := getTokenForLoggedInUser(t, session)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// update values of issue
 | 
				
			||||||
 | 
						milestoneState := "closed"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/milestones/%d?token=%s", owner.Name, repo.Name, milestone.ID, token)
 | 
				
			||||||
 | 
						req := NewRequestWithJSON(t, "PATCH", urlStr, structs.EditMilestoneOption{
 | 
				
			||||||
 | 
							State: &milestoneState,
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						resp := session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
 | 
						var apiMilestone structs.Milestone
 | 
				
			||||||
 | 
						DecodeJSON(t, resp, &apiMilestone)
 | 
				
			||||||
 | 
						assert.EqualValues(t, "closed", apiMilestone.State)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						req = NewRequest(t, "GET", urlStr)
 | 
				
			||||||
 | 
						resp = session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
 | 
						var apiMilestone2 structs.Milestone
 | 
				
			||||||
 | 
						DecodeJSON(t, resp, &apiMilestone2)
 | 
				
			||||||
 | 
						assert.EqualValues(t, "closed", apiMilestone2.State)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -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)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -422,6 +422,9 @@ func doPushCreate(ctx APITestContext, u *url.URL) func(t *testing.T) {
 | 
				
			|||||||
		tmpDir, err := ioutil.TempDir("", ctx.Reponame)
 | 
							tmpDir, err := ioutil.TempDir("", ctx.Reponame)
 | 
				
			||||||
		assert.NoError(t, err)
 | 
							assert.NoError(t, err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							_, err = git.NewCommand("clone", u.String()).RunInDir(tmpDir)
 | 
				
			||||||
 | 
							assert.Error(t, err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		err = git.InitRepository(tmpDir, false)
 | 
							err = git.InitRepository(tmpDir, false)
 | 
				
			||||||
		assert.NoError(t, err)
 | 
							assert.NoError(t, err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -449,6 +452,13 @@ func doPushCreate(ctx APITestContext, u *url.URL) func(t *testing.T) {
 | 
				
			|||||||
		_, err = git.NewCommand("remote", "add", "origin", u.String()).RunInDir(tmpDir)
 | 
							_, err = git.NewCommand("remote", "add", "origin", u.String()).RunInDir(tmpDir)
 | 
				
			||||||
		assert.NoError(t, err)
 | 
							assert.NoError(t, err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							invalidCtx := ctx
 | 
				
			||||||
 | 
							invalidCtx.Reponame = fmt.Sprintf("invalid/repo-tmp-push-create-%s", u.Scheme)
 | 
				
			||||||
 | 
							u.Path = invalidCtx.GitPath()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							_, err = git.NewCommand("remote", "add", "invalid", u.String()).RunInDir(tmpDir)
 | 
				
			||||||
 | 
							assert.NoError(t, err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Push to create disabled
 | 
							// Push to create disabled
 | 
				
			||||||
		setting.Repository.EnablePushCreateUser = false
 | 
							setting.Repository.EnablePushCreateUser = false
 | 
				
			||||||
		_, err = git.NewCommand("push", "origin", "master").RunInDir(tmpDir)
 | 
							_, err = git.NewCommand("push", "origin", "master").RunInDir(tmpDir)
 | 
				
			||||||
@@ -456,6 +466,12 @@ func doPushCreate(ctx APITestContext, u *url.URL) func(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		// Push to create enabled
 | 
							// Push to create enabled
 | 
				
			||||||
		setting.Repository.EnablePushCreateUser = true
 | 
							setting.Repository.EnablePushCreateUser = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Invalid repo
 | 
				
			||||||
 | 
							_, err = git.NewCommand("push", "invalid", "master").RunInDir(tmpDir)
 | 
				
			||||||
 | 
							assert.Error(t, err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Valid repo
 | 
				
			||||||
		_, err = git.NewCommand("push", "origin", "master").RunInDir(tmpDir)
 | 
							_, err = git.NewCommand("push", "origin", "master").RunInDir(tmpDir)
 | 
				
			||||||
		assert.NoError(t, err)
 | 
							assert.NoError(t, err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							@@ -1 +1 @@
 | 
				
			|||||||
0cf15c3f66ec8384480ed9c3cf87c9e97fbb0ec3
 | 
					423313fbd38093bb10d0c8387db9105409c6f196
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -106,3 +106,57 @@ func TestPullCreate_TitleEscape(t *testing.T) {
 | 
				
			|||||||
		assert.Equal(t, "<u>XSS PR</u>", titleHTML)
 | 
							assert.Equal(t, "<u>XSS PR</u>", titleHTML)
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func testUIDeleteBranch(t *testing.T, session *TestSession, ownerName, repoName, branchName string) {
 | 
				
			||||||
 | 
						relURL := "/" + path.Join(ownerName, repoName, "branches")
 | 
				
			||||||
 | 
						req := NewRequest(t, "GET", relURL)
 | 
				
			||||||
 | 
						resp := session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
 | 
						htmlDoc := NewHTMLParser(t, resp.Body)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						req = NewRequestWithValues(t, "POST", relURL+"/delete", map[string]string{
 | 
				
			||||||
 | 
							"_csrf": getCsrf(t, htmlDoc.doc),
 | 
				
			||||||
 | 
							"name":  branchName,
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func testDeleteRepository(t *testing.T, session *TestSession, ownerName, repoName string) {
 | 
				
			||||||
 | 
						relURL := "/" + path.Join(ownerName, repoName, "settings")
 | 
				
			||||||
 | 
						req := NewRequest(t, "GET", relURL)
 | 
				
			||||||
 | 
						resp := session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
 | 
						htmlDoc := NewHTMLParser(t, resp.Body)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						req = NewRequestWithValues(t, "POST", relURL+"?action=delete", map[string]string{
 | 
				
			||||||
 | 
							"_csrf":     getCsrf(t, htmlDoc.doc),
 | 
				
			||||||
 | 
							"repo_name": repoName,
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						session.MakeRequest(t, req, http.StatusFound)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestPullBranchDelete(t *testing.T) {
 | 
				
			||||||
 | 
						onGiteaRun(t, func(t *testing.T, u *url.URL) {
 | 
				
			||||||
 | 
							defer prepareTestEnv(t)()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							session := loginUser(t, "user1")
 | 
				
			||||||
 | 
							testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
 | 
				
			||||||
 | 
							testCreateBranch(t, session, "user1", "repo1", "branch/master", "master1", http.StatusFound)
 | 
				
			||||||
 | 
							testEditFile(t, session, "user1", "repo1", "master1", "README.md", "Hello, World (Edited)\n")
 | 
				
			||||||
 | 
							resp := testPullCreate(t, session, "user1", "repo1", "master1", "This is a pull title")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// check the redirected URL
 | 
				
			||||||
 | 
							url := resp.HeaderMap.Get("Location")
 | 
				
			||||||
 | 
							assert.Regexp(t, "^/user2/repo1/pulls/[0-9]*$", url)
 | 
				
			||||||
 | 
							req := NewRequest(t, "GET", url)
 | 
				
			||||||
 | 
							session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// delete head branch and confirm pull page is ok
 | 
				
			||||||
 | 
							testUIDeleteBranch(t, session, "user1", "repo1", "master1")
 | 
				
			||||||
 | 
							req = NewRequest(t, "GET", url)
 | 
				
			||||||
 | 
							session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// delete head repository and confirm pull page is ok
 | 
				
			||||||
 | 
							testDeleteRepository(t, session, "user1", "repo1")
 | 
				
			||||||
 | 
							req = NewRequest(t, "GET", url)
 | 
				
			||||||
 | 
							session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -432,6 +432,8 @@ func GetFeeds(opts GetFeedsOptions) ([]*Action, error) {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		cond = cond.And(builder.In("repo_id", repoIDs))
 | 
							cond = cond.And(builder.In("repo_id", repoIDs))
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							cond = cond.And(builder.In("repo_id", AccessibleRepoIDsQuery(opts.RequestingUserID)))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cond = cond.And(builder.Eq{"user_id": opts.RequestedUser.ID})
 | 
						cond = cond.And(builder.Eq{"user_id": opts.RequestedUser.ID})
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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())
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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 {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,6 +6,7 @@ package models
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"code.gitea.io/gitea/modules/setting"
 | 
						"code.gitea.io/gitea/modules/setting"
 | 
				
			||||||
	api "code.gitea.io/gitea/modules/structs"
 | 
						api "code.gitea.io/gitea/modules/structs"
 | 
				
			||||||
@@ -95,6 +96,8 @@ func NewMilestone(m *Milestone) (err error) {
 | 
				
			|||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						m.Name = strings.TrimSpace(m.Name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if _, err = sess.Insert(m); err != nil {
 | 
						if _, err = sess.Insert(m); err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -268,6 +271,7 @@ func GetMilestones(repoID int64, page int, isClosed bool, sortType string) (Mile
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func updateMilestone(e Engine, m *Milestone) error {
 | 
					func updateMilestone(e Engine, m *Milestone) error {
 | 
				
			||||||
 | 
						m.Name = strings.TrimSpace(m.Name)
 | 
				
			||||||
	_, err := e.ID(m.ID).AllCols().
 | 
						_, err := e.ID(m.ID).AllCols().
 | 
				
			||||||
		SetExpr("num_issues", builder.Select("count(*)").From("issue").Where(
 | 
							SetExpr("num_issues", builder.Select("count(*)").From("issue").Where(
 | 
				
			||||||
			builder.Eq{"milestone_id": m.ID},
 | 
								builder.Eq{"milestone_id": m.ID},
 | 
				
			||||||
@@ -283,12 +287,33 @@ func updateMilestone(e Engine, m *Milestone) error {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// UpdateMilestone updates information of given milestone.
 | 
					// UpdateMilestone updates information of given milestone.
 | 
				
			||||||
func UpdateMilestone(m *Milestone) error {
 | 
					func UpdateMilestone(m *Milestone, oldIsClosed bool) error {
 | 
				
			||||||
	if err := updateMilestone(x, m); err != nil {
 | 
						sess := x.NewSession()
 | 
				
			||||||
 | 
						defer sess.Close()
 | 
				
			||||||
 | 
						if err := sess.Begin(); err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return updateMilestoneCompleteness(x, m.ID)
 | 
						if m.IsClosed && !oldIsClosed {
 | 
				
			||||||
 | 
							m.ClosedDateUnix = timeutil.TimeStampNow()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err := updateMilestone(sess, m); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err := updateMilestoneCompleteness(sess, m.ID); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// if IsClosed changed, update milestone numbers of repository
 | 
				
			||||||
 | 
						if oldIsClosed != m.IsClosed {
 | 
				
			||||||
 | 
							if err := updateRepoMilestoneNum(sess, m.RepoID); err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return sess.Commit()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func updateMilestoneCompleteness(e Engine, milestoneID int64) error {
 | 
					func updateMilestoneCompleteness(e Engine, milestoneID int64) error {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -158,10 +158,11 @@ func TestUpdateMilestone(t *testing.T) {
 | 
				
			|||||||
	assert.NoError(t, PrepareTestDatabase())
 | 
						assert.NoError(t, PrepareTestDatabase())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	milestone := AssertExistsAndLoadBean(t, &Milestone{ID: 1}).(*Milestone)
 | 
						milestone := AssertExistsAndLoadBean(t, &Milestone{ID: 1}).(*Milestone)
 | 
				
			||||||
	milestone.Name = "newMilestoneName"
 | 
						milestone.Name = " newMilestoneName  "
 | 
				
			||||||
	milestone.Content = "newMilestoneContent"
 | 
						milestone.Content = "newMilestoneContent"
 | 
				
			||||||
	assert.NoError(t, UpdateMilestone(milestone))
 | 
						assert.NoError(t, UpdateMilestone(milestone, milestone.IsClosed))
 | 
				
			||||||
	AssertExistsAndLoadBean(t, milestone)
 | 
						milestone = AssertExistsAndLoadBean(t, &Milestone{ID: 1}).(*Milestone)
 | 
				
			||||||
 | 
						assert.EqualValues(t, "newMilestoneName", milestone.Name)
 | 
				
			||||||
	CheckConsistencyFor(t, &Milestone{})
 | 
						CheckConsistencyFor(t, &Milestone{})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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.
 | 
				
			||||||
@@ -67,7 +68,11 @@ type PullRequest struct {
 | 
				
			|||||||
// MustHeadUserName returns the HeadRepo's username if failed return blank
 | 
					// MustHeadUserName returns the HeadRepo's username if failed return blank
 | 
				
			||||||
func (pr *PullRequest) MustHeadUserName() string {
 | 
					func (pr *PullRequest) MustHeadUserName() string {
 | 
				
			||||||
	if err := pr.LoadHeadRepo(); err != nil {
 | 
						if err := pr.LoadHeadRepo(); err != nil {
 | 
				
			||||||
		log.Error("LoadHeadRepo: %v", err)
 | 
							if !IsErrRepoNotExist(err) {
 | 
				
			||||||
 | 
								log.Error("LoadHeadRepo: %v", err)
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								log.Warn("LoadHeadRepo %d but repository does not exist: %v", pr.HeadRepoID, err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		return ""
 | 
							return ""
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return pr.HeadRepo.MustOwnerName()
 | 
						return pr.HeadRepo.MustOwnerName()
 | 
				
			||||||
@@ -384,6 +389,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)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -408,7 +420,7 @@ func (pr *PullRequest) apiFormat(e Engine) *api.PullRequest {
 | 
				
			|||||||
		err        error
 | 
							err        error
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
	if err = pr.Issue.loadRepo(e); err != nil {
 | 
						if err = pr.Issue.loadRepo(e); err != nil {
 | 
				
			||||||
		log.Error("loadRepo[%d]: %v", pr.ID, err)
 | 
							log.Error("pr.Issue.loadRepo[%d]: %v", pr.ID, err)
 | 
				
			||||||
		return nil
 | 
							return nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	apiIssue := pr.Issue.apiFormat(e)
 | 
						apiIssue := pr.Issue.apiFormat(e)
 | 
				
			||||||
@@ -419,19 +431,14 @@ func (pr *PullRequest) apiFormat(e Engine) *api.PullRequest {
 | 
				
			|||||||
			return nil
 | 
								return nil
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if pr.HeadRepo == nil {
 | 
						if pr.HeadRepoID != 0 && pr.HeadRepo == nil {
 | 
				
			||||||
		pr.HeadRepo, err = getRepositoryByID(e, pr.HeadRepoID)
 | 
							pr.HeadRepo, err = getRepositoryByID(e, pr.HeadRepoID)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil && !IsErrRepoNotExist(err) {
 | 
				
			||||||
			log.Error("GetRepositoryById[%d]: %v", pr.ID, err)
 | 
								log.Error("GetRepositoryById[%d]: %v", pr.ID, err)
 | 
				
			||||||
			return nil
 | 
								return nil
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err = pr.Issue.loadRepo(e); err != nil {
 | 
					 | 
				
			||||||
		log.Error("pr.Issue.loadRepo[%d]: %v", pr.ID, err)
 | 
					 | 
				
			||||||
		return nil
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	apiPullRequest := &api.PullRequest{
 | 
						apiPullRequest := &api.PullRequest{
 | 
				
			||||||
		ID:        pr.ID,
 | 
							ID:        pr.ID,
 | 
				
			||||||
		URL:       pr.Issue.HTMLURL(),
 | 
							URL:       pr.Issue.HTMLURL(),
 | 
				
			||||||
@@ -483,37 +490,45 @@ func (pr *PullRequest) apiFormat(e Engine) *api.PullRequest {
 | 
				
			|||||||
		apiPullRequest.Base = apiBaseBranchInfo
 | 
							apiPullRequest.Base = apiBaseBranchInfo
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	headBranch, err = pr.HeadRepo.GetBranch(pr.HeadBranch)
 | 
						if pr.HeadRepo != nil {
 | 
				
			||||||
	if err != nil {
 | 
							headBranch, err = pr.HeadRepo.GetBranch(pr.HeadBranch)
 | 
				
			||||||
		if git.IsErrBranchNotExist(err) {
 | 
					 | 
				
			||||||
			apiPullRequest.Head = nil
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			log.Error("GetBranch[%s]: %v", pr.HeadBranch, err)
 | 
					 | 
				
			||||||
			return nil
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		apiHeadBranchInfo := &api.PRBranchInfo{
 | 
					 | 
				
			||||||
			Name:       pr.HeadBranch,
 | 
					 | 
				
			||||||
			Ref:        pr.HeadBranch,
 | 
					 | 
				
			||||||
			RepoID:     pr.HeadRepoID,
 | 
					 | 
				
			||||||
			Repository: pr.HeadRepo.innerAPIFormat(e, AccessModeNone, false),
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		headCommit, err = headBranch.GetCommit()
 | 
					 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			if git.IsErrNotExist(err) {
 | 
								if git.IsErrBranchNotExist(err) {
 | 
				
			||||||
				apiHeadBranchInfo.Sha = ""
 | 
									apiPullRequest.Head = nil
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
				log.Error("GetCommit[%s]: %v", headBranch.Name, err)
 | 
									log.Error("GetBranch[%s]: %v", pr.HeadBranch, err)
 | 
				
			||||||
				return nil
 | 
									return nil
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			apiHeadBranchInfo.Sha = headCommit.ID.String()
 | 
								apiHeadBranchInfo := &api.PRBranchInfo{
 | 
				
			||||||
 | 
									Name:       pr.HeadBranch,
 | 
				
			||||||
 | 
									Ref:        pr.HeadBranch,
 | 
				
			||||||
 | 
									RepoID:     pr.HeadRepoID,
 | 
				
			||||||
 | 
									Repository: pr.HeadRepo.innerAPIFormat(e, AccessModeNone, false),
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								headCommit, err = headBranch.GetCommit()
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									if git.IsErrNotExist(err) {
 | 
				
			||||||
 | 
										apiHeadBranchInfo.Sha = ""
 | 
				
			||||||
 | 
									} else {
 | 
				
			||||||
 | 
										log.Error("GetCommit[%s]: %v", headBranch.Name, err)
 | 
				
			||||||
 | 
										return nil
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									apiHeadBranchInfo.Sha = headCommit.ID.String()
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								apiPullRequest.Head = apiHeadBranchInfo
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							apiPullRequest.Head = &api.PRBranchInfo{
 | 
				
			||||||
 | 
								Name:   pr.HeadBranch,
 | 
				
			||||||
 | 
								Ref:    fmt.Sprintf("refs/pull/%d/head", pr.Index),
 | 
				
			||||||
 | 
								RepoID: -1,
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		apiPullRequest.Head = apiHeadBranchInfo
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	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 {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -204,6 +204,14 @@ type Repository struct {
 | 
				
			|||||||
	UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
 | 
						UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// SanitizedOriginalURL returns a sanitized OriginalURL
 | 
				
			||||||
 | 
					func (repo *Repository) SanitizedOriginalURL() string {
 | 
				
			||||||
 | 
						if repo.OriginalURL == "" {
 | 
				
			||||||
 | 
							return ""
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return util.SanitizeURLCredentials(repo.OriginalURL, false)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ColorFormat returns a colored string to represent this repo
 | 
					// ColorFormat returns a colored string to represent this repo
 | 
				
			||||||
func (repo *Repository) ColorFormat(s fmt.State) {
 | 
					func (repo *Repository) ColorFormat(s fmt.State) {
 | 
				
			||||||
	var ownerName interface{}
 | 
						var ownerName interface{}
 | 
				
			||||||
@@ -1902,6 +1910,12 @@ func DeleteRepository(doer *User, uid, repoID int64) error {
 | 
				
			|||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if len(repo.Topics) > 0 {
 | 
				
			||||||
 | 
							if err = removeTopicsFromRepo(sess, repo.ID); err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// FIXME: Remove repository files should be executed after transaction succeed.
 | 
						// FIXME: Remove repository files should be executed after transaction succeed.
 | 
				
			||||||
	repoPath := repo.repoPath(sess)
 | 
						repoPath := repo.repoPath(sess)
 | 
				
			||||||
	removeAllWithNotice(sess, "Delete repository files", repoPath)
 | 
						removeAllWithNotice(sess, "Delete repository files", repoPath)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -315,6 +315,17 @@ func SearchRepository(opts *SearchRepoOptions) (RepositoryList, int64, error) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// accessibleRepositoryCondition takes a user a returns a condition for checking if a repository is accessible
 | 
					// accessibleRepositoryCondition takes a user a returns a condition for checking if a repository is accessible
 | 
				
			||||||
func accessibleRepositoryCondition(userID int64) builder.Cond {
 | 
					func accessibleRepositoryCondition(userID int64) builder.Cond {
 | 
				
			||||||
 | 
						if userID <= 0 {
 | 
				
			||||||
 | 
							return builder.And(
 | 
				
			||||||
 | 
								builder.Eq{"`repository`.is_private": false},
 | 
				
			||||||
 | 
								builder.Or(
 | 
				
			||||||
 | 
									//   A. Aren't in organisations  __OR__
 | 
				
			||||||
 | 
									builder.NotIn("`repository`.owner_id", builder.Select("id").From("`user`").Where(builder.Eq{"type": UserTypeOrganization})),
 | 
				
			||||||
 | 
									//   B. Is a public organisation.
 | 
				
			||||||
 | 
									builder.In("`repository`.owner_id", builder.Select("id").From("`user`").Where(builder.Eq{"visibility": structs.VisibleTypePublic}))),
 | 
				
			||||||
 | 
							)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return builder.Or(
 | 
						return builder.Or(
 | 
				
			||||||
		// 1. Be able to see all non-private repositories that either:
 | 
							// 1. Be able to see all non-private repositories that either:
 | 
				
			||||||
		builder.And(
 | 
							builder.And(
 | 
				
			||||||
@@ -349,6 +360,12 @@ func SearchRepositoryByName(opts *SearchRepoOptions) (RepositoryList, int64, err
 | 
				
			|||||||
	return SearchRepository(opts)
 | 
						return SearchRepository(opts)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// AccessibleRepoIDsQuery queries accessible repository ids. Usable as a subquery wherever repo ids need to be filtered.
 | 
				
			||||||
 | 
					func AccessibleRepoIDsQuery(userID int64) *builder.Builder {
 | 
				
			||||||
 | 
						// NB: Please note this code needs to still work if user is nil
 | 
				
			||||||
 | 
						return builder.Select("id").From("repository").Where(accessibleRepositoryCondition(userID))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// FindUserAccessibleRepoIDs find all accessible repositories' ID by user's id
 | 
					// FindUserAccessibleRepoIDs find all accessible repositories' ID by user's id
 | 
				
			||||||
func FindUserAccessibleRepoIDs(userID int64) ([]int64, error) {
 | 
					func FindUserAccessibleRepoIDs(userID int64) ([]int64, error) {
 | 
				
			||||||
	var accessCond builder.Cond = builder.Eq{"is_private": false}
 | 
						var accessCond builder.Cond = builder.Eq{"is_private": false}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -129,7 +129,7 @@ func addTopicByNameToRepo(e Engine, repoID int64, topicName string) (*Topic, err
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// removeTopicFromRepo remove a topic from a repo and decrements the topic repo count
 | 
					// removeTopicFromRepo remove a topic from a repo and decrements the topic repo count
 | 
				
			||||||
func removeTopicFromRepo(repoID int64, topic *Topic, e Engine) error {
 | 
					func removeTopicFromRepo(e Engine, repoID int64, topic *Topic) error {
 | 
				
			||||||
	topic.RepoCount--
 | 
						topic.RepoCount--
 | 
				
			||||||
	if _, err := e.ID(topic.ID).Cols("repo_count").Update(topic); err != nil {
 | 
						if _, err := e.ID(topic.ID).Cols("repo_count").Update(topic); err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
@@ -145,6 +145,24 @@ func removeTopicFromRepo(repoID int64, topic *Topic, e Engine) error {
 | 
				
			|||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// removeTopicsFromRepo remove all topics from the repo and decrements respective topics repo count
 | 
				
			||||||
 | 
					func removeTopicsFromRepo(e Engine, repoID int64) error {
 | 
				
			||||||
 | 
						_, err := e.Where(
 | 
				
			||||||
 | 
							builder.In("id",
 | 
				
			||||||
 | 
								builder.Select("topic_id").From("repo_topic").Where(builder.Eq{"repo_id": repoID}),
 | 
				
			||||||
 | 
							),
 | 
				
			||||||
 | 
						).Cols("repo_count").SetExpr("repo_count", "repo_count-1").Update(&Topic{})
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if _, err = e.Delete(&RepoTopic{RepoID: repoID}); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// FindTopicOptions represents the options when fdin topics
 | 
					// FindTopicOptions represents the options when fdin topics
 | 
				
			||||||
type FindTopicOptions struct {
 | 
					type FindTopicOptions struct {
 | 
				
			||||||
	RepoID  int64
 | 
						RepoID  int64
 | 
				
			||||||
@@ -217,7 +235,7 @@ func DeleteTopic(repoID int64, topicName string) (*Topic, error) {
 | 
				
			|||||||
		return nil, nil
 | 
							return nil, nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = removeTopicFromRepo(repoID, topic, x)
 | 
						err = removeTopicFromRepo(x, repoID, topic)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return topic, err
 | 
						return topic, err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -278,7 +296,7 @@ func SaveTopics(repoID int64, topicNames ...string) error {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, topic := range removeTopics {
 | 
						for _, topic := range removeTopics {
 | 
				
			||||||
		err := removeTopicFromRepo(repoID, topic, sess)
 | 
							err := removeTopicFromRepo(sess, repoID, topic)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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():
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,10 +7,12 @@ package graceful
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"crypto/tls"
 | 
						"crypto/tls"
 | 
				
			||||||
 | 
						"io/ioutil"
 | 
				
			||||||
	"net"
 | 
						"net"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"sync"
 | 
						"sync"
 | 
				
			||||||
 | 
						"sync/atomic"
 | 
				
			||||||
	"syscall"
 | 
						"syscall"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -99,12 +101,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)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -201,9 +216,12 @@ func (wl *wrappedListener) Accept() (net.Conn, error) {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						closed := int32(0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	c = wrappedConn{
 | 
						c = wrappedConn{
 | 
				
			||||||
		Conn:   c,
 | 
							Conn:   c,
 | 
				
			||||||
		server: wl.server,
 | 
							server: wl.server,
 | 
				
			||||||
 | 
							closed: &closed,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wl.server.wg.Add(1)
 | 
						wl.server.wg.Add(1)
 | 
				
			||||||
@@ -227,12 +245,12 @@ func (wl *wrappedListener) File() (*os.File, error) {
 | 
				
			|||||||
type wrappedConn struct {
 | 
					type wrappedConn struct {
 | 
				
			||||||
	net.Conn
 | 
						net.Conn
 | 
				
			||||||
	server *Server
 | 
						server *Server
 | 
				
			||||||
 | 
						closed *int32
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (w wrappedConn) Close() error {
 | 
					func (w wrappedConn) Close() error {
 | 
				
			||||||
	err := w.Conn.Close()
 | 
						if atomic.CompareAndSwapInt32(w.closed, 0, 1) {
 | 
				
			||||||
	if err == nil {
 | 
					 | 
				
			||||||
		w.server.wg.Done()
 | 
							w.server.wg.Done()
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return err
 | 
						return w.Conn.Close()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -116,7 +116,12 @@ func nonGenesisChanges(repo *models.Repository, revision string) (*repoChanges,
 | 
				
			|||||||
		if len(line) == 0 {
 | 
							if len(line) == 0 {
 | 
				
			||||||
			continue
 | 
								continue
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		filename := strings.TrimSpace(line[1:])
 | 
							fields := strings.Split(line, "\t")
 | 
				
			||||||
 | 
							if len(fields) < 2 {
 | 
				
			||||||
 | 
								log.Warn("Unparseable output for diff --name-status: `%s`)", line)
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							filename := fields[1]
 | 
				
			||||||
		if len(filename) == 0 {
 | 
							if len(filename) == 0 {
 | 
				
			||||||
			continue
 | 
								continue
 | 
				
			||||||
		} else if filename[0] == '"' {
 | 
							} else if filename[0] == '"' {
 | 
				
			||||||
@@ -126,11 +131,31 @@ func nonGenesisChanges(repo *models.Repository, revision string) (*repoChanges,
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		switch status := line[0]; status {
 | 
							switch status := fields[0][0]; status {
 | 
				
			||||||
		case 'M', 'A':
 | 
							case 'M', 'A':
 | 
				
			||||||
			updatedFilenames = append(updatedFilenames, filename)
 | 
								updatedFilenames = append(updatedFilenames, filename)
 | 
				
			||||||
		case 'D':
 | 
							case 'D':
 | 
				
			||||||
			changes.RemovedFilenames = append(changes.RemovedFilenames, filename)
 | 
								changes.RemovedFilenames = append(changes.RemovedFilenames, filename)
 | 
				
			||||||
 | 
							case 'R', 'C':
 | 
				
			||||||
 | 
								if len(fields) < 3 {
 | 
				
			||||||
 | 
									log.Warn("Unparseable output for diff --name-status: `%s`)", line)
 | 
				
			||||||
 | 
									continue
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								dest := fields[2]
 | 
				
			||||||
 | 
								if len(dest) == 0 {
 | 
				
			||||||
 | 
									log.Warn("Unparseable output for diff --name-status: `%s`)", line)
 | 
				
			||||||
 | 
									continue
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if dest[0] == '"' {
 | 
				
			||||||
 | 
									dest, err = strconv.Unquote(dest)
 | 
				
			||||||
 | 
									if err != nil {
 | 
				
			||||||
 | 
										return nil, err
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if status == 'R' {
 | 
				
			||||||
 | 
									changes.RemovedFilenames = append(changes.RemovedFilenames, filename)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								updatedFilenames = append(updatedFilenames, dest)
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			log.Warn("Unrecognized status: %c (line=%s)", status, line)
 | 
								log.Warn("Unrecognized status: %c (line=%s)", status, line)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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,
 | 
				
			||||||
					}),
 | 
										}),
 | 
				
			||||||
				),
 | 
									),
 | 
				
			||||||
			),
 | 
								),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,6 +6,7 @@ package indexer
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"code.gitea.io/gitea/models"
 | 
						"code.gitea.io/gitea/models"
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/git"
 | 
				
			||||||
	code_indexer "code.gitea.io/gitea/modules/indexer/code"
 | 
						code_indexer "code.gitea.io/gitea/modules/indexer/code"
 | 
				
			||||||
	issue_indexer "code.gitea.io/gitea/modules/indexer/issues"
 | 
						issue_indexer "code.gitea.io/gitea/modules/indexer/issues"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/log"
 | 
						"code.gitea.io/gitea/modules/log"
 | 
				
			||||||
@@ -118,7 +119,7 @@ func (r *indexerNotifier) NotifyMigrateRepository(doer *models.User, u *models.U
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (r *indexerNotifier) NotifyPushCommits(pusher *models.User, repo *models.Repository, refName, oldCommitID, newCommitID string, commits *models.PushCommits) {
 | 
					func (r *indexerNotifier) NotifyPushCommits(pusher *models.User, repo *models.Repository, refName, oldCommitID, newCommitID string, commits *models.PushCommits) {
 | 
				
			||||||
	if setting.Indexer.RepoIndexerEnabled && refName == repo.DefaultBranch {
 | 
						if setting.Indexer.RepoIndexerEnabled && refName == git.BranchPrefix+repo.DefaultBranch {
 | 
				
			||||||
		code_indexer.UpdateRepoIndexer(repo)
 | 
							code_indexer.UpdateRepoIndexer(repo)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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{}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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 {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -475,9 +475,18 @@ func PushUpdate(repo *models.Repository, branch string, opts PushUpdateOptions)
 | 
				
			|||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	log.Trace("TriggerTask '%s/%s' by %s", repo.Name, branch, pusher.Name)
 | 
						if !isDelRef {
 | 
				
			||||||
 | 
							if err = models.RemoveDeletedBranch(repo.ID, opts.Branch); err != nil {
 | 
				
			||||||
 | 
								log.Error("models.RemoveDeletedBranch %s/%s failed: %v", repo.ID, opts.Branch, err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	go pull_service.AddTestPullRequestTask(pusher, repo.ID, branch, true)
 | 
							log.Trace("TriggerTask '%s/%s' by %s", repo.Name, branch, pusher.Name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							go pull_service.AddTestPullRequestTask(pusher, repo.ID, branch, true)
 | 
				
			||||||
 | 
							// close all related pulls
 | 
				
			||||||
 | 
						} else if err = pull_service.CloseBranchPulls(pusher, repo.ID, branch); err != nil {
 | 
				
			||||||
 | 
							log.Error("close related pull request failed: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err = models.WatchIfAuto(opts.PusherID, repo.ID, true); err != nil {
 | 
						if err = models.WatchIfAuto(opts.PusherID, repo.ID, true); err != nil {
 | 
				
			||||||
		log.Warn("Fail to perform auto watch on user %v for repo %v: %v", opts.PusherID, repo.ID, err)
 | 
							log.Warn("Fail to perform auto watch on user %v for repo %v: %v", opts.PusherID, repo.ID, err)
 | 
				
			||||||
@@ -524,12 +533,15 @@ func PushUpdates(repo *models.Repository, optsList []*PushUpdateOptions) error {
 | 
				
			|||||||
			if err = models.RemoveDeletedBranch(repo.ID, opts.Branch); err != nil {
 | 
								if err = models.RemoveDeletedBranch(repo.ID, opts.Branch); err != nil {
 | 
				
			||||||
				log.Error("models.RemoveDeletedBranch %s/%s failed: %v", repo.ID, opts.Branch, err)
 | 
									log.Error("models.RemoveDeletedBranch %s/%s failed: %v", repo.ID, opts.Branch, err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								log.Trace("TriggerTask '%s/%s' by %s", repo.Name, opts.Branch, pusher.Name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								go pull_service.AddTestPullRequestTask(pusher, repo.ID, opts.Branch, true)
 | 
				
			||||||
 | 
								// close all related pulls
 | 
				
			||||||
 | 
							} else if err = pull_service.CloseBranchPulls(pusher, repo.ID, opts.Branch); err != nil {
 | 
				
			||||||
 | 
								log.Error("close related pull request failed: %v", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		log.Trace("TriggerTask '%s/%s' by %s", repo.Name, opts.Branch, pusher.Name)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		go pull_service.AddTestPullRequestTask(pusher, repo.ID, opts.Branch, true)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if err = models.WatchIfAuto(opts.PusherID, repo.ID, true); err != nil {
 | 
							if err = models.WatchIfAuto(opts.PusherID, repo.ID, true); err != nil {
 | 
				
			||||||
			log.Warn("Fail to perform auto watch on user %v for repo %v: %v", opts.PusherID, repo.ID, err)
 | 
								log.Warn("Fail to perform auto watch on user %v for repo %v: %v", opts.PusherID, repo.ID, err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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 {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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":
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										63
									
								
								modules/structs/commit_status.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								modules/structs/commit_status.go
									
									
									
									
									
										Normal 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
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -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"`
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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{}{}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,8 @@ package util
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"net/url"
 | 
						"net/url"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/log"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// urlSafeError wraps an error whose message may contain a sensitive URL
 | 
					// urlSafeError wraps an error whose message may contain a sensitive URL
 | 
				
			||||||
@@ -36,6 +38,7 @@ func SanitizeMessage(message, unsanitizedURL string) string {
 | 
				
			|||||||
func SanitizeURLCredentials(unsanitizedURL string, usePlaceholder bool) string {
 | 
					func SanitizeURLCredentials(unsanitizedURL string, usePlaceholder bool) string {
 | 
				
			||||||
	u, err := url.Parse(unsanitizedURL)
 | 
						u, err := url.Parse(unsanitizedURL)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Error("parse url %s failed: %v", unsanitizedURL, err)
 | 
				
			||||||
		// don't log the error, since it might contain unsanitized URL.
 | 
							// don't log the error, since it might contain unsanitized URL.
 | 
				
			||||||
		return "(unparsable url)"
 | 
							return "(unparsable url)"
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										25
									
								
								modules/util/sanitize_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								modules/util/sanitize_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					// 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 util
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/stretchr/testify/assert"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestSanitizeURLCredentials(t *testing.T) {
 | 
				
			||||||
 | 
						var kases = map[string]string{
 | 
				
			||||||
 | 
							"https://github.com/go-gitea/test_repo.git":         "https://github.com/go-gitea/test_repo.git",
 | 
				
			||||||
 | 
							"https://mytoken@github.com/go-gitea/test_repo.git": "https://github.com/go-gitea/test_repo.git",
 | 
				
			||||||
 | 
							"http://github.com/go-gitea/test_repo.git":          "http://github.com/go-gitea/test_repo.git",
 | 
				
			||||||
 | 
							"/test/repos/repo1":                                 "/test/repos/repo1",
 | 
				
			||||||
 | 
							"git@github.com:go-gitea/test_repo.git":             "(unparsable url)",
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for source, value := range kases {
 | 
				
			||||||
 | 
							assert.EqualValues(t, value, SanitizeURLCredentials(source, false))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -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
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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,
 | 
				
			||||||
					},
 | 
										},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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.
 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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.
 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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.
 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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=شما اجازه دسترسی به این قسمت مخزن را ندارید.
 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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.
 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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=このセクションへのアクセスが許可されていません。
 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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=초기 설정
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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.
 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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.
 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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.
 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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.
 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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=У вас немає доступу до жодного розділу цього репозитория.
 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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=您没有权限访问此仓库单元
 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1
									
								
								public/vendor/plugins/fomantic/semantic.css
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								public/vendor/plugins/fomantic/semantic.css
									
									
									
									
										vendored
									
									
								
							@@ -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/
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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/
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,7 @@ package admin
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"errors"
 | 
						"errors"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"code.gitea.io/gitea/models"
 | 
						"code.gitea.io/gitea/models"
 | 
				
			||||||
@@ -226,6 +227,11 @@ func DeleteUser(ctx *context.APIContext) {
 | 
				
			|||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if u.IsOrganization() {
 | 
				
			||||||
 | 
							ctx.Error(http.StatusUnprocessableEntity, "", fmt.Errorf("%s is an organization not a user", u.Name))
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := models.DeleteUser(u); err != nil {
 | 
						if err := models.DeleteUser(u); err != nil {
 | 
				
			||||||
		if models.IsErrUserOwnRepos(err) ||
 | 
							if models.IsErrUserOwnRepos(err) ||
 | 
				
			||||||
			models.IsErrUserHasOrgs(err) {
 | 
								models.IsErrUserHasOrgs(err) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -194,7 +194,12 @@ func EditMilestone(ctx *context.APIContext, form api.EditMilestoneOption) {
 | 
				
			|||||||
		milestone.DeadlineUnix = timeutil.TimeStamp(form.Deadline.Unix())
 | 
							milestone.DeadlineUnix = timeutil.TimeStamp(form.Deadline.Unix())
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := models.UpdateMilestone(milestone); err != nil {
 | 
						var oldIsClosed = milestone.IsClosed
 | 
				
			||||||
 | 
						if form.State != nil {
 | 
				
			||||||
 | 
							milestone.IsClosed = *form.State == string(api.StateClosed)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err := models.UpdateMilestone(milestone, oldIsClosed); err != nil {
 | 
				
			||||||
		ctx.ServerError("UpdateMilestone", err)
 | 
							ctx.ServerError("UpdateMilestone", err)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -115,7 +115,7 @@ func SettingsDeleteAvatar(ctx *context.Context) {
 | 
				
			|||||||
	ctx.Redirect(ctx.Org.OrgLink + "/settings")
 | 
						ctx.Redirect(ctx.Org.OrgLink + "/settings")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// SettingsDelete response for delete repository
 | 
					// SettingsDelete response for deleting an organization
 | 
				
			||||||
func SettingsDelete(ctx *context.Context) {
 | 
					func SettingsDelete(ctx *context.Context) {
 | 
				
			||||||
	ctx.Data["Title"] = ctx.Tr("org.settings")
 | 
						ctx.Data["Title"] = ctx.Tr("org.settings")
 | 
				
			||||||
	ctx.Data["PageIsSettingsDelete"] = true
 | 
						ctx.Data["PageIsSettingsDelete"] = true
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -68,7 +68,6 @@ func ServNoCommand(ctx *macaron.Context) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// ServCommand returns information about the provided keyid
 | 
					// ServCommand returns information about the provided keyid
 | 
				
			||||||
func ServCommand(ctx *macaron.Context) {
 | 
					func ServCommand(ctx *macaron.Context) {
 | 
				
			||||||
	// Although we provide the verbs we don't need them at present they're just for logging purposes
 | 
					 | 
				
			||||||
	keyID := ctx.ParamsInt64(":keyid")
 | 
						keyID := ctx.ParamsInt64(":keyid")
 | 
				
			||||||
	ownerName := ctx.Params(":owner")
 | 
						ownerName := ctx.Params(":owner")
 | 
				
			||||||
	repoName := ctx.Params(":repo")
 | 
						repoName := ctx.Params(":repo")
 | 
				
			||||||
@@ -105,6 +104,17 @@ func ServCommand(ctx *macaron.Context) {
 | 
				
			|||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		if models.IsErrRepoNotExist(err) {
 | 
							if models.IsErrRepoNotExist(err) {
 | 
				
			||||||
			repoExist = false
 | 
								repoExist = false
 | 
				
			||||||
 | 
								for _, verb := range ctx.QueryStrings("verb") {
 | 
				
			||||||
 | 
									if "git-upload-pack" == verb {
 | 
				
			||||||
 | 
										// User is fetching/cloning a non-existent repository
 | 
				
			||||||
 | 
										ctx.JSON(http.StatusNotFound, map[string]interface{}{
 | 
				
			||||||
 | 
											"results": results,
 | 
				
			||||||
 | 
											"type":    "ErrRepoNotExist",
 | 
				
			||||||
 | 
											"err":     fmt.Sprintf("Cannot find repository: %s/%s", results.OwnerName, results.RepoName),
 | 
				
			||||||
 | 
										})
 | 
				
			||||||
 | 
										return
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			log.Error("Unable to get repository: %s/%s Error: %v", results.OwnerName, results.RepoName, err)
 | 
								log.Error("Unable to get repository: %s/%s Error: %v", results.OwnerName, results.RepoName, err)
 | 
				
			||||||
			ctx.JSON(http.StatusInternalServerError, map[string]interface{}{
 | 
								ctx.JSON(http.StatusInternalServerError, map[string]interface{}{
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -238,6 +238,7 @@ func loadBranches(ctx *context.Context) []*Branch {
 | 
				
			|||||||
			} else {
 | 
								} else {
 | 
				
			||||||
				repoIDToRepo[pr.BaseRepoID] = pr.BaseRepo
 | 
									repoIDToRepo[pr.BaseRepoID] = pr.BaseRepo
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
								pr.Issue.Repo = pr.BaseRepo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if pr.HasMerged {
 | 
								if pr.HasMerged {
 | 
				
			||||||
				baseGitRepo, ok := repoIDToGitRepo[pr.BaseRepoID]
 | 
									baseGitRepo, ok := repoIDToGitRepo[pr.BaseRepoID]
 | 
				
			||||||
@@ -260,7 +261,6 @@ func loadBranches(ctx *context.Context) []*Branch {
 | 
				
			|||||||
					mergeMovedOn = true
 | 
										mergeMovedOn = true
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		isIncluded := divergence.Ahead == 0 && ctx.Repo.Repository.DefaultBranch != branchName
 | 
							isIncluded := divergence.Ahead == 0 && ctx.Repo.Repository.DefaultBranch != branchName
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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
 | 
				
			||||||
 
 | 
				
			|||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user