mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-11-03 08:02:36 +09:00 
			
		
		
		
	Compare commits
	
		
			114 Commits
		
	
	
		
			v1.20.0-de
			...
			v1.19.0
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					726d6a5077 | ||
| 
						 | 
					b33cae7a3a | ||
| 
						 | 
					854fcb1434 | ||
| 
						 | 
					4730ed18f1 | ||
| 
						 | 
					937996c74c | ||
| 
						 | 
					3f253b3f5a | ||
| 
						 | 
					f5a98b0f5b | ||
| 
						 | 
					1a97a84023 | ||
| 
						 | 
					420d015b76 | ||
| 
						 | 
					22911a1ece | ||
| 
						 | 
					4b763d8d37 | ||
| 
						 | 
					1254fc668a | ||
| 
						 | 
					09824025f7 | ||
| 
						 | 
					bd1a915bdb | ||
| 
						 | 
					cab7044772 | ||
| 
						 | 
					68c9f1abd8 | ||
| 
						 | 
					301de3ab6b | ||
| 
						 | 
					8f8bd3c0cb | ||
| 
						 | 
					23a6fa9421 | ||
| 
						 | 
					b7c2f48ebf | ||
| 
						 | 
					70e31b4aa0 | ||
| 
						 | 
					d73846f0b4 | ||
| 
						 | 
					527bbf67e8 | ||
| 
						 | 
					5feb31f219 | ||
| 
						 | 
					31efbafbe3 | ||
| 
						 | 
					28af02eea0 | ||
| 
						 | 
					c698a6fc5d | ||
| 
						 | 
					e5a51eca45 | ||
| 
						 | 
					8536dc4b73 | ||
| 
						 | 
					0a0f46f299 | ||
| 
						 | 
					1543ac9c8d | ||
| 
						 | 
					c3c0710412 | ||
| 
						 | 
					fa33919e24 | ||
| 
						 | 
					b1162495af | ||
| 
						 | 
					41655ee878 | ||
| 
						 | 
					0d9b44c0e3 | ||
| 
						 | 
					e87f36e885 | ||
| 
						 | 
					b301cb17a3 | ||
| 
						 | 
					e259daeff8 | ||
| 
						 | 
					edb618c136 | ||
| 
						 | 
					43cf04c031 | ||
| 
						 | 
					e9991b1f06 | ||
| 
						 | 
					975785dd42 | ||
| 
						 | 
					e269e8901f | ||
| 
						 | 
					87c31c2ffe | ||
| 
						 | 
					54c674c936 | ||
| 
						 | 
					2ba58fab22 | ||
| 
						 | 
					cd7bd8568c | ||
| 
						 | 
					cf80f829b4 | ||
| 
						 | 
					ed25e094ab | ||
| 
						 | 
					10df304b2f | ||
| 
						 | 
					ecae62837c | ||
| 
						 | 
					e8e871b44e | ||
| 
						 | 
					6be6c19daf | ||
| 
						 | 
					61f91bdc7e | ||
| 
						 | 
					8ab50be000 | ||
| 
						 | 
					dfab6e2d1c | ||
| 
						 | 
					2f7bbdf8c9 | ||
| 
						 | 
					af4767df5c | ||
| 
						 | 
					233a399706 | ||
| 
						 | 
					dcf1717793 | ||
| 
						 | 
					b1e68f39e7 | ||
| 
						 | 
					ee3d9330a8 | ||
| 
						 | 
					d1d15306d1 | ||
| 
						 | 
					e3b1ebbbfe | ||
| 
						 | 
					17ae7e335e | ||
| 
						 | 
					1edb57eda9 | ||
| 
						 | 
					a2a9b0f977 | ||
| 
						 | 
					ff96f804b6 | ||
| 
						 | 
					a926994bfe | ||
| 
						 | 
					83903535e3 | ||
| 
						 | 
					8142408d3a | ||
| 
						 | 
					a4158d1904 | ||
| 
						 | 
					781019216c | ||
| 
						 | 
					1322cd7a58 | ||
| 
						 | 
					464bbd747e | ||
| 
						 | 
					574182e1eb | ||
| 
						 | 
					ef8209a953 | ||
| 
						 | 
					9309098eab | ||
| 
						 | 
					790a79b04c | ||
| 
						 | 
					f8a40dafb9 | ||
| 
						 | 
					9843a0b741 | ||
| 
						 | 
					085a4debd5 | ||
| 
						 | 
					4c1e24864f | ||
| 
						 | 
					5d5f907e7f | ||
| 
						 | 
					39178b5756 | ||
| 
						 | 
					3d8412dd51 | ||
| 
						 | 
					ff7057a46d | ||
| 
						 | 
					bb8ef28913 | ||
| 
						 | 
					13918ad344 | ||
| 
						 | 
					7528ce60e7 | ||
| 
						 | 
					6c6a7e7d97 | ||
| 
						 | 
					111c509287 | ||
| 
						 | 
					9d7ef0ad63 | ||
| 
						 | 
					9aae54c81f | ||
| 
						 | 
					1bc4ffc337 | ||
| 
						 | 
					27879bc45e | ||
| 
						 | 
					a3694b6989 | ||
| 
						 | 
					28625fba5b | ||
| 
						 | 
					7c3196ceac | ||
| 
						 | 
					80c1264f4b | ||
| 
						 | 
					f0340c28f1 | ||
| 
						 | 
					5beb29ad35 | ||
| 
						 | 
					27e307142b | ||
| 
						 | 
					e02e752f68 | ||
| 
						 | 
					5ddf67a9c2 | ||
| 
						 | 
					4d3e2b23b8 | ||
| 
						 | 
					ddf61373f6 | ||
| 
						 | 
					b4ed3f07e4 | ||
| 
						 | 
					ced94f2e0d | ||
| 
						 | 
					aff432b197 | ||
| 
						 | 
					0ac3be1482 | ||
| 
						 | 
					75eaf99076 | ||
| 
						 | 
					e67d60d336 | 
							
								
								
									
										129
									
								
								.drone.yml
									
									
									
									
									
								
							
							
						
						
									
										129
									
								
								.drone.yml
									
									
									
									
									
								
							@@ -43,7 +43,7 @@ steps:
 | 
			
		||||
    depends_on: [deps-frontend]
 | 
			
		||||
 | 
			
		||||
  - name: lint-backend
 | 
			
		||||
    image: gitea/test_env:linux-amd64  # https://gitea.com/gitea/test-env
 | 
			
		||||
    image: gitea/test_env:linux-1.19-amd64  # https://gitea.com/gitea/test-env
 | 
			
		||||
    pull: always
 | 
			
		||||
    commands:
 | 
			
		||||
      - make lint-backend
 | 
			
		||||
@@ -57,7 +57,7 @@ steps:
 | 
			
		||||
        path: /go
 | 
			
		||||
 | 
			
		||||
  - name: lint-backend-windows
 | 
			
		||||
    image: gitea/test_env:linux-amd64  # https://gitea.com/gitea/test-env
 | 
			
		||||
    image: gitea/test_env:linux-1.19-amd64  # https://gitea.com/gitea/test-env
 | 
			
		||||
    commands:
 | 
			
		||||
      - make golangci-lint-windows vet
 | 
			
		||||
    environment:
 | 
			
		||||
@@ -72,7 +72,7 @@ steps:
 | 
			
		||||
        path: /go
 | 
			
		||||
 | 
			
		||||
  - name: lint-backend-gogit
 | 
			
		||||
    image: gitea/test_env:linux-amd64  # https://gitea.com/gitea/test-env
 | 
			
		||||
    image: gitea/test_env:linux-1.19-amd64  # https://gitea.com/gitea/test-env
 | 
			
		||||
    commands:
 | 
			
		||||
      - make lint-backend
 | 
			
		||||
    environment:
 | 
			
		||||
@@ -264,13 +264,13 @@ steps:
 | 
			
		||||
      - git update-ref refs/heads/tag_test ${DRONE_COMMIT_SHA}
 | 
			
		||||
 | 
			
		||||
  - name: prepare-test-env
 | 
			
		||||
    image: gitea/test_env:linux-amd64  # https://gitea.com/gitea/test-env
 | 
			
		||||
    image: gitea/test_env:linux-1.19-amd64  # https://gitea.com/gitea/test-env
 | 
			
		||||
    pull: always
 | 
			
		||||
    commands:
 | 
			
		||||
      - ./build/test-env-prepare.sh
 | 
			
		||||
 | 
			
		||||
  - name: build
 | 
			
		||||
    image: gitea/test_env:linux-amd64  # https://gitea.com/gitea/test-env
 | 
			
		||||
    image: gitea/test_env:linux-1.19-amd64  # https://gitea.com/gitea/test-env
 | 
			
		||||
    user: gitea
 | 
			
		||||
    commands:
 | 
			
		||||
      - ./build/test-env-check.sh
 | 
			
		||||
@@ -285,7 +285,7 @@ steps:
 | 
			
		||||
        path: /go
 | 
			
		||||
 | 
			
		||||
  - name: unit-test
 | 
			
		||||
    image: gitea/test_env:linux-amd64  # https://gitea.com/gitea/test-env
 | 
			
		||||
    image: gitea/test_env:linux-1.19-amd64  # https://gitea.com/gitea/test-env
 | 
			
		||||
    user: gitea
 | 
			
		||||
    commands:
 | 
			
		||||
      - make unit-test-coverage test-check
 | 
			
		||||
@@ -301,7 +301,7 @@ steps:
 | 
			
		||||
        path: /go
 | 
			
		||||
 | 
			
		||||
  - name: unit-test-gogit
 | 
			
		||||
    image: gitea/test_env:linux-amd64  # https://gitea.com/gitea/test-env
 | 
			
		||||
    image: gitea/test_env:linux-1.19-amd64  # https://gitea.com/gitea/test-env
 | 
			
		||||
    user: gitea
 | 
			
		||||
    commands:
 | 
			
		||||
      - make unit-test-coverage test-check
 | 
			
		||||
@@ -317,7 +317,7 @@ steps:
 | 
			
		||||
        path: /go
 | 
			
		||||
 | 
			
		||||
  - name: test-mysql
 | 
			
		||||
    image: gitea/test_env:linux-amd64  # https://gitea.com/gitea/test-env
 | 
			
		||||
    image: gitea/test_env:linux-1.19-amd64  # https://gitea.com/gitea/test-env
 | 
			
		||||
    user: gitea
 | 
			
		||||
    commands:
 | 
			
		||||
      - make test-mysql-migration integration-test-coverage
 | 
			
		||||
@@ -334,7 +334,7 @@ steps:
 | 
			
		||||
        path: /go
 | 
			
		||||
 | 
			
		||||
  - name: test-mysql8
 | 
			
		||||
    image: gitea/test_env:linux-amd64  # https://gitea.com/gitea/test-env
 | 
			
		||||
    image: gitea/test_env:linux-1.19-amd64  # https://gitea.com/gitea/test-env
 | 
			
		||||
    user: gitea
 | 
			
		||||
    commands:
 | 
			
		||||
      - timeout -s ABRT 50m make test-mysql8-migration test-mysql8
 | 
			
		||||
@@ -350,7 +350,7 @@ steps:
 | 
			
		||||
        path: /go
 | 
			
		||||
 | 
			
		||||
  - name: test-mssql
 | 
			
		||||
    image: gitea/test_env:linux-amd64  # https://gitea.com/gitea/test-env
 | 
			
		||||
    image: gitea/test_env:linux-1.19-amd64  # https://gitea.com/gitea/test-env
 | 
			
		||||
    user: gitea
 | 
			
		||||
    commands:
 | 
			
		||||
      - make test-mssql-migration test-mssql
 | 
			
		||||
@@ -454,13 +454,13 @@ steps:
 | 
			
		||||
        path: /go
 | 
			
		||||
 | 
			
		||||
  - name: prepare-test-env
 | 
			
		||||
    image: gitea/test_env:linux-arm64  # https://gitea.com/gitea/test-env
 | 
			
		||||
    image: gitea/test_env:linux-1.19-arm64  # https://gitea.com/gitea/test-env
 | 
			
		||||
    pull: always
 | 
			
		||||
    commands:
 | 
			
		||||
      - ./build/test-env-prepare.sh
 | 
			
		||||
 | 
			
		||||
  - name: build
 | 
			
		||||
    image: gitea/test_env:linux-arm64  # https://gitea.com/gitea/test-env
 | 
			
		||||
    image: gitea/test_env:linux-1.19-arm64  # https://gitea.com/gitea/test-env
 | 
			
		||||
    user: gitea
 | 
			
		||||
    commands:
 | 
			
		||||
      - ./build/test-env-check.sh
 | 
			
		||||
@@ -475,7 +475,7 @@ steps:
 | 
			
		||||
        path: /go
 | 
			
		||||
 | 
			
		||||
  - name: test-sqlite
 | 
			
		||||
    image: gitea/test_env:linux-arm64  # https://gitea.com/gitea/test-env
 | 
			
		||||
    image: gitea/test_env:linux-1.19-arm64  # https://gitea.com/gitea/test-env
 | 
			
		||||
    user: gitea
 | 
			
		||||
    commands:
 | 
			
		||||
      - timeout -s ABRT 50m make test-sqlite-migration test-sqlite
 | 
			
		||||
@@ -491,7 +491,7 @@ steps:
 | 
			
		||||
        path: /go
 | 
			
		||||
 | 
			
		||||
  - name: test-pgsql
 | 
			
		||||
    image: gitea/test_env:linux-arm64  # https://gitea.com/gitea/test-env
 | 
			
		||||
    image: gitea/test_env:linux-1.19-arm64  # https://gitea.com/gitea/test-env
 | 
			
		||||
    user: gitea
 | 
			
		||||
    commands:
 | 
			
		||||
      - timeout -s ABRT 50m make test-pgsql-migration test-pgsql
 | 
			
		||||
@@ -1016,7 +1016,7 @@ steps:
 | 
			
		||||
      - git fetch --tags --force
 | 
			
		||||
 | 
			
		||||
  - name: publish
 | 
			
		||||
    image: techknowlogick/drone-docker:latest
 | 
			
		||||
    image: plugins/docker:latest
 | 
			
		||||
    pull: always
 | 
			
		||||
    settings:
 | 
			
		||||
      auto_tag: true
 | 
			
		||||
@@ -1028,13 +1028,17 @@ steps:
 | 
			
		||||
        from_secret: docker_password
 | 
			
		||||
      username:
 | 
			
		||||
        from_secret: docker_username
 | 
			
		||||
    environment:
 | 
			
		||||
      PLUGIN_MIRROR:
 | 
			
		||||
        from_secret: plugin_mirror
 | 
			
		||||
      DOCKER_BUILDKIT: 1
 | 
			
		||||
    when:
 | 
			
		||||
      event:
 | 
			
		||||
        exclude:
 | 
			
		||||
        - pull_request
 | 
			
		||||
 | 
			
		||||
  - name: publish-rootless
 | 
			
		||||
    image: techknowlogick/drone-docker:latest
 | 
			
		||||
    image: plugins/docker:latest
 | 
			
		||||
    settings:
 | 
			
		||||
      dockerfile: Dockerfile.rootless
 | 
			
		||||
      auto_tag: true
 | 
			
		||||
@@ -1046,6 +1050,10 @@ steps:
 | 
			
		||||
        from_secret: docker_password
 | 
			
		||||
      username:
 | 
			
		||||
        from_secret: docker_username
 | 
			
		||||
    environment:
 | 
			
		||||
      PLUGIN_MIRROR:
 | 
			
		||||
        from_secret: plugin_mirror
 | 
			
		||||
      DOCKER_BUILDKIT: 1
 | 
			
		||||
    when:
 | 
			
		||||
      event:
 | 
			
		||||
        exclude:
 | 
			
		||||
@@ -1080,7 +1088,7 @@ steps:
 | 
			
		||||
      - git fetch --tags --force
 | 
			
		||||
 | 
			
		||||
  - name: publish
 | 
			
		||||
    image: techknowlogick/drone-docker:latest
 | 
			
		||||
    image: plugins/docker:latest
 | 
			
		||||
    pull: always
 | 
			
		||||
    settings:
 | 
			
		||||
      tags: ${DRONE_TAG##v}-linux-amd64
 | 
			
		||||
@@ -1091,13 +1099,17 @@ steps:
 | 
			
		||||
        from_secret: docker_password
 | 
			
		||||
      username:
 | 
			
		||||
        from_secret: docker_username
 | 
			
		||||
    environment:
 | 
			
		||||
      PLUGIN_MIRROR:
 | 
			
		||||
        from_secret: plugin_mirror
 | 
			
		||||
      DOCKER_BUILDKIT: 1
 | 
			
		||||
    when:
 | 
			
		||||
      event:
 | 
			
		||||
        exclude:
 | 
			
		||||
        - pull_request
 | 
			
		||||
 | 
			
		||||
  - name: publish-rootless
 | 
			
		||||
    image: techknowlogick/drone-docker:latest
 | 
			
		||||
    image: plugins/docker:latest
 | 
			
		||||
    settings:
 | 
			
		||||
      dockerfile: Dockerfile.rootless
 | 
			
		||||
      tags: ${DRONE_TAG##v}-linux-amd64-rootless
 | 
			
		||||
@@ -1108,6 +1120,10 @@ steps:
 | 
			
		||||
        from_secret: docker_password
 | 
			
		||||
      username:
 | 
			
		||||
        from_secret: docker_username
 | 
			
		||||
    environment:
 | 
			
		||||
      PLUGIN_MIRROR:
 | 
			
		||||
        from_secret: plugin_mirror
 | 
			
		||||
      DOCKER_BUILDKIT: 1
 | 
			
		||||
    when:
 | 
			
		||||
      event:
 | 
			
		||||
        exclude:
 | 
			
		||||
@@ -1142,7 +1158,7 @@ steps:
 | 
			
		||||
      - git fetch --tags --force
 | 
			
		||||
 | 
			
		||||
  - name: publish
 | 
			
		||||
    image: techknowlogick/drone-docker:latest
 | 
			
		||||
    image: plugins/docker:latest
 | 
			
		||||
    pull: always
 | 
			
		||||
    settings:
 | 
			
		||||
      auto_tag: false
 | 
			
		||||
@@ -1154,13 +1170,17 @@ steps:
 | 
			
		||||
        from_secret: docker_password
 | 
			
		||||
      username:
 | 
			
		||||
        from_secret: docker_username
 | 
			
		||||
    environment:
 | 
			
		||||
      PLUGIN_MIRROR:
 | 
			
		||||
        from_secret: plugin_mirror
 | 
			
		||||
      DOCKER_BUILDKIT: 1
 | 
			
		||||
    when:
 | 
			
		||||
      event:
 | 
			
		||||
        exclude:
 | 
			
		||||
        - pull_request
 | 
			
		||||
 | 
			
		||||
  - name: publish-rootless
 | 
			
		||||
    image: techknowlogick/drone-docker:latest
 | 
			
		||||
    image: plugins/docker:latest
 | 
			
		||||
    settings:
 | 
			
		||||
      dockerfile: Dockerfile.rootless
 | 
			
		||||
      auto_tag: false
 | 
			
		||||
@@ -1172,6 +1192,10 @@ steps:
 | 
			
		||||
        from_secret: docker_password
 | 
			
		||||
      username:
 | 
			
		||||
        from_secret: docker_username
 | 
			
		||||
    environment:
 | 
			
		||||
      PLUGIN_MIRROR:
 | 
			
		||||
        from_secret: plugin_mirror
 | 
			
		||||
      DOCKER_BUILDKIT: 1
 | 
			
		||||
    when:
 | 
			
		||||
      event:
 | 
			
		||||
        exclude:
 | 
			
		||||
@@ -1205,7 +1229,7 @@ steps:
 | 
			
		||||
      - git fetch --tags --force
 | 
			
		||||
 | 
			
		||||
  - name: publish
 | 
			
		||||
    image: techknowlogick/drone-docker:latest
 | 
			
		||||
    image: plugins/docker:latest
 | 
			
		||||
    pull: always
 | 
			
		||||
    settings:
 | 
			
		||||
      auto_tag: false
 | 
			
		||||
@@ -1217,13 +1241,17 @@ steps:
 | 
			
		||||
        from_secret: docker_password
 | 
			
		||||
      username:
 | 
			
		||||
        from_secret: docker_username
 | 
			
		||||
    environment:
 | 
			
		||||
      PLUGIN_MIRROR:
 | 
			
		||||
        from_secret: plugin_mirror
 | 
			
		||||
      DOCKER_BUILDKIT: 1
 | 
			
		||||
    when:
 | 
			
		||||
      event:
 | 
			
		||||
        exclude:
 | 
			
		||||
        - pull_request
 | 
			
		||||
 | 
			
		||||
  - name: publish-rootless
 | 
			
		||||
    image: techknowlogick/drone-docker:latest
 | 
			
		||||
    image: plugins/docker:latest
 | 
			
		||||
    settings:
 | 
			
		||||
      dockerfile: Dockerfile.rootless
 | 
			
		||||
      auto_tag: false
 | 
			
		||||
@@ -1235,6 +1263,10 @@ steps:
 | 
			
		||||
        from_secret: docker_password
 | 
			
		||||
      username:
 | 
			
		||||
        from_secret: docker_username
 | 
			
		||||
    environment:
 | 
			
		||||
      PLUGIN_MIRROR:
 | 
			
		||||
        from_secret: plugin_mirror
 | 
			
		||||
      DOCKER_BUILDKIT: 1
 | 
			
		||||
    when:
 | 
			
		||||
      event:
 | 
			
		||||
        exclude:
 | 
			
		||||
@@ -1243,7 +1275,7 @@ steps:
 | 
			
		||||
---
 | 
			
		||||
kind: pipeline
 | 
			
		||||
type: docker
 | 
			
		||||
name: docker-linux-arm64-dry-run
 | 
			
		||||
name: docker-linux-amd64-dry-run
 | 
			
		||||
 | 
			
		||||
platform:
 | 
			
		||||
  os: linux
 | 
			
		||||
@@ -1261,7 +1293,7 @@ trigger:
 | 
			
		||||
 | 
			
		||||
steps:
 | 
			
		||||
  - name: dryrun
 | 
			
		||||
    image: techknowlogick/drone-docker:latest
 | 
			
		||||
    image: plugins/docker:latest
 | 
			
		||||
    pull: always
 | 
			
		||||
    settings:
 | 
			
		||||
      dry_run: true
 | 
			
		||||
@@ -1272,6 +1304,7 @@ steps:
 | 
			
		||||
    environment:
 | 
			
		||||
      PLUGIN_MIRROR:
 | 
			
		||||
        from_secret: plugin_mirror
 | 
			
		||||
      DOCKER_BUILDKIT: 1
 | 
			
		||||
    when:
 | 
			
		||||
      event:
 | 
			
		||||
        - pull_request
 | 
			
		||||
@@ -1308,7 +1341,7 @@ steps:
 | 
			
		||||
      - git fetch --tags --force
 | 
			
		||||
 | 
			
		||||
  - name: publish
 | 
			
		||||
    image: techknowlogick/drone-docker:latest
 | 
			
		||||
    image: plugins/docker:latest
 | 
			
		||||
    pull: always
 | 
			
		||||
    settings:
 | 
			
		||||
      auto_tag: true
 | 
			
		||||
@@ -1320,13 +1353,17 @@ steps:
 | 
			
		||||
        from_secret: docker_password
 | 
			
		||||
      username:
 | 
			
		||||
        from_secret: docker_username
 | 
			
		||||
    environment:
 | 
			
		||||
      PLUGIN_MIRROR:
 | 
			
		||||
        from_secret: plugin_mirror
 | 
			
		||||
      DOCKER_BUILDKIT: 1
 | 
			
		||||
    when:
 | 
			
		||||
      event:
 | 
			
		||||
        exclude:
 | 
			
		||||
        - pull_request
 | 
			
		||||
 | 
			
		||||
  - name: publish-rootless
 | 
			
		||||
    image: techknowlogick/drone-docker:latest
 | 
			
		||||
    image: plugins/docker:latest
 | 
			
		||||
    settings:
 | 
			
		||||
      dockerfile: Dockerfile.rootless
 | 
			
		||||
      auto_tag: true
 | 
			
		||||
@@ -1338,6 +1375,10 @@ steps:
 | 
			
		||||
        from_secret: docker_password
 | 
			
		||||
      username:
 | 
			
		||||
        from_secret: docker_username
 | 
			
		||||
    environment:
 | 
			
		||||
      PLUGIN_MIRROR:
 | 
			
		||||
        from_secret: plugin_mirror
 | 
			
		||||
      DOCKER_BUILDKIT: 1
 | 
			
		||||
    when:
 | 
			
		||||
      event:
 | 
			
		||||
        exclude:
 | 
			
		||||
@@ -1372,7 +1413,7 @@ steps:
 | 
			
		||||
      - git fetch --tags --force
 | 
			
		||||
 | 
			
		||||
  - name: publish
 | 
			
		||||
    image: techknowlogick/drone-docker:latest
 | 
			
		||||
    image: plugins/docker:latest
 | 
			
		||||
    pull: always
 | 
			
		||||
    settings:
 | 
			
		||||
      tags: ${DRONE_TAG##v}-linux-arm64
 | 
			
		||||
@@ -1383,13 +1424,17 @@ steps:
 | 
			
		||||
        from_secret: docker_password
 | 
			
		||||
      username:
 | 
			
		||||
        from_secret: docker_username
 | 
			
		||||
    environment:
 | 
			
		||||
      PLUGIN_MIRROR:
 | 
			
		||||
        from_secret: plugin_mirror
 | 
			
		||||
      DOCKER_BUILDKIT: 1
 | 
			
		||||
    when:
 | 
			
		||||
      event:
 | 
			
		||||
        exclude:
 | 
			
		||||
        - pull_request
 | 
			
		||||
 | 
			
		||||
  - name: publish-rootless
 | 
			
		||||
    image: techknowlogick/drone-docker:latest
 | 
			
		||||
    image: plugins/docker:latest
 | 
			
		||||
    settings:
 | 
			
		||||
      dockerfile: Dockerfile.rootless
 | 
			
		||||
      tags: ${DRONE_TAG##v}-linux-arm64-rootless
 | 
			
		||||
@@ -1400,6 +1445,10 @@ steps:
 | 
			
		||||
        from_secret: docker_password
 | 
			
		||||
      username:
 | 
			
		||||
        from_secret: docker_username
 | 
			
		||||
    environment:
 | 
			
		||||
      PLUGIN_MIRROR:
 | 
			
		||||
        from_secret: plugin_mirror
 | 
			
		||||
      DOCKER_BUILDKIT: 1
 | 
			
		||||
    when:
 | 
			
		||||
      event:
 | 
			
		||||
        exclude:
 | 
			
		||||
@@ -1434,7 +1483,7 @@ steps:
 | 
			
		||||
      - git fetch --tags --force
 | 
			
		||||
 | 
			
		||||
  - name: publish
 | 
			
		||||
    image: techknowlogick/drone-docker:latest
 | 
			
		||||
    image: plugins/docker:latest
 | 
			
		||||
    pull: always
 | 
			
		||||
    settings:
 | 
			
		||||
      auto_tag: false
 | 
			
		||||
@@ -1446,13 +1495,17 @@ steps:
 | 
			
		||||
        from_secret: docker_password
 | 
			
		||||
      username:
 | 
			
		||||
        from_secret: docker_username
 | 
			
		||||
    environment:
 | 
			
		||||
      PLUGIN_MIRROR:
 | 
			
		||||
        from_secret: plugin_mirror
 | 
			
		||||
      DOCKER_BUILDKIT: 1
 | 
			
		||||
    when:
 | 
			
		||||
      event:
 | 
			
		||||
        exclude:
 | 
			
		||||
        - pull_request
 | 
			
		||||
 | 
			
		||||
  - name: publish-rootless
 | 
			
		||||
    image: techknowlogick/drone-docker:latest
 | 
			
		||||
    image: plugins/docker:latest
 | 
			
		||||
    settings:
 | 
			
		||||
      dockerfile: Dockerfile.rootless
 | 
			
		||||
      auto_tag: false
 | 
			
		||||
@@ -1464,6 +1517,10 @@ steps:
 | 
			
		||||
        from_secret: docker_password
 | 
			
		||||
      username:
 | 
			
		||||
        from_secret: docker_username
 | 
			
		||||
    environment:
 | 
			
		||||
      PLUGIN_MIRROR:
 | 
			
		||||
        from_secret: plugin_mirror
 | 
			
		||||
      DOCKER_BUILDKIT: 1
 | 
			
		||||
    when:
 | 
			
		||||
      event:
 | 
			
		||||
        exclude:
 | 
			
		||||
@@ -1497,7 +1554,7 @@ steps:
 | 
			
		||||
      - git fetch --tags --force
 | 
			
		||||
 | 
			
		||||
  - name: publish
 | 
			
		||||
    image: techknowlogick/drone-docker:latest
 | 
			
		||||
    image: plugins/docker:latest
 | 
			
		||||
    pull: always
 | 
			
		||||
    settings:
 | 
			
		||||
      auto_tag: false
 | 
			
		||||
@@ -1509,13 +1566,17 @@ steps:
 | 
			
		||||
        from_secret: docker_password
 | 
			
		||||
      username:
 | 
			
		||||
        from_secret: docker_username
 | 
			
		||||
    environment:
 | 
			
		||||
      PLUGIN_MIRROR:
 | 
			
		||||
        from_secret: plugin_mirror
 | 
			
		||||
      DOCKER_BUILDKIT: 1
 | 
			
		||||
    when:
 | 
			
		||||
      event:
 | 
			
		||||
        exclude:
 | 
			
		||||
        - pull_request
 | 
			
		||||
 | 
			
		||||
  - name: publish-rootless
 | 
			
		||||
    image: techknowlogick/drone-docker:latest
 | 
			
		||||
    image: plugins/docker:latest
 | 
			
		||||
    settings:
 | 
			
		||||
      dockerfile: Dockerfile.rootless
 | 
			
		||||
      auto_tag: false
 | 
			
		||||
@@ -1527,6 +1588,10 @@ steps:
 | 
			
		||||
        from_secret: docker_password
 | 
			
		||||
      username:
 | 
			
		||||
        from_secret: docker_username
 | 
			
		||||
    environment:
 | 
			
		||||
      PLUGIN_MIRROR:
 | 
			
		||||
        from_secret: plugin_mirror
 | 
			
		||||
      DOCKER_BUILDKIT: 1
 | 
			
		||||
    when:
 | 
			
		||||
      event:
 | 
			
		||||
        exclude:
 | 
			
		||||
 
 | 
			
		||||
@@ -1,12 +1,16 @@
 | 
			
		||||
plugins:
 | 
			
		||||
  - stylelint-declaration-strict-value
 | 
			
		||||
 | 
			
		||||
ignoreFiles:
 | 
			
		||||
  - "**/*.go"
 | 
			
		||||
 | 
			
		||||
overrides:
 | 
			
		||||
  - files: ["**/*.less"]
 | 
			
		||||
    customSyntax: postcss-less
 | 
			
		||||
  - files: ["**/chroma/*", "**/codemirror/*", "**/standalone/*", "**/console/*"]
 | 
			
		||||
    rules:
 | 
			
		||||
      scale-unlimited/declaration-strict-value: null
 | 
			
		||||
  - files: ["**/chroma/*", "**/codemirror/*"]
 | 
			
		||||
    rules:
 | 
			
		||||
      block-no-empty: null
 | 
			
		||||
 | 
			
		||||
rules:
 | 
			
		||||
  alpha-value-notation: null
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										350
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										350
									
								
								CHANGELOG.md
									
									
									
									
									
								
							@@ -4,6 +4,356 @@ 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
 | 
			
		||||
been added to each release, please refer to the [blog](https://blog.gitea.io).
 | 
			
		||||
 | 
			
		||||
## [1.19.0](https://github.com/go-gitea/gitea/releases/tag/1.19.0) - 2023-03-19
 | 
			
		||||
 | 
			
		||||
* BREAKING
 | 
			
		||||
  * Add loading yaml label template files (#22976) (#23232)
 | 
			
		||||
  * Make issue and code search support camel case for Bleve (#22829)
 | 
			
		||||
  * Repositories: by default disable all units except code and pulls on forks (#22541)
 | 
			
		||||
  * Support template for merge message description (#22248)
 | 
			
		||||
  * Remove ONLY_SHOW_RELEVANT_REPOS setting (#21962)
 | 
			
		||||
  * Implement actions (#21937)
 | 
			
		||||
  * Remove deprecated DSA host key from Docker Container (#21522)
 | 
			
		||||
  * Improve valid user name check (#20136)
 | 
			
		||||
* SECURITY
 | 
			
		||||
  * Return 404 instead of 403 if user can not access the repo (#23155) (#23158)
 | 
			
		||||
  * Support scoped access tokens (#20908)
 | 
			
		||||
* FEATURES
 | 
			
		||||
  * Add support for commit cross references (#22645)
 | 
			
		||||
  * Scoped labels (#22585)
 | 
			
		||||
  * Add Chef package registry (#22554)
 | 
			
		||||
  * Support asciicast files as new markup (#22448)
 | 
			
		||||
  * cgo cross-compile for freebsd (#22397)
 | 
			
		||||
  * Add cron method to gc LFS MetaObjects (#22385)
 | 
			
		||||
  * Add new captcha: cloudflare turnstile (#22369)
 | 
			
		||||
  * Enable `@<user>`- completion popup on the release description textarea (#22359)
 | 
			
		||||
  * make /{username}.png redirect to user/org avatar (#22356)
 | 
			
		||||
  * Add Conda package registry (#22262)
 | 
			
		||||
  * Support org/user level projects (#22235)
 | 
			
		||||
  * Add Mermaid copy button (#22225)
 | 
			
		||||
  * Add user secrets (#22191)
 | 
			
		||||
  * Secrets storage with SecretKey encrypted (#22142)
 | 
			
		||||
  * Preview images for Issue cards in Project Board view (#22112)
 | 
			
		||||
  * Add support for incoming emails (#22056)
 | 
			
		||||
  * Add Cargo package registry (#21888)
 | 
			
		||||
  * Add option to prohibit fork if user reached maximum limit of repositories (#21848)
 | 
			
		||||
  * Add attention blocks within quote blocks for `Note` and `Warning` (#21711)
 | 
			
		||||
  * Add Feed for Releases and Tags (#21696)
 | 
			
		||||
  * Add package registry cleanup rules (#21658)
 | 
			
		||||
  * Add "Copy" button to file view of raw text (#21629)
 | 
			
		||||
  * Allow disable sitemap (#21617)
 | 
			
		||||
  * Add package registry quota limits (#21584)
 | 
			
		||||
  * Map OIDC groups to Orgs/Teams (#21441)
 | 
			
		||||
  * Keep languages defined in .gitattributes (#21403)
 | 
			
		||||
  * Add Webhook authorization header (#20926)
 | 
			
		||||
  * Supports wildcard protected branch (#20825)
 | 
			
		||||
  * Copy citation file content, in APA and BibTex format, on repo home page (#19999)
 | 
			
		||||
* API
 | 
			
		||||
  * Match api migration behavior to web behavior (#23552) (#23573)
 | 
			
		||||
  * Purge API comment (#23451) (#23452)
 | 
			
		||||
  * User creation API: allow custom "created" timestamps (#22549)
 | 
			
		||||
  * Add `updated_at` field to PullReview API object (#21812)
 | 
			
		||||
  * Add API management for issue/pull and comment attachments (#21783)
 | 
			
		||||
  * Add API endpoint to get latest release (#21267)
 | 
			
		||||
  * Support system hook API (#14537)
 | 
			
		||||
* ENHANCEMENTS
 | 
			
		||||
  * Add `.patch` to `attachment.ALLOWED_TYPES` (#23580) (#23582)
 | 
			
		||||
  * Fix sticky header in diff view (#23554) (#23568)
 | 
			
		||||
  * Refactor merge/update git command calls (#23366) (#23544)
 | 
			
		||||
  * Fix review comment context menu clipped bug (#23523) (#23543)
 | 
			
		||||
  * Imrove scroll behavior to hash issuecomment(scroll position, auto expand if file is folded, and on refreshing) (#23513) (#23540)
 | 
			
		||||
  * Increase horizontal page padding (#23507) (#23537)
 | 
			
		||||
  * Use octicon-verified for gpg signatures (#23529) (#23536)
 | 
			
		||||
  * Make time tooltips interactive (#23526) (#23527)
 | 
			
		||||
  * Replace Less with CSS (#23508)
 | 
			
		||||
  * Fix 'View File' button in code search (#23478) (#23483)
 | 
			
		||||
  * Convert GitHub event on actions and fix some pull_request events. (#23037) (#23471)
 | 
			
		||||
  * Support reflogs (#22451) (#23438)
 | 
			
		||||
  * Fix actions frontend bugs (pagination, long name alignment) and small simplify (#23370) (#23436)
 | 
			
		||||
  * Scoped label display and documentation tweaks (#23430) (#23433)
 | 
			
		||||
  * Add missing tabs to org projects page (#22705) (#23412)
 | 
			
		||||
  * Fix and move "Use this template" button (#23398) (#23408)
 | 
			
		||||
  * Handle OpenID discovery URL errors a little nicer when creating/editing sources (#23397) (#23403)
 | 
			
		||||
  * Rename `canWriteUnit` to `canWriteProjects` (#23386) (#23399)
 | 
			
		||||
  * Refactor and tidy-up the merge/update branch code (#22568) (#23365)
 | 
			
		||||
  * Refactor `setting.Database.UseXXX` to methods (#23354) (#23356)
 | 
			
		||||
  * Fix incorrect project links and use symlink icon for org-wide projects (#23325) (#23336)
 | 
			
		||||
  * Fix PR view misalignment caused by long name file (#23321) (#23335)
 | 
			
		||||
  * Scoped labels: don't require holding alt key to remove (#23303) (#23331)
 | 
			
		||||
  * Add context when rendering labels or emojis (#23281) (#23319)
 | 
			
		||||
  * Change interactiveBorder to fix popup preview  (#23169) (#23314)
 | 
			
		||||
  * Scoped labels: set aria-disabled on muted Exclusive option for a11y (#23306) (#23311)
 | 
			
		||||
  * update to mermaid v10 (#23178) (#23299)
 | 
			
		||||
  * Fix code wrap for unbroken lines (#23268) (#23293)
 | 
			
		||||
  * Use async await to fix empty quote reply at first time (#23168) (#23256)
 | 
			
		||||
  * Fix switched citation format (#23250) (#23253)
 | 
			
		||||
  * Allow `<video>` in MarkDown (#22892) (#23236)
 | 
			
		||||
  * Order pull request conflict checking by recently updated, for each push (#23220) (#23225)
 | 
			
		||||
  * Fix Fomantic UI's `touchstart` fastclick, always use `click` for click events (#23065) (#23195)
 | 
			
		||||
  * Add word-break to sidebar-item-link (#23146) (#23180)
 | 
			
		||||
  * Add InsecureSkipVerify to Minio Client for Storage (#23166) (#23177)
 | 
			
		||||
  * Fix height for sticky head on large screen on PR page (#23111) (#23123)
 | 
			
		||||
  * Change style to improve whitespaces trimming inside inline markdown code (#23093) (#23120)
 | 
			
		||||
  * Avoid warning for system setting when start up (#23054) (#23116)
 | 
			
		||||
  * Add accessibility to the menu on the navbar (#23059) (#23095)
 | 
			
		||||
  * Improve accessibility for issue comments (#22612) (#23083)
 | 
			
		||||
  * Remove delete button for review comment (#23036)
 | 
			
		||||
  * Remove dashes between organization member avatars on hover (#23034)
 | 
			
		||||
  * Use `gt-relative` class instead of the ambiguous `gt-pr` class  (#23008)
 | 
			
		||||
  * handle deprecated settings (#22992)
 | 
			
		||||
  * Add scopes to API to create token and display them (#22989)
 | 
			
		||||
  * Improve PR Review Box UI (#22986)
 | 
			
		||||
  * Improve issues.LoadProject (#22982)
 | 
			
		||||
  * Add all units to the units permission list in org team members sidebar (#22971)
 | 
			
		||||
  * Rename `GetUnits` to `LoadUnits` (#22970)
 | 
			
		||||
  * Rename `repo.GetOwner` to `repo.LoadOwner` (#22967)
 | 
			
		||||
  * Rename "People" to "Members" in organization page and use a better icon (#22960)
 | 
			
		||||
  * Fix avatar misalignment (#22955)
 | 
			
		||||
  * Sort issues and pulls by recently updated in user and organization home (#22925)
 | 
			
		||||
  * Add `title` to PR file tree items (#22918)
 | 
			
		||||
  * First step to refactor the `.hide` to `.gt-hidden` (#22916)
 | 
			
		||||
  * Add tooltip to issue reference (#22913)
 | 
			
		||||
  * Always show the `command line instructions` button even if there are conflicts (#22909)
 | 
			
		||||
  * Fix dark-colored description text in arc-green theme (#22908)
 | 
			
		||||
  * Remove Fomantic-UI's `.hidden` CSS class for menu elements (#22895)
 | 
			
		||||
  * Move helpers to be prefixed with `gt-` (#22879)
 | 
			
		||||
  * Move `IsReadmeFile*` from `modules/markup/` to `modules/util` (#22877)
 | 
			
		||||
  * Highlight focused diff file (#22870)
 | 
			
		||||
  * Add some headings to repo views (#22869)
 | 
			
		||||
  * Fix milestone title font problem (#22863)
 | 
			
		||||
  * Pull Requests: setting to allow edits by maintainers by default, tweak UI (#22862)
 | 
			
		||||
  * Introduce customized HTML elements, fix incorrect AppUrl usages in templates (#22861)
 | 
			
		||||
  * Add `/$count` endpoints for NuGet v2 (#22855)
 | 
			
		||||
  * Remove Fomantic-UI's `.hidden` CSS class for checkbox elements (#22851)
 | 
			
		||||
  * Fix notification and stopwatch empty states (#22845)
 | 
			
		||||
  * Always go full width in PR view (#22844)
 | 
			
		||||
  * Improve AppUrl/ROOT_URL checking (#22836)
 | 
			
		||||
  * Fix style of actions rerun button (#22835)
 | 
			
		||||
  * Fix more HTMLURL in templates (#22831)
 | 
			
		||||
  * Fix inconsistent Filter Project name in issue list (#22827)
 | 
			
		||||
  * include build info in Prometheus metrics (#22819)
 | 
			
		||||
  * Make clone URL use current page's host (#22808)
 | 
			
		||||
  * Refactor legacy strange git operations (#22756)
 | 
			
		||||
  * Improve error report when user passes a private key (#22726)
 | 
			
		||||
  * set user dashboard org visibility to basic (#22706)
 | 
			
		||||
  * Fix diff UI for unexpandable items (#22700)
 | 
			
		||||
  * Remove 'primary' class from tab counter labels (#22687)
 | 
			
		||||
  * Add more events details supports for actions (#22680)
 | 
			
		||||
  * Refactor git command package to improve security and maintainability (#22678)
 | 
			
		||||
  * Use relative url in actions view (#22675)
 | 
			
		||||
  * set user visibility class to basic (#22674)
 | 
			
		||||
  * Add repository setting to enable/disable releases unit (#22671)
 | 
			
		||||
  * Remove label color from global issue filters (#22660)
 | 
			
		||||
  * Fix poor alignment of organization description on organization home page (#22656)
 | 
			
		||||
  * Small refactor for loading PRs (#22652)
 | 
			
		||||
  * Allow setting access token scope by CLI (#22648)
 | 
			
		||||
  * Improve accessibility of navigation bar and footer (#22635)
 | 
			
		||||
  * Fixes accessibility behavior of Watching, Staring and Fork buttons (#22634)
 | 
			
		||||
  * Fixes accessibility of empty repository commit status (#22632)
 | 
			
		||||
  * Pull request yaml template support for including commit body in a field (#22629)
 | 
			
		||||
  * Show migration validation error (#22619)
 | 
			
		||||
  * set org visibility class to basic in header (#22605)
 | 
			
		||||
  * Fix cache-control header clearing comment text when editing issue (#22604)
 | 
			
		||||
  * Add ARIA support for Fomantic UI checkboxes (#22599)
 | 
			
		||||
  * Add templates to customize text when creating and migrating repositories (#22597)
 | 
			
		||||
  * Allow setting `redirect_to` cookie on OAuth login (#22594)
 | 
			
		||||
  * Improve checkbox accessibility a bit by adding the title attribute (#22593)
 | 
			
		||||
  * Allow issue templates to not render title (#22589)
 | 
			
		||||
  * Webhooks: for issue close/reopen action, add commit ID that caused it (#22583)
 | 
			
		||||
  * Fix missing title and filter in issue sidebar project menu (#22557)
 | 
			
		||||
  * Issues: support setting issue template field values with query (#22545)
 | 
			
		||||
  * Issues: add Project filter to issues list and search (#22544)
 | 
			
		||||
  * Pull Requests: add color to approved/reject icon in pull requests list (#22543)
 | 
			
		||||
  * Mute all links in issue timeline (#22533)
 | 
			
		||||
  * Dropzone: Add "Copy link" button for new uploads (#22517)
 | 
			
		||||
  * Support importing comment types (#22510)
 | 
			
		||||
  * Load asciicast css async (#22502)
 | 
			
		||||
  * Move delete user to service (#22478)
 | 
			
		||||
  * Change use of Walk to WalkDir to improve disk performance (#22462)
 | 
			
		||||
  * Add reply hint to mail text (#22459)
 | 
			
		||||
  * fix wrong theme class when logged out if default theme is changed (#22408)
 | 
			
		||||
  * Refactor the setting to make unit test easier (#22405)
 | 
			
		||||
  * Improve utils of slices (#22379)
 | 
			
		||||
  * Use context parameter in models/git (#22367)
 | 
			
		||||
  * Always reuse transaction (#22362)
 | 
			
		||||
  * Fix unstable emoji sort (#22346)
 | 
			
		||||
  * Add context cache as a request level cache (#22294)
 | 
			
		||||
  * Reminder for no more logs to console (#22282)
 | 
			
		||||
  * Support estimated count with multiple schemas (#22276)
 | 
			
		||||
  * Move `convert` package to services (#22264)
 | 
			
		||||
  * Use dynamic package type list (#22263)
 | 
			
		||||
  * Hide file borders on sticky diff box (#22217)
 | 
			
		||||
  * Improve notification and stopwatch styles (#22169)
 | 
			
		||||
  * Fixed Project view .board-column height for tall screens. (#22108)
 | 
			
		||||
  * Use multi reader instead to concat strings (#22099)
 | 
			
		||||
  * Use git command instead of exec.Cmd in blame (#22098)
 | 
			
		||||
  * Fix autofilled text visibility in dark mode (#22088)
 | 
			
		||||
  * Rename almost all Ctx functions (#22071)
 | 
			
		||||
  * Rename actions to operations on UI (#22067)
 | 
			
		||||
  * refactor bind functions based on generics (#22055)
 | 
			
		||||
  * Support disabling database auto migration (#22053)
 | 
			
		||||
  * remove duplicated read file code (#22042)
 | 
			
		||||
  * Use link in UI which returned a relative url but not html_url which contains an absolute url (#21986)
 | 
			
		||||
  * Skip initing disabled storages (#21985)
 | 
			
		||||
  * Add doctor command for full GC of LFS (#21978)
 | 
			
		||||
  * Util type to parse ref name (#21969)
 | 
			
		||||
  * Replace fmt.Sprintf with hex.EncodeToString (#21960)
 | 
			
		||||
  * Use random bytes to generate access token (#21959)
 | 
			
		||||
  * Add index for access_token (#21908)
 | 
			
		||||
  * Move all remaining colors into CSS variables (#21903)
 | 
			
		||||
  * Webhook list enhancements (#21893)
 | 
			
		||||
  * Embed Matrix icon as SVG (#21890)
 | 
			
		||||
  * Remove useless "Cancel" buttons (#21872)
 | 
			
		||||
  * fix(web): keep the pages of the navigation in the center (#21867)
 | 
			
		||||
  * fix(web): reduce page jitter on browsers that support overlay scrollbar (#21850)
 | 
			
		||||
  * Improvements for Content Copy (#21842)
 | 
			
		||||
  * Tweak katex options (#21828)
 | 
			
		||||
  * Show syntax lexer name in file view/blame (#21814)
 | 
			
		||||
  * Remove `href="javascript:;"` in "save topics (Done)" button (#21813)
 | 
			
		||||
  * Render number of commits in repo page in a user friendly way (#21786)
 | 
			
		||||
  * Adjust clone timeout error to suggest increasing timeout (#21769)
 | 
			
		||||
  * Update message of reach_limit_of_creation (#21757)
 | 
			
		||||
  * Allow detect whether it's in a database transaction for a context.Context (#21756)
 | 
			
		||||
  * Add configuration for CORS allowed headers (#21747)
 | 
			
		||||
  * Move svg html render to modules/svg (#21716)
 | 
			
		||||
  * Release and Tag List tweaks (#21712)
 | 
			
		||||
  * Remove template previewer (#21701)
 | 
			
		||||
  * Clean up formatting on install page (#21668)
 | 
			
		||||
  * Configure update checker on installation page (#21655)
 | 
			
		||||
  * Merge db.Iterate and IterateObjects (#21641)
 | 
			
		||||
  * Add option to enable CAPTCHA validation for login (#21638)
 | 
			
		||||
  * Allow disable RSS/Atom feed (#21622)
 | 
			
		||||
  * Use CSS color-scheme instead of invert (#21616)
 | 
			
		||||
  * Localize time units on activity heatmap (#21570)
 | 
			
		||||
  * Fix UI column width, button overflow Fomantic's grid (#21559)
 | 
			
		||||
  * feat: notify doers of a merge when automerging (#21553)
 | 
			
		||||
  * Split migrations folder (#21549)
 | 
			
		||||
  * feat: add button to quickly clear merge message (#21548)
 | 
			
		||||
  * Add `context.Context` to more methods (#21546)
 | 
			
		||||
  * Add index for hook_task table (#21545)
 | 
			
		||||
  * Allow disable code tab (#20805)
 | 
			
		||||
* BUGFIXES
 | 
			
		||||
  * Fix template error when reference Project (#23584)
 | 
			
		||||
  * Fix dropdown icon misalignment when using fomantic icon (#23558) (#23577)
 | 
			
		||||
  * Fix diff detail buttons wrapping, use tippy for review box (#23271) (#23546)
 | 
			
		||||
  * Handle missing `README` in create repos API (#23387) (#23510)
 | 
			
		||||
  * Disable sending email after push a commit to a closed PR (#23462) (#23492)
 | 
			
		||||
  * Fix aria.js bugs: incorrect role element problem, mobile focus problem, tippy problem (#23450) (#23486)
 | 
			
		||||
  * Fix due date being wrong on issue list (#23475) (#23477)
 | 
			
		||||
  * Remove wrongly added column on migration test fixtures (#23456) (#23470)
 | 
			
		||||
  * Make branches list page operations remember current page (#23420) (#23460)
 | 
			
		||||
  * Fix missing commit status in PR which from forked repo (#23351) (#23453)
 | 
			
		||||
  * Show edit/close/delete button on organization wide repositories (#23388) (#23429)
 | 
			
		||||
  * Preserve file size when creating attachments (#23406) (#23426)
 | 
			
		||||
  * Fix broken Chroma CSS styles (#23174) (#23402)
 | 
			
		||||
  * Fix incorrect NotFound conditions in org/projects.go (#23384) (#23395)
 | 
			
		||||
  * Set `X-Gitea-Debug` header once (#23361) (#23381)
 | 
			
		||||
  * Pass context to avatar for projects view (#23359) (#23378)
 | 
			
		||||
  * Fix panic when getting notes by ref (#23372) (#23377)
 | 
			
		||||
  * Do not recognize text files as audio (#23355) (#23368)
 | 
			
		||||
  * Fix adding of empty class name (#23352) (#23360)
 | 
			
		||||
  * Fix various ImageDiff/SVG bugs (#23312) (#23358)
 | 
			
		||||
  * Fix incorrect display for comment context menu (#23343) (#23344)
 | 
			
		||||
  * Remove unnecessary space on link (#23334) (#23340)
 | 
			
		||||
  * Fix incorrect redirect link of delete org project (#23327) (#23339)
 | 
			
		||||
  * Fix cannot reopen after pushing commits to a closed PR (#23189) (#23324)
 | 
			
		||||
  * Fix broken code editor diff preview (#23307) (#23320)
 | 
			
		||||
  * Support sanitising the URL by removing extra slashes in the URL (#21333) (#23300)
 | 
			
		||||
  * Avoid panic caused by broken payload when creating commit status (#23216) (#23294)
 | 
			
		||||
  * Fill head commit to in payload when notifying push commits for mirroring (#23215) (#23292)
 | 
			
		||||
  * Fix various bugs for "install" page (#23194) (#23286)
 | 
			
		||||
  * Fix GetFilesChangedBetween if the file name may be escaped (#23272) (#23279)
 | 
			
		||||
  * Revert relative links to absolute links in mail templates (#23267) (#23269)
 | 
			
		||||
  * Fix commit retrieval by tag (#21804) (#23266)
 | 
			
		||||
  * Use correct README link to render the README (#23152) (#23264)
 | 
			
		||||
  * Close the temp file when dumping database to make the temp file can be deleted on Windows (#23249) (#23251)
 | 
			
		||||
  * Use the correct selector to hide the checkmark of selected labels on clear (#23224) (#23228)
 | 
			
		||||
  * Fix incorrect checkbox behaviors in the dashboard repolist's filter (#23147) (#23205)
 | 
			
		||||
  * Properly flush unique queues on startup (#23154) (#23201)
 | 
			
		||||
  * Pass `--global` when calling `git config --get`, for consistency with `git config --set` (#23157) (#23199)
 | 
			
		||||
  * Make `gitea serv` respect git binary home (#23138) (#23197)
 | 
			
		||||
  * Change button text for commenting and closing an issue at the same time (#23135) (#23182)
 | 
			
		||||
  * Fix DBConsistency checks on MSSQL (#23132) (#23134)
 | 
			
		||||
  * Show empty repos in Admin Repository Management page (#23114) (#23130)
 | 
			
		||||
  * Redirect to the commit page after applying patch (#23056) (#23127)
 | 
			
		||||
  * Fix nil context in RenderMarkdownToHtml (#23092) (#23108)
 | 
			
		||||
  * Make issue meta dropdown support Enter, confirm before reloading (#23014) (#23102)
 | 
			
		||||
  * Fix SyncOnCommit always return false in API of push_mirrors (#23088) (#23100)
 | 
			
		||||
  * Fix commit name in Apply Patch page (#23086) (#23099)
 | 
			
		||||
  * Fix some more hidden problems (#23074) (#23075)
 | 
			
		||||
  * Bump golang.org/x/net from 0.4.0 to 0.7.0 (#22980)
 | 
			
		||||
  * Get rules by id when editing branch protection rule (#22932)
 | 
			
		||||
  * Fix panic when call api (/repos/{owner}/{repo}/pulls/{index}/files) (#22921)
 | 
			
		||||
  * Increase Content field size of gpg_import_key to MEDIUMTEXT (#22897)
 | 
			
		||||
  * Fix hidden commit status on multiple checks (#22889)
 | 
			
		||||
  * Fix update by rebase being wrongly disabled by protected base branch (#22825)
 | 
			
		||||
  * Make issue title edit buttons focusable and fix incorrect ajax requests (#22807)
 | 
			
		||||
  * Fix rerun button of Actions (#22798)
 | 
			
		||||
  * remove update language in ProfilePost (#22748)
 | 
			
		||||
  * Do not overwrite empty DefaultBranch (#22708)
 | 
			
		||||
  * Fix ref to trigger Actions (#22679)
 | 
			
		||||
  * Fix time to NotifyPullRequestSynchronized (#22650)
 | 
			
		||||
  * Show all projects, not just repo projects and open/closed projects  (#22640)
 | 
			
		||||
  * Project links should use parent link methods (#22587)
 | 
			
		||||
  * Fix group filter for ldap source sync (#22506)
 | 
			
		||||
  * Check quota limits for container uploads (#22450)
 | 
			
		||||
  * Fix halfCommitter and WithTx (#22366)
 | 
			
		||||
  * Attempt to fix TestExportUserGPGKeys (#22159)
 | 
			
		||||
  * Fix heatmap first color being unused (#22157)
 | 
			
		||||
  * Fix scroll over mermaid frame (#21925)
 | 
			
		||||
  * Move migration test fixtures to the correct directories (#21901)
 | 
			
		||||
  * fix(web): add `alt` for logo in home page (#21887)
 | 
			
		||||
  * Fix webhook attachment text is not set in review comment (#21763)
 | 
			
		||||
  * Alter package_version.metadata_json to LONGTEXT (#21667)
 | 
			
		||||
  * Ensure that Webhook tasks are not double delivered (#21558)
 | 
			
		||||
* TESTING
 | 
			
		||||
  * Make CI use a dummy password hasher for all tests (#22983)
 | 
			
		||||
  * Disable test for incoming email (#22686)
 | 
			
		||||
  * Move fuzz tests into tests/fuzz (#22376)
 | 
			
		||||
  * Test views of LFS files (#22196)
 | 
			
		||||
  * Specify ID in `TestAPITeam` (#22192)
 | 
			
		||||
  * verify nodeinfo response by schema  (#22137)
 | 
			
		||||
  * Skip GitHub migration tests if the API token is undefined (#21824)
 | 
			
		||||
  * Add a simple test for external renderer (#20033)
 | 
			
		||||
* TRANSLATION
 | 
			
		||||
  * Use "Title Case" for text "Reference in new issue" (#22936)
 | 
			
		||||
* BUILD
 | 
			
		||||
  * Wrap unless-check in docker manifests (#23079) (#23081)
 | 
			
		||||
  * Adjust manifest to prevent tagging latest on rcs (#22811)
 | 
			
		||||
  * update to build with go1.20 (#22732)
 | 
			
		||||
  * Add Bash and Zsh completion scripts (#22646)
 | 
			
		||||
  * Add Contributed backport command (#22643)
 | 
			
		||||
  * Remove deprecated packages & staticcheck fixes (#22012)
 | 
			
		||||
  * Update to Alpine 3.17 (#21904)
 | 
			
		||||
  * Fix webpack license warning (#21815)
 | 
			
		||||
* DOCS
 | 
			
		||||
  * Update documentation for the new YAML label file format  (#23020) (#23341)
 | 
			
		||||
  * Update hacking-on-gitea-zh_cn documentation (#23315) (#23323)
 | 
			
		||||
  * Add basic documentation for labels, including scoped labels (#23304) (#23309)
 | 
			
		||||
  * Re-add accidentally removed `hacking-on-gitea.zh-cn.md` (#23297) (#23305)
 | 
			
		||||
  * Fix secrets overview page missing from docs sidebar (#23143) (#23145)
 | 
			
		||||
  * Add some guidelines for refactoring (#22880)
 | 
			
		||||
  * Explain that the no-access team unit does not affect public repositories (#22661)
 | 
			
		||||
  * Fix incorrect Redis URL snippets in the example app.ini (#22573)
 | 
			
		||||
  * docs: add swagger.json file location to FAQ (#22489)
 | 
			
		||||
  * Update index.de-de.md (#22363)
 | 
			
		||||
  * Update Gmail mailer configuration (#22291)
 | 
			
		||||
  * Add missed reverse proxy authentication documentation (#22250)
 | 
			
		||||
  * Add plural definitions for German translations (#21802)
 | 
			
		||||
  * Attempt clarify AppWorkPath etc. (#21656)
 | 
			
		||||
  * Add some documentation to packages (#21648)
 | 
			
		||||
* MISC
 | 
			
		||||
  * Use `<nav>` instead of `<div>` in the global navbar (#23125) (#23533)
 | 
			
		||||
  * Do not create commit graph for temporary repos (#23219) (#23229)
 | 
			
		||||
  * Update button is shown when a Pull Request is marked WIP - Issue #21740 (#22683)
 | 
			
		||||
  * Add main landmark to templates and adjust titles (#22670)
 | 
			
		||||
  * Fix error on account activation with wrong passwd (#22609)
 | 
			
		||||
  * Update JS dependencies (#22538)
 | 
			
		||||
  * Display unreferenced packages total size in package admin panel (#22498)
 | 
			
		||||
  * Mobile fix for Project view: Add delay to Sortable.js on mobile, to ensure scrolling is possible. (#22152)
 | 
			
		||||
  * Update chroma to v2.4.0 (#22000)
 | 
			
		||||
  * Hide collapse icon in diff with no lines (#21094)
 | 
			
		||||
 | 
			
		||||
## [1.18.5](https://github.com/go-gitea/gitea/releases/tag/v1.18.5) - 2023-02-21
 | 
			
		||||
 | 
			
		||||
* ENHANCEMENTS
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										8
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								Makefile
									
									
									
									
									
								
							@@ -105,7 +105,7 @@ GO_TEST_PACKAGES ?= $(filter-out $(shell $(GO) list code.gitea.io/gitea/models/m
 | 
			
		||||
 | 
			
		||||
FOMANTIC_WORK_DIR := web_src/fomantic
 | 
			
		||||
 | 
			
		||||
WEBPACK_SOURCES := $(shell find web_src/js web_src/less -type f)
 | 
			
		||||
WEBPACK_SOURCES := $(shell find web_src/js web_src/css -type f)
 | 
			
		||||
WEBPACK_CONFIGS := webpack.config.js
 | 
			
		||||
WEBPACK_DEST := public/js/index.js public/css/index.css
 | 
			
		||||
WEBPACK_DEST_ENTRIES := public/js public/css public/fonts public/img/webpack public/serviceworker.js
 | 
			
		||||
@@ -131,7 +131,7 @@ TEST_TAGS ?= sqlite sqlite_unlock_notify
 | 
			
		||||
TAR_EXCLUDES := .git data indexers queues log node_modules $(EXECUTABLE) $(FOMANTIC_WORK_DIR)/node_modules $(DIST) $(MAKE_EVIDENCE_DIR) $(AIR_TMP_DIR) $(GO_LICENSE_TMP_DIR)
 | 
			
		||||
 | 
			
		||||
GO_DIRS := cmd tests models modules routers build services tools
 | 
			
		||||
WEB_DIRS := web_src/js web_src/less
 | 
			
		||||
WEB_DIRS := web_src/js web_src/css
 | 
			
		||||
 | 
			
		||||
GO_SOURCES := $(wildcard *.go)
 | 
			
		||||
GO_SOURCES += $(shell find $(GO_DIRS) -type f -name "*.go" -not -path modules/options/bindata.go -not -path modules/public/bindata.go -not -path modules/templates/bindata.go)
 | 
			
		||||
@@ -341,7 +341,7 @@ lint: lint-frontend lint-backend
 | 
			
		||||
.PHONY: lint-frontend
 | 
			
		||||
lint-frontend: node_modules
 | 
			
		||||
	npx eslint --color --max-warnings=0 --ext js,vue web_src/js build *.config.js docs/assets/js tests/e2e
 | 
			
		||||
	npx stylelint --color --max-warnings=0 web_src/less
 | 
			
		||||
	npx stylelint --color --max-warnings=0 web_src/css
 | 
			
		||||
	npx spectral lint -q -F hint $(SWAGGER_SPEC)
 | 
			
		||||
	npx markdownlint docs *.md
 | 
			
		||||
 | 
			
		||||
@@ -859,6 +859,8 @@ fomantic:
 | 
			
		||||
	cp -f $(FOMANTIC_WORK_DIR)/theme.config.less $(FOMANTIC_WORK_DIR)/node_modules/fomantic-ui/src/theme.config
 | 
			
		||||
	cp -rf $(FOMANTIC_WORK_DIR)/_site $(FOMANTIC_WORK_DIR)/node_modules/fomantic-ui/src/
 | 
			
		||||
	cd $(FOMANTIC_WORK_DIR) && npx gulp -f node_modules/fomantic-ui/gulpfile.js build
 | 
			
		||||
	# fomantic uses "touchstart" as click event for some browsers, it's not ideal, so we force fomantic to always use "click" as click event
 | 
			
		||||
	$(SED_INPLACE) -e 's/clickEvent[ \t]*=/clickEvent = "click", unstableClickEvent =/g' $(FOMANTIC_WORK_DIR)/build/semantic.js
 | 
			
		||||
	$(SED_INPLACE) -e 's/\r//g' $(FOMANTIC_WORK_DIR)/build/semantic.css $(FOMANTIC_WORK_DIR)/build/semantic.js
 | 
			
		||||
	rm -f $(FOMANTIC_WORK_DIR)/build/*.min.*
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										5
									
								
								assets/go-licenses.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										5
									
								
								assets/go-licenses.json
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										11
									
								
								cmd/admin.go
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								cmd/admin.go
									
									
									
									
									
								
							@@ -7,6 +7,7 @@ package cmd
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"os"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"text/tabwriter"
 | 
			
		||||
@@ -469,11 +470,19 @@ func runAddOauth(c *cli.Context) error {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	config := parseOAuth2Config(c)
 | 
			
		||||
	if config.Provider == "openidConnect" {
 | 
			
		||||
		discoveryURL, err := url.Parse(config.OpenIDConnectAutoDiscoveryURL)
 | 
			
		||||
		if err != nil || (discoveryURL.Scheme != "http" && discoveryURL.Scheme != "https") {
 | 
			
		||||
			return fmt.Errorf("invalid Auto Discovery URL: %s (this must be a valid URL starting with http:// or https://)", config.OpenIDConnectAutoDiscoveryURL)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return auth_model.CreateSource(&auth_model.Source{
 | 
			
		||||
		Type:     auth_model.OAuth2,
 | 
			
		||||
		Name:     c.String("name"),
 | 
			
		||||
		IsActive: true,
 | 
			
		||||
		Cfg:      parseOAuth2Config(c),
 | 
			
		||||
		Cfg:      config,
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -35,7 +35,7 @@ func runConvert(ctx *cli.Context) error {
 | 
			
		||||
	log.Info("Log path: %s", setting.Log.RootPath)
 | 
			
		||||
	log.Info("Configuration file: %s", setting.CustomConf)
 | 
			
		||||
 | 
			
		||||
	if !setting.Database.UseMySQL {
 | 
			
		||||
	if !setting.Database.Type.IsMySQL() {
 | 
			
		||||
		fmt.Println("This command can only be used with a MySQL database")
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -272,13 +272,14 @@ func runDump(ctx *cli.Context) error {
 | 
			
		||||
		fatal("Failed to create tmp file: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	defer func() {
 | 
			
		||||
		_ = dbDump.Close()
 | 
			
		||||
		if err := util.Remove(dbDump.Name()); err != nil {
 | 
			
		||||
			log.Warn("Unable to remove temporary file: %s: Error: %v", dbDump.Name(), err)
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	targetDBType := ctx.String("database")
 | 
			
		||||
	if len(targetDBType) > 0 && targetDBType != setting.Database.Type {
 | 
			
		||||
	if len(targetDBType) > 0 && targetDBType != setting.Database.Type.String() {
 | 
			
		||||
		log.Info("Dumping database %s => %s...", setting.Database.Type, targetDBType)
 | 
			
		||||
	} else {
 | 
			
		||||
		log.Info("Dumping database...")
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										25
									
								
								cmd/serv.go
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								cmd/serv.go
									
									
									
									
									
								
							@@ -11,6 +11,7 @@ import (
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"os"
 | 
			
		||||
	"os/exec"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"regexp"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
@@ -290,17 +291,21 @@ func runServ(c *cli.Context) error {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Special handle for Windows.
 | 
			
		||||
	if setting.IsWindows {
 | 
			
		||||
		verb = strings.Replace(verb, "-", " ", 1)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var gitcmd *exec.Cmd
 | 
			
		||||
	verbs := strings.Split(verb, " ")
 | 
			
		||||
	if len(verbs) == 2 {
 | 
			
		||||
		gitcmd = exec.CommandContext(ctx, verbs[0], verbs[1], repoPath)
 | 
			
		||||
	} else {
 | 
			
		||||
		gitcmd = exec.CommandContext(ctx, verb, repoPath)
 | 
			
		||||
	gitBinPath := filepath.Dir(git.GitExecutable) // e.g. /usr/bin
 | 
			
		||||
	gitBinVerb := filepath.Join(gitBinPath, verb) // e.g. /usr/bin/git-upload-pack
 | 
			
		||||
	if _, err := os.Stat(gitBinVerb); err != nil {
 | 
			
		||||
		// if the command "git-upload-pack" doesn't exist, try to split "git-upload-pack" to use the sub-command with git
 | 
			
		||||
		// ps: Windows only has "git.exe" in the bin path, so Windows always uses this way
 | 
			
		||||
		verbFields := strings.SplitN(verb, "-", 2)
 | 
			
		||||
		if len(verbFields) == 2 {
 | 
			
		||||
			// use git binary with the sub-command part: "C:\...\bin\git.exe", "upload-pack", ...
 | 
			
		||||
			gitcmd = exec.CommandContext(ctx, git.GitExecutable, verbFields[1], repoPath)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if gitcmd == nil {
 | 
			
		||||
		// by default, use the verb (it has been checked above by allowedCommands)
 | 
			
		||||
		gitcmd = exec.CommandContext(ctx, gitBinVerb, repoPath)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	process.SetSysProcAttribute(gitcmd)
 | 
			
		||||
 
 | 
			
		||||
@@ -1832,7 +1832,7 @@ ROUTER = console
 | 
			
		||||
;ENABLED = true
 | 
			
		||||
;;
 | 
			
		||||
;; Comma-separated list of allowed file extensions (`.zip`), mime types (`text/plain`) or wildcard type (`image/*`, `audio/*`, `video/*`). Empty value or `*/*` allows all types.
 | 
			
		||||
;ALLOWED_TYPES = .csv,.docx,.fodg,.fodp,.fods,.fodt,.gif,.gz,.jpeg,.jpg,.log,.md,.mov,.mp4,.odf,.odg,.odp,.ods,.odt,.pdf,.png,.pptx,.svg,.tgz,.txt,.webm,.xls,.xlsx,.zip
 | 
			
		||||
;ALLOWED_TYPES = .csv,.docx,.fodg,.fodp,.fods,.fodt,.gif,.gz,.jpeg,.jpg,.log,.md,.mov,.mp4,.odf,.odg,.odp,.ods,.odt,.patch,.pdf,.png,.pptx,.svg,.tgz,.txt,.webm,.xls,.xlsx,.zip
 | 
			
		||||
;;
 | 
			
		||||
;; Max size of each file. Defaults to 4MB
 | 
			
		||||
;MAX_SIZE = 4
 | 
			
		||||
@@ -1871,6 +1871,9 @@ ROUTER = console
 | 
			
		||||
;;
 | 
			
		||||
;; Minio enabled ssl only available when STORAGE_TYPE is `minio`
 | 
			
		||||
;MINIO_USE_SSL = false
 | 
			
		||||
;;
 | 
			
		||||
;; Minio skip SSL verification available when STORAGE_TYPE is `minio`
 | 
			
		||||
;MINIO_INSECURE_SKIP_VERIFY = false
 | 
			
		||||
 | 
			
		||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 | 
			
		||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 | 
			
		||||
@@ -2253,6 +2256,17 @@ ROUTER = console
 | 
			
		||||
;PULL = 300
 | 
			
		||||
;GC = 60
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 | 
			
		||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 | 
			
		||||
;; Git Reflog timeout in days
 | 
			
		||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 | 
			
		||||
;[git.reflog]
 | 
			
		||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 | 
			
		||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 | 
			
		||||
;ENABLED = true
 | 
			
		||||
;EXPIRATION = 90
 | 
			
		||||
 | 
			
		||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 | 
			
		||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 | 
			
		||||
;[mirror]
 | 
			
		||||
@@ -2552,6 +2566,9 @@ ROUTER = console
 | 
			
		||||
;;
 | 
			
		||||
;; Minio enabled ssl only available when STORAGE_TYPE is `minio`
 | 
			
		||||
;MINIO_USE_SSL = false
 | 
			
		||||
;;
 | 
			
		||||
;; Minio skip SSL verification available when STORAGE_TYPE is `minio`
 | 
			
		||||
;MINIO_INSECURE_SKIP_VERIFY = false
 | 
			
		||||
 | 
			
		||||
;[proxy]
 | 
			
		||||
;; Enable the proxy, all requests to external via HTTP will be affected
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}{{#if (hasPrefix "refs/heads/release/v" build.ref)}}{{trimPrefix "refs/heads/release/v" build.ref}}-{{/if}}dev{{/if}}-rootless
 | 
			
		||||
{{#if build.tags}}
 | 
			
		||||
{{#unless contains "-rc" build.tag}}
 | 
			
		||||
{{#unless (contains "-rc" build.tag)}}
 | 
			
		||||
tags:
 | 
			
		||||
{{#each build.tags}}
 | 
			
		||||
  - {{this}}-rootless
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}{{#if (hasPrefix "refs/heads/release/v" build.ref)}}{{trimPrefix "refs/heads/release/v" build.ref}}-{{/if}}dev{{/if}}
 | 
			
		||||
{{#if build.tags}}
 | 
			
		||||
{{#unless contains "-rc" build.tag }}
 | 
			
		||||
{{#unless (contains "-rc" build.tag)}}
 | 
			
		||||
tags:
 | 
			
		||||
{{#each build.tags}}
 | 
			
		||||
  - {{this}}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
THEME := themes/gitea
 | 
			
		||||
PUBLIC := public
 | 
			
		||||
ARCHIVE := https://dl.gitea.io/theme/master.tar.gz
 | 
			
		||||
ARCHIVE := https://dl.gitea.com/theme/main.tar.gz
 | 
			
		||||
 | 
			
		||||
HUGO_PACKAGE := github.com/gohugoio/hugo@v0.82.0
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -841,7 +841,7 @@ Default templates for project boards:
 | 
			
		||||
## Issue and pull request attachments (`attachment`)
 | 
			
		||||
 | 
			
		||||
- `ENABLED`: **true**: Whether issue and pull request attachments are enabled.
 | 
			
		||||
- `ALLOWED_TYPES`: **.csv,.docx,.fodg,.fodp,.fods,.fodt,.gif,.gz,.jpeg,.jpg,.log,.md,.mov,.mp4,.odf,.odg,.odp,.ods,.odt,.pdf,.png,.pptx,.svg,.tgz,.txt,.webm,.xls,.xlsx,.zip**: Comma-separated list of allowed file extensions (`.zip`), mime types (`text/plain`) or wildcard type (`image/*`, `audio/*`, `video/*`). Empty value or `*/*` allows all types.
 | 
			
		||||
- `ALLOWED_TYPES`: **.csv,.docx,.fodg,.fodp,.fods,.fodt,.gif,.gz,.jpeg,.jpg,.log,.md,.mov,.mp4,.odf,.odg,.odp,.ods,.odt,.patch,.pdf,.png,.pptx,.svg,.tgz,.txt,.webm,.xls,.xlsx,.zip**: Comma-separated list of allowed file extensions (`.zip`), mime types (`text/plain`) or wildcard type (`image/*`, `audio/*`, `video/*`). Empty value or `*/*` allows all types.
 | 
			
		||||
- `MAX_SIZE`: **4**: Maximum size (MB).
 | 
			
		||||
- `MAX_FILES`: **5**: Maximum number of attachments that can be uploaded at once.
 | 
			
		||||
- `STORAGE_TYPE`: **local**: Storage type for attachments, `local` for local disk or `minio` for s3 compatible object storage service, default is `local` or other name defined with `[storage.xxx]`
 | 
			
		||||
@@ -854,6 +854,7 @@ Default templates for project boards:
 | 
			
		||||
- `MINIO_LOCATION`: **us-east-1**: Minio location to create bucket only available when STORAGE_TYPE is `minio`
 | 
			
		||||
- `MINIO_BASE_PATH`: **attachments/**: Minio base path on the bucket only available when STORAGE_TYPE is `minio`
 | 
			
		||||
- `MINIO_USE_SSL`: **false**: Minio enabled ssl only available when STORAGE_TYPE is `minio`
 | 
			
		||||
- `MINIO_INSECURE_SKIP_VERIFY`: **false**: Minio skip SSL verification available when STORAGE_TYPE is `minio`
 | 
			
		||||
 | 
			
		||||
## Log (`log`)
 | 
			
		||||
 | 
			
		||||
@@ -1086,6 +1087,11 @@ Default templates for project boards:
 | 
			
		||||
- `DISABLE_CORE_PROTECT_NTFS`: **false** Set to true to forcibly set `core.protectNTFS` to false.
 | 
			
		||||
- `DISABLE_PARTIAL_CLONE`: **false** Disable the usage of using partial clones for git.
 | 
			
		||||
 | 
			
		||||
## Git - Reflog settings (`git.reflog`)
 | 
			
		||||
 | 
			
		||||
- `ENABLED`: **true** Set to true to enable Git to write changes to reflogs in each repo.
 | 
			
		||||
- `EXPIRATION`: **90** Reflog entry lifetime, in days. Entries are removed opportunistically by Git.
 | 
			
		||||
 | 
			
		||||
## Git - Timeout settings (`git.timeout`)
 | 
			
		||||
 | 
			
		||||
- `DEFAULT`: **360**: Git operations default timeout seconds.
 | 
			
		||||
@@ -1268,6 +1274,7 @@ is `data/lfs` and the default of `MINIO_BASE_PATH` is `lfs/`.
 | 
			
		||||
- `MINIO_LOCATION`: **us-east-1**: Minio location to create bucket only available when `STORAGE_TYPE` is `minio`
 | 
			
		||||
- `MINIO_BASE_PATH`: **lfs/**: Minio base path on the bucket only available when `STORAGE_TYPE` is `minio`
 | 
			
		||||
- `MINIO_USE_SSL`: **false**: Minio enabled ssl only available when `STORAGE_TYPE` is `minio`
 | 
			
		||||
- `MINIO_INSECURE_SKIP_VERIFY`: **false**: Minio skip SSL verification available when STORAGE_TYPE is `minio`
 | 
			
		||||
 | 
			
		||||
## Storage (`storage`)
 | 
			
		||||
 | 
			
		||||
@@ -1280,6 +1287,7 @@ Default storage configuration for attachments, lfs, avatars and etc.
 | 
			
		||||
- `MINIO_BUCKET`: **gitea**: Minio bucket to store the data only available when `STORAGE_TYPE` is `minio`
 | 
			
		||||
- `MINIO_LOCATION`: **us-east-1**: Minio location to create bucket only available when `STORAGE_TYPE` is `minio`
 | 
			
		||||
- `MINIO_USE_SSL`: **false**: Minio enabled ssl only available when `STORAGE_TYPE` is `minio`
 | 
			
		||||
- `MINIO_INSECURE_SKIP_VERIFY`: **false**: Minio skip SSL verification available when STORAGE_TYPE is `minio`
 | 
			
		||||
 | 
			
		||||
And you can also define a customize storage like below:
 | 
			
		||||
 | 
			
		||||
@@ -1298,6 +1306,8 @@ MINIO_BUCKET = gitea
 | 
			
		||||
MINIO_LOCATION = us-east-1
 | 
			
		||||
; Minio enabled ssl only available when STORAGE_TYPE is `minio`
 | 
			
		||||
MINIO_USE_SSL = false
 | 
			
		||||
; Minio skip SSL verification available when STORAGE_TYPE is `minio`
 | 
			
		||||
MINIO_INSECURE_SKIP_VERIFY = false
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
And used by `[attachment]`, `[lfs]` and etc. as `STORAGE_TYPE`.
 | 
			
		||||
@@ -1318,6 +1328,7 @@ is `data/repo-archive` and the default of `MINIO_BASE_PATH` is `repo-archive/`.
 | 
			
		||||
- `MINIO_LOCATION`: **us-east-1**: Minio location to create bucket only available when `STORAGE_TYPE` is `minio`
 | 
			
		||||
- `MINIO_BASE_PATH`: **repo-archive/**: Minio base path on the bucket only available when `STORAGE_TYPE` is `minio`
 | 
			
		||||
- `MINIO_USE_SSL`: **false**: Minio enabled ssl only available when `STORAGE_TYPE` is `minio`
 | 
			
		||||
- `MINIO_INSECURE_SKIP_VERIFY`: **false**: Minio skip SSL verification available when STORAGE_TYPE is `minio`
 | 
			
		||||
 | 
			
		||||
## Proxy (`proxy`)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -431,6 +431,8 @@ MINIO_BUCKET = gitea
 | 
			
		||||
MINIO_LOCATION = us-east-1
 | 
			
		||||
; Minio enabled ssl only available when STORAGE_TYPE is `minio`
 | 
			
		||||
MINIO_USE_SSL = false
 | 
			
		||||
; Minio skip SSL verification available when STORAGE_TYPE is `minio`
 | 
			
		||||
MINIO_INSECURE_SKIP_VERIFY = false
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
然后你在 `[attachment]`, `[lfs]` 等中可以把这个名字用作 `STORAGE_TYPE` 的值。
 | 
			
		||||
 
 | 
			
		||||
@@ -282,9 +282,22 @@ To add custom .gitignore, add a file with existing [.gitignore rules](https://gi
 | 
			
		||||
 | 
			
		||||
### Labels
 | 
			
		||||
 | 
			
		||||
To add a custom label set, add a file that follows the [label format](https://github.com/go-gitea/gitea/blob/main/options/label/Default) to `$GITEA_CUSTOM/options/label`
 | 
			
		||||
Starting with Gitea 1.19, you can add a file that follows the [YAML label format](https://github.com/go-gitea/gitea/blob/main/options/label/Advanced.yaml) to `$GITEA_CUSTOM/options/label`:
 | 
			
		||||
 | 
			
		||||
```yaml
 | 
			
		||||
labels:
 | 
			
		||||
  - name: "foo/bar"  # name of the label that will appear in the dropdown
 | 
			
		||||
    exclusive: true # whether to use the exclusive namespace for scoped labels. scoped delimiter is /
 | 
			
		||||
    color: aabbcc # hex colour coding
 | 
			
		||||
    description: Some label # long description of label intent
 | 
			
		||||
 ```
 | 
			
		||||
 | 
			
		||||
The [legacy file format](https://github.com/go-gitea/gitea/blob/main/options/label/Default) can still be used following the format below, however we strongly recommend using the newer YAML format instead.
 | 
			
		||||
 | 
			
		||||
`#hex-color label name ; label description`
 | 
			
		||||
 | 
			
		||||
For more information, see the [labels documentation]({{< relref "doc/usage/labels.en-us.md" >}}).
 | 
			
		||||
 | 
			
		||||
### Licenses
 | 
			
		||||
 | 
			
		||||
To add a custom license, add a file with the license text to `$GITEA_CUSTOM/options/license`
 | 
			
		||||
@@ -341,7 +354,7 @@ To make a custom theme available to all users:
 | 
			
		||||
 | 
			
		||||
Community themes are listed in [gitea/awesome-gitea#themes](https://gitea.com/gitea/awesome-gitea#themes).
 | 
			
		||||
 | 
			
		||||
The `arc-green` theme source can be found [here](https://github.com/go-gitea/gitea/blob/main/web_src/less/themes/theme-arc-green.less).
 | 
			
		||||
The `arc-green` theme source can be found [here](https://github.com/go-gitea/gitea/blob/main/web_src/css/themes/theme-arc-green.css).
 | 
			
		||||
 | 
			
		||||
If your custom theme is considered a dark theme, set the global css variable `--is-dark-theme` to `true`.
 | 
			
		||||
This allows Gitea to adjust the Monaco code editor's theme accordingly.
 | 
			
		||||
 
 | 
			
		||||
@@ -21,13 +21,13 @@ menu:
 | 
			
		||||
 | 
			
		||||
## Background
 | 
			
		||||
 | 
			
		||||
Gitea uses [Less CSS](https://lesscss.org), [Fomantic-UI](https://fomantic-ui.com/introduction/getting-started.html) (based on [jQuery](https://api.jquery.com)) and [Vue3](https://vuejs.org/) for its frontend.
 | 
			
		||||
Gitea uses [Fomantic-UI](https://fomantic-ui.com/introduction/getting-started.html) (based on [jQuery](https://api.jquery.com)) and [Vue3](https://vuejs.org/) for its frontend.
 | 
			
		||||
 | 
			
		||||
The HTML pages are rendered by [Go HTML Template](https://pkg.go.dev/html/template).
 | 
			
		||||
 | 
			
		||||
The source files can be found in the following directories:
 | 
			
		||||
 | 
			
		||||
* **Less styles:** `web_src/less/`
 | 
			
		||||
* **CSS styles:** `web_src/css/`
 | 
			
		||||
* **JavaScript files:** `web_src/js/`
 | 
			
		||||
* **Vue components:** `web_src/js/components/`
 | 
			
		||||
* **Go HTML templates:** `templates/`
 | 
			
		||||
 
 | 
			
		||||
@@ -6,11 +6,11 @@ weight: 20
 | 
			
		||||
toc: false
 | 
			
		||||
draft: false
 | 
			
		||||
menu:
 | 
			
		||||
sidebar:
 | 
			
		||||
parent: "developers"
 | 
			
		||||
name: "Guidelines for Refactoring"
 | 
			
		||||
weight: 20
 | 
			
		||||
identifier: "guidelines-refactoring"
 | 
			
		||||
  sidebar:
 | 
			
		||||
    parent: "developers"
 | 
			
		||||
    name: "Guidelines for Refactoring"
 | 
			
		||||
    weight: 20
 | 
			
		||||
    identifier: "guidelines-refactoring"
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
# Guidelines for Refactoring
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										349
									
								
								docs/content/doc/developers/hacking-on-gitea.zh-cn.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										349
									
								
								docs/content/doc/developers/hacking-on-gitea.zh-cn.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,349 @@
 | 
			
		||||
---
 | 
			
		||||
date: "2016-12-01T16:00:00+02:00"
 | 
			
		||||
title: "玩转 Gitea"
 | 
			
		||||
slug: "hacking-on-gitea"
 | 
			
		||||
weight: 10
 | 
			
		||||
toc: false
 | 
			
		||||
draft: false
 | 
			
		||||
menu:
 | 
			
		||||
  sidebar:
 | 
			
		||||
    parent: "developers"
 | 
			
		||||
    name: "玩转 Gitea"
 | 
			
		||||
    weight: 10
 | 
			
		||||
    identifier: "hacking-on-gitea"
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
# Hacking on Gitea
 | 
			
		||||
 | 
			
		||||
**目录**
 | 
			
		||||
 | 
			
		||||
{{< toc >}}
 | 
			
		||||
 | 
			
		||||
## 快速入门
 | 
			
		||||
 | 
			
		||||
要获得快速工作的开发环境,您可以使用 Gitpod。
 | 
			
		||||
 | 
			
		||||
[](https://gitpod.io/#https://github.com/go-gitea/gitea)
 | 
			
		||||
 | 
			
		||||
## 安装 Golang
 | 
			
		||||
 | 
			
		||||
您需要 [安装 go]( https://golang.org/doc/install ) 并设置您的 go 环境。
 | 
			
		||||
 | 
			
		||||
接下来,[使用 npm 安装 Node.js](https://nodejs.org/en/download/) ,这是构建
 | 
			
		||||
JavaScript 和 CSS 文件的必要工具。最低支持的 Node.js 版本是 {{< min-node-version >}}
 | 
			
		||||
并且推荐使用最新的 LTS 版本。
 | 
			
		||||
 | 
			
		||||
**注意** :当执行需要外部工具的 make 任务时,比如
 | 
			
		||||
`make watch-backend`,Gitea 会自动下载并构建这些必要的组件。为了能够使用这些,你必须
 | 
			
		||||
将 `"$GOPATH"/bin` 目录加入到可执行路径上。如果你不把go bin目录添加到可执行路径你必须手动
 | 
			
		||||
指定可执行程序路径。
 | 
			
		||||
 | 
			
		||||
**注意2** :Go版本 {{< min-go-version >}} 或更高版本是必须的。Gitea 使用 `gofmt` 来
 | 
			
		||||
格式化源代码。然而,`gofmt` 的结果可能因 `go` 的版本而有差异。因此推荐安装我们持续集成使用
 | 
			
		||||
的 Go版本。截至上次更新,Go 版本应该是 {{< go-version >}}。
 | 
			
		||||
 | 
			
		||||
## 安装 Make
 | 
			
		||||
 | 
			
		||||
Gitea 大量使用 `Make` 来自动化任务和改进开发。本指南涵盖了如何安装 Make。
 | 
			
		||||
 | 
			
		||||
### 在 Linux 上
 | 
			
		||||
 | 
			
		||||
使用包管理器安装。
 | 
			
		||||
 | 
			
		||||
在 Ubuntu/Debian 上:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
sudo apt-get install make
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
在 Fedora/RHEL/CentOS 上:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
sudo yum install make
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### 在 Windows 上
 | 
			
		||||
 | 
			
		||||
Make 的这三个发行版都可以在 Windows 上运行:
 | 
			
		||||
 | 
			
		||||
- [单个二进制构建]( http://www.equation.com/servlet/equation.cmd?fa=make )。复制到某处并添加到 `PATH`。
 | 
			
		||||
  - [32 位版本](http://www.equation.com/ftpdir/make/32/make.exe)
 | 
			
		||||
  - [64 位版本](http://www.equation.com/ftpdir/make/64/make.exe)
 | 
			
		||||
- [MinGW-w64](https://www.mingw-w64.org) / [MSYS2](https://www.msys2.org/)。
 | 
			
		||||
  - MSYS2 是一个工具和库的集合,为您提供一个易于使用的环境来构建、安装和运行本机 Windows 软件,它包括 MinGW-w64。
 | 
			
		||||
  - 在 MingGW-w64 中,二进制文件称为 `mingw32-make.exe` 而不是 `make.exe`。将 `bin` 文件夹添加到 `PATH`。
 | 
			
		||||
  - 在 MSYS2 中,您可以直接使用 `make`。请参阅 [MSYS2 移植](https://www.msys2.org/wiki/Porting/)。
 | 
			
		||||
  - 要使用 CGO_ENABLED(例如:SQLite3)编译 Gitea,您可能需要使用 [tdm-gcc](https://jmeubank.github.io/tdm-gcc/) 而不是 MSYS2 gcc,因为 MSYS2 gcc 标头缺少一些 Windows -只有 CRT 函数像 _beginthread 一样。
 | 
			
		||||
- [Chocolatey包管理器]( https://chocolatey.org/packages/make )。运行`choco install make`
 | 
			
		||||
 | 
			
		||||
**注意** :如果您尝试在 Windows 命令提示符下使用 make 进行构建,您可能会遇到问题。建议使用上述提示(Git bash 或 MinGW),但是如果您只有命令提示符(或可能是 PowerShell),则可以使用 [set](https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/set_1) 命令,例如 `set TAGS=bindata`。
 | 
			
		||||
 | 
			
		||||
## 下载并克隆 Gitea 源代码
 | 
			
		||||
 | 
			
		||||
获取源代码的推荐方法是使用 `git clone`。
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
git clone https://github.com/go-gitea/gitea
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
(自从go modules出现后,不再需要构建 go 项目从 `$GOPATH` 中获取,因此不再推荐使用 `go get` 方法。)
 | 
			
		||||
 | 
			
		||||
## 派生 Gitea
 | 
			
		||||
 | 
			
		||||
如上所述下载主要的 Gitea 源代码。然后,派生 [Gitea 仓库](https://github.com/go-gitea/gitea),
 | 
			
		||||
并为您的本地仓库切换 git 远程源,或添加另一个远程源:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
# 将原来的 Gitea origin 重命名为 upstream
 | 
			
		||||
git remote rename origin upstream
 | 
			
		||||
git remote add origin "git@github.com:$GITHUB_USERNAME/gitea.git"
 | 
			
		||||
git fetch --all --prune
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
或者:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
# 为我们的 fork 添加新的远程
 | 
			
		||||
git remote add "$FORK_NAME" "git@github.com:$GITHUB_USERNAME/gitea.git"
 | 
			
		||||
git fetch --all --prune
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
为了能够创建合并请求,应将分叉存储库添加为 Gitea 本地仓库的远程,否则无法推送更改。
 | 
			
		||||
 | 
			
		||||
## 构建 Gitea(基本)
 | 
			
		||||
 | 
			
		||||
看看我们的
 | 
			
		||||
<a href='{{ < relref "doc/installation/from-source.en-us.md" > }}'>说明</a>
 | 
			
		||||
关于如何 <a href='{{ < relref "doc/installation/from-source.en-us.md" > }}'>从源代码构建</a> 。
 | 
			
		||||
 | 
			
		||||
从源代码构建的最简单推荐方法是:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
TAGS="bindata sqlite sqlite_unlock_notify" make build
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
`build` 目标将同时执行 `frontend` 和 `backend` 子目标。如果存在 `bindata` 标签,资源文件将被编译成二进制文件。建议在进行前端开发时省略 `bindata` 标签,以便实时反映更改。
 | 
			
		||||
 | 
			
		||||
有关所有可用的 `make` 目标,请参阅 `make help`。另请参阅 [`.drone.yml`](https://github.com/go-gitea/gitea/blob/main/.drone.yml) 以了解我们的持续集成是如何工作的。
 | 
			
		||||
 | 
			
		||||
## 持续构建
 | 
			
		||||
 | 
			
		||||
要在源文件更改时运行并持续构建:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
# 对于前端和后端
 | 
			
		||||
make watch
 | 
			
		||||
 | 
			
		||||
# 或者:只看前端文件(html/js/css)
 | 
			
		||||
make watch-frontend
 | 
			
		||||
 | 
			
		||||
# 或者:只看后端文件 (go)
 | 
			
		||||
make watch-backend
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
在 macOS 上,监视所有后端源文件可能会达到默认的打开文件限制,这可以通过当前 shell 的 `ulimit -n 12288` 或所有未来 shell 的 shell 启动文件来增加。
 | 
			
		||||
 | 
			
		||||
### 格式化、代码分析和拼写检查
 | 
			
		||||
 | 
			
		||||
我们的持续集成将拒绝未通过代码检查(包括格式检查、代码分析和拼写检查)的 PR。
 | 
			
		||||
 | 
			
		||||
你应该格式化你的代码:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
make fmt
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
并检查源代码:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
# lint 前端和后端代码
 | 
			
		||||
make lint
 | 
			
		||||
# 仅 lint 后端代码
 | 
			
		||||
make lint-backend
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**注意** :`gofmt` 的结果取决于 `go` 的版本。您应该运行与持续集成相同的 go 版本。
 | 
			
		||||
 | 
			
		||||
### 处理 JS 和 CSS
 | 
			
		||||
 | 
			
		||||
前端开发应遵循 [Guidelines for Frontend Development]({{ < 相关参考 "doc/developers/guidelines-frontend.en-us.md" > }})
 | 
			
		||||
 | 
			
		||||
要使用前端资源构建,请使用上面提到的“watch-frontend”目标或只构建一次:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
make build && ./gitea
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
在提交之前,确保 linters 通过:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
make lint-frontend
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### 配置本地 ElasticSearch 实例
 | 
			
		||||
 | 
			
		||||
使用 docker 启动本地 ElasticSearch 实例:
 | 
			
		||||
 | 
			
		||||
```sh
 | 
			
		||||
mkdir -p $(pwd) /data/elasticsearch
 | 
			
		||||
sudo chown -R 1000:1000 $(pwd) /data/elasticsearch
 | 
			
		||||
docker run --rm --memory= "4g" -p 127.0.0.1:9200:9200 -p 127.0.0.1:9300:9300 -e "discovery.type=single-node" -v "$(pwd)/data /elasticsearch:/usr/share/elasticsearch/data" docker.elastic.co/elasticsearch/elasticsearch:7.16.3
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
配置`app.ini`:
 | 
			
		||||
 | 
			
		||||
```ini
 | 
			
		||||
[indexer]
 | 
			
		||||
ISSUE_INDEXER_TYPE = elasticsearch
 | 
			
		||||
ISSUE_INDEXER_CONN_STR = http://elastic:changeme@localhost:9200
 | 
			
		||||
REPO_INDEXER_ENABLED = true
 | 
			
		||||
REPO_INDEXER_TYPE = elasticsearch
 | 
			
		||||
REPO_INDEXER_CONN_STR = http://elastic:changeme@localhost:9200
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### 构建和添加 SVGs
 | 
			
		||||
 | 
			
		||||
SVG 图标是使用 `make svg` 目标构建的,该目标将 `build/generate-svg.js` 中定义的图标源编译到输出目录 `public/img/svg` 中。可以在 `web_src/svg` 目录中添加自定义图标。
 | 
			
		||||
 | 
			
		||||
### 构建 Logo
 | 
			
		||||
 | 
			
		||||
Gitea Logo的 PNG 和 SVG 版本是使用 `TAGS="gitea" make generate-images` 目标从单个 SVG 源文件 assets/logo.svg 构建的。要运行它,Node.js 和 npm 必须可用。
 | 
			
		||||
 | 
			
		||||
通过更新 `assets/logo.svg` 并运行 `make generate-images`,同样的过程也可用于从 SVG 源文件生成自定义 Logo PNG。忽略 gitea 编译选项将仅更新用户指定的 LOGO 文件。
 | 
			
		||||
 | 
			
		||||
### 更新 API
 | 
			
		||||
 | 
			
		||||
创建新的 API 路由或修改现有的 API 路由时,您**必须**
 | 
			
		||||
更新和/或创建 [Swagger](https://swagger.io/docs/specification/2-0/what-is-swagger/)
 | 
			
		||||
这些使用 [go-swagger](https://goswagger.io/) 评论的文档。
 | 
			
		||||
[规范]( https://goswagger.io/use/spec.html#annotation-syntax )中描述了这些注释的结构。
 | 
			
		||||
如果您想了解更多有关 Swagger 结构的信息,可以查看
 | 
			
		||||
[Swagger 2.0 文档](https://swagger.io/docs/specification/2-0/basic-structure/)
 | 
			
		||||
或与添加新 API 端点的先前 PR 进行比较,例如 [PR #5483](https://github.com/go-gitea/gitea/pull/5843/files#diff-2e0a7b644cf31e1c8ef7d76b444fe3aaR20)
 | 
			
		||||
 | 
			
		||||
您应该注意不要破坏下游用户依赖的 API。在稳定的 API 上,一般来说添加是可以接受的,但删除
 | 
			
		||||
或对 API 进行根本性更改将会被拒绝。
 | 
			
		||||
 | 
			
		||||
创建或更改 API 端点后,请用以下命令重新生成 Swagger 文档:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
make generate-swagger
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
您应该验证生成的 Swagger 文件并使用以下命令对其进行拼写检查:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
make swagger-validate misspell-check
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
您应该提交更改后的 swagger JSON 文件。持续集成服务器将使用以下方法检查是否已完成:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
make swagger-check
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**注意** :请注意,您应该使用 Swagger 2.0 文档,而不是 OpenAPI 3 文档。
 | 
			
		||||
 | 
			
		||||
### 创建新的配置选项
 | 
			
		||||
 | 
			
		||||
创建新的配置选项时,将它们添加到 `modules/setting` 的对应文件。您应该将信息添加到 `custom/conf/app.ini`
 | 
			
		||||
并到 <a href = '{{ < relref "doc/advanced/config-cheat-sheet.en-us.md" > }}'>配置备忘单</a>
 | 
			
		||||
在 `docs/content/doc/advanced/config-cheat-sheet.en-us.md` 中找到
 | 
			
		||||
 | 
			
		||||
### 更改Logo
 | 
			
		||||
 | 
			
		||||
更改 Gitea Logo SVG 时,您将需要运行并提交结果的:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
make generate-images
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
这将创建必要的 Gitea 图标和其他图标。
 | 
			
		||||
 | 
			
		||||
### 数据库迁移
 | 
			
		||||
 | 
			
		||||
如果您对数据库中的任何数据库持久结构进行重大更改
 | 
			
		||||
`models/` 目录,您将需要进行新的迁移。可以找到这些
 | 
			
		||||
在 `models/migrations/` 中。您可以确保您的迁移适用于主要
 | 
			
		||||
数据库类型使用:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
make test-sqlite-migration # 将 SQLite 切换为适当的数据库
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## 测试
 | 
			
		||||
 | 
			
		||||
Gitea 运行两种类型的测试:单元测试和集成测试。
 | 
			
		||||
 | 
			
		||||
### 单元测试
 | 
			
		||||
 | 
			
		||||
`go test` 系统中的`*_test.go` 涵盖了单元测试。
 | 
			
		||||
您可以设置环境变量 `GITEA_UNIT_TESTS_LOG_SQL=1` 以在详细模式下运行测试时显示所有 SQL 语句(即设置`GOTESTFLAGS=-v` 时)。
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
TAGS="bindata sqlite sqlite_unlock_notify" make test # Runs the unit tests
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### 集成测试
 | 
			
		||||
 | 
			
		||||
单元测试不会也不能完全单独测试 Gitea。因此,我们编写了集成测试;但是,这些依赖于数据库。
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
TAGS="bindata sqlite sqlite_unlock_notify" make build test-sqlite
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
将在 SQLite 环境中运行集成测试。集成测试需要安装 `git lfs`。其他数据库测试可用,但
 | 
			
		||||
可能需要适应当地环境。
 | 
			
		||||
 | 
			
		||||
看看 [`tests/integration/README.md`](https://github.com/go-gitea/gitea/blob/main/tests/integration/README.md) 有关更多信息以及如何运行单个测试。
 | 
			
		||||
 | 
			
		||||
### 测试 PR
 | 
			
		||||
 | 
			
		||||
我们的持续集成将测试代码是否通过了单元测试,并且所有支持的数据库都将在 Docker 环境中通过集成测试。
 | 
			
		||||
还将测试从几个最新版本的 Gitea 迁移。
 | 
			
		||||
 | 
			
		||||
请在PR中附带提交适当的单元测试和集成测试。
 | 
			
		||||
 | 
			
		||||
## 网站文档
 | 
			
		||||
 | 
			
		||||
该网站的文档位于 `docs/` 中。如果你改变了文档内容,你可以使用以下测试方法进行持续集成:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
# 来自 Gitea 中的 docs 目录
 | 
			
		||||
make trans-copy clean build
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
运行此任务依赖于 [Hugo](https://gohugo.io/)。请注意:这可能会生成一些未跟踪的 Git 对象,
 | 
			
		||||
需要被清理干净。
 | 
			
		||||
 | 
			
		||||
## Visual Studio Code
 | 
			
		||||
 | 
			
		||||
`contrib/ide/vscode` 中为 Visual Studio Code 提供了 `launch.json` 和 `tasks.json`。查看
 | 
			
		||||
[`contrib/ide/README.md`](https://github.com/go-gitea/gitea/blob/main/contrib/ide/README.md) 了解更多信息。
 | 
			
		||||
 | 
			
		||||
## Goland
 | 
			
		||||
 | 
			
		||||
单击 `/main.go` 中函数 `func main()` 上的 `Run Application` 箭头
 | 
			
		||||
可以快速启动一个可调试的 Gitea 实例。
 | 
			
		||||
 | 
			
		||||
`Run/Debug Configuration` 中的 `Output Directory` 必须设置为
 | 
			
		||||
gitea 项目目录(包含 `main.go` 和 `go.mod`),
 | 
			
		||||
否则,启动实例的工作目录是 GoLand 的临时目录
 | 
			
		||||
并防止 Gitea 在开发环境中加载动态资源(例如:模板)。
 | 
			
		||||
 | 
			
		||||
要在 GoLand 中使用 SQLite 运行单元测试,请设置 `-tags sqlite,sqlite_unlock_notify`
 | 
			
		||||
在 `运行/调试配置` 的 `Go 工具参数` 中。
 | 
			
		||||
 | 
			
		||||
## 提交 PR
 | 
			
		||||
 | 
			
		||||
对更改感到满意后,将它们推送并打开拉取请求。它建议您允许 Gitea Managers 和 Owners 修改您的 PR
 | 
			
		||||
分支,因为我们需要在合并之前将其更新为 main 和/或可能是能够直接帮助解决问题。
 | 
			
		||||
 | 
			
		||||
任何 PR 都需要 Gitea 维护者的两次批准,并且需要通过持续集成。看看我们的
 | 
			
		||||
[CONTRIBUTING.md](https://github.com/go-gitea/gitea/blob/main/CONTRIBUTING.md)
 | 
			
		||||
文档。
 | 
			
		||||
 | 
			
		||||
如果您需要更多帮助,请访问 [Discord](https://discord.gg/gitea) #Develop 频道
 | 
			
		||||
并在那里聊天。
 | 
			
		||||
 | 
			
		||||
现在,您已准备好 Hacking Gitea。
 | 
			
		||||
@@ -9,7 +9,7 @@ menu:
 | 
			
		||||
    parent: "packages"
 | 
			
		||||
    name: "Overview"
 | 
			
		||||
    weight: 1
 | 
			
		||||
    identifier: "overview"
 | 
			
		||||
    identifier: "packages-overview"
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
# Package Registry
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,7 @@ menu:
 | 
			
		||||
    parent: "secrets"
 | 
			
		||||
    name: "Overview"
 | 
			
		||||
    weight: 1
 | 
			
		||||
    identifier: "overview"
 | 
			
		||||
    identifier: "secrets-overview"
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
# Secrets
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										40
									
								
								docs/content/doc/usage/labels.en-us.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								docs/content/doc/usage/labels.en-us.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,40 @@
 | 
			
		||||
---
 | 
			
		||||
date: "2023-03-04T19:00:00+00:00"
 | 
			
		||||
title: "Usage: Labels"
 | 
			
		||||
slug: "labels"
 | 
			
		||||
weight: 13
 | 
			
		||||
toc: false
 | 
			
		||||
draft: false
 | 
			
		||||
menu:
 | 
			
		||||
  sidebar:
 | 
			
		||||
    parent: "usage"
 | 
			
		||||
    name: "Labels"
 | 
			
		||||
    weight: 13
 | 
			
		||||
    identifier: "labels"
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
# Labels
 | 
			
		||||
 | 
			
		||||
You can use labels to classify issues and pull requests and to improve your overview over them.
 | 
			
		||||
 | 
			
		||||
## Creating Labels
 | 
			
		||||
 | 
			
		||||
For repositories, labels can be created by going to `Issues` and clicking on `Labels`.
 | 
			
		||||
 | 
			
		||||
For organizations, you can define organization-wide labels that are shared with all organization repositories, including both already-existing repositories as well as newly created ones. Organization-wide labels can be created in the organization `Settings`.
 | 
			
		||||
 | 
			
		||||
Labels have a mandatory name, a mandatory color, an optional description, and must either be exclusive or not (see `Scoped Labels` below).
 | 
			
		||||
 | 
			
		||||
When you create a repository, you can ensure certain labels exist by using the `Issue Labels` option. This option lists a number of available label sets that are [configured globally on your instance](../customizing-gitea/#labels). Its contained labels will all be created as well while creating the repository.
 | 
			
		||||
 | 
			
		||||
## Scoped Labels
 | 
			
		||||
 | 
			
		||||
Scoped labels are used to ensure at most a single label with the same scope is assigned to an issue or pull request. For example, if labels `kind/bug` and `kind/enhancement` have the Exclusive option set, an issue can only be classified as a bug or an enhancement.
 | 
			
		||||
 | 
			
		||||
A scoped label must contain `/` in its name (not at either end of the name). The scope of a label is determined based on the **last** `/`, so for example the scope of label `scope/subscope/item` is `scope/subscope`.
 | 
			
		||||
 | 
			
		||||
## Filtering by Label
 | 
			
		||||
 | 
			
		||||
Issue and pull request lists can be filtered by label. Selecting multiple labels shows issues and pull requests that have all selected labels assigned.
 | 
			
		||||
 | 
			
		||||
By holding alt to click the label, issues and pull requests with the chosen label are excluded from the list.
 | 
			
		||||
							
								
								
									
										13
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								go.mod
									
									
									
									
									
								
							@@ -41,7 +41,7 @@ require (
 | 
			
		||||
	github.com/go-chi/cors v1.2.1
 | 
			
		||||
	github.com/go-enry/go-enry/v2 v2.8.3
 | 
			
		||||
	github.com/go-fed/httpsig v1.1.1-0.20201223112313-55836744818e
 | 
			
		||||
	github.com/go-git/go-billy/v5 v5.4.0
 | 
			
		||||
	github.com/go-git/go-billy/v5 v5.4.1
 | 
			
		||||
	github.com/go-git/go-git/v5 v5.5.2
 | 
			
		||||
	github.com/go-ldap/ldap/v3 v3.4.4
 | 
			
		||||
	github.com/go-redis/redis/v8 v8.11.5
 | 
			
		||||
@@ -77,7 +77,7 @@ require (
 | 
			
		||||
	github.com/microcosm-cc/bluemonday v1.0.21
 | 
			
		||||
	github.com/minio/minio-go/v7 v7.0.46
 | 
			
		||||
	github.com/msteinert/pam v1.1.0
 | 
			
		||||
	github.com/nektos/act v0.0.0
 | 
			
		||||
	github.com/nektos/act v0.2.43
 | 
			
		||||
	github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
 | 
			
		||||
	github.com/niklasfasching/go-org v1.6.5
 | 
			
		||||
	github.com/oliamb/cutter v0.2.2
 | 
			
		||||
@@ -105,7 +105,7 @@ require (
 | 
			
		||||
	golang.org/x/crypto v0.4.0
 | 
			
		||||
	golang.org/x/net v0.7.0
 | 
			
		||||
	golang.org/x/oauth2 v0.3.0
 | 
			
		||||
	golang.org/x/sys v0.5.0
 | 
			
		||||
	golang.org/x/sys v0.6.0
 | 
			
		||||
	golang.org/x/text v0.7.0
 | 
			
		||||
	golang.org/x/tools v0.1.12
 | 
			
		||||
	google.golang.org/grpc v1.47.0
 | 
			
		||||
@@ -172,7 +172,6 @@ require (
 | 
			
		||||
	github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect
 | 
			
		||||
	github.com/go-enry/go-oniguruma v1.2.1 // indirect
 | 
			
		||||
	github.com/go-git/gcfg v1.5.0 // indirect
 | 
			
		||||
	github.com/go-ini/ini v1.67.0 // indirect
 | 
			
		||||
	github.com/go-openapi/analysis v0.21.4 // indirect
 | 
			
		||||
	github.com/go-openapi/errors v0.20.3 // indirect
 | 
			
		||||
	github.com/go-openapi/inflect v0.19.0 // indirect
 | 
			
		||||
@@ -239,7 +238,7 @@ require (
 | 
			
		||||
	github.com/prometheus/client_model v0.3.0 // indirect
 | 
			
		||||
	github.com/prometheus/common v0.37.0 // indirect
 | 
			
		||||
	github.com/prometheus/procfs v0.8.0 // indirect
 | 
			
		||||
	github.com/rhysd/actionlint v1.6.22 // indirect
 | 
			
		||||
	github.com/rhysd/actionlint v1.6.23 // indirect
 | 
			
		||||
	github.com/rivo/uniseg v0.4.3 // indirect
 | 
			
		||||
	github.com/robfig/cron v1.2.0 // indirect
 | 
			
		||||
	github.com/rogpeppe/go-internal v1.9.0 // indirect
 | 
			
		||||
@@ -271,7 +270,7 @@ require (
 | 
			
		||||
	go.uber.org/multierr v1.9.0 // indirect
 | 
			
		||||
	go.uber.org/zap v1.24.0 // indirect
 | 
			
		||||
	golang.org/x/mod v0.7.0 // indirect
 | 
			
		||||
	golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde // indirect
 | 
			
		||||
	golang.org/x/sync v0.1.0 // indirect
 | 
			
		||||
	golang.org/x/time v0.3.0 // indirect
 | 
			
		||||
	google.golang.org/appengine v1.6.7 // indirect
 | 
			
		||||
	google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90 // indirect
 | 
			
		||||
@@ -286,7 +285,7 @@ replace github.com/shurcooL/vfsgen => github.com/lunny/vfsgen v0.0.0-20220105142
 | 
			
		||||
 | 
			
		||||
replace github.com/blevesearch/zapx/v15 v15.3.6 => github.com/zeripath/zapx/v15 v15.3.6-alignment-fix
 | 
			
		||||
 | 
			
		||||
replace github.com/nektos/act => gitea.com/gitea/act v0.234.2-0.20230131074955-e46ede1b1744
 | 
			
		||||
replace github.com/nektos/act => gitea.com/gitea/act v0.243.1
 | 
			
		||||
 | 
			
		||||
exclude github.com/gofrs/uuid v3.2.0+incompatible
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										25
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								go.sum
									
									
									
									
									
								
							@@ -70,8 +70,8 @@ codeberg.org/gusted/mcaptcha v0.0.0-20220723083913-4f3072e1d570/go.mod h1:IIAjsi
 | 
			
		||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
 | 
			
		||||
git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078 h1:cliQ4HHsCo6xi2oWZYKWW4bly/Ory9FuTpFPRxj/mAg=
 | 
			
		||||
git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078/go.mod h1:g/V2Hjas6Z1UHUp4yIx6bATpNzJ7DYtD0FG3+xARWxs=
 | 
			
		||||
gitea.com/gitea/act v0.234.2-0.20230131074955-e46ede1b1744 h1:cqzKmGlX0wynSXO04NILpL25eBGwogDrKpkkbwmIpj4=
 | 
			
		||||
gitea.com/gitea/act v0.234.2-0.20230131074955-e46ede1b1744/go.mod h1:2C/WbTalu1VPNgbVaZJaZDzlOtAKqkXJhdOClxkMy14=
 | 
			
		||||
gitea.com/gitea/act v0.243.1 h1:zIVlhGOLE4SHFPW++u3+5Y/jX5mub3QIhB13oNf6rtA=
 | 
			
		||||
gitea.com/gitea/act v0.243.1/go.mod h1:iLHCXqOPUElA2nSyHo4wtxSmvdkym3WU7CkP3AxF39Q=
 | 
			
		||||
gitea.com/go-chi/binding v0.0.0-20221013104517-b29891619681 h1:MMSPgnVULVwV9kEBgvyEUhC9v/uviZ55hPJEMjpbNR4=
 | 
			
		||||
gitea.com/go-chi/binding v0.0.0-20221013104517-b29891619681/go.mod h1:77TZu701zMXWJFvB8gvTbQ92zQ3DQq/H7l5wAEjQRKc=
 | 
			
		||||
gitea.com/go-chi/cache v0.0.0-20210110083709-82c4c9ce2d5e/go.mod h1:k2V/gPDEtXGjjMGuBJiapffAXTv76H4snSmlJRLUhH0=
 | 
			
		||||
@@ -402,8 +402,9 @@ github.com/go-fed/httpsig v1.1.1-0.20201223112313-55836744818e/go.mod h1:RCMrTZv
 | 
			
		||||
github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4=
 | 
			
		||||
github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E=
 | 
			
		||||
github.com/go-git/go-billy/v5 v5.3.1/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
 | 
			
		||||
github.com/go-git/go-billy/v5 v5.4.0 h1:Vaw7LaSTRJOUric7pe4vnzBSgyuf2KrLsu2Y4ZpQBDE=
 | 
			
		||||
github.com/go-git/go-billy/v5 v5.4.0/go.mod h1:vjbugF6Fz7JIflbVpl1hJsGjSHNltrSw45YK/ukIvQg=
 | 
			
		||||
github.com/go-git/go-billy/v5 v5.4.1 h1:Uwp5tDRkPr+l/TnbHOQzp+tmJfLceOlbVucgpTz8ix4=
 | 
			
		||||
github.com/go-git/go-billy/v5 v5.4.1/go.mod h1:vjbugF6Fz7JIflbVpl1hJsGjSHNltrSw45YK/ukIvQg=
 | 
			
		||||
github.com/go-git/go-git-fixtures/v4 v4.3.1 h1:y5z6dd3qi8Hl+stezc8p3JxDkoTRqMAlKnXHuzrfjTQ=
 | 
			
		||||
github.com/go-git/go-git-fixtures/v4 v4.3.1/go.mod h1:8LHG1a3SRW71ettAD/jW13h8c6AqjVSeL11RAdgaqpo=
 | 
			
		||||
github.com/go-git/go-git/v5 v5.5.2 h1:v8lgZa5k9ylUw+OR/roJHTxR4QItsNFI5nKtAXFuynw=
 | 
			
		||||
@@ -411,8 +412,6 @@ github.com/go-git/go-git/v5 v5.5.2/go.mod h1:BE5hUJ5yaV2YMxhmaP4l6RBQ08kMxKSPD4B
 | 
			
		||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
 | 
			
		||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
 | 
			
		||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
 | 
			
		||||
github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A=
 | 
			
		||||
github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
 | 
			
		||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
 | 
			
		||||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
 | 
			
		||||
github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o=
 | 
			
		||||
@@ -791,7 +790,7 @@ github.com/jhillyerd/enmime v0.10.1 h1:3VP8gFhK7R948YJBrna5bOgnTXEuPAoICo79kKkBK
 | 
			
		||||
github.com/jhillyerd/enmime v0.10.1/go.mod h1:Qpe8EEemJMFAF8+NZoWdpXvK2Yb9dRF0k/z6mkcDHsA=
 | 
			
		||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
 | 
			
		||||
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
 | 
			
		||||
github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg=
 | 
			
		||||
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
 | 
			
		||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
 | 
			
		||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
 | 
			
		||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
 | 
			
		||||
@@ -1099,8 +1098,8 @@ github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqn
 | 
			
		||||
github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
 | 
			
		||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
 | 
			
		||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
 | 
			
		||||
github.com/rhysd/actionlint v1.6.22 h1:cAEf2PGNwJXhdcTVF2xS/0ORqWS+ueUHwjQYsqFsGSk=
 | 
			
		||||
github.com/rhysd/actionlint v1.6.22/go.mod h1:gIKOdxtV40mBOcD0ZR8EBa8NqjEXToAZioroS3oedMg=
 | 
			
		||||
github.com/rhysd/actionlint v1.6.23 h1:041VOXgZddfvSJa9Il+WT3Iwuo/j0Nmu4bhpAScrds4=
 | 
			
		||||
github.com/rhysd/actionlint v1.6.23/go.mod h1:o5qc1K3I9taGMBhL7mVkpRd64hx3YqI+3t8ewGfYXfE=
 | 
			
		||||
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
 | 
			
		||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
 | 
			
		||||
github.com/rivo/uniseg v0.4.3 h1:utMvzDsuh3suAEnhH0RdHmoPbU648o6CvXxTx4SBMOw=
 | 
			
		||||
@@ -1501,8 +1500,8 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ
 | 
			
		||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 | 
			
		||||
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 | 
			
		||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 | 
			
		||||
golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde h1:ejfdSekXMDxDLbRrJMwUk6KnSLZ2McaUCVcIKM+N6jc=
 | 
			
		||||
golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 | 
			
		||||
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
 | 
			
		||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 | 
			
		||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 | 
			
		||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 | 
			
		||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 | 
			
		||||
@@ -1610,14 +1609,14 @@ golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64/go.mod h1:oPkhp1MJrh7nUepCBc
 | 
			
		||||
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
			
		||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
			
		||||
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
			
		||||
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
 | 
			
		||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
			
		||||
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
 | 
			
		||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
			
		||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
 | 
			
		||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 | 
			
		||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 | 
			
		||||
golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 | 
			
		||||
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
 | 
			
		||||
golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY=
 | 
			
		||||
golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw=
 | 
			
		||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 | 
			
		||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 | 
			
		||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 | 
			
		||||
 
 | 
			
		||||
@@ -126,6 +126,17 @@ func (run *ActionRun) GetPushEventPayload() (*api.PushPayload, error) {
 | 
			
		||||
	return nil, fmt.Errorf("event %s is not a push event", run.Event)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (run *ActionRun) GetPullRequestEventPayload() (*api.PullRequestPayload, error) {
 | 
			
		||||
	if run.Event == webhook_module.HookEventPullRequest {
 | 
			
		||||
		var payload api.PullRequestPayload
 | 
			
		||||
		if err := json.Unmarshal([]byte(run.EventPayload), &payload); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		return &payload, nil
 | 
			
		||||
	}
 | 
			
		||||
	return nil, fmt.Errorf("event %s is not a pull request event", run.Event)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func updateRepoRunsNumbers(ctx context.Context, repo *repo_model.Repository) error {
 | 
			
		||||
	_, err := db.GetEngine(ctx).ID(repo.ID).
 | 
			
		||||
		SetExpr("num_action_runs",
 | 
			
		||||
@@ -194,6 +205,7 @@ func InsertRun(ctx context.Context, run *ActionRun, jobs []*jobparser.SingleWork
 | 
			
		||||
		if len(needs) > 0 {
 | 
			
		||||
			status = StatusBlocked
 | 
			
		||||
		}
 | 
			
		||||
		job.Name, _ = util.SplitStringAtByteN(job.Name, 255)
 | 
			
		||||
		runJobs = append(runJobs, &ActionRunJob{
 | 
			
		||||
			RunID:             run.ID,
 | 
			
		||||
			RepoID:            run.RepoID,
 | 
			
		||||
 
 | 
			
		||||
@@ -298,8 +298,9 @@ func CreateTaskForRunner(ctx context.Context, runner *ActionRunner) (*ActionTask
 | 
			
		||||
	if len(workflowJob.Steps) > 0 {
 | 
			
		||||
		steps := make([]*ActionTaskStep, len(workflowJob.Steps))
 | 
			
		||||
		for i, v := range workflowJob.Steps {
 | 
			
		||||
			name, _ := util.SplitStringAtByteN(v.String(), 255)
 | 
			
		||||
			steps[i] = &ActionTaskStep{
 | 
			
		||||
				Name:   v.String(),
 | 
			
		||||
				Name:   name,
 | 
			
		||||
				TaskID: task.ID,
 | 
			
		||||
				Index:  int64(i),
 | 
			
		||||
				RepoID: task.RepoID,
 | 
			
		||||
 
 | 
			
		||||
@@ -99,7 +99,7 @@ func (a *Action) TableIndices() []*schemas.Index {
 | 
			
		||||
	actUserIndex.AddColumn("act_user_id", "repo_id", "created_unix", "user_id", "is_deleted")
 | 
			
		||||
 | 
			
		||||
	indices := []*schemas.Index{actUserIndex, repoIndex}
 | 
			
		||||
	if setting.Database.UsePostgreSQL {
 | 
			
		||||
	if setting.Database.Type.IsPostgreSQL() {
 | 
			
		||||
		cudIndex := schemas.NewIndex("c_u_d", schemas.IndexType)
 | 
			
		||||
		cudIndex.AddColumn("created_unix", "user_id", "is_deleted")
 | 
			
		||||
		indices = append(indices, cudIndex)
 | 
			
		||||
@@ -640,7 +640,7 @@ func DeleteIssueActions(ctx context.Context, repoID, issueID int64) error {
 | 
			
		||||
 | 
			
		||||
// CountActionCreatedUnixString count actions where created_unix is an empty string
 | 
			
		||||
func CountActionCreatedUnixString(ctx context.Context) (int64, error) {
 | 
			
		||||
	if setting.Database.UseSQLite3 {
 | 
			
		||||
	if setting.Database.Type.IsSQLite3() {
 | 
			
		||||
		return db.GetEngine(ctx).Where(`created_unix = ""`).Count(new(Action))
 | 
			
		||||
	}
 | 
			
		||||
	return 0, nil
 | 
			
		||||
@@ -648,7 +648,7 @@ func CountActionCreatedUnixString(ctx context.Context) (int64, error) {
 | 
			
		||||
 | 
			
		||||
// FixActionCreatedUnixString set created_unix to zero if it is an empty string
 | 
			
		||||
func FixActionCreatedUnixString(ctx context.Context) (int64, error) {
 | 
			
		||||
	if setting.Database.UseSQLite3 {
 | 
			
		||||
	if setting.Database.Type.IsSQLite3() {
 | 
			
		||||
		res, err := db.GetEngine(ctx).Exec(`UPDATE action SET created_unix = 0 WHERE created_unix = ""`)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return 0, err
 | 
			
		||||
 
 | 
			
		||||
@@ -234,7 +234,7 @@ func TestGetFeedsCorrupted(t *testing.T) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestConsistencyUpdateAction(t *testing.T) {
 | 
			
		||||
	if !setting.Database.UseSQLite3 {
 | 
			
		||||
	if !setting.Database.Type.IsSQLite3() {
 | 
			
		||||
		t.Skip("Test is only for SQLite database.")
 | 
			
		||||
	}
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 
 | 
			
		||||
@@ -39,9 +39,9 @@ func getUserHeatmapData(user *user_model.User, team *organization.Team, doer *us
 | 
			
		||||
	groupBy := "created_unix / 900 * 900"
 | 
			
		||||
	groupByName := "timestamp" // We need this extra case because mssql doesn't allow grouping by alias
 | 
			
		||||
	switch {
 | 
			
		||||
	case setting.Database.UseMySQL:
 | 
			
		||||
	case setting.Database.Type.IsMySQL():
 | 
			
		||||
		groupBy = "created_unix DIV 900 * 900"
 | 
			
		||||
	case setting.Database.UseMSSQL:
 | 
			
		||||
	case setting.Database.Type.IsMSSQL():
 | 
			
		||||
		groupByName = groupBy
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -153,7 +153,7 @@ func generateEmailAvatarLink(ctx context.Context, email string, size int, final
 | 
			
		||||
		return DefaultAvatarLink()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	enableFederatedAvatar := system_model.GetSettingBool(ctx, system_model.KeyPictureEnableFederatedAvatar)
 | 
			
		||||
	enableFederatedAvatar := system_model.GetSettingWithCacheBool(ctx, system_model.KeyPictureEnableFederatedAvatar)
 | 
			
		||||
 | 
			
		||||
	var err error
 | 
			
		||||
	if enableFederatedAvatar && system_model.LibravatarService != nil {
 | 
			
		||||
@@ -174,7 +174,7 @@ func generateEmailAvatarLink(ctx context.Context, email string, size int, final
 | 
			
		||||
		return urlStr
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	disableGravatar := system_model.GetSettingBool(ctx, system_model.KeyPictureDisableGravatar)
 | 
			
		||||
	disableGravatar := system_model.GetSettingWithCacheBool(ctx, system_model.KeyPictureDisableGravatar)
 | 
			
		||||
	if !disableGravatar {
 | 
			
		||||
		// copy GravatarSourceURL, because we will modify its Path.
 | 
			
		||||
		avatarURLCopy := *system_model.GravatarSourceURL
 | 
			
		||||
 
 | 
			
		||||
@@ -28,7 +28,7 @@ func enableGravatar(t *testing.T) {
 | 
			
		||||
	err := system_model.SetSettingNoVersion(db.DefaultContext, system_model.KeyPictureDisableGravatar, "false")
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	setting.GravatarSource = gravatarSource
 | 
			
		||||
	err = system_model.Init()
 | 
			
		||||
	err = system_model.Init(db.DefaultContext)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -15,7 +15,7 @@ import (
 | 
			
		||||
// BuildCaseInsensitiveLike returns a condition to check if the given value is like the given key case-insensitively.
 | 
			
		||||
// Handles especially SQLite correctly as UPPER there only transforms ASCII letters.
 | 
			
		||||
func BuildCaseInsensitiveLike(key, value string) builder.Cond {
 | 
			
		||||
	if setting.Database.UseSQLite3 {
 | 
			
		||||
	if setting.Database.Type.IsSQLite3() {
 | 
			
		||||
		return builder.Like{"UPPER(" + key + ")", util.ToUpperASCII(value)}
 | 
			
		||||
	}
 | 
			
		||||
	return builder.Like{"UPPER(" + key + ")", strings.ToUpper(value)}
 | 
			
		||||
 
 | 
			
		||||
@@ -100,12 +100,12 @@ func newXORMEngine() (*xorm.Engine, error) {
 | 
			
		||||
 | 
			
		||||
	var engine *xorm.Engine
 | 
			
		||||
 | 
			
		||||
	if setting.Database.UsePostgreSQL && len(setting.Database.Schema) > 0 {
 | 
			
		||||
	if setting.Database.Type.IsPostgreSQL() && len(setting.Database.Schema) > 0 {
 | 
			
		||||
		// OK whilst we sort out our schema issues - create a schema aware postgres
 | 
			
		||||
		registerPostgresSchemaDriver()
 | 
			
		||||
		engine, err = xorm.NewEngine("postgresschema", connStr)
 | 
			
		||||
	} else {
 | 
			
		||||
		engine, err = xorm.NewEngine(setting.Database.Type, connStr)
 | 
			
		||||
		engine, err = xorm.NewEngine(setting.Database.Type.String(), connStr)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
 
 | 
			
		||||
@@ -73,7 +73,7 @@ func postgresGetNextResourceIndex(ctx context.Context, tableName string, groupID
 | 
			
		||||
 | 
			
		||||
// GetNextResourceIndex generates a resource index, it must run in the same transaction where the resource is created
 | 
			
		||||
func GetNextResourceIndex(ctx context.Context, tableName string, groupID int64) (int64, error) {
 | 
			
		||||
	if setting.Database.UsePostgreSQL {
 | 
			
		||||
	if setting.Database.Type.IsPostgreSQL() {
 | 
			
		||||
		return postgresGetNextResourceIndex(ctx, tableName, groupID)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -134,7 +134,7 @@ func Find[T any](ctx context.Context, opts FindOptions, objects *[]T) error {
 | 
			
		||||
	if !opts.IsListAll() {
 | 
			
		||||
		sess.Limit(opts.GetSkipTake())
 | 
			
		||||
	}
 | 
			
		||||
	return sess.Find(&objects)
 | 
			
		||||
	return sess.Find(objects)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Count represents a common count function which accept an options interface
 | 
			
		||||
@@ -148,5 +148,5 @@ func FindAndCount[T any](ctx context.Context, opts FindOptions, objects *[]T) (i
 | 
			
		||||
	if !opts.IsListAll() {
 | 
			
		||||
		sess.Limit(opts.GetSkipTake())
 | 
			
		||||
	}
 | 
			
		||||
	return sess.FindAndCount(&objects)
 | 
			
		||||
	return sess.FindAndCount(objects)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										48
									
								
								models/db/list_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								models/db/list_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,48 @@
 | 
			
		||||
// Copyright 2023 The Gitea Authors. All rights reserved.
 | 
			
		||||
// SPDX-License-Identifier: MIT
 | 
			
		||||
 | 
			
		||||
package db_test
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/models/db"
 | 
			
		||||
	repo_model "code.gitea.io/gitea/models/repo"
 | 
			
		||||
	"code.gitea.io/gitea/models/unittest"
 | 
			
		||||
 | 
			
		||||
	"github.com/stretchr/testify/assert"
 | 
			
		||||
	"xorm.io/builder"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type mockListOptions struct {
 | 
			
		||||
	db.ListOptions
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (opts *mockListOptions) IsListAll() bool {
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (opts *mockListOptions) ToConds() builder.Cond {
 | 
			
		||||
	return builder.NewCond()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestFind(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	xe := unittest.GetXORMEngine()
 | 
			
		||||
	assert.NoError(t, xe.Sync(&repo_model.RepoUnit{}))
 | 
			
		||||
 | 
			
		||||
	opts := mockListOptions{}
 | 
			
		||||
	var repoUnits []repo_model.RepoUnit
 | 
			
		||||
	err := db.Find(db.DefaultContext, &opts, &repoUnits)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.EqualValues(t, 83, len(repoUnits))
 | 
			
		||||
 | 
			
		||||
	cnt, err := db.Count(db.DefaultContext, &opts, new(repo_model.RepoUnit))
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.EqualValues(t, 83, cnt)
 | 
			
		||||
 | 
			
		||||
	repoUnits = make([]repo_model.RepoUnit, 0, 10)
 | 
			
		||||
	newCnt, err := db.FindAndCount(db.DefaultContext, &opts, &repoUnits)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.EqualValues(t, cnt, newCnt)
 | 
			
		||||
}
 | 
			
		||||
@@ -13,7 +13,7 @@ import (
 | 
			
		||||
 | 
			
		||||
// CountBadSequences looks for broken sequences from recreate-table mistakes
 | 
			
		||||
func CountBadSequences(_ context.Context) (int64, error) {
 | 
			
		||||
	if !setting.Database.UsePostgreSQL {
 | 
			
		||||
	if !setting.Database.Type.IsPostgreSQL() {
 | 
			
		||||
		return 0, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -34,7 +34,7 @@ func CountBadSequences(_ context.Context) (int64, error) {
 | 
			
		||||
 | 
			
		||||
// FixBadSequences fixes for broken sequences from recreate-table mistakes
 | 
			
		||||
func FixBadSequences(_ context.Context) error {
 | 
			
		||||
	if !setting.Database.UsePostgreSQL {
 | 
			
		||||
	if !setting.Database.Type.IsPostgreSQL() {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -25,7 +25,7 @@
 | 
			
		||||
  fork_id: 0
 | 
			
		||||
  is_template: false
 | 
			
		||||
  template_id: 0
 | 
			
		||||
  size: 6708
 | 
			
		||||
  size: 7028
 | 
			
		||||
  is_fsck_enabled: true
 | 
			
		||||
  close_issues_via_commit_in_any_branch: false
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -65,7 +65,7 @@ func postgresGetCommitStatusIndex(ctx context.Context, repoID int64, sha string)
 | 
			
		||||
 | 
			
		||||
// GetNextCommitStatusIndex retried 3 times to generate a resource index
 | 
			
		||||
func GetNextCommitStatusIndex(ctx context.Context, repoID int64, sha string) (int64, error) {
 | 
			
		||||
	if setting.Database.UsePostgreSQL {
 | 
			
		||||
	if setting.Database.Type.IsPostgreSQL() {
 | 
			
		||||
		return postgresGetCommitStatusIndex(ctx, repoID, sha)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -7,12 +7,12 @@ package issues
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"regexp"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/models/db"
 | 
			
		||||
	user_model "code.gitea.io/gitea/models/user"
 | 
			
		||||
	"code.gitea.io/gitea/modules/label"
 | 
			
		||||
	"code.gitea.io/gitea/modules/timeutil"
 | 
			
		||||
	"code.gitea.io/gitea/modules/util"
 | 
			
		||||
 | 
			
		||||
@@ -78,9 +78,6 @@ func (err ErrLabelNotExist) Unwrap() error {
 | 
			
		||||
	return util.ErrNotExist
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// LabelColorPattern is a regexp witch can validate LabelColor
 | 
			
		||||
var LabelColorPattern = regexp.MustCompile("^#?(?:[0-9a-fA-F]{6}|[0-9a-fA-F]{3})$")
 | 
			
		||||
 | 
			
		||||
// Label represents a label of repository for issues.
 | 
			
		||||
type Label struct {
 | 
			
		||||
	ID              int64 `xorm:"pk autoincr"`
 | 
			
		||||
@@ -109,12 +106,12 @@ func init() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CalOpenIssues sets the number of open issues of a label based on the already stored number of closed issues.
 | 
			
		||||
func (label *Label) CalOpenIssues() {
 | 
			
		||||
	label.NumOpenIssues = label.NumIssues - label.NumClosedIssues
 | 
			
		||||
func (l *Label) CalOpenIssues() {
 | 
			
		||||
	l.NumOpenIssues = l.NumIssues - l.NumClosedIssues
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CalOpenOrgIssues calculates the open issues of a label for a specific repo
 | 
			
		||||
func (label *Label) CalOpenOrgIssues(ctx context.Context, repoID, labelID int64) {
 | 
			
		||||
func (l *Label) CalOpenOrgIssues(ctx context.Context, repoID, labelID int64) {
 | 
			
		||||
	counts, _ := CountIssuesByRepo(ctx, &IssuesOptions{
 | 
			
		||||
		RepoID:   repoID,
 | 
			
		||||
		LabelIDs: []int64{labelID},
 | 
			
		||||
@@ -122,22 +119,22 @@ func (label *Label) CalOpenOrgIssues(ctx context.Context, repoID, labelID int64)
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	for _, count := range counts {
 | 
			
		||||
		label.NumOpenRepoIssues += count
 | 
			
		||||
		l.NumOpenRepoIssues += count
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// LoadSelectedLabelsAfterClick calculates the set of selected labels when a label is clicked
 | 
			
		||||
func (label *Label) LoadSelectedLabelsAfterClick(currentSelectedLabels []int64, currentSelectedExclusiveScopes []string) {
 | 
			
		||||
func (l *Label) LoadSelectedLabelsAfterClick(currentSelectedLabels []int64, currentSelectedExclusiveScopes []string) {
 | 
			
		||||
	var labelQuerySlice []string
 | 
			
		||||
	labelSelected := false
 | 
			
		||||
	labelID := strconv.FormatInt(label.ID, 10)
 | 
			
		||||
	labelScope := label.ExclusiveScope()
 | 
			
		||||
	labelID := strconv.FormatInt(l.ID, 10)
 | 
			
		||||
	labelScope := l.ExclusiveScope()
 | 
			
		||||
	for i, s := range currentSelectedLabels {
 | 
			
		||||
		if s == label.ID {
 | 
			
		||||
		if s == l.ID {
 | 
			
		||||
			labelSelected = true
 | 
			
		||||
		} else if -s == label.ID {
 | 
			
		||||
		} else if -s == l.ID {
 | 
			
		||||
			labelSelected = true
 | 
			
		||||
			label.IsExcluded = true
 | 
			
		||||
			l.IsExcluded = true
 | 
			
		||||
		} else if s != 0 {
 | 
			
		||||
			// Exclude other labels in the same scope from selection
 | 
			
		||||
			if s < 0 || labelScope == "" || labelScope != currentSelectedExclusiveScopes[i] {
 | 
			
		||||
@@ -148,23 +145,23 @@ func (label *Label) LoadSelectedLabelsAfterClick(currentSelectedLabels []int64,
 | 
			
		||||
	if !labelSelected {
 | 
			
		||||
		labelQuerySlice = append(labelQuerySlice, labelID)
 | 
			
		||||
	}
 | 
			
		||||
	label.IsSelected = labelSelected
 | 
			
		||||
	label.QueryString = strings.Join(labelQuerySlice, ",")
 | 
			
		||||
	l.IsSelected = labelSelected
 | 
			
		||||
	l.QueryString = strings.Join(labelQuerySlice, ",")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// BelongsToOrg returns true if label is an organization label
 | 
			
		||||
func (label *Label) BelongsToOrg() bool {
 | 
			
		||||
	return label.OrgID > 0
 | 
			
		||||
func (l *Label) BelongsToOrg() bool {
 | 
			
		||||
	return l.OrgID > 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// BelongsToRepo returns true if label is a repository label
 | 
			
		||||
func (label *Label) BelongsToRepo() bool {
 | 
			
		||||
	return label.RepoID > 0
 | 
			
		||||
func (l *Label) BelongsToRepo() bool {
 | 
			
		||||
	return l.RepoID > 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Get color as RGB values in 0..255 range
 | 
			
		||||
func (label *Label) ColorRGB() (float64, float64, float64, error) {
 | 
			
		||||
	color, err := strconv.ParseUint(label.Color[1:], 16, 64)
 | 
			
		||||
func (l *Label) ColorRGB() (float64, float64, float64, error) {
 | 
			
		||||
	color, err := strconv.ParseUint(l.Color[1:], 16, 64)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, 0, 0, err
 | 
			
		||||
	}
 | 
			
		||||
@@ -176,9 +173,9 @@ func (label *Label) ColorRGB() (float64, float64, float64, error) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Determine if label text should be light or dark to be readable on background color
 | 
			
		||||
func (label *Label) UseLightTextColor() bool {
 | 
			
		||||
	if strings.HasPrefix(label.Color, "#") {
 | 
			
		||||
		if r, g, b, err := label.ColorRGB(); err == nil {
 | 
			
		||||
func (l *Label) UseLightTextColor() bool {
 | 
			
		||||
	if strings.HasPrefix(l.Color, "#") {
 | 
			
		||||
		if r, g, b, err := l.ColorRGB(); err == nil {
 | 
			
		||||
			// Perceived brightness from: https://www.w3.org/TR/AERT/#color-contrast
 | 
			
		||||
			// In the future WCAG 3 APCA may be a better solution
 | 
			
		||||
			brightness := (0.299*r + 0.587*g + 0.114*b) / 255
 | 
			
		||||
@@ -190,40 +187,26 @@ func (label *Label) UseLightTextColor() bool {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Return scope substring of label name, or empty string if none exists
 | 
			
		||||
func (label *Label) ExclusiveScope() string {
 | 
			
		||||
	if !label.Exclusive {
 | 
			
		||||
func (l *Label) ExclusiveScope() string {
 | 
			
		||||
	if !l.Exclusive {
 | 
			
		||||
		return ""
 | 
			
		||||
	}
 | 
			
		||||
	lastIndex := strings.LastIndex(label.Name, "/")
 | 
			
		||||
	if lastIndex == -1 || lastIndex == 0 || lastIndex == len(label.Name)-1 {
 | 
			
		||||
	lastIndex := strings.LastIndex(l.Name, "/")
 | 
			
		||||
	if lastIndex == -1 || lastIndex == 0 || lastIndex == len(l.Name)-1 {
 | 
			
		||||
		return ""
 | 
			
		||||
	}
 | 
			
		||||
	return label.Name[:lastIndex]
 | 
			
		||||
	return l.Name[:lastIndex]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewLabel creates a new label
 | 
			
		||||
func NewLabel(ctx context.Context, label *Label) error {
 | 
			
		||||
	if !LabelColorPattern.MatchString(label.Color) {
 | 
			
		||||
		return fmt.Errorf("bad color code: %s", label.Color)
 | 
			
		||||
func NewLabel(ctx context.Context, l *Label) error {
 | 
			
		||||
	color, err := label.NormalizeColor(l.Color)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	l.Color = color
 | 
			
		||||
 | 
			
		||||
	// normalize case
 | 
			
		||||
	label.Color = strings.ToLower(label.Color)
 | 
			
		||||
 | 
			
		||||
	// add leading hash
 | 
			
		||||
	if label.Color[0] != '#' {
 | 
			
		||||
		label.Color = "#" + label.Color
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// convert 3-character shorthand into 6-character version
 | 
			
		||||
	if len(label.Color) == 4 {
 | 
			
		||||
		r := label.Color[1]
 | 
			
		||||
		g := label.Color[2]
 | 
			
		||||
		b := label.Color[3]
 | 
			
		||||
		label.Color = fmt.Sprintf("#%c%c%c%c%c%c", r, r, g, g, b, b)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return db.Insert(ctx, label)
 | 
			
		||||
	return db.Insert(ctx, l)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewLabels creates new labels
 | 
			
		||||
@@ -234,11 +217,14 @@ func NewLabels(labels ...*Label) error {
 | 
			
		||||
	}
 | 
			
		||||
	defer committer.Close()
 | 
			
		||||
 | 
			
		||||
	for _, label := range labels {
 | 
			
		||||
		if !LabelColorPattern.MatchString(label.Color) {
 | 
			
		||||
			return fmt.Errorf("bad color code: %s", label.Color)
 | 
			
		||||
	for _, l := range labels {
 | 
			
		||||
		color, err := label.NormalizeColor(l.Color)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		if err := db.Insert(ctx, label); err != nil {
 | 
			
		||||
		l.Color = color
 | 
			
		||||
 | 
			
		||||
		if err := db.Insert(ctx, l); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
@@ -247,15 +233,18 @@ func NewLabels(labels ...*Label) error {
 | 
			
		||||
 | 
			
		||||
// UpdateLabel updates label information.
 | 
			
		||||
func UpdateLabel(l *Label) error {
 | 
			
		||||
	if !LabelColorPattern.MatchString(l.Color) {
 | 
			
		||||
		return fmt.Errorf("bad color code: %s", l.Color)
 | 
			
		||||
	color, err := label.NormalizeColor(l.Color)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	l.Color = color
 | 
			
		||||
 | 
			
		||||
	return updateLabelCols(db.DefaultContext, l, "name", "description", "color", "exclusive")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeleteLabel delete a label
 | 
			
		||||
func DeleteLabel(id, labelID int64) error {
 | 
			
		||||
	label, err := GetLabelByID(db.DefaultContext, labelID)
 | 
			
		||||
	l, err := GetLabelByID(db.DefaultContext, labelID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if IsErrLabelNotExist(err) {
 | 
			
		||||
			return nil
 | 
			
		||||
@@ -271,10 +260,10 @@ func DeleteLabel(id, labelID int64) error {
 | 
			
		||||
 | 
			
		||||
	sess := db.GetEngine(ctx)
 | 
			
		||||
 | 
			
		||||
	if label.BelongsToOrg() && label.OrgID != id {
 | 
			
		||||
	if l.BelongsToOrg() && l.OrgID != id {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	if label.BelongsToRepo() && label.RepoID != id {
 | 
			
		||||
	if l.BelongsToRepo() && l.RepoID != id {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -682,14 +671,14 @@ func newIssueLabels(ctx context.Context, issue *Issue, labels []*Label, doer *us
 | 
			
		||||
	if err = issue.LoadRepo(ctx); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	for _, label := range labels {
 | 
			
		||||
	for _, l := range labels {
 | 
			
		||||
		// Don't add already present labels and invalid labels
 | 
			
		||||
		if HasIssueLabel(ctx, issue.ID, label.ID) ||
 | 
			
		||||
			(label.RepoID != issue.RepoID && label.OrgID != issue.Repo.OwnerID) {
 | 
			
		||||
		if HasIssueLabel(ctx, issue.ID, l.ID) ||
 | 
			
		||||
			(l.RepoID != issue.RepoID && l.OrgID != issue.Repo.OwnerID) {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if err = newIssueLabel(ctx, issue, label, doer); err != nil {
 | 
			
		||||
		if err = newIssueLabel(ctx, issue, l, doer); err != nil {
 | 
			
		||||
			return fmt.Errorf("newIssueLabel: %w", err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
@@ -778,7 +767,7 @@ func CountOrphanedLabels(ctx context.Context) (int64, error) {
 | 
			
		||||
	norepo, err := db.GetEngine(ctx).Table("label").
 | 
			
		||||
		Where(builder.And(
 | 
			
		||||
			builder.Gt{"repo_id": 0},
 | 
			
		||||
			builder.NotIn("repo_id", builder.Select("id").From("repository")),
 | 
			
		||||
			builder.NotIn("repo_id", builder.Select("id").From("`repository`")),
 | 
			
		||||
		)).
 | 
			
		||||
		Count()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
@@ -788,7 +777,7 @@ func CountOrphanedLabels(ctx context.Context) (int64, error) {
 | 
			
		||||
	noorg, err := db.GetEngine(ctx).Table("label").
 | 
			
		||||
		Where(builder.And(
 | 
			
		||||
			builder.Gt{"org_id": 0},
 | 
			
		||||
			builder.NotIn("org_id", builder.Select("id").From("user")),
 | 
			
		||||
			builder.NotIn("org_id", builder.Select("id").From("`user`")),
 | 
			
		||||
		)).
 | 
			
		||||
		Count()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
@@ -809,7 +798,7 @@ func DeleteOrphanedLabels(ctx context.Context) error {
 | 
			
		||||
	if _, err := db.GetEngine(ctx).
 | 
			
		||||
		Where(builder.And(
 | 
			
		||||
			builder.Gt{"repo_id": 0},
 | 
			
		||||
			builder.NotIn("repo_id", builder.Select("id").From("repository")),
 | 
			
		||||
			builder.NotIn("repo_id", builder.Select("id").From("`repository`")),
 | 
			
		||||
		)).
 | 
			
		||||
		Delete(Label{}); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
@@ -819,7 +808,7 @@ func DeleteOrphanedLabels(ctx context.Context) error {
 | 
			
		||||
	if _, err := db.GetEngine(ctx).
 | 
			
		||||
		Where(builder.And(
 | 
			
		||||
			builder.Gt{"org_id": 0},
 | 
			
		||||
			builder.NotIn("org_id", builder.Select("id").From("user")),
 | 
			
		||||
			builder.NotIn("org_id", builder.Select("id").From("`user`")),
 | 
			
		||||
		)).
 | 
			
		||||
		Delete(Label{}); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
 
 | 
			
		||||
@@ -15,8 +15,6 @@ import (
 | 
			
		||||
	"github.com/stretchr/testify/assert"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// TODO TestGetLabelTemplateFile
 | 
			
		||||
 | 
			
		||||
func TestLabel_CalOpenIssues(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	label := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 1})
 | 
			
		||||
 
 | 
			
		||||
@@ -52,13 +52,16 @@ func listPullRequestStatement(baseRepoID int64, opts *PullRequestsOptions) (*xor
 | 
			
		||||
 | 
			
		||||
// GetUnmergedPullRequestsByHeadInfo returns all pull requests that are open and has not been merged
 | 
			
		||||
// by given head information (repo and branch).
 | 
			
		||||
func GetUnmergedPullRequestsByHeadInfo(repoID int64, branch string) ([]*PullRequest, error) {
 | 
			
		||||
// arg `includeClosed` controls whether the SQL returns closed PRs
 | 
			
		||||
func GetUnmergedPullRequestsByHeadInfo(repoID int64, branch string, includeClosed bool) ([]*PullRequest, error) {
 | 
			
		||||
	prs := make([]*PullRequest, 0, 2)
 | 
			
		||||
	return prs, db.GetEngine(db.DefaultContext).
 | 
			
		||||
		Where("head_repo_id = ? AND head_branch = ? AND has_merged = ? AND issue.is_closed = ? AND flow = ?",
 | 
			
		||||
			repoID, branch, false, false, PullRequestFlowGithub).
 | 
			
		||||
	sess := db.GetEngine(db.DefaultContext).
 | 
			
		||||
		Join("INNER", "issue", "issue.id = pull_request.issue_id").
 | 
			
		||||
		Find(&prs)
 | 
			
		||||
		Where("head_repo_id = ? AND head_branch = ? AND has_merged = ? AND flow = ?", repoID, branch, false, PullRequestFlowGithub)
 | 
			
		||||
	if !includeClosed {
 | 
			
		||||
		sess.Where("issue.is_closed = ?", false)
 | 
			
		||||
	}
 | 
			
		||||
	return prs, sess.Find(&prs)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CanMaintainerWriteToBranch check whether user is a maintainer and could write to the branch
 | 
			
		||||
@@ -71,7 +74,7 @@ func CanMaintainerWriteToBranch(p access_model.Permission, branch string, user *
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	prs, err := GetUnmergedPullRequestsByHeadInfo(p.Units[0].RepoID, branch)
 | 
			
		||||
	prs, err := GetUnmergedPullRequestsByHeadInfo(p.Units[0].RepoID, branch, false)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
@@ -111,6 +114,7 @@ func GetUnmergedPullRequestsByBaseInfo(repoID int64, branch string) ([]*PullRequ
 | 
			
		||||
	return prs, db.GetEngine(db.DefaultContext).
 | 
			
		||||
		Where("base_repo_id=? AND base_branch=? AND has_merged=? AND issue.is_closed=?",
 | 
			
		||||
			repoID, branch, false, false).
 | 
			
		||||
		OrderBy("issue.updated_unix DESC").
 | 
			
		||||
		Join("INNER", "issue", "issue.id=pull_request.issue_id").
 | 
			
		||||
		Find(&prs)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -118,7 +118,7 @@ func TestHasUnmergedPullRequestsByHeadInfo(t *testing.T) {
 | 
			
		||||
 | 
			
		||||
func TestGetUnmergedPullRequestsByHeadInfo(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	prs, err := issues_model.GetUnmergedPullRequestsByHeadInfo(1, "branch2")
 | 
			
		||||
	prs, err := issues_model.GetUnmergedPullRequestsByHeadInfo(1, "branch2", false)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.Len(t, prs, 1)
 | 
			
		||||
	for _, pr := range prs {
 | 
			
		||||
 
 | 
			
		||||
@@ -89,7 +89,7 @@ func RecreateTable(sess *xorm.Session, bean interface{}) error {
 | 
			
		||||
		hasID = hasID || (column.IsPrimaryKey && column.IsAutoIncrement)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if hasID && setting.Database.UseMSSQL {
 | 
			
		||||
	if hasID && setting.Database.Type.IsMSSQL() {
 | 
			
		||||
		if _, err := sess.Exec(fmt.Sprintf("SET IDENTITY_INSERT `%s` ON", tempTableName)); err != nil {
 | 
			
		||||
			log.Error("Unable to set identity insert for table %s. Error: %v", tempTableName, err)
 | 
			
		||||
			return err
 | 
			
		||||
@@ -143,7 +143,7 @@ func RecreateTable(sess *xorm.Session, bean interface{}) error {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if hasID && setting.Database.UseMSSQL {
 | 
			
		||||
	if hasID && setting.Database.Type.IsMSSQL() {
 | 
			
		||||
		if _, err := sess.Exec(fmt.Sprintf("SET IDENTITY_INSERT `%s` OFF", tempTableName)); err != nil {
 | 
			
		||||
			log.Error("Unable to switch off identity insert for table %s. Error: %v", tempTableName, err)
 | 
			
		||||
			return err
 | 
			
		||||
@@ -151,7 +151,7 @@ func RecreateTable(sess *xorm.Session, bean interface{}) error {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch {
 | 
			
		||||
	case setting.Database.UseSQLite3:
 | 
			
		||||
	case setting.Database.Type.IsSQLite3():
 | 
			
		||||
		// SQLite will drop all the constraints on the old table
 | 
			
		||||
		if _, err := sess.Exec(fmt.Sprintf("DROP TABLE `%s`", tableName)); err != nil {
 | 
			
		||||
			log.Error("Unable to drop old table %s. Error: %v", tableName, err)
 | 
			
		||||
@@ -178,7 +178,7 @@ func RecreateTable(sess *xorm.Session, bean interface{}) error {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	case setting.Database.UseMySQL:
 | 
			
		||||
	case setting.Database.Type.IsMySQL():
 | 
			
		||||
		// MySQL will drop all the constraints on the old table
 | 
			
		||||
		if _, err := sess.Exec(fmt.Sprintf("DROP TABLE `%s`", tableName)); err != nil {
 | 
			
		||||
			log.Error("Unable to drop old table %s. Error: %v", tableName, err)
 | 
			
		||||
@@ -205,7 +205,7 @@ func RecreateTable(sess *xorm.Session, bean interface{}) error {
 | 
			
		||||
			log.Error("Unable to recreate uniques on table %s. Error: %v", tableName, err)
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	case setting.Database.UsePostgreSQL:
 | 
			
		||||
	case setting.Database.Type.IsPostgreSQL():
 | 
			
		||||
		var originalSequences []string
 | 
			
		||||
		type sequenceData struct {
 | 
			
		||||
			LastValue int  `xorm:"'last_value'"`
 | 
			
		||||
@@ -296,7 +296,7 @@ func RecreateTable(sess *xorm.Session, bean interface{}) error {
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	case setting.Database.UseMSSQL:
 | 
			
		||||
	case setting.Database.Type.IsMSSQL():
 | 
			
		||||
		// MSSQL will drop all the constraints on the old table
 | 
			
		||||
		if _, err := sess.Exec(fmt.Sprintf("DROP TABLE `%s`", tableName)); err != nil {
 | 
			
		||||
			log.Error("Unable to drop old table %s. Error: %v", tableName, err)
 | 
			
		||||
@@ -323,7 +323,7 @@ func DropTableColumns(sess *xorm.Session, tableName string, columnNames ...strin
 | 
			
		||||
	// TODO: This will not work if there are foreign keys
 | 
			
		||||
 | 
			
		||||
	switch {
 | 
			
		||||
	case setting.Database.UseSQLite3:
 | 
			
		||||
	case setting.Database.Type.IsSQLite3():
 | 
			
		||||
		// First drop the indexes on the columns
 | 
			
		||||
		res, errIndex := sess.Query(fmt.Sprintf("PRAGMA index_list(`%s`)", tableName))
 | 
			
		||||
		if errIndex != nil {
 | 
			
		||||
@@ -405,7 +405,7 @@ func DropTableColumns(sess *xorm.Session, tableName string, columnNames ...strin
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	case setting.Database.UsePostgreSQL:
 | 
			
		||||
	case setting.Database.Type.IsPostgreSQL():
 | 
			
		||||
		cols := ""
 | 
			
		||||
		for _, col := range columnNames {
 | 
			
		||||
			if cols != "" {
 | 
			
		||||
@@ -416,7 +416,7 @@ func DropTableColumns(sess *xorm.Session, tableName string, columnNames ...strin
 | 
			
		||||
		if _, err := sess.Exec(fmt.Sprintf("ALTER TABLE `%s` %s", tableName, cols)); err != nil {
 | 
			
		||||
			return fmt.Errorf("Drop table `%s` columns %v: %v", tableName, columnNames, err)
 | 
			
		||||
		}
 | 
			
		||||
	case setting.Database.UseMySQL:
 | 
			
		||||
	case setting.Database.Type.IsMySQL():
 | 
			
		||||
		// Drop indexes on columns first
 | 
			
		||||
		sql := fmt.Sprintf("SHOW INDEX FROM %s WHERE column_name IN ('%s')", tableName, strings.Join(columnNames, "','"))
 | 
			
		||||
		res, err := sess.Query(sql)
 | 
			
		||||
@@ -444,7 +444,7 @@ func DropTableColumns(sess *xorm.Session, tableName string, columnNames ...strin
 | 
			
		||||
		if _, err := sess.Exec(fmt.Sprintf("ALTER TABLE `%s` %s", tableName, cols)); err != nil {
 | 
			
		||||
			return fmt.Errorf("Drop table `%s` columns %v: %v", tableName, columnNames, err)
 | 
			
		||||
		}
 | 
			
		||||
	case setting.Database.UseMSSQL:
 | 
			
		||||
	case setting.Database.Type.IsMSSQL():
 | 
			
		||||
		cols := ""
 | 
			
		||||
		for _, col := range columnNames {
 | 
			
		||||
			if cols != "" {
 | 
			
		||||
@@ -543,13 +543,13 @@ func newXORMEngine() (*xorm.Engine, error) {
 | 
			
		||||
 | 
			
		||||
func deleteDB() error {
 | 
			
		||||
	switch {
 | 
			
		||||
	case setting.Database.UseSQLite3:
 | 
			
		||||
	case setting.Database.Type.IsSQLite3():
 | 
			
		||||
		if err := util.Remove(setting.Database.Path); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		return os.MkdirAll(path.Dir(setting.Database.Path), os.ModePerm)
 | 
			
		||||
 | 
			
		||||
	case setting.Database.UseMySQL:
 | 
			
		||||
	case setting.Database.Type.IsMySQL():
 | 
			
		||||
		db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@tcp(%s)/",
 | 
			
		||||
			setting.Database.User, setting.Database.Passwd, setting.Database.Host))
 | 
			
		||||
		if err != nil {
 | 
			
		||||
@@ -565,7 +565,7 @@ func deleteDB() error {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		return nil
 | 
			
		||||
	case setting.Database.UsePostgreSQL:
 | 
			
		||||
	case setting.Database.Type.IsPostgreSQL():
 | 
			
		||||
		db, err := sql.Open("postgres", fmt.Sprintf("postgres://%s:%s@%s/?sslmode=%s",
 | 
			
		||||
			setting.Database.User, setting.Database.Passwd, setting.Database.Host, setting.Database.SSLMode))
 | 
			
		||||
		if err != nil {
 | 
			
		||||
@@ -612,7 +612,7 @@ func deleteDB() error {
 | 
			
		||||
			}
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
	case setting.Database.UseMSSQL:
 | 
			
		||||
	case setting.Database.Type.IsMSSQL():
 | 
			
		||||
		host, port := setting.ParseMSSQLHostPort(setting.Database.Host)
 | 
			
		||||
		db, err := sql.Open("mssql", fmt.Sprintf("server=%s; port=%s; database=%s; user id=%s; password=%s;",
 | 
			
		||||
			host, port, "master", setting.Database.User, setting.Database.Passwd))
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,6 @@
 | 
			
		||||
  org_id: 0
 | 
			
		||||
  name: label1
 | 
			
		||||
  color: '#abcdef'
 | 
			
		||||
  exclusive: false
 | 
			
		||||
  num_issues: 2
 | 
			
		||||
  num_closed_issues: 0
 | 
			
		||||
 | 
			
		||||
@@ -14,7 +13,6 @@
 | 
			
		||||
  org_id: 0
 | 
			
		||||
  name: label2
 | 
			
		||||
  color: '#000000'
 | 
			
		||||
  exclusive: false
 | 
			
		||||
  num_issues: 1
 | 
			
		||||
  num_closed_issues: 1
 | 
			
		||||
-
 | 
			
		||||
@@ -23,7 +21,6 @@
 | 
			
		||||
  org_id:  3
 | 
			
		||||
  name: orglabel3
 | 
			
		||||
  color: '#abcdef'
 | 
			
		||||
  exclusive: false
 | 
			
		||||
  num_issues: 0
 | 
			
		||||
  num_closed_issues: 0
 | 
			
		||||
 | 
			
		||||
@@ -33,7 +30,6 @@
 | 
			
		||||
  org_id: 3
 | 
			
		||||
  name: orglabel4
 | 
			
		||||
  color: '#000000'
 | 
			
		||||
  exclusive: false
 | 
			
		||||
  num_issues: 1
 | 
			
		||||
  num_closed_issues: 0
 | 
			
		||||
 | 
			
		||||
@@ -43,6 +39,5 @@
 | 
			
		||||
  org_id: 0
 | 
			
		||||
  name: pull-test-label
 | 
			
		||||
  color: '#000000'
 | 
			
		||||
  exclusive: false
 | 
			
		||||
  num_issues: 0
 | 
			
		||||
  num_closed_issues: 0
 | 
			
		||||
 
 | 
			
		||||
@@ -13,9 +13,9 @@ func PrependRefsHeadsToIssueRefs(x *xorm.Engine) error {
 | 
			
		||||
	var query string
 | 
			
		||||
 | 
			
		||||
	switch {
 | 
			
		||||
	case setting.Database.UseMSSQL:
 | 
			
		||||
	case setting.Database.Type.IsMSSQL():
 | 
			
		||||
		query = "UPDATE `issue` SET `ref` = 'refs/heads/' + `ref` WHERE `ref` IS NOT NULL AND `ref` <> '' AND `ref` NOT LIKE 'refs/%'"
 | 
			
		||||
	case setting.Database.UseMySQL:
 | 
			
		||||
	case setting.Database.Type.IsMySQL():
 | 
			
		||||
		query = "UPDATE `issue` SET `ref` = CONCAT('refs/heads/', `ref`) WHERE `ref` IS NOT NULL AND `ref` <> '' AND `ref` NOT LIKE 'refs/%';"
 | 
			
		||||
	default:
 | 
			
		||||
		query = "UPDATE `issue` SET `ref` = 'refs/heads/' || `ref` WHERE `ref` IS NOT NULL AND `ref` <> '' AND `ref` NOT LIKE 'refs/%'"
 | 
			
		||||
 
 | 
			
		||||
@@ -41,7 +41,7 @@ func FixLanguageStatsToSaveSize(x *xorm.Engine) error {
 | 
			
		||||
 | 
			
		||||
	// Delete language stat statuses
 | 
			
		||||
	truncExpr := "TRUNCATE TABLE"
 | 
			
		||||
	if setting.Database.UseSQLite3 {
 | 
			
		||||
	if setting.Database.Type.IsSQLite3() {
 | 
			
		||||
		truncExpr = "DELETE FROM"
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -21,7 +21,7 @@ func IncreaseLanguageField(x *xorm.Engine) error {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if setting.Database.UseSQLite3 {
 | 
			
		||||
	if setting.Database.Type.IsSQLite3() {
 | 
			
		||||
		// SQLite maps VARCHAR to TEXT without size so we're done
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
@@ -41,11 +41,11 @@ func IncreaseLanguageField(x *xorm.Engine) error {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch {
 | 
			
		||||
	case setting.Database.UseMySQL:
 | 
			
		||||
	case setting.Database.Type.IsMySQL():
 | 
			
		||||
		if _, err := sess.Exec(fmt.Sprintf("ALTER TABLE language_stat MODIFY COLUMN language %s", sqlType)); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	case setting.Database.UseMSSQL:
 | 
			
		||||
	case setting.Database.Type.IsMSSQL():
 | 
			
		||||
		// Yet again MSSQL just has to be awkward.
 | 
			
		||||
		// Here we have to drop the constraints first and then rebuild them
 | 
			
		||||
		constraints := make([]string, 0)
 | 
			
		||||
@@ -71,7 +71,7 @@ func IncreaseLanguageField(x *xorm.Engine) error {
 | 
			
		||||
		if err := sess.CreateUniques(new(LanguageStat)); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	case setting.Database.UsePostgreSQL:
 | 
			
		||||
	case setting.Database.Type.IsPostgreSQL():
 | 
			
		||||
		if _, err := sess.Exec(fmt.Sprintf("ALTER TABLE language_stat ALTER COLUMN language TYPE %s", sqlType)); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
@@ -17,13 +17,13 @@ import (
 | 
			
		||||
 | 
			
		||||
func SetDefaultPasswordToArgon2(x *xorm.Engine) error {
 | 
			
		||||
	switch {
 | 
			
		||||
	case setting.Database.UseMySQL:
 | 
			
		||||
	case setting.Database.Type.IsMySQL():
 | 
			
		||||
		_, err := x.Exec("ALTER TABLE `user` ALTER passwd_hash_algo SET DEFAULT 'argon2';")
 | 
			
		||||
		return err
 | 
			
		||||
	case setting.Database.UsePostgreSQL:
 | 
			
		||||
	case setting.Database.Type.IsPostgreSQL():
 | 
			
		||||
		_, err := x.Exec("ALTER TABLE `user` ALTER COLUMN passwd_hash_algo SET DEFAULT 'argon2';")
 | 
			
		||||
		return err
 | 
			
		||||
	case setting.Database.UseMSSQL:
 | 
			
		||||
	case setting.Database.Type.IsMSSQL():
 | 
			
		||||
		// need to find the constraint and drop it, then recreate it.
 | 
			
		||||
		sess := x.NewSession()
 | 
			
		||||
		defer sess.Close()
 | 
			
		||||
@@ -53,7 +53,7 @@ func SetDefaultPasswordToArgon2(x *xorm.Engine) error {
 | 
			
		||||
		}
 | 
			
		||||
		return sess.Commit()
 | 
			
		||||
 | 
			
		||||
	case setting.Database.UseSQLite3:
 | 
			
		||||
	case setting.Database.Type.IsSQLite3():
 | 
			
		||||
		// drop through
 | 
			
		||||
	default:
 | 
			
		||||
		log.Fatal("Unrecognized DB")
 | 
			
		||||
 
 | 
			
		||||
@@ -62,7 +62,7 @@ func UpdateCodeCommentReplies(x *xorm.Engine) error {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if setting.Database.UseMSSQL {
 | 
			
		||||
		if setting.Database.Type.IsMSSQL() {
 | 
			
		||||
			if _, err := sess.Exec(sqlSelect + " INTO #temp_comments" + sqlTail); err != nil {
 | 
			
		||||
				log.Error("unable to create temporary table")
 | 
			
		||||
				return err
 | 
			
		||||
@@ -72,13 +72,13 @@ func UpdateCodeCommentReplies(x *xorm.Engine) error {
 | 
			
		||||
		comments := make([]*Comment, 0, batchSize)
 | 
			
		||||
 | 
			
		||||
		switch {
 | 
			
		||||
		case setting.Database.UseMySQL:
 | 
			
		||||
		case setting.Database.Type.IsMySQL():
 | 
			
		||||
			sqlCmd = sqlSelect + sqlTail + " LIMIT " + strconv.Itoa(batchSize) + ", " + strconv.Itoa(start)
 | 
			
		||||
		case setting.Database.UsePostgreSQL:
 | 
			
		||||
		case setting.Database.Type.IsPostgreSQL():
 | 
			
		||||
			fallthrough
 | 
			
		||||
		case setting.Database.UseSQLite3:
 | 
			
		||||
		case setting.Database.Type.IsSQLite3():
 | 
			
		||||
			sqlCmd = sqlSelect + sqlTail + " LIMIT " + strconv.Itoa(batchSize) + " OFFSET " + strconv.Itoa(start)
 | 
			
		||||
		case setting.Database.UseMSSQL:
 | 
			
		||||
		case setting.Database.Type.IsMSSQL():
 | 
			
		||||
			sqlCmd = "SELECT TOP " + strconv.Itoa(batchSize) + " * FROM #temp_comments WHERE " +
 | 
			
		||||
				"(id NOT IN ( SELECT TOP " + strconv.Itoa(start) + " id FROM #temp_comments ORDER BY id )) ORDER BY id"
 | 
			
		||||
		default:
 | 
			
		||||
 
 | 
			
		||||
@@ -14,7 +14,7 @@ import (
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func FixPostgresIDSequences(x *xorm.Engine) error {
 | 
			
		||||
	if !setting.Database.UsePostgreSQL {
 | 
			
		||||
	if !setting.Database.Type.IsPostgreSQL() {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -54,11 +54,11 @@ func RenameTaskErrorsToMessage(x *xorm.Engine) error {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch {
 | 
			
		||||
	case setting.Database.UseMySQL:
 | 
			
		||||
	case setting.Database.Type.IsMySQL():
 | 
			
		||||
		if _, err := sess.Exec("ALTER TABLE `task` CHANGE errors message text"); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	case setting.Database.UseMSSQL:
 | 
			
		||||
	case setting.Database.Type.IsMSSQL():
 | 
			
		||||
		if _, err := sess.Exec("sp_rename 'task.errors', 'message', 'COLUMN'"); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,7 @@ func AlterIssueAndCommentTextFieldsToLongText(x *xorm.Engine) error {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if setting.Database.UseMySQL {
 | 
			
		||||
	if setting.Database.Type.IsMySQL() {
 | 
			
		||||
		if _, err := sess.Exec("ALTER TABLE `issue` CHANGE `content` `content` LONGTEXT"); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,7 @@ func AlterHookTaskTextFieldsToLongText(x *xorm.Engine) error {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if setting.Database.UseMySQL {
 | 
			
		||||
	if setting.Database.Type.IsMySQL() {
 | 
			
		||||
		if _, err := sess.Exec("ALTER TABLE `hook_task` CHANGE `payload_content` `payload_content` LONGTEXT, CHANGE `request_content` `request_content` LONGTEXT, change `response_content` `response_content` LONGTEXT"); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
@@ -38,7 +38,7 @@ func (*improveActionTableIndicesAction) TableIndices() []*schemas.Index {
 | 
			
		||||
	actUserIndex := schemas.NewIndex("au_r_c_u_d", schemas.IndexType)
 | 
			
		||||
	actUserIndex.AddColumn("act_user_id", "repo_id", "created_unix", "user_id", "is_deleted")
 | 
			
		||||
	indices := []*schemas.Index{actUserIndex, repoIndex}
 | 
			
		||||
	if setting.Database.UsePostgreSQL {
 | 
			
		||||
	if setting.Database.Type.IsPostgreSQL() {
 | 
			
		||||
		cudIndex := schemas.NewIndex("c_u_d", schemas.IndexType)
 | 
			
		||||
		cudIndex.AddColumn("created_unix", "user_id", "is_deleted")
 | 
			
		||||
		indices = append(indices, cudIndex)
 | 
			
		||||
 
 | 
			
		||||
@@ -65,11 +65,11 @@ func RenameCredentialIDBytes(x *xorm.Engine) error {
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		switch {
 | 
			
		||||
		case setting.Database.UseMySQL:
 | 
			
		||||
		case setting.Database.Type.IsMySQL():
 | 
			
		||||
			if _, err := sess.Exec("ALTER TABLE `webauthn_credential` CHANGE credential_id_bytes credential_id VARBINARY(1024)"); err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		case setting.Database.UseMSSQL:
 | 
			
		||||
		case setting.Database.Type.IsMSSQL():
 | 
			
		||||
			if _, err := sess.Exec("sp_rename 'webauthn_credential.credential_id_bytes', 'credential_id', 'COLUMN'"); err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,7 @@ func AlterPublicGPGKeyContentFieldsToMediumText(x *xorm.Engine) error {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if setting.Database.UseMySQL {
 | 
			
		||||
	if setting.Database.Type.IsMySQL() {
 | 
			
		||||
		if _, err := sess.Exec("ALTER TABLE `gpg_key` CHANGE `content` `content` MEDIUMTEXT"); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,7 @@ func AlterPackageVersionMetadataToLongText(x *xorm.Engine) error {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if setting.Database.UseMySQL {
 | 
			
		||||
	if setting.Database.Type.IsMySQL() {
 | 
			
		||||
		if _, err := sess.Exec("ALTER TABLE `package_version` MODIFY COLUMN `metadata_json` LONGTEXT"); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
@@ -17,7 +17,7 @@ func AlterPublicGPGKeyImportContentFieldToMediumText(x *xorm.Engine) error {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if setting.Database.UseMySQL {
 | 
			
		||||
	if setting.Database.Type.IsMySQL() {
 | 
			
		||||
		if _, err := sess.Exec("ALTER TABLE `gpg_key_import` CHANGE `content` `content` MEDIUMTEXT"); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
@@ -239,6 +239,32 @@ func (org *Organization) CustomAvatarRelativePath() string {
 | 
			
		||||
	return org.Avatar
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UnitPermission returns unit permission
 | 
			
		||||
func (org *Organization) UnitPermission(ctx context.Context, doer *user_model.User, unitType unit.Type) perm.AccessMode {
 | 
			
		||||
	if doer != nil {
 | 
			
		||||
		teams, err := GetUserOrgTeams(ctx, org.ID, doer.ID)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			log.Error("GetUserOrgTeams: %v", err)
 | 
			
		||||
			return perm.AccessModeNone
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if err := teams.LoadUnits(ctx); err != nil {
 | 
			
		||||
			log.Error("LoadUnits: %v", err)
 | 
			
		||||
			return perm.AccessModeNone
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if len(teams) > 0 {
 | 
			
		||||
			return teams.UnitMaxAccess(unitType)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if org.Visibility.IsPublic() {
 | 
			
		||||
		return perm.AccessModeRead
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return perm.AccessModeNone
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CreateOrganization creates record of a new organization.
 | 
			
		||||
func CreateOrganization(org *Organization, owner *user_model.User) (err error) {
 | 
			
		||||
	if !owner.CanCreateOrganization() {
 | 
			
		||||
 
 | 
			
		||||
@@ -416,7 +416,7 @@ func DeleteProjectByID(ctx context.Context, id int64) error {
 | 
			
		||||
 | 
			
		||||
func DeleteProjectByRepoID(ctx context.Context, repoID int64) error {
 | 
			
		||||
	switch {
 | 
			
		||||
	case setting.Database.UseSQLite3:
 | 
			
		||||
	case setting.Database.Type.IsSQLite3():
 | 
			
		||||
		if _, err := db.GetEngine(ctx).Exec("DELETE FROM project_issue WHERE project_issue.id IN (SELECT project_issue.id FROM project_issue INNER JOIN project WHERE project.id = project_issue.project_id AND project.repo_id = ?)", repoID); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
@@ -426,7 +426,7 @@ func DeleteProjectByRepoID(ctx context.Context, repoID int64) error {
 | 
			
		||||
		if _, err := db.GetEngine(ctx).Table("project").Where("repo_id = ? ", repoID).Delete(&Project{}); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	case setting.Database.UsePostgreSQL:
 | 
			
		||||
	case setting.Database.Type.IsPostgreSQL():
 | 
			
		||||
		if _, err := db.GetEngine(ctx).Exec("DELETE FROM project_issue USING project WHERE project.id = project_issue.project_id AND project.repo_id = ? ", repoID); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
@@ -39,9 +39,9 @@ import (
 | 
			
		||||
var ItemsPerPage = 40
 | 
			
		||||
 | 
			
		||||
// Init initialize model
 | 
			
		||||
func Init() error {
 | 
			
		||||
func Init(ctx context.Context) error {
 | 
			
		||||
	unit.LoadUnitConfig()
 | 
			
		||||
	return system_model.Init()
 | 
			
		||||
	return system_model.Init(ctx)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeleteRepository deletes a repository for a user or organization.
 | 
			
		||||
 
 | 
			
		||||
@@ -498,7 +498,7 @@ func SearchRepositoryCondition(opts *SearchRepoOptions) builder.Cond {
 | 
			
		||||
		subQueryCond := builder.NewCond()
 | 
			
		||||
 | 
			
		||||
		// Topic checking. Topics are present.
 | 
			
		||||
		if setting.Database.UsePostgreSQL { // postgres stores the topics as json and not as text
 | 
			
		||||
		if setting.Database.Type.IsPostgreSQL() { // postgres stores the topics as json and not as text
 | 
			
		||||
			subQueryCond = subQueryCond.Or(builder.And(builder.NotNull{"topics"}, builder.Neq{"(topics)::text": "[]"}))
 | 
			
		||||
		} else {
 | 
			
		||||
			subQueryCond = subQueryCond.Or(builder.And(builder.Neq{"topics": "null"}, builder.Neq{"topics": "[]"}))
 | 
			
		||||
 
 | 
			
		||||
@@ -79,8 +79,8 @@ func IsErrDataExpired(err error) bool {
 | 
			
		||||
	return ok
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetSettingNoCache returns specific setting without using the cache
 | 
			
		||||
func GetSettingNoCache(ctx context.Context, key string) (*Setting, error) {
 | 
			
		||||
// GetSetting returns specific setting without using the cache
 | 
			
		||||
func GetSetting(ctx context.Context, key string) (*Setting, error) {
 | 
			
		||||
	v, err := GetSettings(ctx, []string{key})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
@@ -93,11 +93,11 @@ func GetSettingNoCache(ctx context.Context, key string) (*Setting, error) {
 | 
			
		||||
 | 
			
		||||
const contextCacheKey = "system_setting"
 | 
			
		||||
 | 
			
		||||
// GetSetting returns the setting value via the key
 | 
			
		||||
func GetSetting(ctx context.Context, key string) (string, error) {
 | 
			
		||||
// GetSettingWithCache returns the setting value via the key
 | 
			
		||||
func GetSettingWithCache(ctx context.Context, key string) (string, error) {
 | 
			
		||||
	return cache.GetWithContextCache(ctx, contextCacheKey, key, func() (string, error) {
 | 
			
		||||
		return cache.GetString(genSettingCacheKey(key), func() (string, error) {
 | 
			
		||||
			res, err := GetSettingNoCache(ctx, key)
 | 
			
		||||
			res, err := GetSetting(ctx, key)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return "", err
 | 
			
		||||
			}
 | 
			
		||||
@@ -110,6 +110,15 @@ func GetSetting(ctx context.Context, key string) (string, error) {
 | 
			
		||||
// none existing keys and errors are ignored and result in false
 | 
			
		||||
func GetSettingBool(ctx context.Context, key string) bool {
 | 
			
		||||
	s, _ := GetSetting(ctx, key)
 | 
			
		||||
	if s == nil {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	v, _ := strconv.ParseBool(s.SettingValue)
 | 
			
		||||
	return v
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func GetSettingWithCacheBool(ctx context.Context, key string) bool {
 | 
			
		||||
	s, _ := GetSettingWithCache(ctx, key)
 | 
			
		||||
	v, _ := strconv.ParseBool(s)
 | 
			
		||||
	return v
 | 
			
		||||
}
 | 
			
		||||
@@ -120,7 +129,7 @@ func GetSettings(ctx context.Context, keys []string) (map[string]*Setting, error
 | 
			
		||||
		keys[i] = strings.ToLower(keys[i])
 | 
			
		||||
	}
 | 
			
		||||
	settings := make([]*Setting, 0, len(keys))
 | 
			
		||||
	if err := db.GetEngine(db.DefaultContext).
 | 
			
		||||
	if err := db.GetEngine(ctx).
 | 
			
		||||
		Where(builder.In("setting_key", keys)).
 | 
			
		||||
		Find(&settings); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
@@ -151,9 +160,9 @@ func (settings AllSettings) GetVersion(key string) int {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetAllSettings returns all settings from user
 | 
			
		||||
func GetAllSettings() (AllSettings, error) {
 | 
			
		||||
func GetAllSettings(ctx context.Context) (AllSettings, error) {
 | 
			
		||||
	settings := make([]*Setting, 0, 5)
 | 
			
		||||
	if err := db.GetEngine(db.DefaultContext).
 | 
			
		||||
	if err := db.GetEngine(ctx).
 | 
			
		||||
		Find(&settings); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
@@ -168,12 +177,12 @@ func GetAllSettings() (AllSettings, error) {
 | 
			
		||||
func DeleteSetting(ctx context.Context, setting *Setting) error {
 | 
			
		||||
	cache.RemoveContextData(ctx, contextCacheKey, setting.SettingKey)
 | 
			
		||||
	cache.Remove(genSettingCacheKey(setting.SettingKey))
 | 
			
		||||
	_, err := db.GetEngine(db.DefaultContext).Delete(setting)
 | 
			
		||||
	_, err := db.GetEngine(ctx).Delete(setting)
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func SetSettingNoVersion(ctx context.Context, key, value string) error {
 | 
			
		||||
	s, err := GetSettingNoCache(ctx, key)
 | 
			
		||||
	s, err := GetSetting(ctx, key)
 | 
			
		||||
	if IsErrSettingIsNotExist(err) {
 | 
			
		||||
		return SetSetting(ctx, &Setting{
 | 
			
		||||
			SettingKey:   key,
 | 
			
		||||
@@ -189,7 +198,7 @@ func SetSettingNoVersion(ctx context.Context, key, value string) error {
 | 
			
		||||
 | 
			
		||||
// SetSetting updates a users' setting for a specific key
 | 
			
		||||
func SetSetting(ctx context.Context, setting *Setting) error {
 | 
			
		||||
	if err := upsertSettingValue(strings.ToLower(setting.SettingKey), setting.SettingValue, setting.Version); err != nil {
 | 
			
		||||
	if err := upsertSettingValue(ctx, strings.ToLower(setting.SettingKey), setting.SettingValue, setting.Version); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -205,8 +214,8 @@ func SetSetting(ctx context.Context, setting *Setting) error {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func upsertSettingValue(key, value string, version int) error {
 | 
			
		||||
	return db.WithTx(db.DefaultContext, func(ctx context.Context) error {
 | 
			
		||||
func upsertSettingValue(parentCtx context.Context, key, value string, version int) error {
 | 
			
		||||
	return db.WithTx(parentCtx, func(ctx context.Context) error {
 | 
			
		||||
		e := db.GetEngine(ctx)
 | 
			
		||||
 | 
			
		||||
		// here we use a general method to do a safe upsert for different databases (and most transaction levels)
 | 
			
		||||
@@ -249,9 +258,9 @@ var (
 | 
			
		||||
	LibravatarService *libravatar.Libravatar
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func Init() error {
 | 
			
		||||
func Init(ctx context.Context) error {
 | 
			
		||||
	var disableGravatar bool
 | 
			
		||||
	disableGravatarSetting, err := GetSettingNoCache(db.DefaultContext, KeyPictureDisableGravatar)
 | 
			
		||||
	disableGravatarSetting, err := GetSetting(ctx, KeyPictureDisableGravatar)
 | 
			
		||||
	if IsErrSettingIsNotExist(err) {
 | 
			
		||||
		disableGravatar = setting_module.GetDefaultDisableGravatar()
 | 
			
		||||
		disableGravatarSetting = &Setting{SettingValue: strconv.FormatBool(disableGravatar)}
 | 
			
		||||
@@ -262,7 +271,7 @@ func Init() error {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var enableFederatedAvatar bool
 | 
			
		||||
	enableFederatedAvatarSetting, err := GetSettingNoCache(db.DefaultContext, KeyPictureEnableFederatedAvatar)
 | 
			
		||||
	enableFederatedAvatarSetting, err := GetSetting(ctx, KeyPictureEnableFederatedAvatar)
 | 
			
		||||
	if IsErrSettingIsNotExist(err) {
 | 
			
		||||
		enableFederatedAvatar = setting_module.GetDefaultEnableFederatedAvatar(disableGravatar)
 | 
			
		||||
		enableFederatedAvatarSetting = &Setting{SettingValue: strconv.FormatBool(enableFederatedAvatar)}
 | 
			
		||||
@@ -275,13 +284,13 @@ func Init() error {
 | 
			
		||||
	if setting_module.OfflineMode {
 | 
			
		||||
		disableGravatar = true
 | 
			
		||||
		enableFederatedAvatar = false
 | 
			
		||||
		if !GetSettingBool(db.DefaultContext, KeyPictureDisableGravatar) {
 | 
			
		||||
			if err := SetSettingNoVersion(db.DefaultContext, KeyPictureDisableGravatar, "true"); err != nil {
 | 
			
		||||
		if !GetSettingBool(ctx, KeyPictureDisableGravatar) {
 | 
			
		||||
			if err := SetSettingNoVersion(ctx, KeyPictureDisableGravatar, "true"); err != nil {
 | 
			
		||||
				return fmt.Errorf("Failed to set setting %q: %w", KeyPictureDisableGravatar, err)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if GetSettingBool(db.DefaultContext, KeyPictureEnableFederatedAvatar) {
 | 
			
		||||
			if err := SetSettingNoVersion(db.DefaultContext, KeyPictureEnableFederatedAvatar, "false"); err != nil {
 | 
			
		||||
		if GetSettingBool(ctx, KeyPictureEnableFederatedAvatar) {
 | 
			
		||||
			if err := SetSettingNoVersion(ctx, KeyPictureEnableFederatedAvatar, "false"); err != nil {
 | 
			
		||||
				return fmt.Errorf("Failed to set setting %q: %w", KeyPictureEnableFederatedAvatar, err)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
@@ -40,10 +40,10 @@ func TestSettings(t *testing.T) {
 | 
			
		||||
 | 
			
		||||
	value, err := system.GetSetting(db.DefaultContext, keyName)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.EqualValues(t, updatedSetting.SettingValue, value)
 | 
			
		||||
	assert.EqualValues(t, updatedSetting.SettingValue, value.SettingValue)
 | 
			
		||||
 | 
			
		||||
	// get all settings
 | 
			
		||||
	settings, err = system.GetAllSettings()
 | 
			
		||||
	settings, err = system.GetAllSettings(db.DefaultContext)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.Len(t, settings, 3)
 | 
			
		||||
	assert.EqualValues(t, updatedSetting.SettingValue, settings[strings.ToLower(updatedSetting.SettingKey)].SettingValue)
 | 
			
		||||
@@ -51,7 +51,7 @@ func TestSettings(t *testing.T) {
 | 
			
		||||
	// delete setting
 | 
			
		||||
	err = system.DeleteSetting(db.DefaultContext, &system.Setting{SettingKey: strings.ToLower(keyName)})
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	settings, err = system.GetAllSettings()
 | 
			
		||||
	settings, err = system.GetAllSettings(db.DefaultContext)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.Len(t, settings, 2)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -76,7 +76,7 @@ func MainTest(m *testing.M, testOpts *TestOptions) {
 | 
			
		||||
	setting.SSH.BuiltinServerUser = "builtinuser"
 | 
			
		||||
	setting.SSH.Port = 3000
 | 
			
		||||
	setting.SSH.Domain = "try.gitea.io"
 | 
			
		||||
	setting.Database.UseSQLite3 = true
 | 
			
		||||
	setting.Database.Type = "sqlite3"
 | 
			
		||||
	setting.Repository.DefaultBranch = "master" // many test code still assume that default branch is called "master"
 | 
			
		||||
	repoRootPath, err := os.MkdirTemp(os.TempDir(), "repos")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
@@ -113,7 +113,7 @@ func MainTest(m *testing.M, testOpts *TestOptions) {
 | 
			
		||||
	if err = storage.Init(); err != nil {
 | 
			
		||||
		fatalTestError("storage.Init: %v\n", err)
 | 
			
		||||
	}
 | 
			
		||||
	if err = system_model.Init(); err != nil {
 | 
			
		||||
	if err = system_model.Init(db.DefaultContext); err != nil {
 | 
			
		||||
		fatalTestError("models.Init: %v\n", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -67,7 +67,7 @@ func (u *User) AvatarLinkWithSize(ctx context.Context, size int) string {
 | 
			
		||||
	useLocalAvatar := false
 | 
			
		||||
	autoGenerateAvatar := false
 | 
			
		||||
 | 
			
		||||
	disableGravatar := system_model.GetSettingBool(ctx, system_model.KeyPictureDisableGravatar)
 | 
			
		||||
	disableGravatar := system_model.GetSettingWithCacheBool(ctx, system_model.KeyPictureDisableGravatar)
 | 
			
		||||
 | 
			
		||||
	switch {
 | 
			
		||||
	case u.UseCustomAvatar:
 | 
			
		||||
 
 | 
			
		||||
@@ -393,6 +393,11 @@ func (u *User) IsOrganization() bool {
 | 
			
		||||
	return u.Type == UserTypeOrganization
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsIndividual returns true if user is actually a individual user.
 | 
			
		||||
func (u *User) IsIndividual() bool {
 | 
			
		||||
	return u.Type == UserTypeIndividual
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DisplayName returns full name if it's not empty,
 | 
			
		||||
// returns username otherwise.
 | 
			
		||||
func (u *User) DisplayName() string {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										41
									
								
								modules/actions/github.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								modules/actions/github.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,41 @@
 | 
			
		||||
// Copyright 2023 The Gitea Authors. All rights reserved.
 | 
			
		||||
// SPDX-License-Identifier: MIT
 | 
			
		||||
 | 
			
		||||
package actions
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	webhook_module "code.gitea.io/gitea/modules/webhook"
 | 
			
		||||
 | 
			
		||||
	"github.com/nektos/act/pkg/jobparser"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	githubEventPullRequest              = "pull_request"
 | 
			
		||||
	githubEventPullRequestTarget        = "pull_request_target"
 | 
			
		||||
	githubEventPullRequestReviewComment = "pull_request_review_comment"
 | 
			
		||||
	githubEventPullRequestReview        = "pull_request_review"
 | 
			
		||||
	githubEventRegistryPackage          = "registry_package"
 | 
			
		||||
	githubEventCreate                   = "create"
 | 
			
		||||
	githubEventDelete                   = "delete"
 | 
			
		||||
	githubEventFork                     = "fork"
 | 
			
		||||
	githubEventPush                     = "push"
 | 
			
		||||
	githubEventIssues                   = "issues"
 | 
			
		||||
	githubEventIssueComment             = "issue_comment"
 | 
			
		||||
	githubEventRelease                  = "release"
 | 
			
		||||
	githubEventPullRequestComment       = "pull_request_comment"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func convertFromGithubEvent(evt *jobparser.Event) string {
 | 
			
		||||
	switch evt.Name {
 | 
			
		||||
	case githubEventPullRequest, githubEventPullRequestTarget, githubEventPullRequestReview,
 | 
			
		||||
		githubEventPullRequestReviewComment:
 | 
			
		||||
		return string(webhook_module.HookEventPullRequest)
 | 
			
		||||
	case githubEventRegistryPackage:
 | 
			
		||||
		return string(webhook_module.HookEventPackage)
 | 
			
		||||
	case githubEventCreate, githubEventDelete, githubEventFork, githubEventPush,
 | 
			
		||||
		githubEventIssues, githubEventIssueComment, githubEventRelease, githubEventPullRequestComment:
 | 
			
		||||
		fallthrough
 | 
			
		||||
	default:
 | 
			
		||||
		return evt.Name
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -72,9 +72,7 @@ func DetectWorkflows(commit *git.Commit, triggedEvent webhook_module.HookEventTy
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		for _, evt := range events {
 | 
			
		||||
			if evt.Name != triggedEvent.Event() {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			log.Trace("detect workflow %q for event %#v matching %q", entry.Name(), evt, triggedEvent)
 | 
			
		||||
			if detectMatched(commit, triggedEvent, payload, evt) {
 | 
			
		||||
				workflows[entry.Name()] = content
 | 
			
		||||
			}
 | 
			
		||||
@@ -85,138 +83,197 @@ func DetectWorkflows(commit *git.Commit, triggedEvent webhook_module.HookEventTy
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func detectMatched(commit *git.Commit, triggedEvent webhook_module.HookEventType, payload api.Payloader, evt *jobparser.Event) bool {
 | 
			
		||||
	if convertFromGithubEvent(evt) != string(triggedEvent) {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch triggedEvent {
 | 
			
		||||
	case webhook_module.HookEventCreate,
 | 
			
		||||
		webhook_module.HookEventDelete,
 | 
			
		||||
		webhook_module.HookEventFork,
 | 
			
		||||
		webhook_module.HookEventIssueAssign,
 | 
			
		||||
		webhook_module.HookEventIssueLabel,
 | 
			
		||||
		webhook_module.HookEventIssueMilestone,
 | 
			
		||||
		webhook_module.HookEventPullRequestAssign,
 | 
			
		||||
		webhook_module.HookEventPullRequestLabel,
 | 
			
		||||
		webhook_module.HookEventPullRequestMilestone,
 | 
			
		||||
		webhook_module.HookEventPullRequestComment,
 | 
			
		||||
		webhook_module.HookEventPullRequestReviewApproved,
 | 
			
		||||
		webhook_module.HookEventPullRequestReviewRejected,
 | 
			
		||||
		webhook_module.HookEventPullRequestReviewComment,
 | 
			
		||||
		webhook_module.HookEventWiki,
 | 
			
		||||
		webhook_module.HookEventRepository,
 | 
			
		||||
		webhook_module.HookEventRelease,
 | 
			
		||||
		webhook_module.HookEventPackage:
 | 
			
		||||
		if len(evt.Acts) != 0 {
 | 
			
		||||
			log.Warn("Ignore unsupported %s event arguments %q", triggedEvent, evt.Acts)
 | 
			
		||||
		}
 | 
			
		||||
		// no special filter parameters for these events, just return true if name matched
 | 
			
		||||
		return true
 | 
			
		||||
 | 
			
		||||
	case webhook_module.HookEventPush:
 | 
			
		||||
		return matchPushEvent(commit, payload.(*api.PushPayload), evt)
 | 
			
		||||
 | 
			
		||||
	case webhook_module.HookEventIssues:
 | 
			
		||||
		return matchIssuesEvent(commit, payload.(*api.IssuePayload), evt)
 | 
			
		||||
 | 
			
		||||
	case webhook_module.HookEventPullRequest, webhook_module.HookEventPullRequestSync:
 | 
			
		||||
		return matchPullRequestEvent(commit, payload.(*api.PullRequestPayload), evt)
 | 
			
		||||
 | 
			
		||||
	case webhook_module.HookEventIssueComment:
 | 
			
		||||
		return matchIssueCommentEvent(commit, payload.(*api.IssueCommentPayload), evt)
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
		log.Warn("unsupported event %q", triggedEvent)
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func matchPushEvent(commit *git.Commit, pushPayload *api.PushPayload, evt *jobparser.Event) bool {
 | 
			
		||||
	// with no special filter parameters
 | 
			
		||||
	if len(evt.Acts) == 0 {
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch triggedEvent {
 | 
			
		||||
	case webhook_module.HookEventCreate:
 | 
			
		||||
		fallthrough
 | 
			
		||||
	case webhook_module.HookEventDelete:
 | 
			
		||||
		fallthrough
 | 
			
		||||
	case webhook_module.HookEventFork:
 | 
			
		||||
		log.Warn("unsupported event %q", triggedEvent.Event())
 | 
			
		||||
		return false
 | 
			
		||||
	case webhook_module.HookEventPush:
 | 
			
		||||
		pushPayload := payload.(*api.PushPayload)
 | 
			
		||||
		matchTimes := 0
 | 
			
		||||
		// all acts conditions should be satisfied
 | 
			
		||||
		for cond, vals := range evt.Acts {
 | 
			
		||||
			switch cond {
 | 
			
		||||
			case "branches", "tags":
 | 
			
		||||
				refShortName := git.RefName(pushPayload.Ref).ShortName()
 | 
			
		||||
				for _, val := range vals {
 | 
			
		||||
					if glob.MustCompile(val, '/').Match(refShortName) {
 | 
			
		||||
						matchTimes++
 | 
			
		||||
						break
 | 
			
		||||
					}
 | 
			
		||||
	matchTimes := 0
 | 
			
		||||
	// all acts conditions should be satisfied
 | 
			
		||||
	for cond, vals := range evt.Acts {
 | 
			
		||||
		switch cond {
 | 
			
		||||
		case "branches", "tags":
 | 
			
		||||
			refShortName := git.RefName(pushPayload.Ref).ShortName()
 | 
			
		||||
			for _, val := range vals {
 | 
			
		||||
				if glob.MustCompile(val, '/').Match(refShortName) {
 | 
			
		||||
					matchTimes++
 | 
			
		||||
					break
 | 
			
		||||
				}
 | 
			
		||||
			case "paths":
 | 
			
		||||
				filesChanged, err := commit.GetFilesChangedSinceCommit(pushPayload.Before)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					log.Error("GetFilesChangedSinceCommit [commit_sha1: %s]: %v", commit.ID.String(), err)
 | 
			
		||||
				} else {
 | 
			
		||||
					for _, val := range vals {
 | 
			
		||||
						matched := false
 | 
			
		||||
						for _, file := range filesChanged {
 | 
			
		||||
							if glob.MustCompile(val, '/').Match(file) {
 | 
			
		||||
								matched = true
 | 
			
		||||
								break
 | 
			
		||||
							}
 | 
			
		||||
						}
 | 
			
		||||
						if matched {
 | 
			
		||||
							matchTimes++
 | 
			
		||||
			}
 | 
			
		||||
		case "paths":
 | 
			
		||||
			filesChanged, err := commit.GetFilesChangedSinceCommit(pushPayload.Before)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				log.Error("GetFilesChangedSinceCommit [commit_sha1: %s]: %v", commit.ID.String(), err)
 | 
			
		||||
			} else {
 | 
			
		||||
				for _, val := range vals {
 | 
			
		||||
					matched := false
 | 
			
		||||
					for _, file := range filesChanged {
 | 
			
		||||
						if glob.MustCompile(val, '/').Match(file) {
 | 
			
		||||
							matched = true
 | 
			
		||||
							break
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			default:
 | 
			
		||||
				log.Warn("unsupported condition %q", cond)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return matchTimes == len(evt.Acts)
 | 
			
		||||
 | 
			
		||||
	case webhook_module.HookEventIssues:
 | 
			
		||||
		fallthrough
 | 
			
		||||
	case webhook_module.HookEventIssueAssign:
 | 
			
		||||
		fallthrough
 | 
			
		||||
	case webhook_module.HookEventIssueLabel:
 | 
			
		||||
		fallthrough
 | 
			
		||||
	case webhook_module.HookEventIssueMilestone:
 | 
			
		||||
		fallthrough
 | 
			
		||||
	case webhook_module.HookEventIssueComment:
 | 
			
		||||
		fallthrough
 | 
			
		||||
	case webhook_module.HookEventPullRequest:
 | 
			
		||||
		prPayload := payload.(*api.PullRequestPayload)
 | 
			
		||||
		matchTimes := 0
 | 
			
		||||
		// all acts conditions should be satisfied
 | 
			
		||||
		for cond, vals := range evt.Acts {
 | 
			
		||||
			switch cond {
 | 
			
		||||
			case "types":
 | 
			
		||||
				for _, val := range vals {
 | 
			
		||||
					if glob.MustCompile(val, '/').Match(string(prPayload.Action)) {
 | 
			
		||||
					if matched {
 | 
			
		||||
						matchTimes++
 | 
			
		||||
						break
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			case "branches":
 | 
			
		||||
				refShortName := git.RefName(prPayload.PullRequest.Base.Ref).ShortName()
 | 
			
		||||
				for _, val := range vals {
 | 
			
		||||
					if glob.MustCompile(val, '/').Match(refShortName) {
 | 
			
		||||
						matchTimes++
 | 
			
		||||
						break
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			case "paths":
 | 
			
		||||
				filesChanged, err := commit.GetFilesChangedSinceCommit(prPayload.PullRequest.Base.Ref)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					log.Error("GetFilesChangedSinceCommit [commit_sha1: %s]: %v", commit.ID.String(), err)
 | 
			
		||||
				} else {
 | 
			
		||||
					for _, val := range vals {
 | 
			
		||||
						matched := false
 | 
			
		||||
						for _, file := range filesChanged {
 | 
			
		||||
							if glob.MustCompile(val, '/').Match(file) {
 | 
			
		||||
								matched = true
 | 
			
		||||
								break
 | 
			
		||||
							}
 | 
			
		||||
						}
 | 
			
		||||
						if matched {
 | 
			
		||||
							matchTimes++
 | 
			
		||||
							break
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			default:
 | 
			
		||||
				log.Warn("unsupported condition %q", cond)
 | 
			
		||||
			}
 | 
			
		||||
		default:
 | 
			
		||||
			log.Warn("push event unsupported condition %q", cond)
 | 
			
		||||
		}
 | 
			
		||||
		return matchTimes == len(evt.Acts)
 | 
			
		||||
	case webhook_module.HookEventPullRequestAssign:
 | 
			
		||||
		fallthrough
 | 
			
		||||
	case webhook_module.HookEventPullRequestLabel:
 | 
			
		||||
		fallthrough
 | 
			
		||||
	case webhook_module.HookEventPullRequestMilestone:
 | 
			
		||||
		fallthrough
 | 
			
		||||
	case webhook_module.HookEventPullRequestComment:
 | 
			
		||||
		fallthrough
 | 
			
		||||
	case webhook_module.HookEventPullRequestReviewApproved:
 | 
			
		||||
		fallthrough
 | 
			
		||||
	case webhook_module.HookEventPullRequestReviewRejected:
 | 
			
		||||
		fallthrough
 | 
			
		||||
	case webhook_module.HookEventPullRequestReviewComment:
 | 
			
		||||
		fallthrough
 | 
			
		||||
	case webhook_module.HookEventPullRequestSync:
 | 
			
		||||
		fallthrough
 | 
			
		||||
	case webhook_module.HookEventWiki:
 | 
			
		||||
		fallthrough
 | 
			
		||||
	case webhook_module.HookEventRepository:
 | 
			
		||||
		fallthrough
 | 
			
		||||
	case webhook_module.HookEventRelease:
 | 
			
		||||
		fallthrough
 | 
			
		||||
	case webhook_module.HookEventPackage:
 | 
			
		||||
		fallthrough
 | 
			
		||||
	default:
 | 
			
		||||
		log.Warn("unsupported event %q", triggedEvent.Event())
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
	return matchTimes == len(evt.Acts)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func matchIssuesEvent(commit *git.Commit, issuePayload *api.IssuePayload, evt *jobparser.Event) bool {
 | 
			
		||||
	// with no special filter parameters
 | 
			
		||||
	if len(evt.Acts) == 0 {
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	matchTimes := 0
 | 
			
		||||
	// all acts conditions should be satisfied
 | 
			
		||||
	for cond, vals := range evt.Acts {
 | 
			
		||||
		switch cond {
 | 
			
		||||
		case "types":
 | 
			
		||||
			for _, val := range vals {
 | 
			
		||||
				if glob.MustCompile(val, '/').Match(string(issuePayload.Action)) {
 | 
			
		||||
					matchTimes++
 | 
			
		||||
					break
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		default:
 | 
			
		||||
			log.Warn("issue event unsupported condition %q", cond)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return matchTimes == len(evt.Acts)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func matchPullRequestEvent(commit *git.Commit, prPayload *api.PullRequestPayload, evt *jobparser.Event) bool {
 | 
			
		||||
	// with no special filter parameters
 | 
			
		||||
	if len(evt.Acts) == 0 {
 | 
			
		||||
		// defaultly, only pull request opened and synchronized will trigger workflow
 | 
			
		||||
		return prPayload.Action == api.HookIssueSynchronized || prPayload.Action == api.HookIssueOpened
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	matchTimes := 0
 | 
			
		||||
	// all acts conditions should be satisfied
 | 
			
		||||
	for cond, vals := range evt.Acts {
 | 
			
		||||
		switch cond {
 | 
			
		||||
		case "types":
 | 
			
		||||
			action := prPayload.Action
 | 
			
		||||
			if prPayload.Action == api.HookIssueSynchronized {
 | 
			
		||||
				action = "synchronize"
 | 
			
		||||
			}
 | 
			
		||||
			log.Trace("matching pull_request %s with %v", action, vals)
 | 
			
		||||
			for _, val := range vals {
 | 
			
		||||
				if glob.MustCompile(val, '/').Match(string(action)) {
 | 
			
		||||
					matchTimes++
 | 
			
		||||
					break
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		case "branches":
 | 
			
		||||
			refShortName := git.RefName(prPayload.PullRequest.Base.Ref).ShortName()
 | 
			
		||||
			for _, val := range vals {
 | 
			
		||||
				if glob.MustCompile(val, '/').Match(refShortName) {
 | 
			
		||||
					matchTimes++
 | 
			
		||||
					break
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		case "paths":
 | 
			
		||||
			filesChanged, err := commit.GetFilesChangedSinceCommit(prPayload.PullRequest.Base.Ref)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				log.Error("GetFilesChangedSinceCommit [commit_sha1: %s]: %v", commit.ID.String(), err)
 | 
			
		||||
			} else {
 | 
			
		||||
				for _, val := range vals {
 | 
			
		||||
					matched := false
 | 
			
		||||
					for _, file := range filesChanged {
 | 
			
		||||
						if glob.MustCompile(val, '/').Match(file) {
 | 
			
		||||
							matched = true
 | 
			
		||||
							break
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
					if matched {
 | 
			
		||||
						matchTimes++
 | 
			
		||||
						break
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		default:
 | 
			
		||||
			log.Warn("pull request event unsupported condition %q", cond)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return matchTimes == len(evt.Acts)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func matchIssueCommentEvent(commit *git.Commit, issueCommentPayload *api.IssueCommentPayload, evt *jobparser.Event) bool {
 | 
			
		||||
	// with no special filter parameters
 | 
			
		||||
	if len(evt.Acts) == 0 {
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	matchTimes := 0
 | 
			
		||||
	// all acts conditions should be satisfied
 | 
			
		||||
	for cond, vals := range evt.Acts {
 | 
			
		||||
		switch cond {
 | 
			
		||||
		case "types":
 | 
			
		||||
			for _, val := range vals {
 | 
			
		||||
				if glob.MustCompile(val, '/').Match(string(issueCommentPayload.Action)) {
 | 
			
		||||
					matchTimes++
 | 
			
		||||
					break
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		default:
 | 
			
		||||
			log.Warn("issue comment unsupported condition %q", cond)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return matchTimes == len(evt.Acts)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -41,9 +41,8 @@ var RecommendedHashAlgorithms = []string{
 | 
			
		||||
	"pbkdf2_hi",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetDefaultPasswordHashAlgorithm will take a provided algorithmName and dealias it to
 | 
			
		||||
// a complete algorithm specification.
 | 
			
		||||
func SetDefaultPasswordHashAlgorithm(algorithmName string) (string, *PasswordHashAlgorithm) {
 | 
			
		||||
// hashAlgorithmToSpec converts an algorithm name or a specification to a full algorithm specification
 | 
			
		||||
func hashAlgorithmToSpec(algorithmName string) string {
 | 
			
		||||
	if algorithmName == "" {
 | 
			
		||||
		algorithmName = DefaultHashAlgorithmName
 | 
			
		||||
	}
 | 
			
		||||
@@ -52,10 +51,26 @@ func SetDefaultPasswordHashAlgorithm(algorithmName string) (string, *PasswordHas
 | 
			
		||||
		algorithmName = alias
 | 
			
		||||
		alias, has = aliasAlgorithmNames[algorithmName]
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// algorithmName should now be a full algorithm specification
 | 
			
		||||
	// e.g. pbkdf2$50000$50 rather than pbdkf2
 | 
			
		||||
	DefaultHashAlgorithm = Parse(algorithmName)
 | 
			
		||||
 | 
			
		||||
	return algorithmName, DefaultHashAlgorithm
 | 
			
		||||
	return algorithmName
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetDefaultPasswordHashAlgorithm will take a provided algorithmName and de-alias it to
 | 
			
		||||
// a complete algorithm specification.
 | 
			
		||||
func SetDefaultPasswordHashAlgorithm(algorithmName string) (string, *PasswordHashAlgorithm) {
 | 
			
		||||
	algoSpec := hashAlgorithmToSpec(algorithmName)
 | 
			
		||||
	// now we get a full specification, e.g. pbkdf2$50000$50 rather than pbdkf2
 | 
			
		||||
	DefaultHashAlgorithm = Parse(algoSpec)
 | 
			
		||||
	return algoSpec, DefaultHashAlgorithm
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ConfigHashAlgorithm will try to find a "recommended algorithm name" defined by RecommendedHashAlgorithms for config
 | 
			
		||||
// This function is not fast and is only used for the installation page
 | 
			
		||||
func ConfigHashAlgorithm(algorithm string) string {
 | 
			
		||||
	algorithm = hashAlgorithmToSpec(algorithm)
 | 
			
		||||
	for _, recommAlgo := range RecommendedHashAlgorithms {
 | 
			
		||||
		if algorithm == hashAlgorithmToSpec(recommAlgo) {
 | 
			
		||||
			return recommAlgo
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return algorithm
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -244,7 +244,7 @@ func APIContexter() func(http.Handler) http.Handler {
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			httpcache.AddCacheControlToHeader(ctx.Resp.Header(), 0, "no-transform")
 | 
			
		||||
			httpcache.SetCacheControlInHeader(ctx.Resp.Header(), 0, "no-transform")
 | 
			
		||||
			ctx.Resp.Header().Set(`X-Frame-Options`, setting.CORSConfig.XFrameOptions)
 | 
			
		||||
 | 
			
		||||
			ctx.Data["Context"] = &ctx
 | 
			
		||||
 
 | 
			
		||||
@@ -388,7 +388,7 @@ func (ctx *Context) SetServeHeaders(opts *ServeHeaderOptions) {
 | 
			
		||||
	if duration == 0 {
 | 
			
		||||
		duration = 5 * time.Minute
 | 
			
		||||
	}
 | 
			
		||||
	httpcache.AddCacheControlToHeader(header, duration)
 | 
			
		||||
	httpcache.SetCacheControlInHeader(header, duration)
 | 
			
		||||
 | 
			
		||||
	if !opts.LastModified.IsZero() {
 | 
			
		||||
		header.Set("Last-Modified", opts.LastModified.UTC().Format(http.TimeFormat))
 | 
			
		||||
@@ -753,7 +753,7 @@ func Contexter(ctx context.Context) func(next http.Handler) http.Handler {
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			httpcache.AddCacheControlToHeader(ctx.Resp.Header(), 0, "no-transform")
 | 
			
		||||
			httpcache.SetCacheControlInHeader(ctx.Resp.Header(), 0, "no-transform")
 | 
			
		||||
			ctx.Resp.Header().Set(`X-Frame-Options`, setting.CORSConfig.XFrameOptions)
 | 
			
		||||
 | 
			
		||||
			ctx.Data["CsrfToken"] = ctx.csrf.GetToken()
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,6 @@ import (
 | 
			
		||||
	"code.gitea.io/gitea/models/perm"
 | 
			
		||||
	"code.gitea.io/gitea/models/unit"
 | 
			
		||||
	user_model "code.gitea.io/gitea/models/user"
 | 
			
		||||
	"code.gitea.io/gitea/modules/log"
 | 
			
		||||
	"code.gitea.io/gitea/modules/setting"
 | 
			
		||||
	"code.gitea.io/gitea/modules/structs"
 | 
			
		||||
)
 | 
			
		||||
@@ -31,29 +30,34 @@ type Organization struct {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (org *Organization) CanWriteUnit(ctx *Context, unitType unit.Type) bool {
 | 
			
		||||
	if ctx.Doer == nil {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	return org.UnitPermission(ctx, ctx.Doer.ID, unitType) >= perm.AccessModeWrite
 | 
			
		||||
	return org.Organization.UnitPermission(ctx, ctx.Doer, unitType) >= perm.AccessModeWrite
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (org *Organization) UnitPermission(ctx *Context, doerID int64, unitType unit.Type) perm.AccessMode {
 | 
			
		||||
	if doerID > 0 {
 | 
			
		||||
		teams, err := organization.GetUserOrgTeams(ctx, org.Organization.ID, doerID)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			log.Error("GetUserOrgTeams: %v", err)
 | 
			
		||||
			return perm.AccessModeNone
 | 
			
		||||
		}
 | 
			
		||||
		if len(teams) > 0 {
 | 
			
		||||
			return teams.UnitMaxAccess(unitType)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
func (org *Organization) CanReadUnit(ctx *Context, unitType unit.Type) bool {
 | 
			
		||||
	return org.Organization.UnitPermission(ctx, ctx.Doer, unitType) >= perm.AccessModeRead
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
	if org.Organization.Visibility == structs.VisibleTypePublic {
 | 
			
		||||
		return perm.AccessModeRead
 | 
			
		||||
	}
 | 
			
		||||
func GetOrganizationByParams(ctx *Context) {
 | 
			
		||||
	orgName := ctx.Params(":org")
 | 
			
		||||
 | 
			
		||||
	return perm.AccessModeNone
 | 
			
		||||
	var err error
 | 
			
		||||
 | 
			
		||||
	ctx.Org.Organization, err = organization.GetOrgByName(ctx, orgName)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if organization.IsErrOrgNotExist(err) {
 | 
			
		||||
			redirectUserID, err := user_model.LookupUserRedirect(orgName)
 | 
			
		||||
			if err == nil {
 | 
			
		||||
				RedirectToUser(ctx, orgName, redirectUserID)
 | 
			
		||||
			} else if user_model.IsErrUserRedirectNotExist(err) {
 | 
			
		||||
				ctx.NotFound("GetUserByName", err)
 | 
			
		||||
			} else {
 | 
			
		||||
				ctx.ServerError("LookupUserRedirect", err)
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			ctx.ServerError("GetUserByName", err)
 | 
			
		||||
		}
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// HandleOrgAssignment handles organization assignment
 | 
			
		||||
@@ -77,25 +81,26 @@ func HandleOrgAssignment(ctx *Context, args ...bool) {
 | 
			
		||||
		requireTeamAdmin = args[3]
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	orgName := ctx.Params(":org")
 | 
			
		||||
 | 
			
		||||
	var err error
 | 
			
		||||
	ctx.Org.Organization, err = organization.GetOrgByName(ctx, orgName)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if organization.IsErrOrgNotExist(err) {
 | 
			
		||||
			redirectUserID, err := user_model.LookupUserRedirect(orgName)
 | 
			
		||||
			if err == nil {
 | 
			
		||||
				RedirectToUser(ctx, orgName, redirectUserID)
 | 
			
		||||
			} else if user_model.IsErrUserRedirectNotExist(err) {
 | 
			
		||||
				ctx.NotFound("GetUserByName", err)
 | 
			
		||||
			} else {
 | 
			
		||||
				ctx.ServerError("LookupUserRedirect", err)
 | 
			
		||||
 | 
			
		||||
	if ctx.ContextUser == nil {
 | 
			
		||||
		// if Organization is not defined, get it from params
 | 
			
		||||
		if ctx.Org.Organization == nil {
 | 
			
		||||
			GetOrganizationByParams(ctx)
 | 
			
		||||
			if ctx.Written() {
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			ctx.ServerError("GetUserByName", err)
 | 
			
		||||
		}
 | 
			
		||||
	} else if ctx.ContextUser.IsOrganization() {
 | 
			
		||||
		if ctx.Org == nil {
 | 
			
		||||
			ctx.Org = &Organization{}
 | 
			
		||||
		}
 | 
			
		||||
		ctx.Org.Organization = (*organization.Organization)(ctx.ContextUser)
 | 
			
		||||
	} else {
 | 
			
		||||
		// ContextUser is an individual User
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	org := ctx.Org.Organization
 | 
			
		||||
 | 
			
		||||
	// Handle Visibility
 | 
			
		||||
@@ -156,6 +161,7 @@ func HandleOrgAssignment(ctx *Context, args ...bool) {
 | 
			
		||||
	}
 | 
			
		||||
	ctx.Data["IsOrganizationOwner"] = ctx.Org.IsOwner
 | 
			
		||||
	ctx.Data["IsOrganizationMember"] = ctx.Org.IsMember
 | 
			
		||||
	ctx.Data["IsProjectEnabled"] = true
 | 
			
		||||
	ctx.Data["IsPackageEnabled"] = setting.Packages.Enabled
 | 
			
		||||
	ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
 | 
			
		||||
	ctx.Data["IsPublicMember"] = func(uid int64) bool {
 | 
			
		||||
@@ -231,6 +237,10 @@ func HandleOrgAssignment(ctx *Context, args ...bool) {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ctx.Data["CanReadProjects"] = ctx.Org.CanReadUnit(ctx, unit.TypeProjects)
 | 
			
		||||
	ctx.Data["CanReadPackages"] = ctx.Org.CanReadUnit(ctx, unit.TypePackages)
 | 
			
		||||
	ctx.Data["CanReadCode"] = ctx.Org.CanReadUnit(ctx, unit.TypeCode)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// OrgAssignment returns a middleware to handle organization assignment
 | 
			
		||||
 
 | 
			
		||||
@@ -18,10 +18,11 @@ type Pagination struct {
 | 
			
		||||
	urlParams []string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewPagination creates a new instance of the Pagination struct
 | 
			
		||||
func NewPagination(total, page, issueNum, numPages int) *Pagination {
 | 
			
		||||
// NewPagination creates a new instance of the Pagination struct.
 | 
			
		||||
// "pagingNum" is "page size" or "limit", "current" is "page"
 | 
			
		||||
func NewPagination(total, pagingNum, current, numPages int) *Pagination {
 | 
			
		||||
	p := &Pagination{}
 | 
			
		||||
	p.Paginater = paginator.New(total, page, issueNum, numPages)
 | 
			
		||||
	p.Paginater = paginator.New(total, pagingNum, current, numPages)
 | 
			
		||||
	return p
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -11,6 +11,7 @@ import (
 | 
			
		||||
	"strings"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/modules/git"
 | 
			
		||||
	"code.gitea.io/gitea/modules/markup"
 | 
			
		||||
 | 
			
		||||
	"github.com/stretchr/testify/assert"
 | 
			
		||||
@@ -229,7 +230,10 @@ John Doe	john@doe.com	This,note,had,a,lot,of,commas,to,test,delimiters`,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for n, c := range cases {
 | 
			
		||||
		delimiter := determineDelimiter(&markup.RenderContext{RelativePath: c.filename}, []byte(decodeSlashes(t, c.csv)))
 | 
			
		||||
		delimiter := determineDelimiter(&markup.RenderContext{
 | 
			
		||||
			Ctx:          git.DefaultContext,
 | 
			
		||||
			RelativePath: c.filename,
 | 
			
		||||
		}, []byte(decodeSlashes(t, c.csv)))
 | 
			
		||||
		assert.EqualValues(t, c.expectedDelimiter, delimiter, "case %d: delimiter should be equal, expected '%c' got '%c'", n, c.expectedDelimiter, delimiter)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -155,7 +155,7 @@ func checkDBConsistency(ctx context.Context, logger log.Logger, autofix bool) er
 | 
			
		||||
 | 
			
		||||
	// TODO: function to recalc all counters
 | 
			
		||||
 | 
			
		||||
	if setting.Database.UsePostgreSQL {
 | 
			
		||||
	if setting.Database.Type.IsPostgreSQL() {
 | 
			
		||||
		consistencyChecks = append(consistencyChecks, consistencyCheck{
 | 
			
		||||
			Name:         "Sequence values",
 | 
			
		||||
			Counter:      db.CountBadSequences,
 | 
			
		||||
 
 | 
			
		||||
@@ -179,7 +179,7 @@ func (c *Command) AddDashesAndList(list ...string) *Command {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ToTrustedCmdArgs converts a list of strings (trusted as argument) to TrustedCmdArgs
 | 
			
		||||
// In most cases, it shouldn't be used. Use AddXxx function instead
 | 
			
		||||
// In most cases, it shouldn't be used. Use NewCommand().AddXxx() function instead
 | 
			
		||||
func ToTrustedCmdArgs(args []string) TrustedCmdArgs {
 | 
			
		||||
	ret := make(TrustedCmdArgs, len(args))
 | 
			
		||||
	for i, arg := range args {
 | 
			
		||||
 
 | 
			
		||||
@@ -201,6 +201,23 @@ func InitFull(ctx context.Context) (err error) {
 | 
			
		||||
	return syncGitConfig()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func enableReflogs() error {
 | 
			
		||||
	if err := configSet("core.logAllRefUpdates", "true"); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	err := configSet("gc.reflogExpire", fmt.Sprintf("%d", setting.Git.Reflog.Expiration))
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func disableReflogs() error {
 | 
			
		||||
	if err := configUnsetAll("core.logAllRefUpdates", "true"); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	} else if err := configUnsetAll("gc.reflogExpire", ""); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// syncGitConfig only modifies gitconfig, won't change global variables (otherwise there will be data-race problem)
 | 
			
		||||
func syncGitConfig() (err error) {
 | 
			
		||||
	if err = os.MkdirAll(HomeDir(), os.ModePerm); err != nil {
 | 
			
		||||
@@ -224,6 +241,16 @@ func syncGitConfig() (err error) {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if setting.Git.Reflog.Enabled {
 | 
			
		||||
		if err := enableReflogs(); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		if err := disableReflogs(); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if CheckGitVersionAtLeast("2.10") == nil {
 | 
			
		||||
		if err := configSet("receive.advertisePushOptions", "true"); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
@@ -312,7 +339,7 @@ func CheckGitVersionAtLeast(atLeast string) error {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func configSet(key, value string) error {
 | 
			
		||||
	stdout, _, err := NewCommand(DefaultContext, "config", "--get").AddDynamicArguments(key).RunStdString(nil)
 | 
			
		||||
	stdout, _, err := NewCommand(DefaultContext, "config", "--global", "--get").AddDynamicArguments(key).RunStdString(nil)
 | 
			
		||||
	if err != nil && !err.IsExitCode(1) {
 | 
			
		||||
		return fmt.Errorf("failed to get git config %s, err: %w", key, err)
 | 
			
		||||
	}
 | 
			
		||||
@@ -331,7 +358,7 @@ func configSet(key, value string) error {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func configSetNonExist(key, value string) error {
 | 
			
		||||
	_, _, err := NewCommand(DefaultContext, "config", "--get").AddDynamicArguments(key).RunStdString(nil)
 | 
			
		||||
	_, _, err := NewCommand(DefaultContext, "config", "--global", "--get").AddDynamicArguments(key).RunStdString(nil)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		// already exist
 | 
			
		||||
		return nil
 | 
			
		||||
@@ -349,7 +376,7 @@ func configSetNonExist(key, value string) error {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func configAddNonExist(key, value string) error {
 | 
			
		||||
	_, _, err := NewCommand(DefaultContext, "config", "--get").AddDynamicArguments(key, regexp.QuoteMeta(value)).RunStdString(nil)
 | 
			
		||||
	_, _, err := NewCommand(DefaultContext, "config", "--global", "--get").AddDynamicArguments(key, regexp.QuoteMeta(value)).RunStdString(nil)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		// already exist
 | 
			
		||||
		return nil
 | 
			
		||||
@@ -366,7 +393,7 @@ func configAddNonExist(key, value string) error {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func configUnsetAll(key, value string) error {
 | 
			
		||||
	_, _, err := NewCommand(DefaultContext, "config", "--get").AddDynamicArguments(key).RunStdString(nil)
 | 
			
		||||
	_, _, err := NewCommand(DefaultContext, "config", "--global", "--get").AddDynamicArguments(key).RunStdString(nil)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		// exist, need to remove
 | 
			
		||||
		_, _, err = NewCommand(DefaultContext, "config", "--global", "--unset-all").AddDynamicArguments(key, regexp.QuoteMeta(value)).RunStdString(nil)
 | 
			
		||||
 
 | 
			
		||||
@@ -42,7 +42,10 @@ func RevListObjects(ctx context.Context, revListWriter *io.PipeWriter, wg *sync.
 | 
			
		||||
	defer revListWriter.Close()
 | 
			
		||||
	stderr := new(bytes.Buffer)
 | 
			
		||||
	var errbuf strings.Builder
 | 
			
		||||
	cmd := git.NewCommand(ctx, "rev-list", "--objects").AddDynamicArguments(headSHA).AddArguments("--not").AddDynamicArguments(baseSHA)
 | 
			
		||||
	cmd := git.NewCommand(ctx, "rev-list", "--objects").AddDynamicArguments(headSHA)
 | 
			
		||||
	if baseSHA != "" {
 | 
			
		||||
		cmd = cmd.AddArguments("--not").AddDynamicArguments(baseSHA)
 | 
			
		||||
	}
 | 
			
		||||
	if err := cmd.Run(&git.RunOpts{
 | 
			
		||||
		Dir:    tmpBasePath,
 | 
			
		||||
		Stdout: revListWriter,
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,6 @@
 | 
			
		||||
package git
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/go-git/go-git/v5/plumbing"
 | 
			
		||||
@@ -67,38 +66,6 @@ func (repo *Repository) IsCommitExist(name string) bool {
 | 
			
		||||
	return err == nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func convertPGPSignatureForTag(t *object.Tag) *CommitGPGSignature {
 | 
			
		||||
	if t.PGPSignature == "" {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var w strings.Builder
 | 
			
		||||
	var err error
 | 
			
		||||
 | 
			
		||||
	if _, err = fmt.Fprintf(&w,
 | 
			
		||||
		"object %s\ntype %s\ntag %s\ntagger ",
 | 
			
		||||
		t.Target.String(), t.TargetType.Bytes(), t.Name); err != nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err = t.Tagger.Encode(&w); err != nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if _, err = fmt.Fprintf(&w, "\n\n"); err != nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if _, err = fmt.Fprintf(&w, t.Message); err != nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &CommitGPGSignature{
 | 
			
		||||
		Signature: t.PGPSignature,
 | 
			
		||||
		Payload:   strings.TrimSpace(w.String()) + "\n",
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (repo *Repository) getCommit(id SHA1) (*Commit, error) {
 | 
			
		||||
	var tagObject *object.Tag
 | 
			
		||||
 | 
			
		||||
@@ -122,12 +89,6 @@ func (repo *Repository) getCommit(id SHA1) (*Commit, error) {
 | 
			
		||||
	commit := convertCommit(gogitCommit)
 | 
			
		||||
	commit.repo = repo
 | 
			
		||||
 | 
			
		||||
	if tagObject != nil {
 | 
			
		||||
		commit.CommitMessage = strings.TrimSpace(tagObject.Message)
 | 
			
		||||
		commit.Author = &tagObject.Tagger
 | 
			
		||||
		commit.Signature = convertPGPSignatureForTag(tagObject)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	tree, err := gogitCommit.Tree()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
 
 | 
			
		||||
@@ -107,10 +107,6 @@ func (repo *Repository) getCommitFromBatchReader(rd *bufio.Reader, id SHA1) (*Co
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		commit.CommitMessage = strings.TrimSpace(tag.Message)
 | 
			
		||||
		commit.Author = tag.Tagger
 | 
			
		||||
		commit.Signature = tag.Signature
 | 
			
		||||
 | 
			
		||||
		return commit, nil
 | 
			
		||||
	case "commit":
 | 
			
		||||
		commit, err := CommitFromReader(repo, id, io.LimitReader(rd, size))
 | 
			
		||||
 
 | 
			
		||||
@@ -43,12 +43,13 @@ func TestGetTagCommitWithSignature(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	defer bareRepo1.Close()
 | 
			
		||||
 | 
			
		||||
	commit, err := bareRepo1.GetCommit("3ad28a9149a2864384548f3d17ed7f38014c9e8a")
 | 
			
		||||
	// both the tag and the commit are signed here, this validates only the commit signature
 | 
			
		||||
	commit, err := bareRepo1.GetCommit("28b55526e7100924d864dd89e35c1ea62e7a5a32")
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.NotNil(t, commit)
 | 
			
		||||
	assert.NotNil(t, commit.Signature)
 | 
			
		||||
	// test that signature is not in message
 | 
			
		||||
	assert.Equal(t, "tag", commit.CommitMessage)
 | 
			
		||||
	assert.Equal(t, "signed-commit\n", commit.CommitMessage)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestGetCommitWithBadCommitID(t *testing.T) {
 | 
			
		||||
 
 | 
			
		||||
@@ -277,11 +277,18 @@ func (repo *Repository) GetPatch(base, head string, w io.Writer) error {
 | 
			
		||||
 | 
			
		||||
// GetFilesChangedBetween returns a list of all files that have been changed between the given commits
 | 
			
		||||
func (repo *Repository) GetFilesChangedBetween(base, head string) ([]string, error) {
 | 
			
		||||
	stdout, _, err := NewCommand(repo.Ctx, "diff", "--name-only").AddDynamicArguments(base + ".." + head).RunStdString(&RunOpts{Dir: repo.Path})
 | 
			
		||||
	stdout, _, err := NewCommand(repo.Ctx, "diff", "--name-only", "-z").AddDynamicArguments(base + ".." + head).RunStdString(&RunOpts{Dir: repo.Path})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return strings.Split(stdout, "\n"), err
 | 
			
		||||
	split := strings.Split(stdout, "\000")
 | 
			
		||||
 | 
			
		||||
	// Because Git will always emit filenames with a terminal NUL ignore the last entry in the split - which will always be empty.
 | 
			
		||||
	if len(split) > 0 {
 | 
			
		||||
		split = split[:len(split)-1]
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return split, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetDiffFromMergeBase generates and return patch data from merge base to head
 | 
			
		||||
 
 | 
			
		||||
@@ -19,13 +19,14 @@ func TestRepository_GetRefs(t *testing.T) {
 | 
			
		||||
	refs, err := bareRepo1.GetRefs()
 | 
			
		||||
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.Len(t, refs, 5)
 | 
			
		||||
	assert.Len(t, refs, 6)
 | 
			
		||||
 | 
			
		||||
	expectedRefs := []string{
 | 
			
		||||
		BranchPrefix + "branch1",
 | 
			
		||||
		BranchPrefix + "branch2",
 | 
			
		||||
		BranchPrefix + "master",
 | 
			
		||||
		TagPrefix + "test",
 | 
			
		||||
		TagPrefix + "signed-tag",
 | 
			
		||||
		NotesRef,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -43,9 +44,12 @@ func TestRepository_GetRefsFiltered(t *testing.T) {
 | 
			
		||||
	refs, err := bareRepo1.GetRefsFiltered(TagPrefix)
 | 
			
		||||
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	if assert.Len(t, refs, 1) {
 | 
			
		||||
		assert.Equal(t, TagPrefix+"test", refs[0].Name)
 | 
			
		||||
	if assert.Len(t, refs, 2) {
 | 
			
		||||
		assert.Equal(t, TagPrefix+"signed-tag", refs[0].Name)
 | 
			
		||||
		assert.Equal(t, "tag", refs[0].Type)
 | 
			
		||||
		assert.Equal(t, "3ad28a9149a2864384548f3d17ed7f38014c9e8a", refs[0].Object.String())
 | 
			
		||||
		assert.Equal(t, "36f97d9a96457e2bab511db30fe2db03893ebc64", refs[0].Object.String())
 | 
			
		||||
		assert.Equal(t, TagPrefix+"test", refs[1].Name)
 | 
			
		||||
		assert.Equal(t, "tag", refs[1].Type)
 | 
			
		||||
		assert.Equal(t, "3ad28a9149a2864384548f3d17ed7f38014c9e8a", refs[1].Object.String())
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -24,9 +24,9 @@ func TestRepository_GetCodeActivityStats(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.NotNil(t, code)
 | 
			
		||||
 | 
			
		||||
	assert.EqualValues(t, 9, code.CommitCount)
 | 
			
		||||
	assert.EqualValues(t, 10, code.CommitCount)
 | 
			
		||||
	assert.EqualValues(t, 3, code.AuthorCount)
 | 
			
		||||
	assert.EqualValues(t, 9, code.CommitCountInAllBranches)
 | 
			
		||||
	assert.EqualValues(t, 10, code.CommitCountInAllBranches)
 | 
			
		||||
	assert.EqualValues(t, 10, code.Additions)
 | 
			
		||||
	assert.EqualValues(t, 1, code.Deletions)
 | 
			
		||||
	assert.Len(t, code.Authors, 3)
 | 
			
		||||
 
 | 
			
		||||
@@ -25,11 +25,14 @@ func TestRepository_GetTags(t *testing.T) {
 | 
			
		||||
		assert.NoError(t, err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	assert.Len(t, tags, 1)
 | 
			
		||||
	assert.Len(t, tags, 2)
 | 
			
		||||
	assert.Equal(t, len(tags), total)
 | 
			
		||||
	assert.EqualValues(t, "test", tags[0].Name)
 | 
			
		||||
	assert.EqualValues(t, "3ad28a9149a2864384548f3d17ed7f38014c9e8a", tags[0].ID.String())
 | 
			
		||||
	assert.EqualValues(t, "signed-tag", tags[0].Name)
 | 
			
		||||
	assert.EqualValues(t, "36f97d9a96457e2bab511db30fe2db03893ebc64", tags[0].ID.String())
 | 
			
		||||
	assert.EqualValues(t, "tag", tags[0].Type)
 | 
			
		||||
	assert.EqualValues(t, "test", tags[1].Name)
 | 
			
		||||
	assert.EqualValues(t, "3ad28a9149a2864384548f3d17ed7f38014c9e8a", tags[1].ID.String())
 | 
			
		||||
	assert.EqualValues(t, "tag", tags[1].Type)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestRepository_GetTag(t *testing.T) {
 | 
			
		||||
 
 | 
			
		||||
@@ -14,10 +14,10 @@ func TestGetLatestCommitTime(t *testing.T) {
 | 
			
		||||
	bareRepo1Path := filepath.Join(testReposDir, "repo1_bare")
 | 
			
		||||
	lct, err := GetLatestCommitTime(DefaultContext, bareRepo1Path)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	// Time is Sun Jul 21 22:43:13 2019 +0200
 | 
			
		||||
	// Time is Sun Nov 13 16:40:14 2022 +0100
 | 
			
		||||
	// which is the time of commit
 | 
			
		||||
	// feaf4ba6bc635fec442f46ddd4512416ec43c2c2 (refs/heads/master)
 | 
			
		||||
	assert.EqualValues(t, 1563741793, lct.Unix())
 | 
			
		||||
	// ce064814f4a0d337b333e646ece456cd39fab612 (refs/heads/master)
 | 
			
		||||
	assert.EqualValues(t, 1668354014, lct.Unix())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestRepoIsEmpty(t *testing.T) {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								modules/git/tests/repos/repo1_bare/index
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								modules/git/tests/repos/repo1_bare/index
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							@@ -1 +1,2 @@
 | 
			
		||||
37991dec2c8e592043f47155ce4808d4580f9123 feaf4ba6bc635fec442f46ddd4512416ec43c2c2 silverwind <me@silverwind.io> 1563741799 +0200	push
 | 
			
		||||
feaf4ba6bc635fec442f46ddd4512416ec43c2c2 ce064814f4a0d337b333e646ece456cd39fab612 silverwind <me@silverwind.io> 1668354026 +0100	push
 | 
			
		||||
 
 | 
			
		||||
@@ -1 +1,2 @@
 | 
			
		||||
37991dec2c8e592043f47155ce4808d4580f9123 feaf4ba6bc635fec442f46ddd4512416ec43c2c2 silverwind <me@silverwind.io> 1563741799 +0200	push
 | 
			
		||||
feaf4ba6bc635fec442f46ddd4512416ec43c2c2 ce064814f4a0d337b333e646ece456cd39fab612 silverwind <me@silverwind.io> 1668354026 +0100	push
 | 
			
		||||
 
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							@@ -1 +1 @@
 | 
			
		||||
feaf4ba6bc635fec442f46ddd4512416ec43c2c2
 | 
			
		||||
ce064814f4a0d337b333e646ece456cd39fab612
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1
									
								
								modules/git/tests/repos/repo1_bare/refs/tags/signed-tag
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								modules/git/tests/repos/repo1_bare/refs/tags/signed-tag
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
36f97d9a96457e2bab511db30fe2db03893ebc64
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user