mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-11-03 08:02:36 +09:00 
			
		
		
		
	Compare commits
	
		
			69 Commits
		
	
	
		
			v1.13.0-de
			...
			v1.9.2
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					30dbddcc4d | ||
| 
						 | 
					c491c22279 | ||
| 
						 | 
					5649f0d2b3 | ||
| 
						 | 
					7dd726faeb | ||
| 
						 | 
					14c979c1b2 | ||
| 
						 | 
					6b84a1d72b | ||
| 
						 | 
					68424eddf0 | ||
| 
						 | 
					ab23e4b7f4 | ||
| 
						 | 
					1bb88dad20 | ||
| 
						 | 
					94f0151789 | ||
| 
						 | 
					1e2fe9f0b4 | ||
| 
						 | 
					f3496c88b2 | ||
| 
						 | 
					89915ca8a0 | ||
| 
						 | 
					24fa56830f | ||
| 
						 | 
					0fa9ea516a | ||
| 
						 | 
					9b95b41aa8 | ||
| 
						 | 
					38e799779f | ||
| 
						 | 
					4f39e56795 | ||
| 
						 | 
					7b92f91e88 | ||
| 
						 | 
					aea49d0b92 | ||
| 
						 | 
					1b5908fb6a | ||
| 
						 | 
					65a76b7cb0 | ||
| 
						 | 
					c6f1825fe9 | ||
| 
						 | 
					4f5dbc4d00 | ||
| 
						 | 
					4ee8982e91 | ||
| 
						 | 
					0d10482168 | ||
| 
						 | 
					6d441de2bd | ||
| 
						 | 
					d15e49f7ff | ||
| 
						 | 
					39da4ac6d4 | ||
| 
						 | 
					8f29011723 | ||
| 
						 | 
					ee43d20d3b | ||
| 
						 | 
					99ffd826e5 | ||
| 
						 | 
					93bac4e10d | ||
| 
						 | 
					9fbb898058 | ||
| 
						 | 
					0a9794a6bc | ||
| 
						 | 
					d4044b9c98 | ||
| 
						 | 
					1e6d2e47e9 | ||
| 
						 | 
					d827b0bfb7 | ||
| 
						 | 
					d789170e31 | ||
| 
						 | 
					9bbe3eb0b4 | ||
| 
						 | 
					650fdceb5a | ||
| 
						 | 
					4c69e158e5 | ||
| 
						 | 
					b7e41f7b8f | ||
| 
						 | 
					5a3d9861ba | ||
| 
						 | 
					adb43358bc | ||
| 
						 | 
					d6a980501b | ||
| 
						 | 
					103a66ae83 | ||
| 
						 | 
					426fd2a816 | ||
| 
						 | 
					337f2625ac | ||
| 
						 | 
					5ebf4990a5 | ||
| 
						 | 
					3fd07a0be6 | ||
| 
						 | 
					d372539f79 | ||
| 
						 | 
					91e24a3a10 | ||
| 
						 | 
					a29e667eff | ||
| 
						 | 
					92b993c91f | ||
| 
						 | 
					33b1027c76 | ||
| 
						 | 
					b45f9260bf | ||
| 
						 | 
					ee1a8d7b41 | ||
| 
						 | 
					ba19a35b6b | ||
| 
						 | 
					cc8e7dd355 | ||
| 
						 | 
					f52840623c | ||
| 
						 | 
					97d4a38e01 | ||
| 
						 | 
					60ccd87d6e | ||
| 
						 | 
					2477737fff | ||
| 
						 | 
					a360daeff9 | ||
| 
						 | 
					82d4d725ae | ||
| 
						 | 
					1e585d7991 | ||
| 
						 | 
					f849766998 | ||
| 
						 | 
					f4818671e4 | 
							
								
								
									
										160
									
								
								.drone.yml
									
									
									
									
									
								
							
							
						
						
									
										160
									
								
								.drone.yml
									
									
									
									
									
								
							@@ -114,6 +114,17 @@ steps:
 | 
				
			|||||||
        - push
 | 
					        - push
 | 
				
			||||||
        - pull_request
 | 
					        - pull_request
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  - name: tag-pre-condition
 | 
				
			||||||
 | 
					    pull: always
 | 
				
			||||||
 | 
					    image: alpine/git
 | 
				
			||||||
 | 
					    commands:
 | 
				
			||||||
 | 
					      - git update-ref refs/heads/tag_test ${DRONE_COMMIT_SHA}
 | 
				
			||||||
 | 
					    depends_on:
 | 
				
			||||||
 | 
					      - build
 | 
				
			||||||
 | 
					    when:
 | 
				
			||||||
 | 
					      event:
 | 
				
			||||||
 | 
					        - tag
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  - name: tag-test
 | 
					  - name: tag-test
 | 
				
			||||||
    pull: always
 | 
					    pull: always
 | 
				
			||||||
    image: golang:1.12
 | 
					    image: golang:1.12
 | 
				
			||||||
@@ -122,7 +133,7 @@ steps:
 | 
				
			|||||||
    environment:
 | 
					    environment:
 | 
				
			||||||
      TAGS: bindata
 | 
					      TAGS: bindata
 | 
				
			||||||
    depends_on:
 | 
					    depends_on:
 | 
				
			||||||
      - build
 | 
					      - tag-pre-condition
 | 
				
			||||||
    when:
 | 
					    when:
 | 
				
			||||||
      event:
 | 
					      event:
 | 
				
			||||||
        - tag
 | 
					        - tag
 | 
				
			||||||
@@ -442,7 +453,6 @@ trigger:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
depends_on:
 | 
					depends_on:
 | 
				
			||||||
  - testing
 | 
					  - testing
 | 
				
			||||||
  - translations
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
steps:
 | 
					steps:
 | 
				
			||||||
  - name: fetch-tags
 | 
					  - name: fetch-tags
 | 
				
			||||||
@@ -548,7 +558,7 @@ steps:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
---
 | 
					---
 | 
				
			||||||
kind: pipeline
 | 
					kind: pipeline
 | 
				
			||||||
name: docker
 | 
					name: docker-linux-amd64
 | 
				
			||||||
 | 
					
 | 
				
			||||||
platform:
 | 
					platform:
 | 
				
			||||||
  os: linux
 | 
					  os: linux
 | 
				
			||||||
@@ -558,6 +568,15 @@ workspace:
 | 
				
			|||||||
  base: /go
 | 
					  base: /go
 | 
				
			||||||
  path: src/code.gitea.io/gitea
 | 
					  path: src/code.gitea.io/gitea
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					depends_on:
 | 
				
			||||||
 | 
					  - testing
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					trigger:
 | 
				
			||||||
 | 
					  ref:
 | 
				
			||||||
 | 
					  - refs/heads/master
 | 
				
			||||||
 | 
					  - "refs/tags/**"
 | 
				
			||||||
 | 
					  - "refs/pull/**"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
steps:
 | 
					steps:
 | 
				
			||||||
  - name: fetch-tags
 | 
					  - name: fetch-tags
 | 
				
			||||||
    pull: default
 | 
					    pull: default
 | 
				
			||||||
@@ -571,56 +590,121 @@ steps:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  - name: dryrun
 | 
					  - name: dryrun
 | 
				
			||||||
    pull: always
 | 
					    pull: always
 | 
				
			||||||
    image: plugins/docker:18.09
 | 
					    image: plugins/docker:linux-amd64
 | 
				
			||||||
    settings:
 | 
					    settings:
 | 
				
			||||||
      cache_from: gitea/gitea
 | 
					 | 
				
			||||||
      dry_run: true
 | 
					      dry_run: true
 | 
				
			||||||
      repo: gitea/gitea
 | 
					      repo: gitea/gitea
 | 
				
			||||||
 | 
					      tags: linux-amd64
 | 
				
			||||||
    when:
 | 
					    when:
 | 
				
			||||||
      event:
 | 
					      event:
 | 
				
			||||||
        - pull_request
 | 
					        - pull_request
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  - name: release
 | 
					  - name: publish
 | 
				
			||||||
    pull: always
 | 
					    pull: always
 | 
				
			||||||
    image: plugins/docker:18.09
 | 
					    image: plugins/docker:linux-amd64
 | 
				
			||||||
    settings:
 | 
					    settings:
 | 
				
			||||||
      cache_from: gitea/gitea
 | 
					      auto_tag: true
 | 
				
			||||||
 | 
					      auto_tag_suffix: linux-amd64
 | 
				
			||||||
      repo: gitea/gitea
 | 
					      repo: gitea/gitea
 | 
				
			||||||
      tags:
 | 
					      password:
 | 
				
			||||||
        - "${DRONE_BRANCH##release/v}"
 | 
					 | 
				
			||||||
    environment:
 | 
					 | 
				
			||||||
      DOCKER_PASSWORD:
 | 
					 | 
				
			||||||
        from_secret: docker_password
 | 
					        from_secret: docker_password
 | 
				
			||||||
      DOCKER_USERNAME:
 | 
					      username:
 | 
				
			||||||
        from_secret: docker_username
 | 
					        from_secret: docker_username
 | 
				
			||||||
    depends_on:
 | 
					 | 
				
			||||||
      - dryrun
 | 
					 | 
				
			||||||
    when:
 | 
					    when:
 | 
				
			||||||
      branch:
 | 
					 | 
				
			||||||
        - "release/*"
 | 
					 | 
				
			||||||
      event:
 | 
					      event:
 | 
				
			||||||
        - push
 | 
					        exclude:
 | 
				
			||||||
 | 
					        - pull_request
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  - name: latest
 | 
					
 | 
				
			||||||
    pull: always
 | 
					
 | 
				
			||||||
    image: plugins/docker:18.09
 | 
					---
 | 
				
			||||||
    settings:
 | 
					kind: pipeline
 | 
				
			||||||
      cache_from: gitea/gitea
 | 
					name: docker-linux-arm64
 | 
				
			||||||
      default_tags: true
 | 
					
 | 
				
			||||||
      repo: gitea/gitea
 | 
					platform:
 | 
				
			||||||
    environment:
 | 
					  os: linux
 | 
				
			||||||
      DOCKER_PASSWORD:
 | 
					  arch: arm64
 | 
				
			||||||
        from_secret: docker_password
 | 
					
 | 
				
			||||||
      DOCKER_USERNAME:
 | 
					workspace:
 | 
				
			||||||
        from_secret: docker_username
 | 
					  base: /go
 | 
				
			||||||
    depends_on:
 | 
					  path: src/code.gitea.io/gitea
 | 
				
			||||||
      - dryrun
 | 
					
 | 
				
			||||||
 | 
					depends_on:
 | 
				
			||||||
 | 
					  - testing
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					trigger:
 | 
				
			||||||
 | 
					  ref:
 | 
				
			||||||
 | 
					  - refs/heads/master
 | 
				
			||||||
 | 
					  - "refs/tags/**"
 | 
				
			||||||
 | 
					  - "refs/pull/**"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					steps:
 | 
				
			||||||
 | 
					  - name: fetch-tags
 | 
				
			||||||
 | 
					    pull: default
 | 
				
			||||||
 | 
					    image: docker:git
 | 
				
			||||||
 | 
					    commands:
 | 
				
			||||||
 | 
					      - git fetch --tags --force
 | 
				
			||||||
    when:
 | 
					    when:
 | 
				
			||||||
      branch:
 | 
					 | 
				
			||||||
        - master
 | 
					 | 
				
			||||||
      event:
 | 
					      event:
 | 
				
			||||||
        - push
 | 
					        exclude:
 | 
				
			||||||
        - tag
 | 
					          - pull_request
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  - name: dryrun
 | 
				
			||||||
 | 
					    pull: always
 | 
				
			||||||
 | 
					    image: plugins/docker:linux-arm64
 | 
				
			||||||
 | 
					    settings:
 | 
				
			||||||
 | 
					      dry_run: true
 | 
				
			||||||
 | 
					      repo: gitea/gitea
 | 
				
			||||||
 | 
					      tags: linux-arm64
 | 
				
			||||||
 | 
					    when:
 | 
				
			||||||
 | 
					      event:
 | 
				
			||||||
 | 
					        - pull_request
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  - name: publish
 | 
				
			||||||
 | 
					    pull: always
 | 
				
			||||||
 | 
					    image: plugins/docker:linux-arm64
 | 
				
			||||||
 | 
					    settings:
 | 
				
			||||||
 | 
					      auto_tag: true
 | 
				
			||||||
 | 
					      auto_tag_suffix: linux-arm64
 | 
				
			||||||
 | 
					      repo: gitea/gitea
 | 
				
			||||||
 | 
					      password:
 | 
				
			||||||
 | 
					        from_secret: docker_password
 | 
				
			||||||
 | 
					      username:
 | 
				
			||||||
 | 
					        from_secret: docker_username
 | 
				
			||||||
 | 
					    when:
 | 
				
			||||||
 | 
					      event:
 | 
				
			||||||
 | 
					        exclude:
 | 
				
			||||||
 | 
					        - pull_request
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					kind: pipeline
 | 
				
			||||||
 | 
					name: docker-manifest
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					platform:
 | 
				
			||||||
 | 
					  os: linux
 | 
				
			||||||
 | 
					  arch: amd64
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					steps:
 | 
				
			||||||
 | 
					  - name: manifest
 | 
				
			||||||
 | 
					    pull: always
 | 
				
			||||||
 | 
					    image: plugins/manifest
 | 
				
			||||||
 | 
					    settings:
 | 
				
			||||||
 | 
					      auto_tag: true
 | 
				
			||||||
 | 
					      ignore_missing: true
 | 
				
			||||||
 | 
					      spec: docker/manifest.tmpl
 | 
				
			||||||
 | 
					      password:
 | 
				
			||||||
 | 
					        from_secret: docker_password
 | 
				
			||||||
 | 
					      username:
 | 
				
			||||||
 | 
					        from_secret: docker_username
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					trigger:
 | 
				
			||||||
 | 
					  ref:
 | 
				
			||||||
 | 
					  - refs/heads/master
 | 
				
			||||||
 | 
					  - "refs/tags/**"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					depends_on:
 | 
				
			||||||
 | 
					  - docker-linux-amd64
 | 
				
			||||||
 | 
					  - docker-linux-arm64
 | 
				
			||||||
 | 
					
 | 
				
			||||||
---
 | 
					---
 | 
				
			||||||
kind: pipeline
 | 
					kind: pipeline
 | 
				
			||||||
@@ -644,7 +728,9 @@ depends_on:
 | 
				
			|||||||
  - translations
 | 
					  - translations
 | 
				
			||||||
  - release-version
 | 
					  - release-version
 | 
				
			||||||
  - release-master
 | 
					  - release-master
 | 
				
			||||||
  - docker
 | 
					  - docker-linux-amd64
 | 
				
			||||||
 | 
					  - docker-linux-arm64
 | 
				
			||||||
 | 
					  - docker-manifest
 | 
				
			||||||
  - docs
 | 
					  - docs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
steps:
 | 
					steps:
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										85
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										85
									
								
								CHANGELOG.md
									
									
									
									
									
								
							@@ -4,9 +4,56 @@ This changelog goes through all the changes that have been made in each release
 | 
				
			|||||||
without substantial changes to our git log; to see the highlights of what has
 | 
					without substantial changes to our git log; to see the highlights of what has
 | 
				
			||||||
been added to each release, please refer to the [blog](https://blog.gitea.io).
 | 
					been added to each release, please refer to the [blog](https://blog.gitea.io).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## [1.9.0-RC1](https://github.com/go-gitea/gitea/releases/tag/v1.9.0-rc1) - 2019-07-06
 | 
					## [1.9.2](https://github.com/go-gitea/gitea/releases/tag/v1.9.2) - 2019-08-22
 | 
				
			||||||
 | 
					* BUGFIXES
 | 
				
			||||||
 | 
					  * Fix wrong sender when send slack webhook (#7918) (#7924)
 | 
				
			||||||
 | 
					  * Upload support text/plain; charset=utf8 (#7899)
 | 
				
			||||||
 | 
					  * Lfs/lock: round locked_at timestamp to second (#7872) (#7875)
 | 
				
			||||||
 | 
					  * Fix non existent milestone with 500 error (#7867) (#7873)
 | 
				
			||||||
 | 
					* SECURITY
 | 
				
			||||||
 | 
					  * Fix No PGP signature on 1.9.1 tag (#7874)
 | 
				
			||||||
 | 
					  * Release built with go 1.12.9 to fix security fixes in golang std lib, ref: https://groups.google.com/forum/#!msg/golang-announce/oeMaeUnkvVE/a49yvTLqAAAJ
 | 
				
			||||||
 | 
					* ENHANCEMENT
 | 
				
			||||||
 | 
					  * Fix pull creation with empty changes (#7920) (#7926)
 | 
				
			||||||
 | 
					* BUILD
 | 
				
			||||||
 | 
					  * Drone/docker: prepare multi-arch release + provide arm64 image (#7571) (#7884)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## [1.9.1](https://github.com/go-gitea/gitea/releases/tag/v1.9.1) - 2019-08-14
 | 
				
			||||||
 | 
					* BREAKING
 | 
				
			||||||
 | 
					  * Add pagination for admin api get orgs and fix only list public orgs bug (#7742) (#7752)
 | 
				
			||||||
 | 
					* SECURITY
 | 
				
			||||||
 | 
					  * Be more strict with git arguments (#7715) (#7762)
 | 
				
			||||||
 | 
					  * Release built with go 1.12.8 to fix security fixes in golang std lib, ref: https://groups.google.com/forum/#!topic/golang-nuts/fCQWxqxP8aA
 | 
				
			||||||
 | 
					* BUGFIXES
 | 
				
			||||||
 | 
					  * Fix local runs of ssh-requiring integration tests (#7855) (#7857)
 | 
				
			||||||
 | 
					  * Fix hook problem (#7856) (#7754)
 | 
				
			||||||
 | 
					  * Use .ExpiredUnix.IsZero to display green color of forever valid gpg key (#7850) (#7846)
 | 
				
			||||||
 | 
					  * Do not fetch all refs (#7797) (#7837)
 | 
				
			||||||
 | 
					  * Fix duplicate call of webhook (#7824) (#7821)
 | 
				
			||||||
 | 
					  * Enable switching to a different source branch when PR already exists (#7823)
 | 
				
			||||||
 | 
					  * Rewrite existing repo units if setting is not included in api body (#7811)
 | 
				
			||||||
 | 
					  * Prevent Commit Status and Message From Overflowing On Branch Page (#7800) (#7808)
 | 
				
			||||||
 | 
					  * API: fix multiple bugs with statuses endpoints (Backport #7785) (#7807)
 | 
				
			||||||
 | 
					  * Fix Slack webhook fork message (1.9 release backport) (#7783)
 | 
				
			||||||
 | 
					  * Fix approvals counting (#7757) (#7777)
 | 
				
			||||||
 | 
					  * Fix rename failed when rewrite public keys (#7761) (#7769)
 | 
				
			||||||
 | 
					  * Fix dropTableColumns sqlite implementation (#7710) (#7765)
 | 
				
			||||||
 | 
					  * Fix repo_index_status lingering when deleting a repository (#7738)
 | 
				
			||||||
 | 
					  * Fix milestone completness calculation when migrating (#7725) (#7732)
 | 
				
			||||||
 | 
					  * Fixes indexed repos keeping outdated indexes when files grow too large (#7731)
 | 
				
			||||||
 | 
					  * Skip non-regular files (e.g. submodules) on repo indexing (#7717)
 | 
				
			||||||
 | 
					  * Improve branches list performance and fix protected branch icon when no-login (#7695) (#7704)
 | 
				
			||||||
 | 
					  * Correct wrong datetime format for git (#7689) (#7690)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## [1.9.0](https://github.com/go-gitea/gitea/releases/tag/v1.9.0) - 2019-07-30
 | 
				
			||||||
* BREAKING
 | 
					* BREAKING
 | 
				
			||||||
  * Better logging (#6038) (#6095)
 | 
					  * Better logging (#6038) (#6095)
 | 
				
			||||||
 | 
					* SECURITY
 | 
				
			||||||
 | 
					  * Shadow the password on cache and session config on admin panel (#7300)
 | 
				
			||||||
 | 
					  * Fix markdown invoke sequence (#7513) (#7560)
 | 
				
			||||||
 | 
					  * Reserve .well-known username (#7638)
 | 
				
			||||||
 | 
					  * Do not leak secrets via timing side channel (#7364)
 | 
				
			||||||
 | 
					  * Ensure that decryption of cookie actually suceeds (#7363)
 | 
				
			||||||
* FEATURE
 | 
					* FEATURE
 | 
				
			||||||
  * Content API for Creating, Updating, Deleting Files (#6314)
 | 
					  * Content API for Creating, Updating, Deleting Files (#6314)
 | 
				
			||||||
  * Enable tls-alpn-01: Use certmanager provided TLSConfig for LetsEncrypt (#7229)
 | 
					  * Enable tls-alpn-01: Use certmanager provided TLSConfig for LetsEncrypt (#7229)
 | 
				
			||||||
@@ -29,6 +76,39 @@ been added to each release, please refer to the [blog](https://blog.gitea.io).
 | 
				
			|||||||
  * Implement Default Webhooks (#4299)
 | 
					  * Implement Default Webhooks (#4299)
 | 
				
			||||||
  * Telegram webhook (#4227)
 | 
					  * Telegram webhook (#4227)
 | 
				
			||||||
* BUGFIXES
 | 
					* BUGFIXES
 | 
				
			||||||
 | 
					  * Send webhook after commit when creating issue with assignees (#7681) (#7684)
 | 
				
			||||||
 | 
					  * Upgrade macaron/captcha to fix random error problem (#7407) (#7683)
 | 
				
			||||||
 | 
					  * Move add to hook queue for created repo to outside xorm session. (#7682) (#7675)
 | 
				
			||||||
 | 
					  * Show protection symbol if needed on default branch (#7660) (#7668)
 | 
				
			||||||
 | 
					  * Hide delete/restore button on archived repos (#7660)
 | 
				
			||||||
 | 
					  * Fix bug on migrating milestone from github (#7665) (#7666) 
 | 
				
			||||||
 | 
					  * Use flex to fix floating paginate (#7656) (#7662)
 | 
				
			||||||
 | 
					  * Change length of some repository's columns (#7652) (#7655)
 | 
				
			||||||
 | 
					  * Fix wrong email when use gitea as OAuth2 provider (#7640) (#7647)
 | 
				
			||||||
 | 
					  * Fix syntax highlight initialization (#7617) (#7626) 
 | 
				
			||||||
 | 
					  * Fix bug create/edit wiki pages when code master branch protected (#7580) (#7623)
 | 
				
			||||||
 | 
					  * Fix panic on push at #7611 (#7615) (#7618)
 | 
				
			||||||
 | 
					  * Handle ErrUserProhibitLogin in http git (#7586, #7591) (#7590) 
 | 
				
			||||||
 | 
					  * Fix color of split-diff view in dark theme (#7587) (#7589)
 | 
				
			||||||
 | 
					  * Fix file header overflow in file and blame views (#7562) (#7579) 
 | 
				
			||||||
 | 
					  * Malformed URLs in API git/commits response (#7565) (#7567)
 | 
				
			||||||
 | 
					  * Fix empty commits now showing in repo overview (#7521) (#7563)
 | 
				
			||||||
 | 
					  * Fix repository's pull request count error (#7518) (#7524) 
 | 
				
			||||||
 | 
					  * Remove duplicated webhook trigger (#7511) (#7516) 
 | 
				
			||||||
 | 
					  * Handles all redirects for Web UI File CRUD (#7478) (#7507)
 | 
				
			||||||
 | 
					  * Fix regex for issues in commit messages (#7444) (#7466)
 | 
				
			||||||
 | 
					  * cmd/serv: actually exit after fatal errors (#7458) (#7460)
 | 
				
			||||||
 | 
					  * Fix an issue with some pages throwing 'not defined' js exceptions #7450 (#7453)
 | 
				
			||||||
 | 
					  * Fix Dropzone.js integration (#7445) (#7448)
 | 
				
			||||||
 | 
					  * Create class for inline positioned lists (#7439) (#7393)
 | 
				
			||||||
 | 
					  * Diff: Fix indentation on unhighlighted code (#7435) (#7443)
 | 
				
			||||||
 | 
					  * jQuery 3 (#7442) (#7425)
 | 
				
			||||||
 | 
					  * Only show "New Pull Request" button if repo allows pulls (#7426) (#7432)
 | 
				
			||||||
 | 
					  * Fix vendor references (#7394) (#7396)
 | 
				
			||||||
 | 
					  * Only return head: null if source branch was deleted (#6705) (#7376)
 | 
				
			||||||
 | 
					  * Add missing template variable on organisation settings (#7386) (#7385)
 | 
				
			||||||
 | 
					  * Fix post parameter on issue list which had unset assignee (#7380) (#7383)
 | 
				
			||||||
 | 
					  * Fix migration tests due to issue 7 being resolved (#7375) (#7381)
 | 
				
			||||||
  * Correctly adjust mirror url (#6593)
 | 
					  * Correctly adjust mirror url (#6593)
 | 
				
			||||||
  * Handle early git version's lack of get-url (#7065)
 | 
					  * Handle early git version's lack of get-url (#7065)
 | 
				
			||||||
  * Fix icon position in issue view (#7354)
 | 
					  * Fix icon position in issue view (#7354)
 | 
				
			||||||
@@ -166,6 +246,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.io).
 | 
				
			|||||||
  * Disable benchmarking during tag events on DroneIO (#6365)
 | 
					  * Disable benchmarking during tag events on DroneIO (#6365)
 | 
				
			||||||
  * Comments list performance optimization (#5305)
 | 
					  * Comments list performance optimization (#5305)
 | 
				
			||||||
* ENHANCEMENT
 | 
					* ENHANCEMENT
 | 
				
			||||||
 | 
					  * Update Drone docker generation to standard format (#7480) (#7496) (#7504)
 | 
				
			||||||
  * Add API Endpoint for Repo Edit (#7006)
 | 
					  * Add API Endpoint for Repo Edit (#7006)
 | 
				
			||||||
  * Add state param to milestone listing API (#7131)
 | 
					  * Add state param to milestone listing API (#7131)
 | 
				
			||||||
  * Make captcha and password optional for external accounts (#6606)
 | 
					  * Make captcha and password optional for external accounts (#6606)
 | 
				
			||||||
@@ -285,8 +366,6 @@ been added to each release, please refer to the [blog](https://blog.gitea.io).
 | 
				
			|||||||
  * Refactor: append, build variable and type switch (#4940)
 | 
					  * Refactor: append, build variable and type switch (#4940)
 | 
				
			||||||
  * Git statistics in Activity tab (#4724)
 | 
					  * Git statistics in Activity tab (#4724)
 | 
				
			||||||
  * Drop the bits argument when generating an ed25519 key (#6504)
 | 
					  * Drop the bits argument when generating an ed25519 key (#6504)
 | 
				
			||||||
* SECURITY
 | 
					 | 
				
			||||||
  * Shadow the password on cache and session config on admin panel (#7300)
 | 
					 | 
				
			||||||
* TESTING
 | 
					* TESTING
 | 
				
			||||||
  * Exclude pull_request from fetch-tags step, fixes #7108 (#7120)
 | 
					  * Exclude pull_request from fetch-tags step, fixes #7108 (#7120)
 | 
				
			||||||
  * Refactor and improve git test (#7086)
 | 
					  * Refactor and improve git test (#7086)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -96,6 +96,7 @@ func runHookPreReceive(c *cli.Context) error {
 | 
				
			|||||||
				UserID:                          userID,
 | 
									UserID:                          userID,
 | 
				
			||||||
				GitAlternativeObjectDirectories: os.Getenv(private.GitAlternativeObjectDirectories),
 | 
									GitAlternativeObjectDirectories: os.Getenv(private.GitAlternativeObjectDirectories),
 | 
				
			||||||
				GitObjectDirectory:              os.Getenv(private.GitObjectDirectory),
 | 
									GitObjectDirectory:              os.Getenv(private.GitObjectDirectory),
 | 
				
			||||||
 | 
									GitQuarantinePath:               os.Getenv(private.GitQuarantinePath),
 | 
				
			||||||
				ProtectedBranchID:               prID,
 | 
									ProtectedBranchID:               prID,
 | 
				
			||||||
			})
 | 
								})
 | 
				
			||||||
			switch statusCode {
 | 
								switch statusCode {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -73,7 +73,6 @@ func fail(userMessage, logMessage string, args ...interface{}) {
 | 
				
			|||||||
		if !setting.ProdMode {
 | 
							if !setting.ProdMode {
 | 
				
			||||||
			fmt.Fprintf(os.Stderr, logMessage+"\n", args...)
 | 
								fmt.Fprintf(os.Stderr, logMessage+"\n", args...)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	os.Exit(1)
 | 
						os.Exit(1)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										19
									
								
								docker/manifest.tmpl
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								docker/manifest.tmpl
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}latest{{/if}}
 | 
				
			||||||
 | 
					{{#if build.tags}}
 | 
				
			||||||
 | 
					tags:
 | 
				
			||||||
 | 
					{{#each build.tags}}
 | 
				
			||||||
 | 
					  - {{this}}
 | 
				
			||||||
 | 
					{{/each}}
 | 
				
			||||||
 | 
					{{/if}}
 | 
				
			||||||
 | 
					manifests:
 | 
				
			||||||
 | 
					  -
 | 
				
			||||||
 | 
					    image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-amd64
 | 
				
			||||||
 | 
					    platform:
 | 
				
			||||||
 | 
					      architecture: amd64
 | 
				
			||||||
 | 
					      os: linux
 | 
				
			||||||
 | 
					  -
 | 
				
			||||||
 | 
					    image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-arm64
 | 
				
			||||||
 | 
					    platform:
 | 
				
			||||||
 | 
					      architecture: arm64
 | 
				
			||||||
 | 
					      os: linux
 | 
				
			||||||
 | 
					      variant: v8
 | 
				
			||||||
							
								
								
									
										4
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								go.mod
									
									
									
									
									
								
							@@ -45,7 +45,7 @@ require (
 | 
				
			|||||||
	github.com/glycerine/goconvey v0.0.0-20190315024820-982ee783a72e // indirect
 | 
						github.com/glycerine/goconvey v0.0.0-20190315024820-982ee783a72e // indirect
 | 
				
			||||||
	github.com/go-macaron/binding v0.0.0-20160711225916-9440f336b443
 | 
						github.com/go-macaron/binding v0.0.0-20160711225916-9440f336b443
 | 
				
			||||||
	github.com/go-macaron/cache v0.0.0-20151013081102-561735312776
 | 
						github.com/go-macaron/cache v0.0.0-20151013081102-561735312776
 | 
				
			||||||
	github.com/go-macaron/captcha v0.0.0-20151123225153-8aa5919789ab
 | 
						github.com/go-macaron/captcha v0.0.0-20190710000913-8dc5911259df
 | 
				
			||||||
	github.com/go-macaron/cors v0.0.0-20190309005821-6fd6a9bfe14e9
 | 
						github.com/go-macaron/cors v0.0.0-20190309005821-6fd6a9bfe14e9
 | 
				
			||||||
	github.com/go-macaron/csrf v0.0.0-20180426211211-503617c6b372
 | 
						github.com/go-macaron/csrf v0.0.0-20180426211211-503617c6b372
 | 
				
			||||||
	github.com/go-macaron/i18n v0.0.0-20160612092837-ef57533c3b0f
 | 
						github.com/go-macaron/i18n v0.0.0-20160612092837-ef57533c3b0f
 | 
				
			||||||
@@ -135,4 +135,4 @@ require (
 | 
				
			|||||||
	xorm.io/core v0.6.3
 | 
						xorm.io/core v0.6.3
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
replace github.com/denisenkom/go-mssqldb => github.com/denisenkom/go-mssqldb v0.0.0-20180314172330-6a30f4e59a44
 | 
					replace github.com/denisenkom/go-mssqldb => github.com/denisenkom/go-mssqldb v0.0.0-20180315180555-6a30f4e59a44
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										8
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								go.sum
									
									
									
									
									
								
							@@ -66,8 +66,8 @@ github.com/cznic/strutil v0.0.0-20181122101858-275e90344537/go.mod h1:AHHPPPXTw0
 | 
				
			|||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 | 
					github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 | 
				
			||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 | 
					github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 | 
				
			||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 | 
					github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 | 
				
			||||||
github.com/denisenkom/go-mssqldb v0.0.0-20180314172330-6a30f4e59a44 h1:x0uHqLQTSEL9LKic8sWDt3ASkq07ve5ojIIUl5uF64M=
 | 
					github.com/denisenkom/go-mssqldb v0.0.0-20180315180555-6a30f4e59a44 h1:DWxZh2sImfCFn/79OUBhzFkPTKnsdDzXH/JTxpw5n6w=
 | 
				
			||||||
github.com/denisenkom/go-mssqldb v0.0.0-20180314172330-6a30f4e59a44/go.mod h1:xN/JuLBIz4bjkxNmByTiV1IbhfnYb6oo99phBn4Eqhc=
 | 
					github.com/denisenkom/go-mssqldb v0.0.0-20180315180555-6a30f4e59a44/go.mod h1:xN/JuLBIz4bjkxNmByTiV1IbhfnYb6oo99phBn4Eqhc=
 | 
				
			||||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
 | 
					github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
 | 
				
			||||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
 | 
					github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
 | 
				
			||||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
 | 
					github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
 | 
				
			||||||
@@ -113,8 +113,8 @@ github.com/go-macaron/binding v0.0.0-20160711225916-9440f336b443 h1:i801KPR7j76u
 | 
				
			|||||||
github.com/go-macaron/binding v0.0.0-20160711225916-9440f336b443/go.mod h1:u+H6rwW+HQwUL+w5uaEJSpIlVZDye1o9MB4Su0JfRfM=
 | 
					github.com/go-macaron/binding v0.0.0-20160711225916-9440f336b443/go.mod h1:u+H6rwW+HQwUL+w5uaEJSpIlVZDye1o9MB4Su0JfRfM=
 | 
				
			||||||
github.com/go-macaron/cache v0.0.0-20151013081102-561735312776 h1:UYIHS1r0WotqB5cIa0PAiV0m6GzD9rDBcn4alp5JgCw=
 | 
					github.com/go-macaron/cache v0.0.0-20151013081102-561735312776 h1:UYIHS1r0WotqB5cIa0PAiV0m6GzD9rDBcn4alp5JgCw=
 | 
				
			||||||
github.com/go-macaron/cache v0.0.0-20151013081102-561735312776/go.mod h1:hHAsZm/oBZVcY+S7qdQL6Vbg5VrXF6RuKGuqsszt3Ok=
 | 
					github.com/go-macaron/cache v0.0.0-20151013081102-561735312776/go.mod h1:hHAsZm/oBZVcY+S7qdQL6Vbg5VrXF6RuKGuqsszt3Ok=
 | 
				
			||||||
github.com/go-macaron/captcha v0.0.0-20151123225153-8aa5919789ab h1:4VFhsA3GE5Wwq1Ymr8KWCmrOWi1wRLEgdj48LPfQjxI=
 | 
					github.com/go-macaron/captcha v0.0.0-20190710000913-8dc5911259df h1:MdgvtI3Y1u/DHNj7xUGOqAv+KGoTikjy8xQtCm12L78=
 | 
				
			||||||
github.com/go-macaron/captcha v0.0.0-20151123225153-8aa5919789ab/go.mod h1:j9TJ+0nwUOWBvNnm0bheHIPFf3cC62EQo7n7O6PbjZA=
 | 
					github.com/go-macaron/captcha v0.0.0-20190710000913-8dc5911259df/go.mod h1:j9TJ+0nwUOWBvNnm0bheHIPFf3cC62EQo7n7O6PbjZA=
 | 
				
			||||||
github.com/go-macaron/cors v0.0.0-20190309005821-6fd6a9bfe14e9 h1:A0QGzY6UHHEil0I2e7C21JenNNG0mmrj5d9SFWTlgr8=
 | 
					github.com/go-macaron/cors v0.0.0-20190309005821-6fd6a9bfe14e9 h1:A0QGzY6UHHEil0I2e7C21JenNNG0mmrj5d9SFWTlgr8=
 | 
				
			||||||
github.com/go-macaron/cors v0.0.0-20190309005821-6fd6a9bfe14e9/go.mod h1:utmMRnVIrXPSfA9MFcpIYKEpKawjKxf62vv62k4707E=
 | 
					github.com/go-macaron/cors v0.0.0-20190309005821-6fd6a9bfe14e9/go.mod h1:utmMRnVIrXPSfA9MFcpIYKEpKawjKxf62vv62k4707E=
 | 
				
			||||||
github.com/go-macaron/csrf v0.0.0-20180426211211-503617c6b372 h1:acrx8CnDmlKl+BPoOOLEK9Ko+SrWFB5pxRuGkKj4iqo=
 | 
					github.com/go-macaron/csrf v0.0.0-20180426211211-503617c6b372 h1:acrx8CnDmlKl+BPoOOLEK9Ko+SrWFB5pxRuGkKj4iqo=
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -104,8 +104,11 @@ func TestAPILFSLocksLogged(t *testing.T) {
 | 
				
			|||||||
		req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/%s.git/info/lfs/locks", test.repo.FullName()), map[string]string{"path": test.path})
 | 
							req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/%s.git/info/lfs/locks", test.repo.FullName()), map[string]string{"path": test.path})
 | 
				
			||||||
		req.Header.Set("Accept", "application/vnd.git-lfs+json")
 | 
							req.Header.Set("Accept", "application/vnd.git-lfs+json")
 | 
				
			||||||
		req.Header.Set("Content-Type", "application/vnd.git-lfs+json")
 | 
							req.Header.Set("Content-Type", "application/vnd.git-lfs+json")
 | 
				
			||||||
		session.MakeRequest(t, req, test.httpResult)
 | 
							resp := session.MakeRequest(t, req, test.httpResult)
 | 
				
			||||||
		if len(test.addTime) > 0 {
 | 
							if len(test.addTime) > 0 {
 | 
				
			||||||
 | 
								var lfsLock api.LFSLockResponse
 | 
				
			||||||
 | 
								DecodeJSON(t, resp, &lfsLock)
 | 
				
			||||||
 | 
								assert.EqualValues(t, lfsLock.Lock.LockedAt.Format(time.RFC3339), lfsLock.Lock.LockedAt.Format(time.RFC3339Nano)) //locked at should be rounded to second
 | 
				
			||||||
			for _, id := range test.addTime {
 | 
								for _, id := range test.addTime {
 | 
				
			||||||
				resultsTests[id].locksTimes = append(resultsTests[id].locksTimes, time.Now())
 | 
									resultsTests[id].locksTimes = append(resultsTests[id].locksTimes, time.Now())
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@@ -124,6 +127,7 @@ func TestAPILFSLocksLogged(t *testing.T) {
 | 
				
			|||||||
		for i, lock := range lfsLocks.Locks {
 | 
							for i, lock := range lfsLocks.Locks {
 | 
				
			||||||
			assert.EqualValues(t, test.locksOwners[i].DisplayName(), lock.Owner.Name)
 | 
								assert.EqualValues(t, test.locksOwners[i].DisplayName(), lock.Owner.Name)
 | 
				
			||||||
			assert.WithinDuration(t, test.locksTimes[i], lock.LockedAt, 3*time.Second)
 | 
								assert.WithinDuration(t, test.locksTimes[i], lock.LockedAt, 3*time.Second)
 | 
				
			||||||
 | 
								assert.EqualValues(t, lock.LockedAt.Format(time.RFC3339), lock.LockedAt.Format(time.RFC3339Nano)) //locked at should be rounded to second
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		req = NewRequestWithJSON(t, "POST", fmt.Sprintf("/%s.git/info/lfs/locks/verify", test.repo.FullName()), map[string]string{})
 | 
							req = NewRequestWithJSON(t, "POST", fmt.Sprintf("/%s.git/info/lfs/locks/verify", test.repo.FullName()), map[string]string{})
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,20 +24,24 @@ import (
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func withKeyFile(t *testing.T, keyname string, callback func(string)) {
 | 
					func withKeyFile(t *testing.T, keyname string, callback func(string)) {
 | 
				
			||||||
	keyFile := filepath.Join(setting.AppDataPath, keyname)
 | 
					
 | 
				
			||||||
	err := ssh.GenKeyPair(keyFile)
 | 
						tmpDir, err := ioutil.TempDir("", "key-file")
 | 
				
			||||||
 | 
						assert.NoError(t, err)
 | 
				
			||||||
 | 
						defer os.RemoveAll(tmpDir)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = os.Chmod(tmpDir, 0700)
 | 
				
			||||||
 | 
						assert.NoError(t, err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						keyFile := filepath.Join(tmpDir, keyname)
 | 
				
			||||||
 | 
						err = ssh.GenKeyPair(keyFile)
 | 
				
			||||||
	assert.NoError(t, err)
 | 
						assert.NoError(t, err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	//Setup ssh wrapper
 | 
						//Setup ssh wrapper
 | 
				
			||||||
	os.Setenv("GIT_SSH_COMMAND",
 | 
						os.Setenv("GIT_SSH_COMMAND",
 | 
				
			||||||
		"ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i "+
 | 
							"ssh -o \"UserKnownHostsFile=/dev/null\" -o \"StrictHostKeyChecking=no\" -o \"IdentitiesOnly=yes\" -i \""+keyFile+"\"")
 | 
				
			||||||
			filepath.Join(setting.AppWorkPath, keyFile))
 | 
					 | 
				
			||||||
	os.Setenv("GIT_SSH_VARIANT", "ssh")
 | 
						os.Setenv("GIT_SSH_VARIANT", "ssh")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	callback(keyFile)
 | 
						callback(keyFile)
 | 
				
			||||||
 | 
					 | 
				
			||||||
	defer os.RemoveAll(keyFile)
 | 
					 | 
				
			||||||
	defer os.RemoveAll(keyFile + ".pub")
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func createSSHUrl(gitPath string, u *url.URL) *url.URL {
 | 
					func createSSHUrl(gitPath string, u *url.URL) *url.URL {
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										
											BIN
										
									
								
								integrations/migration-test/gitea-v1.3.3.sqlite3.sql.gz
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								integrations/migration-test/gitea-v1.3.3.sqlite3.sql.gz
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							@@ -54,6 +54,10 @@ func testPullCleanUp(t *testing.T, session *TestSession, user, repo, pullnum str
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func TestPullMerge(t *testing.T) {
 | 
					func TestPullMerge(t *testing.T) {
 | 
				
			||||||
	onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
 | 
						onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
 | 
				
			||||||
 | 
							hookTasks, err := models.HookTasks(1, 1) //Retrieve previous hook number
 | 
				
			||||||
 | 
							assert.NoError(t, err)
 | 
				
			||||||
 | 
							hookTasksLenBefore := len(hookTasks)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		session := loginUser(t, "user1")
 | 
							session := loginUser(t, "user1")
 | 
				
			||||||
		testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
 | 
							testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
 | 
				
			||||||
		testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
 | 
							testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
 | 
				
			||||||
@@ -63,11 +67,19 @@ func TestPullMerge(t *testing.T) {
 | 
				
			|||||||
		elem := strings.Split(test.RedirectURL(resp), "/")
 | 
							elem := strings.Split(test.RedirectURL(resp), "/")
 | 
				
			||||||
		assert.EqualValues(t, "pulls", elem[3])
 | 
							assert.EqualValues(t, "pulls", elem[3])
 | 
				
			||||||
		testPullMerge(t, session, elem[1], elem[2], elem[4], models.MergeStyleMerge)
 | 
							testPullMerge(t, session, elem[1], elem[2], elem[4], models.MergeStyleMerge)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							hookTasks, err = models.HookTasks(1, 1)
 | 
				
			||||||
 | 
							assert.NoError(t, err)
 | 
				
			||||||
 | 
							assert.Len(t, hookTasks, hookTasksLenBefore+1)
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestPullRebase(t *testing.T) {
 | 
					func TestPullRebase(t *testing.T) {
 | 
				
			||||||
	onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
 | 
						onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
 | 
				
			||||||
 | 
							hookTasks, err := models.HookTasks(1, 1) //Retrieve previous hook number
 | 
				
			||||||
 | 
							assert.NoError(t, err)
 | 
				
			||||||
 | 
							hookTasksLenBefore := len(hookTasks)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		session := loginUser(t, "user1")
 | 
							session := loginUser(t, "user1")
 | 
				
			||||||
		testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
 | 
							testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
 | 
				
			||||||
		testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
 | 
							testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
 | 
				
			||||||
@@ -77,12 +89,21 @@ func TestPullRebase(t *testing.T) {
 | 
				
			|||||||
		elem := strings.Split(test.RedirectURL(resp), "/")
 | 
							elem := strings.Split(test.RedirectURL(resp), "/")
 | 
				
			||||||
		assert.EqualValues(t, "pulls", elem[3])
 | 
							assert.EqualValues(t, "pulls", elem[3])
 | 
				
			||||||
		testPullMerge(t, session, elem[1], elem[2], elem[4], models.MergeStyleRebase)
 | 
							testPullMerge(t, session, elem[1], elem[2], elem[4], models.MergeStyleRebase)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							hookTasks, err = models.HookTasks(1, 1)
 | 
				
			||||||
 | 
							assert.NoError(t, err)
 | 
				
			||||||
 | 
							assert.Len(t, hookTasks, hookTasksLenBefore+1)
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestPullRebaseMerge(t *testing.T) {
 | 
					func TestPullRebaseMerge(t *testing.T) {
 | 
				
			||||||
	onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
 | 
						onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
 | 
				
			||||||
		prepareTestEnv(t)
 | 
							prepareTestEnv(t)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							hookTasks, err := models.HookTasks(1, 1) //Retrieve previous hook number
 | 
				
			||||||
 | 
							assert.NoError(t, err)
 | 
				
			||||||
 | 
							hookTasksLenBefore := len(hookTasks)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		session := loginUser(t, "user1")
 | 
							session := loginUser(t, "user1")
 | 
				
			||||||
		testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
 | 
							testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
 | 
				
			||||||
		testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
 | 
							testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
 | 
				
			||||||
@@ -92,12 +113,21 @@ func TestPullRebaseMerge(t *testing.T) {
 | 
				
			|||||||
		elem := strings.Split(test.RedirectURL(resp), "/")
 | 
							elem := strings.Split(test.RedirectURL(resp), "/")
 | 
				
			||||||
		assert.EqualValues(t, "pulls", elem[3])
 | 
							assert.EqualValues(t, "pulls", elem[3])
 | 
				
			||||||
		testPullMerge(t, session, elem[1], elem[2], elem[4], models.MergeStyleRebaseMerge)
 | 
							testPullMerge(t, session, elem[1], elem[2], elem[4], models.MergeStyleRebaseMerge)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							hookTasks, err = models.HookTasks(1, 1)
 | 
				
			||||||
 | 
							assert.NoError(t, err)
 | 
				
			||||||
 | 
							assert.Len(t, hookTasks, hookTasksLenBefore+1)
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestPullSquash(t *testing.T) {
 | 
					func TestPullSquash(t *testing.T) {
 | 
				
			||||||
	onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
 | 
						onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
 | 
				
			||||||
		prepareTestEnv(t)
 | 
							prepareTestEnv(t)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							hookTasks, err := models.HookTasks(1, 1) //Retrieve previous hook number
 | 
				
			||||||
 | 
							assert.NoError(t, err)
 | 
				
			||||||
 | 
							hookTasksLenBefore := len(hookTasks)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		session := loginUser(t, "user1")
 | 
							session := loginUser(t, "user1")
 | 
				
			||||||
		testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
 | 
							testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
 | 
				
			||||||
		testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
 | 
							testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
 | 
				
			||||||
@@ -108,6 +138,10 @@ func TestPullSquash(t *testing.T) {
 | 
				
			|||||||
		elem := strings.Split(test.RedirectURL(resp), "/")
 | 
							elem := strings.Split(test.RedirectURL(resp), "/")
 | 
				
			||||||
		assert.EqualValues(t, "pulls", elem[3])
 | 
							assert.EqualValues(t, "pulls", elem[3])
 | 
				
			||||||
		testPullMerge(t, session, elem[1], elem[2], elem[4], models.MergeStyleSquash)
 | 
							testPullMerge(t, session, elem[1], elem[2], elem[4], models.MergeStyleSquash)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							hookTasks, err = models.HookTasks(1, 1)
 | 
				
			||||||
 | 
							assert.NoError(t, err)
 | 
				
			||||||
 | 
							assert.Len(t, hookTasks, hookTasksLenBefore+1)
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,7 @@ import (
 | 
				
			|||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
	"net/url"
 | 
						"net/url"
 | 
				
			||||||
	"path"
 | 
						"path"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"code.gitea.io/gitea/models"
 | 
						"code.gitea.io/gitea/models"
 | 
				
			||||||
@@ -93,3 +94,28 @@ func TestPullCreate_CommitStatus(t *testing.T) {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestPullCreate_EmptyChangesWithCommits(t *testing.T) {
 | 
				
			||||||
 | 
						onGiteaRun(t, func(t *testing.T, u *url.URL) {
 | 
				
			||||||
 | 
							session := loginUser(t, "user1")
 | 
				
			||||||
 | 
							testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
 | 
				
			||||||
 | 
							testEditFileToNewBranch(t, session, "user1", "repo1", "master", "status1", "README.md", "status1")
 | 
				
			||||||
 | 
							testEditFileToNewBranch(t, session, "user1", "repo1", "status1", "status1", "README.md", "# repo1\n\nDescription for repo1")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							url := path.Join("user1", "repo1", "compare", "master...status1")
 | 
				
			||||||
 | 
							req := NewRequestWithValues(t, "POST", url,
 | 
				
			||||||
 | 
								map[string]string{
 | 
				
			||||||
 | 
									"_csrf": GetCSRF(t, session, url),
 | 
				
			||||||
 | 
									"title": "pull request from status1",
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							)
 | 
				
			||||||
 | 
							session.MakeRequest(t, req, http.StatusFound)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							req = NewRequest(t, "GET", "/user1/repo1/pulls/1")
 | 
				
			||||||
 | 
							resp := session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
 | 
							doc := NewHTMLParser(t, resp.Body)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							text := strings.TrimSpace(doc.doc.Find(".item.text.green").Text())
 | 
				
			||||||
 | 
							assert.EqualValues(t, "This pull request can be merged automatically.", text)
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,10 +5,13 @@
 | 
				
			|||||||
package integrations
 | 
					package integrations
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"encoding/json"
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
 | 
						"net/http/httptest"
 | 
				
			||||||
	"path"
 | 
						"path"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/setting"
 | 
				
			||||||
	api "code.gitea.io/gitea/modules/structs"
 | 
						api "code.gitea.io/gitea/modules/structs"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/stretchr/testify/assert"
 | 
						"github.com/stretchr/testify/assert"
 | 
				
			||||||
@@ -67,6 +70,29 @@ func doTestRepoCommitWithStatus(t *testing.T, state string, classes ...string) {
 | 
				
			|||||||
	for _, class := range classes {
 | 
						for _, class := range classes {
 | 
				
			||||||
		assert.True(t, sel.HasClass(class))
 | 
							assert.True(t, sel.HasClass(class))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						//By SHA
 | 
				
			||||||
 | 
						req = NewRequest(t, "GET", "/api/v1/repos/user2/repo1/commits/"+path.Base(commitURL)+"/statuses")
 | 
				
			||||||
 | 
						testRepoCommitsWithStatus(t, session.MakeRequest(t, req, http.StatusOK), state)
 | 
				
			||||||
 | 
						//By Ref
 | 
				
			||||||
 | 
						req = NewRequest(t, "GET", "/api/v1/repos/user2/repo1/commits/master/statuses")
 | 
				
			||||||
 | 
						testRepoCommitsWithStatus(t, session.MakeRequest(t, req, http.StatusOK), state)
 | 
				
			||||||
 | 
						req = NewRequest(t, "GET", "/api/v1/repos/user2/repo1/commits/v1.1/statuses")
 | 
				
			||||||
 | 
						testRepoCommitsWithStatus(t, session.MakeRequest(t, req, http.StatusOK), state)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func testRepoCommitsWithStatus(t *testing.T, resp *httptest.ResponseRecorder, state string) {
 | 
				
			||||||
 | 
						decoder := json.NewDecoder(resp.Body)
 | 
				
			||||||
 | 
						statuses := []*api.Status{}
 | 
				
			||||||
 | 
						assert.NoError(t, decoder.Decode(&statuses))
 | 
				
			||||||
 | 
						assert.Len(t, statuses, 1)
 | 
				
			||||||
 | 
						for _, s := range statuses {
 | 
				
			||||||
 | 
							assert.Equal(t, api.StatusState(state), s.State)
 | 
				
			||||||
 | 
							assert.Equal(t, setting.AppURL+"api/v1/repos/user2/repo1/statuses/65f1bf27bc3bf70f64657658635e66094edbcb4d", s.URL)
 | 
				
			||||||
 | 
							assert.Equal(t, "http://test.ci/", s.TargetURL)
 | 
				
			||||||
 | 
							assert.Equal(t, "", s.Description)
 | 
				
			||||||
 | 
							assert.Equal(t, "testci", s.Context)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestRepoCommitsWithStatusPending(t *testing.T) {
 | 
					func TestRepoCommitsWithStatusPending(t *testing.T) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -65,6 +65,7 @@ var (
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const issueRefRegexpStr = `(?:([0-9a-zA-Z-_\.]+)/([0-9a-zA-Z-_\.]+))?(#[0-9]+)+`
 | 
					const issueRefRegexpStr = `(?:([0-9a-zA-Z-_\.]+)/([0-9a-zA-Z-_\.]+))?(#[0-9]+)+`
 | 
				
			||||||
 | 
					const issueRefRegexpStrNoKeyword = `(?:\s|^|\(|\[)(?:([0-9a-zA-Z-_\.]+)/([0-9a-zA-Z-_\.]+))?(#[0-9]+)(?:\s|$|\)|\]|\.(\s|$))`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func assembleKeywordsPattern(words []string) string {
 | 
					func assembleKeywordsPattern(words []string) string {
 | 
				
			||||||
	return fmt.Sprintf(`(?i)(?:%s)(?::?) %s`, strings.Join(words, "|"), issueRefRegexpStr)
 | 
						return fmt.Sprintf(`(?i)(?:%s)(?::?) %s`, strings.Join(words, "|"), issueRefRegexpStr)
 | 
				
			||||||
@@ -73,7 +74,7 @@ func assembleKeywordsPattern(words []string) string {
 | 
				
			|||||||
func init() {
 | 
					func init() {
 | 
				
			||||||
	issueCloseKeywordsPat = regexp.MustCompile(assembleKeywordsPattern(issueCloseKeywords))
 | 
						issueCloseKeywordsPat = regexp.MustCompile(assembleKeywordsPattern(issueCloseKeywords))
 | 
				
			||||||
	issueReopenKeywordsPat = regexp.MustCompile(assembleKeywordsPattern(issueReopenKeywords))
 | 
						issueReopenKeywordsPat = regexp.MustCompile(assembleKeywordsPattern(issueReopenKeywords))
 | 
				
			||||||
	issueReferenceKeywordsPat = regexp.MustCompile(issueRefRegexpStr)
 | 
						issueReferenceKeywordsPat = regexp.MustCompile(issueRefRegexpStrNoKeyword)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Action represents user operation type and other information to
 | 
					// Action represents user operation type and other information to
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -155,6 +155,25 @@ func TestPushCommits_AvatarLink(t *testing.T) {
 | 
				
			|||||||
		pushCommits.AvatarLink("nonexistent@example.com"))
 | 
							pushCommits.AvatarLink("nonexistent@example.com"))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestRegExp_issueReferenceKeywordsPat(t *testing.T) {
 | 
				
			||||||
 | 
						trueTestCases := []string{
 | 
				
			||||||
 | 
							"#2",
 | 
				
			||||||
 | 
							"[#2]",
 | 
				
			||||||
 | 
							"please see go-gitea/gitea#5",
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						falseTestCases := []string{
 | 
				
			||||||
 | 
							"kb#2",
 | 
				
			||||||
 | 
							"#2xy",
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, testCase := range trueTestCases {
 | 
				
			||||||
 | 
							assert.True(t, issueReferenceKeywordsPat.MatchString(testCase))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for _, testCase := range falseTestCases {
 | 
				
			||||||
 | 
							assert.False(t, issueReferenceKeywordsPat.MatchString(testCase))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func Test_getIssueFromRef(t *testing.T) {
 | 
					func Test_getIssueFromRef(t *testing.T) {
 | 
				
			||||||
	assert.NoError(t, PrepareTestDatabase())
 | 
						assert.NoError(t, PrepareTestDatabase())
 | 
				
			||||||
	repo := AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository)
 | 
						repo := AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -101,7 +101,7 @@ func (protectBranch *ProtectedBranch) HasEnoughApprovals(pr *PullRequest) bool {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// GetGrantedApprovalsCount returns the number of granted approvals for pr. A granted approval must be authored by a user in an approval whitelist.
 | 
					// GetGrantedApprovalsCount returns the number of granted approvals for pr. A granted approval must be authored by a user in an approval whitelist.
 | 
				
			||||||
func (protectBranch *ProtectedBranch) GetGrantedApprovalsCount(pr *PullRequest) int64 {
 | 
					func (protectBranch *ProtectedBranch) GetGrantedApprovalsCount(pr *PullRequest) int64 {
 | 
				
			||||||
	reviews, err := GetReviewersByPullID(pr.Issue.ID)
 | 
						reviews, err := GetReviewersByPullID(pr.IssueID)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		log.Error("GetReviewersByPullID: %v", err)
 | 
							log.Error("GetReviewersByPullID: %v", err)
 | 
				
			||||||
		return 0
 | 
							return 0
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -87,7 +87,7 @@ func (status *CommitStatus) loadRepo(e Engine) (err error) {
 | 
				
			|||||||
// APIURL returns the absolute APIURL to this commit-status.
 | 
					// APIURL returns the absolute APIURL to this commit-status.
 | 
				
			||||||
func (status *CommitStatus) APIURL() string {
 | 
					func (status *CommitStatus) APIURL() string {
 | 
				
			||||||
	_ = status.loadRepo(x)
 | 
						_ = status.loadRepo(x)
 | 
				
			||||||
	return fmt.Sprintf("%sapi/v1/%s/statuses/%s",
 | 
						return fmt.Sprintf("%sapi/v1/repos/%s/statuses/%s",
 | 
				
			||||||
		setting.AppURL, status.Repo.FullName(), status.SHA)
 | 
							setting.AppURL, status.Repo.FullName(), status.SHA)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,20 +19,25 @@ func TestGetCommitStatuses(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	statuses, err := GetCommitStatuses(repo1, sha1, 0)
 | 
						statuses, err := GetCommitStatuses(repo1, sha1, 0)
 | 
				
			||||||
	assert.NoError(t, err)
 | 
						assert.NoError(t, err)
 | 
				
			||||||
	if assert.Len(t, statuses, 5) {
 | 
						assert.Len(t, statuses, 5)
 | 
				
			||||||
		assert.Equal(t, statuses[0].Context, "ci/awesomeness")
 | 
					 | 
				
			||||||
		assert.Equal(t, statuses[0].State, CommitStatusPending)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		assert.Equal(t, statuses[1].Context, "cov/awesomeness")
 | 
						assert.Equal(t, "ci/awesomeness", statuses[0].Context)
 | 
				
			||||||
		assert.Equal(t, statuses[1].State, CommitStatusWarning)
 | 
						assert.Equal(t, CommitStatusPending, statuses[0].State)
 | 
				
			||||||
 | 
						assert.Equal(t, "https://try.gitea.io/api/v1/repos/user2/repo1/statuses/1234123412341234123412341234123412341234", statuses[0].APIURL())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		assert.Equal(t, statuses[2].Context, "cov/awesomeness")
 | 
						assert.Equal(t, "cov/awesomeness", statuses[1].Context)
 | 
				
			||||||
		assert.Equal(t, statuses[2].State, CommitStatusSuccess)
 | 
						assert.Equal(t, CommitStatusWarning, statuses[1].State)
 | 
				
			||||||
 | 
						assert.Equal(t, "https://try.gitea.io/api/v1/repos/user2/repo1/statuses/1234123412341234123412341234123412341234", statuses[1].APIURL())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		assert.Equal(t, statuses[3].Context, "ci/awesomeness")
 | 
						assert.Equal(t, "cov/awesomeness", statuses[2].Context)
 | 
				
			||||||
		assert.Equal(t, statuses[3].State, CommitStatusFailure)
 | 
						assert.Equal(t, CommitStatusSuccess, statuses[2].State)
 | 
				
			||||||
 | 
						assert.Equal(t, "https://try.gitea.io/api/v1/repos/user2/repo1/statuses/1234123412341234123412341234123412341234", statuses[2].APIURL())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		assert.Equal(t, statuses[4].Context, "deploy/awesomeness")
 | 
						assert.Equal(t, "ci/awesomeness", statuses[3].Context)
 | 
				
			||||||
		assert.Equal(t, statuses[4].State, CommitStatusError)
 | 
						assert.Equal(t, CommitStatusFailure, statuses[3].State)
 | 
				
			||||||
	}
 | 
						assert.Equal(t, "https://try.gitea.io/api/v1/repos/user2/repo1/statuses/1234123412341234123412341234123412341234", statuses[3].APIURL())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						assert.Equal(t, "deploy/awesomeness", statuses[4].Context)
 | 
				
			||||||
 | 
						assert.Equal(t, CommitStatusError, statuses[4].State)
 | 
				
			||||||
 | 
						assert.Equal(t, "https://try.gitea.io/api/v1/repos/user2/repo1/statuses/1234123412341234123412341234123412341234", statuses[4].APIURL())
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,13 +12,13 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// PushingEnvironment returns an os environment to allow hooks to work on push
 | 
					// PushingEnvironment returns an os environment to allow hooks to work on push
 | 
				
			||||||
func PushingEnvironment(doer *User, repo *Repository) []string {
 | 
					func PushingEnvironment(doer *User, repo *Repository) []string {
 | 
				
			||||||
	return FullPushingEnvironment(doer, doer, repo, 0)
 | 
						return FullPushingEnvironment(doer, doer, repo, repo.Name, 0)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// FullPushingEnvironment returns an os environment to allow hooks to work on push
 | 
					// FullPushingEnvironment returns an os environment to allow hooks to work on push
 | 
				
			||||||
func FullPushingEnvironment(author, committer *User, repo *Repository, prID int64) []string {
 | 
					func FullPushingEnvironment(author, committer *User, repo *Repository, repoName string, prID int64) []string {
 | 
				
			||||||
	isWiki := "false"
 | 
						isWiki := "false"
 | 
				
			||||||
	if strings.HasSuffix(repo.Name, ".wiki") {
 | 
						if strings.HasSuffix(repoName, ".wiki") {
 | 
				
			||||||
		isWiki = "true"
 | 
							isWiki = "true"
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -32,7 +32,7 @@ func FullPushingEnvironment(author, committer *User, repo *Repository, prID int6
 | 
				
			|||||||
		"GIT_AUTHOR_EMAIL="+authorSig.Email,
 | 
							"GIT_AUTHOR_EMAIL="+authorSig.Email,
 | 
				
			||||||
		"GIT_COMMITTER_NAME="+committerSig.Name,
 | 
							"GIT_COMMITTER_NAME="+committerSig.Name,
 | 
				
			||||||
		"GIT_COMMITTER_EMAIL="+committerSig.Email,
 | 
							"GIT_COMMITTER_EMAIL="+committerSig.Email,
 | 
				
			||||||
		EnvRepoName+"="+repo.Name,
 | 
							EnvRepoName+"="+repoName,
 | 
				
			||||||
		EnvRepoUsername+"="+repo.MustOwnerName(),
 | 
							EnvRepoUsername+"="+repo.MustOwnerName(),
 | 
				
			||||||
		EnvRepoIsWiki+"="+isWiki,
 | 
							EnvRepoIsWiki+"="+isWiki,
 | 
				
			||||||
		EnvPusherName+"="+committer.Name,
 | 
							EnvPusherName+"="+committer.Name,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1835,3 +1835,22 @@ func (issue *Issue) BlockedByDependencies() ([]*Issue, error) {
 | 
				
			|||||||
func (issue *Issue) BlockingDependencies() ([]*Issue, error) {
 | 
					func (issue *Issue) BlockingDependencies() ([]*Issue, error) {
 | 
				
			||||||
	return issue.getBlockingDependencies(x)
 | 
						return issue.getBlockingDependencies(x)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (issue *Issue) updateClosedNum(e Engine) (err error) {
 | 
				
			||||||
 | 
						if issue.IsPull {
 | 
				
			||||||
 | 
							_, err = e.Exec("UPDATE `repository` SET num_closed_pulls=(SELECT count(*) FROM issue WHERE repo_id=? AND is_pull=? AND is_closed=?) WHERE id=?",
 | 
				
			||||||
 | 
								issue.RepoID,
 | 
				
			||||||
 | 
								true,
 | 
				
			||||||
 | 
								true,
 | 
				
			||||||
 | 
								issue.RepoID,
 | 
				
			||||||
 | 
							)
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							_, err = e.Exec("UPDATE `repository` SET num_closed_issues=(SELECT count(*) FROM issue WHERE repo_id=? AND is_pull=? AND is_closed=?) WHERE id=?",
 | 
				
			||||||
 | 
								issue.RepoID,
 | 
				
			||||||
 | 
								false,
 | 
				
			||||||
 | 
								true,
 | 
				
			||||||
 | 
								issue.RepoID,
 | 
				
			||||||
 | 
							)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -142,11 +142,15 @@ func (issue *Issue) ChangeAssignee(doer *User, assigneeID int64) (err error) {
 | 
				
			|||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return sess.Commit()
 | 
						if err := sess.Commit(); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						go HookQueue.Add(issue.RepoID)
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (issue *Issue) changeAssignee(sess *xorm.Session, doer *User, assigneeID int64, isCreate bool) (err error) {
 | 
					func (issue *Issue) changeAssignee(sess *xorm.Session, doer *User, assigneeID int64, isCreate bool) (err error) {
 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Update the assignee
 | 
						// Update the assignee
 | 
				
			||||||
	removed, err := updateIssueAssignee(sess, issue, assigneeID)
 | 
						removed, err := updateIssueAssignee(sess, issue, assigneeID)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
@@ -209,7 +213,6 @@ func (issue *Issue) changeAssignee(sess *xorm.Session, doer *User, assigneeID in
 | 
				
			|||||||
			return nil
 | 
								return nil
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	go HookQueue.Add(issue.RepoID)
 | 
					 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -632,12 +632,7 @@ func sendCreateCommentAction(e *xorm.Session, opts *CreateCommentOptions, commen
 | 
				
			|||||||
			act.OpType = ActionReopenPullRequest
 | 
								act.OpType = ActionReopenPullRequest
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if opts.Issue.IsPull {
 | 
							if err = opts.Issue.updateClosedNum(e); err != nil {
 | 
				
			||||||
			_, err = e.Exec("UPDATE `repository` SET num_closed_pulls=num_closed_pulls-1 WHERE id=?", opts.Repo.ID)
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			_, err = e.Exec("UPDATE `repository` SET num_closed_issues=num_closed_issues-1 WHERE id=?", opts.Repo.ID)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -647,12 +642,7 @@ func sendCreateCommentAction(e *xorm.Session, opts *CreateCommentOptions, commen
 | 
				
			|||||||
			act.OpType = ActionClosePullRequest
 | 
								act.OpType = ActionClosePullRequest
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if opts.Issue.IsPull {
 | 
							if err = opts.Issue.updateClosedNum(e); err != nil {
 | 
				
			||||||
			_, err = e.Exec("UPDATE `repository` SET num_closed_pulls=num_closed_pulls+1 WHERE id=?", opts.Repo.ID)
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			_, err = e.Exec("UPDATE `repository` SET num_closed_issues=num_closed_issues+1 WHERE id=?", opts.Repo.ID)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -56,7 +56,7 @@ func (l *LFSLock) APIFormat() *api.LFSLock {
 | 
				
			|||||||
	return &api.LFSLock{
 | 
						return &api.LFSLock{
 | 
				
			||||||
		ID:       strconv.FormatInt(l.ID, 10),
 | 
							ID:       strconv.FormatInt(l.ID, 10),
 | 
				
			||||||
		Path:     l.Path,
 | 
							Path:     l.Path,
 | 
				
			||||||
		LockedAt: l.Created,
 | 
							LockedAt: l.Created.Round(time.Second),
 | 
				
			||||||
		Owner: &api.LFSLockOwner{
 | 
							Owner: &api.LFSLockOwner{
 | 
				
			||||||
			Name: l.Owner.DisplayName(),
 | 
								Name: l.Owner.DisplayName(),
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -62,38 +62,50 @@ func insertIssue(sess *xorm.Session, issue *Issue) error {
 | 
				
			|||||||
	if _, err := sess.Insert(issueLabels); err != nil {
 | 
						if _, err := sess.Insert(issueLabels); err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cols := make([]string, 0)
 | 
				
			||||||
	if !issue.IsPull {
 | 
						if !issue.IsPull {
 | 
				
			||||||
		sess.ID(issue.RepoID).Incr("num_issues")
 | 
							sess.ID(issue.RepoID).Incr("num_issues")
 | 
				
			||||||
 | 
							cols = append(cols, "num_issues")
 | 
				
			||||||
		if issue.IsClosed {
 | 
							if issue.IsClosed {
 | 
				
			||||||
			sess.Incr("num_closed_issues")
 | 
								sess.Incr("num_closed_issues")
 | 
				
			||||||
 | 
								cols = append(cols, "num_closed_issues")
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		sess.ID(issue.RepoID).Incr("num_pulls")
 | 
							sess.ID(issue.RepoID).Incr("num_pulls")
 | 
				
			||||||
 | 
							cols = append(cols, "num_pulls")
 | 
				
			||||||
		if issue.IsClosed {
 | 
							if issue.IsClosed {
 | 
				
			||||||
			sess.Incr("num_closed_pulls")
 | 
								sess.Incr("num_closed_pulls")
 | 
				
			||||||
 | 
								cols = append(cols, "num_closed_pulls")
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if _, err := sess.NoAutoTime().Update(issue.Repo); err != nil {
 | 
						if _, err := sess.NoAutoTime().Cols(cols...).Update(issue.Repo); err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cols = []string{"num_issues"}
 | 
				
			||||||
	sess.Incr("num_issues")
 | 
						sess.Incr("num_issues")
 | 
				
			||||||
	if issue.IsClosed {
 | 
						if issue.IsClosed {
 | 
				
			||||||
		sess.Incr("num_closed_issues")
 | 
							sess.Incr("num_closed_issues")
 | 
				
			||||||
 | 
							cols = append(cols, "num_closed_issues")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if _, err := sess.In("id", labelIDs).NoAutoTime().Update(new(Label)); err != nil {
 | 
						if _, err := sess.In("id", labelIDs).NoAutoTime().Cols(cols...).Update(new(Label)); err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if issue.MilestoneID > 0 {
 | 
						if issue.MilestoneID > 0 {
 | 
				
			||||||
 | 
							cols = []string{"num_issues"}
 | 
				
			||||||
		sess.Incr("num_issues")
 | 
							sess.Incr("num_issues")
 | 
				
			||||||
 | 
							cl := "num_closed_issues"
 | 
				
			||||||
		if issue.IsClosed {
 | 
							if issue.IsClosed {
 | 
				
			||||||
			sess.Incr("num_closed_issues")
 | 
								sess.Incr("num_closed_issues")
 | 
				
			||||||
 | 
								cols = append(cols, "num_closed_issues")
 | 
				
			||||||
 | 
								cl = "(num_closed_issues + 1)"
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if _, err := sess.ID(issue.MilestoneID).
 | 
							if _, err := sess.ID(issue.MilestoneID).
 | 
				
			||||||
			SetExpr("completeness", "num_closed_issues * 100 / num_issues").
 | 
								SetExpr("completeness", cl+" * 100 / (num_issues + 1)").
 | 
				
			||||||
			NoAutoTime().
 | 
								NoAutoTime().Cols(cols...).
 | 
				
			||||||
			Update(new(Milestone)); err != nil {
 | 
								Update(new(Milestone)); err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -321,11 +321,25 @@ func dropTableColumns(sess *xorm.Session, tableName string, columnNames ...strin
 | 
				
			|||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		tableSQL := string(res[0]["sql"])
 | 
							tableSQL := string(res[0]["sql"])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Separate out the column definitions
 | 
				
			||||||
		tableSQL = tableSQL[strings.Index(tableSQL, "("):]
 | 
							tableSQL = tableSQL[strings.Index(tableSQL, "("):]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Remove the required columnNames
 | 
				
			||||||
		for _, name := range columnNames {
 | 
							for _, name := range columnNames {
 | 
				
			||||||
			tableSQL = regexp.MustCompile(regexp.QuoteMeta("`"+name+"`")+"[^`,)]*[,)]").ReplaceAllString(tableSQL, "")
 | 
								tableSQL = regexp.MustCompile(regexp.QuoteMeta("`"+name+"`")+"[^`,)]*?[,)]").ReplaceAllString(tableSQL, "")
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Ensure the query is ended properly
 | 
				
			||||||
 | 
							tableSQL = strings.TrimSpace(tableSQL)
 | 
				
			||||||
 | 
							if tableSQL[len(tableSQL)-1] != ')' {
 | 
				
			||||||
 | 
								if tableSQL[len(tableSQL)-1] == ',' {
 | 
				
			||||||
 | 
									tableSQL = tableSQL[:len(tableSQL)-1]
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								tableSQL += ")"
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Find all the columns in the table
 | 
				
			||||||
		columns := regexp.MustCompile("`([^`]*)`").FindAllString(tableSQL, -1)
 | 
							columns := regexp.MustCompile("`([^`]*)`").FindAllString(tableSQL, -1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		tableSQL = fmt.Sprintf("CREATE TABLE `new_%s_new` ", tableName) + tableSQL
 | 
							tableSQL = fmt.Sprintf("CREATE TABLE `new_%s_new` ", tableName) + tableSQL
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,13 +5,7 @@
 | 
				
			|||||||
package migrations
 | 
					package migrations
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"code.gitea.io/gitea/models"
 | 
					 | 
				
			||||||
	"code.gitea.io/gitea/modules/log"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/go-xorm/xorm"
 | 
						"github.com/go-xorm/xorm"
 | 
				
			||||||
	"xorm.io/core"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func renameRepoIsBareToIsEmpty(x *xorm.Engine) error {
 | 
					func renameRepoIsBareToIsEmpty(x *xorm.Engine) error {
 | 
				
			||||||
@@ -21,73 +15,28 @@ func renameRepoIsBareToIsEmpty(x *xorm.Engine) error {
 | 
				
			|||||||
		IsEmpty bool `xorm:"INDEX"`
 | 
							IsEmpty bool `xorm:"INDEX"`
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// First remove the index
 | 
					 | 
				
			||||||
	sess := x.NewSession()
 | 
						sess := x.NewSession()
 | 
				
			||||||
	defer sess.Close()
 | 
						defer sess.Close()
 | 
				
			||||||
	if err := sess.Begin(); err != nil {
 | 
						if err := sess.Begin(); err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var err error
 | 
					 | 
				
			||||||
	if models.DbCfg.Type == core.POSTGRES || models.DbCfg.Type == core.SQLITE {
 | 
					 | 
				
			||||||
		_, err = sess.Exec("DROP INDEX IF EXISTS IDX_repository_is_bare")
 | 
					 | 
				
			||||||
	} else if models.DbCfg.Type == core.MSSQL {
 | 
					 | 
				
			||||||
		_, err = sess.Exec(`DECLARE @ConstraintName VARCHAR(256)
 | 
					 | 
				
			||||||
		DECLARE @SQL NVARCHAR(256)
 | 
					 | 
				
			||||||
		SELECT @ConstraintName = obj.name FROM sys.columns col LEFT OUTER JOIN sys.objects obj ON obj.object_id = col.default_object_id AND obj.type = 'D' WHERE col.object_id = OBJECT_ID('repository') AND obj.name IS NOT NULL AND col.name = 'is_bare'
 | 
					 | 
				
			||||||
		SET @SQL = N'ALTER TABLE [repository] DROP CONSTRAINT [' + @ConstraintName + N']'
 | 
					 | 
				
			||||||
		EXEC sp_executesql @SQL`)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	} else if models.DbCfg.Type == core.MYSQL {
 | 
					 | 
				
			||||||
		indexes, err := sess.QueryString(`SHOW INDEX FROM repository WHERE KEY_NAME = 'IDX_repository_is_bare'`)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if len(indexes) >= 1 {
 | 
					 | 
				
			||||||
			_, err = sess.Exec("DROP INDEX IDX_repository_is_bare ON repository")
 | 
					 | 
				
			||||||
			if err != nil {
 | 
					 | 
				
			||||||
				return fmt.Errorf("Drop index failed: %v", err)
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		_, err = sess.Exec("DROP INDEX IDX_repository_is_bare ON repository")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return fmt.Errorf("Drop index failed: %v", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if err = sess.Commit(); err != nil {
 | 
					 | 
				
			||||||
		return err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if err := sess.Begin(); err != nil {
 | 
					 | 
				
			||||||
		return err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if err := sess.Sync2(new(Repository)); err != nil {
 | 
						if err := sess.Sync2(new(Repository)); err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if _, err := sess.Exec("UPDATE repository SET is_empty = is_bare;"); err != nil {
 | 
						if _, err := sess.Exec("UPDATE repository SET is_empty = is_bare;"); err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if err := sess.Commit(); err != nil {
 | 
				
			||||||
	if models.DbCfg.Type != core.SQLITE {
 | 
					 | 
				
			||||||
		_, err = sess.Exec("ALTER TABLE repository DROP COLUMN is_bare")
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return fmt.Errorf("Drop column failed: %v", err)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if err = sess.Commit(); err != nil {
 | 
					 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if models.DbCfg.Type == core.SQLITE {
 | 
						if err := sess.Begin(); err != nil {
 | 
				
			||||||
		log.Warn("TABLE repository's COLUMN is_bare should be DROP but sqlite is not supported, you could manually do that.")
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return nil
 | 
						if err := dropTableColumns(sess, "repository", "is_bare"); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return sess.Commit()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,9 +8,7 @@ import (
 | 
				
			|||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/go-xorm/xorm"
 | 
						"github.com/go-xorm/xorm"
 | 
				
			||||||
	"xorm.io/core"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"code.gitea.io/gitea/models"
 | 
					 | 
				
			||||||
	"code.gitea.io/gitea/modules/generate"
 | 
						"code.gitea.io/gitea/modules/generate"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/log"
 | 
						"code.gitea.io/gitea/modules/log"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/util"
 | 
						"code.gitea.io/gitea/modules/util"
 | 
				
			||||||
@@ -37,41 +35,6 @@ func hashAppToken(x *xorm.Engine) error {
 | 
				
			|||||||
	// First remove the index
 | 
						// First remove the index
 | 
				
			||||||
	sess := x.NewSession()
 | 
						sess := x.NewSession()
 | 
				
			||||||
	defer sess.Close()
 | 
						defer sess.Close()
 | 
				
			||||||
	if err := sess.Begin(); err != nil {
 | 
					 | 
				
			||||||
		return err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	var err error
 | 
					 | 
				
			||||||
	if models.DbCfg.Type == core.POSTGRES || models.DbCfg.Type == core.SQLITE {
 | 
					 | 
				
			||||||
		_, err = sess.Exec("DROP INDEX IF EXISTS UQE_access_token_sha1")
 | 
					 | 
				
			||||||
	} else if models.DbCfg.Type == core.MSSQL {
 | 
					 | 
				
			||||||
		_, err = sess.Exec(`DECLARE @ConstraintName VARCHAR(256)
 | 
					 | 
				
			||||||
		DECLARE @SQL NVARCHAR(256)
 | 
					 | 
				
			||||||
		SELECT @ConstraintName = obj.name FROM sys.columns col LEFT OUTER JOIN sys.objects obj ON obj.object_id = col.default_object_id AND obj.type = 'D' WHERE col.object_id = OBJECT_ID('access_token') AND obj.name IS NOT NULL AND col.name = 'sha1'
 | 
					 | 
				
			||||||
		SET @SQL = N'ALTER TABLE [access_token] DROP CONSTRAINT [' + @ConstraintName + N']'
 | 
					 | 
				
			||||||
		EXEC sp_executesql @SQL`)
 | 
					 | 
				
			||||||
	} else if models.DbCfg.Type == core.MYSQL {
 | 
					 | 
				
			||||||
		indexes, err := sess.QueryString(`SHOW INDEX FROM access_token WHERE KEY_NAME = 'UQE_access_token_sha1'`)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if len(indexes) >= 1 {
 | 
					 | 
				
			||||||
			_, err = sess.Exec("DROP INDEX UQE_access_token_sha1 ON access_token")
 | 
					 | 
				
			||||||
			if err != nil {
 | 
					 | 
				
			||||||
				return err
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		_, err = sess.Exec("DROP INDEX UQE_access_token_sha1 ON access_token")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return fmt.Errorf("Drop index failed: %v", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if err = sess.Commit(); err != nil {
 | 
					 | 
				
			||||||
		return err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := sess.Begin(); err != nil {
 | 
						if err := sess.Begin(); err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
@@ -81,7 +44,7 @@ func hashAppToken(x *xorm.Engine) error {
 | 
				
			|||||||
		return fmt.Errorf("Sync2: %v", err)
 | 
							return fmt.Errorf("Sync2: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err = sess.Commit(); err != nil {
 | 
						if err := sess.Commit(); err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -755,11 +755,14 @@ func IsUserInTeams(userID int64, teamIDs []int64) (bool, error) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// UsersInTeamsCount counts the number of users which are in userIDs and teamIDs
 | 
					// UsersInTeamsCount counts the number of users which are in userIDs and teamIDs
 | 
				
			||||||
func UsersInTeamsCount(userIDs []int64, teamIDs []int64) (count int64, err error) {
 | 
					func UsersInTeamsCount(userIDs []int64, teamIDs []int64) (int64, error) {
 | 
				
			||||||
	if count, err = x.In("uid", userIDs).In("team_id", teamIDs).Count(new(TeamUser)); err != nil {
 | 
						var ids []int64
 | 
				
			||||||
 | 
						if err := x.In("uid", userIDs).In("team_id", teamIDs).
 | 
				
			||||||
 | 
							Table("team_user").
 | 
				
			||||||
 | 
							Cols("uid").GroupBy("uid").Find(&ids); err != nil {
 | 
				
			||||||
		return 0, err
 | 
							return 0, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return
 | 
						return int64(len(ids)), nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ___________                  __________
 | 
					// ___________                  __________
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -370,7 +370,7 @@ func TestUsersInTeamsCount(t *testing.T) {
 | 
				
			|||||||
		assert.Equal(t, expected, count)
 | 
							assert.Equal(t, expected, count)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	test([]int64{2}, []int64{1, 2, 3, 4}, 2)
 | 
						test([]int64{2}, []int64{1, 2, 3, 4}, 1)          // only userid 2
 | 
				
			||||||
	test([]int64{1, 2, 3, 4, 5}, []int64{2, 5}, 2)
 | 
						test([]int64{1, 2, 3, 4, 5}, []int64{2, 5}, 2)    // userid 2,4
 | 
				
			||||||
	test([]int64{1, 2, 3, 4, 5}, []int64{2, 3, 5}, 3)
 | 
						test([]int64{1, 2, 3, 4, 5}, []int64{2, 3, 5}, 3) // userid 2,4,5
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										107
									
								
								models/pull.go
									
									
									
									
									
								
							
							
						
						
									
										107
									
								
								models/pull.go
									
									
									
									
									
								
							@@ -189,36 +189,6 @@ func (pr *PullRequest) apiFormat(e Engine) *api.PullRequest {
 | 
				
			|||||||
			return nil
 | 
								return nil
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if baseBranch, err = pr.BaseRepo.GetBranch(pr.BaseBranch); err != nil {
 | 
					 | 
				
			||||||
		log.Error("pr.BaseRepo.GetBranch[%d]: %v", pr.BaseBranch, err)
 | 
					 | 
				
			||||||
		return nil
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if baseCommit, err = baseBranch.GetCommit(); err != nil {
 | 
					 | 
				
			||||||
		log.Error("baseBranch.GetCommit[%d]: %v", pr.ID, err)
 | 
					 | 
				
			||||||
		return nil
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if headBranch, err = pr.HeadRepo.GetBranch(pr.HeadBranch); err != nil {
 | 
					 | 
				
			||||||
		log.Error("pr.HeadRepo.GetBranch[%d]: %v", pr.HeadBranch, err)
 | 
					 | 
				
			||||||
		return nil
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if headCommit, err = headBranch.GetCommit(); err != nil {
 | 
					 | 
				
			||||||
		log.Error("headBranch.GetCommit[%d]: %v", pr.ID, err)
 | 
					 | 
				
			||||||
		return nil
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	apiBaseBranchInfo := &api.PRBranchInfo{
 | 
					 | 
				
			||||||
		Name:       pr.BaseBranch,
 | 
					 | 
				
			||||||
		Ref:        pr.BaseBranch,
 | 
					 | 
				
			||||||
		Sha:        baseCommit.ID.String(),
 | 
					 | 
				
			||||||
		RepoID:     pr.BaseRepoID,
 | 
					 | 
				
			||||||
		Repository: pr.BaseRepo.innerAPIFormat(e, AccessModeNone, false),
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	apiHeadBranchInfo := &api.PRBranchInfo{
 | 
					 | 
				
			||||||
		Name:       pr.HeadBranch,
 | 
					 | 
				
			||||||
		Ref:        pr.HeadBranch,
 | 
					 | 
				
			||||||
		Sha:        headCommit.ID.String(),
 | 
					 | 
				
			||||||
		RepoID:     pr.HeadRepoID,
 | 
					 | 
				
			||||||
		Repository: pr.HeadRepo.innerAPIFormat(e, AccessModeNone, false),
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err = pr.Issue.loadRepo(e); err != nil {
 | 
						if err = pr.Issue.loadRepo(e); err != nil {
 | 
				
			||||||
		log.Error("pr.Issue.loadRepo[%d]: %v", pr.ID, err)
 | 
							log.Error("pr.Issue.loadRepo[%d]: %v", pr.ID, err)
 | 
				
			||||||
@@ -227,6 +197,7 @@ func (pr *PullRequest) apiFormat(e Engine) *api.PullRequest {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	apiPullRequest := &api.PullRequest{
 | 
						apiPullRequest := &api.PullRequest{
 | 
				
			||||||
		ID:        pr.ID,
 | 
							ID:        pr.ID,
 | 
				
			||||||
 | 
							URL:       pr.Issue.HTMLURL(),
 | 
				
			||||||
		Index:     pr.Index,
 | 
							Index:     pr.Index,
 | 
				
			||||||
		Poster:    apiIssue.Poster,
 | 
							Poster:    apiIssue.Poster,
 | 
				
			||||||
		Title:     apiIssue.Title,
 | 
							Title:     apiIssue.Title,
 | 
				
			||||||
@@ -241,13 +212,68 @@ func (pr *PullRequest) apiFormat(e Engine) *api.PullRequest {
 | 
				
			|||||||
		DiffURL:   pr.Issue.DiffURL(),
 | 
							DiffURL:   pr.Issue.DiffURL(),
 | 
				
			||||||
		PatchURL:  pr.Issue.PatchURL(),
 | 
							PatchURL:  pr.Issue.PatchURL(),
 | 
				
			||||||
		HasMerged: pr.HasMerged,
 | 
							HasMerged: pr.HasMerged,
 | 
				
			||||||
		Base:      apiBaseBranchInfo,
 | 
					 | 
				
			||||||
		Head:      apiHeadBranchInfo,
 | 
					 | 
				
			||||||
		MergeBase: pr.MergeBase,
 | 
							MergeBase: pr.MergeBase,
 | 
				
			||||||
		Deadline:  apiIssue.Deadline,
 | 
							Deadline:  apiIssue.Deadline,
 | 
				
			||||||
		Created:   pr.Issue.CreatedUnix.AsTimePtr(),
 | 
							Created:   pr.Issue.CreatedUnix.AsTimePtr(),
 | 
				
			||||||
		Updated:   pr.Issue.UpdatedUnix.AsTimePtr(),
 | 
							Updated:   pr.Issue.UpdatedUnix.AsTimePtr(),
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						baseBranch, err = pr.BaseRepo.GetBranch(pr.BaseBranch)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							if git.IsErrBranchNotExist(err) {
 | 
				
			||||||
 | 
								apiPullRequest.Base = nil
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								log.Error("GetBranch[%s]: %v", pr.BaseBranch, err)
 | 
				
			||||||
 | 
								return nil
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							apiBaseBranchInfo := &api.PRBranchInfo{
 | 
				
			||||||
 | 
								Name:       pr.BaseBranch,
 | 
				
			||||||
 | 
								Ref:        pr.BaseBranch,
 | 
				
			||||||
 | 
								RepoID:     pr.BaseRepoID,
 | 
				
			||||||
 | 
								Repository: pr.BaseRepo.innerAPIFormat(e, AccessModeNone, false),
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							baseCommit, err = baseBranch.GetCommit()
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								if git.IsErrNotExist(err) {
 | 
				
			||||||
 | 
									apiBaseBranchInfo.Sha = ""
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									log.Error("GetCommit[%s]: %v", baseBranch.Name, err)
 | 
				
			||||||
 | 
									return nil
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								apiBaseBranchInfo.Sha = baseCommit.ID.String()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							apiPullRequest.Base = apiBaseBranchInfo
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						headBranch, err = pr.HeadRepo.GetBranch(pr.HeadBranch)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							if git.IsErrBranchNotExist(err) {
 | 
				
			||||||
 | 
								apiPullRequest.Head = nil
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								log.Error("GetBranch[%s]: %v", pr.HeadBranch, err)
 | 
				
			||||||
 | 
								return nil
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							apiHeadBranchInfo := &api.PRBranchInfo{
 | 
				
			||||||
 | 
								Name:       pr.HeadBranch,
 | 
				
			||||||
 | 
								Ref:        pr.HeadBranch,
 | 
				
			||||||
 | 
								RepoID:     pr.HeadRepoID,
 | 
				
			||||||
 | 
								Repository: pr.HeadRepo.innerAPIFormat(e, AccessModeNone, false),
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							headCommit, err = headBranch.GetCommit()
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								if git.IsErrNotExist(err) {
 | 
				
			||||||
 | 
									apiHeadBranchInfo.Sha = ""
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									log.Error("GetCommit[%s]: %v", headBranch.Name, err)
 | 
				
			||||||
 | 
									return nil
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								apiHeadBranchInfo.Sha = headCommit.ID.String()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							apiPullRequest.Head = apiHeadBranchInfo
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if pr.Status != PullRequestStatusChecking {
 | 
						if pr.Status != PullRequestStatusChecking {
 | 
				
			||||||
		mergeable := pr.Status != PullRequestStatusConflict && !pr.IsWorkInProgress()
 | 
							mergeable := pr.Status != PullRequestStatusConflict && !pr.IsWorkInProgress()
 | 
				
			||||||
@@ -572,7 +598,7 @@ func (pr *PullRequest) testPatch(e Engine) (err error) {
 | 
				
			|||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		for i := range patchConflicts {
 | 
							for i := range patchConflicts {
 | 
				
			||||||
			if strings.Contains(stderr, patchConflicts[i]) {
 | 
								if strings.Contains(stderr, patchConflicts[i]) {
 | 
				
			||||||
				log.Trace("PullRequest[%d].testPatch (apply): has conflict", pr.ID)
 | 
									log.Trace("PullRequest[%d].testPatch (apply): has conflict: %s", pr.ID, stderr)
 | 
				
			||||||
				const prefix = "error: patch failed:"
 | 
									const prefix = "error: patch failed:"
 | 
				
			||||||
				pr.Status = PullRequestStatusConflict
 | 
									pr.Status = PullRequestStatusConflict
 | 
				
			||||||
				pr.ConflictedFiles = make([]string, 0, 5)
 | 
									pr.ConflictedFiles = make([]string, 0, 5)
 | 
				
			||||||
@@ -635,13 +661,16 @@ func NewPullRequest(repo *Repository, pull *Issue, labelIDs []int64, uuids []str
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pr.Index = pull.Index
 | 
						pr.Index = pull.Index
 | 
				
			||||||
	if err = repo.savePatch(sess, pr.Index, patch); err != nil {
 | 
					 | 
				
			||||||
		return fmt.Errorf("SavePatch: %v", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	pr.BaseRepo = repo
 | 
						pr.BaseRepo = repo
 | 
				
			||||||
	if err = pr.testPatch(sess); err != nil {
 | 
						pr.Status = PullRequestStatusChecking
 | 
				
			||||||
		return fmt.Errorf("testPatch: %v", err)
 | 
						if len(patch) > 0 {
 | 
				
			||||||
 | 
							if err = repo.savePatch(sess, pr.Index, patch); err != nil {
 | 
				
			||||||
 | 
								return fmt.Errorf("SavePatch: %v", err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if err = pr.testPatch(sess); err != nil {
 | 
				
			||||||
 | 
								return fmt.Errorf("testPatch: %v", err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	// No conflict appears after test means mergeable.
 | 
						// No conflict appears after test means mergeable.
 | 
				
			||||||
	if pr.Status == PullRequestStatusChecking {
 | 
						if pr.Status == PullRequestStatusChecking {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -31,7 +31,15 @@ func TestPullRequest_LoadIssue(t *testing.T) {
 | 
				
			|||||||
	assert.Equal(t, int64(2), pr.Issue.ID)
 | 
						assert.Equal(t, int64(2), pr.Issue.ID)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// TODO TestPullRequest_APIFormat
 | 
					func TestPullRequest_APIFormat(t *testing.T) {
 | 
				
			||||||
 | 
						assert.NoError(t, PrepareTestDatabase())
 | 
				
			||||||
 | 
						pr := AssertExistsAndLoadBean(t, &PullRequest{ID: 1}).(*PullRequest)
 | 
				
			||||||
 | 
						assert.NoError(t, pr.LoadAttributes())
 | 
				
			||||||
 | 
						assert.NoError(t, pr.LoadIssue())
 | 
				
			||||||
 | 
						apiPullRequest := pr.APIFormat()
 | 
				
			||||||
 | 
						assert.NotNil(t, apiPullRequest)
 | 
				
			||||||
 | 
						assert.Nil(t, apiPullRequest.Head)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestPullRequest_GetBaseRepo(t *testing.T) {
 | 
					func TestPullRequest_GetBaseRepo(t *testing.T) {
 | 
				
			||||||
	assert.NoError(t, PrepareTestDatabase())
 | 
						assert.NoError(t, PrepareTestDatabase())
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -409,7 +409,7 @@ func UpdateRelease(doer *User, gitRepo *git.Repository, rel *Release, attachment
 | 
				
			|||||||
		Action:     api.HookReleaseUpdated,
 | 
							Action:     api.HookReleaseUpdated,
 | 
				
			||||||
		Release:    rel.APIFormat(),
 | 
							Release:    rel.APIFormat(),
 | 
				
			||||||
		Repository: rel.Repo.APIFormat(mode),
 | 
							Repository: rel.Repo.APIFormat(mode),
 | 
				
			||||||
		Sender:     rel.Publisher.APIFormat(),
 | 
							Sender:     doer.APIFormat(),
 | 
				
			||||||
	}); err1 != nil {
 | 
						}); err1 != nil {
 | 
				
			||||||
		log.Error("PrepareWebhooks: %v", err)
 | 
							log.Error("PrepareWebhooks: %v", err)
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
@@ -420,7 +420,7 @@ func UpdateRelease(doer *User, gitRepo *git.Repository, rel *Release, attachment
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// DeleteReleaseByID deletes a release and corresponding Git tag by given ID.
 | 
					// DeleteReleaseByID deletes a release and corresponding Git tag by given ID.
 | 
				
			||||||
func DeleteReleaseByID(id int64, u *User, delTag bool) error {
 | 
					func DeleteReleaseByID(id int64, doer *User, delTag bool) error {
 | 
				
			||||||
	rel, err := GetReleaseByID(id)
 | 
						rel, err := GetReleaseByID(id)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return fmt.Errorf("GetReleaseByID: %v", err)
 | 
							return fmt.Errorf("GetReleaseByID: %v", err)
 | 
				
			||||||
@@ -459,12 +459,12 @@ func DeleteReleaseByID(id int64, u *User, delTag bool) error {
 | 
				
			|||||||
		return fmt.Errorf("LoadAttributes: %v", err)
 | 
							return fmt.Errorf("LoadAttributes: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mode, _ := AccessLevel(u, rel.Repo)
 | 
						mode, _ := AccessLevel(doer, rel.Repo)
 | 
				
			||||||
	if err := PrepareWebhooks(rel.Repo, HookEventRelease, &api.ReleasePayload{
 | 
						if err := PrepareWebhooks(rel.Repo, HookEventRelease, &api.ReleasePayload{
 | 
				
			||||||
		Action:     api.HookReleaseDeleted,
 | 
							Action:     api.HookReleaseDeleted,
 | 
				
			||||||
		Release:    rel.APIFormat(),
 | 
							Release:    rel.APIFormat(),
 | 
				
			||||||
		Repository: rel.Repo.APIFormat(mode),
 | 
							Repository: rel.Repo.APIFormat(mode),
 | 
				
			||||||
		Sender:     rel.Publisher.APIFormat(),
 | 
							Sender:     doer.APIFormat(),
 | 
				
			||||||
	}); err != nil {
 | 
						}); err != nil {
 | 
				
			||||||
		log.Error("PrepareWebhooks: %v", err)
 | 
							log.Error("PrepareWebhooks: %v", err)
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -134,8 +134,8 @@ type Repository struct {
 | 
				
			|||||||
	Owner         *User  `xorm:"-"`
 | 
						Owner         *User  `xorm:"-"`
 | 
				
			||||||
	LowerName     string `xorm:"UNIQUE(s) INDEX NOT NULL"`
 | 
						LowerName     string `xorm:"UNIQUE(s) INDEX NOT NULL"`
 | 
				
			||||||
	Name          string `xorm:"INDEX NOT NULL"`
 | 
						Name          string `xorm:"INDEX NOT NULL"`
 | 
				
			||||||
	Description   string
 | 
						Description   string `xorm:"TEXT"`
 | 
				
			||||||
	Website       string
 | 
						Website       string `xorm:"VARCHAR(2048)"`
 | 
				
			||||||
	DefaultBranch string
 | 
						DefaultBranch string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	NumWatches          int
 | 
						NumWatches          int
 | 
				
			||||||
@@ -1324,7 +1324,6 @@ func createRepository(e *xorm.Session, doer, u *User, repo *Repository) (err err
 | 
				
			|||||||
		}); err != nil {
 | 
							}); err != nil {
 | 
				
			||||||
			return fmt.Errorf("prepareWebhooks: %v", err)
 | 
								return fmt.Errorf("prepareWebhooks: %v", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		go HookQueue.Add(repo.ID)
 | 
					 | 
				
			||||||
	} else if err = repo.recalculateAccesses(e); err != nil {
 | 
						} else if err = repo.recalculateAccesses(e); err != nil {
 | 
				
			||||||
		// Organization automatically called this in addRepository method.
 | 
							// Organization automatically called this in addRepository method.
 | 
				
			||||||
		return fmt.Errorf("recalculateAccesses: %v", err)
 | 
							return fmt.Errorf("recalculateAccesses: %v", err)
 | 
				
			||||||
@@ -1393,7 +1392,16 @@ func CreateRepository(doer, u *User, opts CreateRepoOptions) (_ *Repository, err
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return repo, sess.Commit()
 | 
						if err = sess.Commit(); err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Add to hook queue for created repo after session commit.
 | 
				
			||||||
 | 
						if u.IsOrganization() {
 | 
				
			||||||
 | 
							go HookQueue.Add(repo.ID)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return repo, err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func countRepositories(userID int64, private bool) int64 {
 | 
					func countRepositories(userID int64, private bool) int64 {
 | 
				
			||||||
@@ -1783,6 +1791,7 @@ func DeleteRepository(doer *User, uid, repoID int64) error {
 | 
				
			|||||||
		&HookTask{RepoID: repoID},
 | 
							&HookTask{RepoID: repoID},
 | 
				
			||||||
		&Notification{RepoID: repoID},
 | 
							&Notification{RepoID: repoID},
 | 
				
			||||||
		&CommitStatus{RepoID: repoID},
 | 
							&CommitStatus{RepoID: repoID},
 | 
				
			||||||
 | 
							&RepoIndexerStatus{RepoID: repoID},
 | 
				
			||||||
	); err != nil {
 | 
						); err != nil {
 | 
				
			||||||
		return fmt.Errorf("deleteBeans: %v", err)
 | 
							return fmt.Errorf("deleteBeans: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -2327,6 +2336,23 @@ func CheckRepoStats() {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	// ***** END: Repository.NumClosedIssues *****
 | 
						// ***** END: Repository.NumClosedIssues *****
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// ***** START: Repository.NumClosedPulls *****
 | 
				
			||||||
 | 
						desc = "repository count 'num_closed_pulls'"
 | 
				
			||||||
 | 
						results, err = x.Query("SELECT repo.id FROM `repository` repo WHERE repo.num_closed_pulls!=(SELECT COUNT(*) FROM `issue` WHERE repo_id=repo.id AND is_closed=? AND is_pull=?)", true, true)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Error("Select %s: %v", desc, err)
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							for _, result := range results {
 | 
				
			||||||
 | 
								id := com.StrTo(result["id"]).MustInt64()
 | 
				
			||||||
 | 
								log.Trace("Updating %s: %d", desc, id)
 | 
				
			||||||
 | 
								_, err = x.Exec("UPDATE `repository` SET num_closed_pulls=(SELECT COUNT(*) FROM `issue` WHERE repo_id=? AND is_closed=? AND is_pull=?) WHERE id=?", id, true, true, id)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									log.Error("Update %s[%d]: %v", desc, id, err)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// ***** END: Repository.NumClosedPulls *****
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// FIXME: use checker when stop supporting old fork repo format.
 | 
						// FIXME: use checker when stop supporting old fork repo format.
 | 
				
			||||||
	// ***** START: Repository.NumForks *****
 | 
						// ***** START: Repository.NumForks *****
 | 
				
			||||||
	results, err = x.Query("SELECT repo.id FROM `repository` repo WHERE repo.num_forks!=(SELECT COUNT(*) FROM `repository` WHERE fork_id=repo.id)")
 | 
						results, err = x.Query("SELECT repo.id FROM `repository` repo WHERE repo.num_forks!=(SELECT COUNT(*) FROM `repository` WHERE fork_id=repo.id)")
 | 
				
			||||||
@@ -2461,6 +2487,11 @@ func ForkRepository(doer, u *User, oldRepo *Repository, name, desc string) (_ *R
 | 
				
			|||||||
		go HookQueue.Add(oldRepo.ID)
 | 
							go HookQueue.Add(oldRepo.ID)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Add to hook queue for created repo after session commit.
 | 
				
			||||||
 | 
						if u.IsOrganization() {
 | 
				
			||||||
 | 
							go HookQueue.Add(repo.ID)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err = repo.UpdateSize(); err != nil {
 | 
						if err = repo.UpdateSize(); err != nil {
 | 
				
			||||||
		log.Error("Failed to update size for repository: %v", err)
 | 
							log.Error("Failed to update size for repository: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -199,7 +199,7 @@ func addUpdate(update fileUpdate, repo *Repository, batch rupture.FlushingBatch)
 | 
				
			|||||||
	if size, err := strconv.Atoi(strings.TrimSpace(stdout)); err != nil {
 | 
						if size, err := strconv.Atoi(strings.TrimSpace(stdout)); err != nil {
 | 
				
			||||||
		return fmt.Errorf("Misformatted git cat-file output: %v", err)
 | 
							return fmt.Errorf("Misformatted git cat-file output: %v", err)
 | 
				
			||||||
	} else if int64(size) > setting.Indexer.MaxIndexerFileSize {
 | 
						} else if int64(size) > setting.Indexer.MaxIndexerFileSize {
 | 
				
			||||||
		return nil
 | 
							return addDelete(update.Filename, repo, batch)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fileContents, err := git.NewCommand("cat-file", "blob", update.BlobSha).
 | 
						fileContents, err := git.NewCommand("cat-file", "blob", update.BlobSha).
 | 
				
			||||||
@@ -231,20 +231,28 @@ func addDelete(filename string, repo *Repository, batch rupture.FlushingBatch) e
 | 
				
			|||||||
	return indexerUpdate.AddToFlushingBatch(batch)
 | 
						return indexerUpdate.AddToFlushingBatch(batch)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func isIndexable(entry *git.TreeEntry) bool {
 | 
				
			||||||
 | 
						return entry.IsRegular() || entry.IsExecutable()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// parseGitLsTreeOutput parses the output of a `git ls-tree -r --full-name` command
 | 
					// parseGitLsTreeOutput parses the output of a `git ls-tree -r --full-name` command
 | 
				
			||||||
func parseGitLsTreeOutput(stdout []byte) ([]fileUpdate, error) {
 | 
					func parseGitLsTreeOutput(stdout []byte) ([]fileUpdate, error) {
 | 
				
			||||||
	entries, err := git.ParseTreeEntries(stdout)
 | 
						entries, err := git.ParseTreeEntries(stdout)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						var idxCount = 0
 | 
				
			||||||
	updates := make([]fileUpdate, len(entries))
 | 
						updates := make([]fileUpdate, len(entries))
 | 
				
			||||||
	for i, entry := range entries {
 | 
						for _, entry := range entries {
 | 
				
			||||||
		updates[i] = fileUpdate{
 | 
							if isIndexable(entry) {
 | 
				
			||||||
			Filename: entry.Name(),
 | 
								updates[idxCount] = fileUpdate{
 | 
				
			||||||
			BlobSha:  entry.ID.String(),
 | 
									Filename: entry.Name(),
 | 
				
			||||||
 | 
									BlobSha:  entry.ID.String(),
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								idxCount++
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return updates, nil
 | 
						return updates[:idxCount], nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// genesisChanges get changes to add repo to the indexer for the first time
 | 
					// genesisChanges get changes to add repo to the indexer for the first time
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -642,12 +642,14 @@ func rewriteAllPublicKeys(e Engine) error {
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
			_, err = t.WriteString(line + "\n")
 | 
								_, err = t.WriteString(line + "\n")
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
 | 
									f.Close()
 | 
				
			||||||
				return err
 | 
									return err
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		defer f.Close()
 | 
							f.Close()
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						t.Close()
 | 
				
			||||||
	return os.Rename(tmpPath, fPath)
 | 
						return os.Rename(tmpPath, fPath)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -195,9 +195,9 @@ func (u *User) UpdateTheme(themeName string) error {
 | 
				
			|||||||
	return UpdateUserCols(u, "theme")
 | 
						return UpdateUserCols(u, "theme")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// getEmail returns an noreply email, if the user has set to keep his
 | 
					// GetEmail returns an noreply email, if the user has set to keep his
 | 
				
			||||||
// email address private, otherwise the primary email address.
 | 
					// email address private, otherwise the primary email address.
 | 
				
			||||||
func (u *User) getEmail() string {
 | 
					func (u *User) GetEmail() string {
 | 
				
			||||||
	if u.KeepEmailPrivate {
 | 
						if u.KeepEmailPrivate {
 | 
				
			||||||
		return fmt.Sprintf("%s@%s", u.LowerName, setting.Service.NoReplyAddress)
 | 
							return fmt.Sprintf("%s@%s", u.LowerName, setting.Service.NoReplyAddress)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -210,7 +210,7 @@ func (u *User) APIFormat() *api.User {
 | 
				
			|||||||
		ID:        u.ID,
 | 
							ID:        u.ID,
 | 
				
			||||||
		UserName:  u.Name,
 | 
							UserName:  u.Name,
 | 
				
			||||||
		FullName:  u.FullName,
 | 
							FullName:  u.FullName,
 | 
				
			||||||
		Email:     u.getEmail(),
 | 
							Email:     u.GetEmail(),
 | 
				
			||||||
		AvatarURL: u.AvatarLink(),
 | 
							AvatarURL: u.AvatarLink(),
 | 
				
			||||||
		Language:  u.Language,
 | 
							Language:  u.Language,
 | 
				
			||||||
		IsAdmin:   u.IsAdmin,
 | 
							IsAdmin:   u.IsAdmin,
 | 
				
			||||||
@@ -425,7 +425,7 @@ func (u *User) GetFollowing(page int) ([]*User, error) {
 | 
				
			|||||||
func (u *User) NewGitSig() *git.Signature {
 | 
					func (u *User) NewGitSig() *git.Signature {
 | 
				
			||||||
	return &git.Signature{
 | 
						return &git.Signature{
 | 
				
			||||||
		Name:  u.GitName(),
 | 
							Name:  u.GitName(),
 | 
				
			||||||
		Email: u.getEmail(),
 | 
							Email: u.GetEmail(),
 | 
				
			||||||
		When:  time.Now(),
 | 
							When:  time.Now(),
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -751,6 +751,7 @@ var (
 | 
				
			|||||||
		"robots.txt",
 | 
							"robots.txt",
 | 
				
			||||||
		".",
 | 
							".",
 | 
				
			||||||
		"..",
 | 
							"..",
 | 
				
			||||||
 | 
							".well-known",
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	reservedUserPatterns = []string{"*.keys", "*.gpg"}
 | 
						reservedUserPatterns = []string{"*.keys", "*.gpg"}
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -1375,9 +1376,7 @@ type SearchUserOptions struct {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (opts *SearchUserOptions) toConds() builder.Cond {
 | 
					func (opts *SearchUserOptions) toConds() builder.Cond {
 | 
				
			||||||
 | 
						var cond builder.Cond = builder.Eq{"type": opts.Type}
 | 
				
			||||||
	var cond = builder.NewCond()
 | 
					 | 
				
			||||||
	cond = cond.And(builder.Eq{"type": opts.Type})
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if len(opts.Keyword) > 0 {
 | 
						if len(opts.Keyword) > 0 {
 | 
				
			||||||
		lowerKeyword := strings.ToLower(opts.Keyword)
 | 
							lowerKeyword := strings.ToLower(opts.Keyword)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -890,7 +890,6 @@ func DeliverHooks() {
 | 
				
			|||||||
	for _, t := range tasks {
 | 
						for _, t := range tasks {
 | 
				
			||||||
		if err = t.deliver(); err != nil {
 | 
							if err = t.deliver(); err != nil {
 | 
				
			||||||
			log.Error("deliver: %v", err)
 | 
								log.Error("deliver: %v", err)
 | 
				
			||||||
			continue
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -120,8 +120,8 @@ func getSlackDeletePayload(p *api.DeletePayload, slack *SlackMeta) (*SlackPayloa
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// getSlackForkPayload composes Slack payload for forked by a repository.
 | 
					// getSlackForkPayload composes Slack payload for forked by a repository.
 | 
				
			||||||
func getSlackForkPayload(p *api.ForkPayload, slack *SlackMeta) (*SlackPayload, error) {
 | 
					func getSlackForkPayload(p *api.ForkPayload, slack *SlackMeta) (*SlackPayload, error) {
 | 
				
			||||||
	baseLink := SlackLinkFormatter(p.Repo.HTMLURL, p.Repo.Name)
 | 
						baseLink := SlackLinkFormatter(p.Forkee.HTMLURL, p.Forkee.FullName)
 | 
				
			||||||
	forkLink := SlackLinkFormatter(p.Forkee.HTMLURL, p.Forkee.FullName)
 | 
						forkLink := SlackLinkFormatter(p.Repo.HTMLURL, p.Repo.FullName)
 | 
				
			||||||
	text := fmt.Sprintf("%s is forked to %s", baseLink, forkLink)
 | 
						text := fmt.Sprintf("%s is forked to %s", baseLink, forkLink)
 | 
				
			||||||
	return &SlackPayload{
 | 
						return &SlackPayload{
 | 
				
			||||||
		Channel:  slack.Channel,
 | 
							Channel:  slack.Channel,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -217,7 +217,13 @@ func (repo *Repository) updateWikiPage(doer *User, oldWikiName, newWikiName, con
 | 
				
			|||||||
	if err := git.Push(basePath, git.PushOptions{
 | 
						if err := git.Push(basePath, git.PushOptions{
 | 
				
			||||||
		Remote: "origin",
 | 
							Remote: "origin",
 | 
				
			||||||
		Branch: fmt.Sprintf("%s:%s%s", commitHash.String(), git.BranchPrefix, "master"),
 | 
							Branch: fmt.Sprintf("%s:%s%s", commitHash.String(), git.BranchPrefix, "master"),
 | 
				
			||||||
		Env:    PushingEnvironment(doer, repo),
 | 
							Env: FullPushingEnvironment(
 | 
				
			||||||
 | 
								doer,
 | 
				
			||||||
 | 
								doer,
 | 
				
			||||||
 | 
								repo,
 | 
				
			||||||
 | 
								repo.Name+".wiki",
 | 
				
			||||||
 | 
								0,
 | 
				
			||||||
 | 
							),
 | 
				
			||||||
	}); err != nil {
 | 
						}); err != nil {
 | 
				
			||||||
		log.Error("%v", err)
 | 
							log.Error("%v", err)
 | 
				
			||||||
		return fmt.Errorf("Push: %v", err)
 | 
							return fmt.Errorf("Push: %v", err)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -169,6 +169,7 @@ func AddChanges(repoPath string, all bool, files ...string) error {
 | 
				
			|||||||
	if all {
 | 
						if all {
 | 
				
			||||||
		cmd.AddArguments("--all")
 | 
							cmd.AddArguments("--all")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						cmd.AddArguments("--")
 | 
				
			||||||
	_, err := cmd.AddArguments(files...).RunInDir(repoPath)
 | 
						_, err := cmd.AddArguments(files...).RunInDir(repoPath)
 | 
				
			||||||
	return err
 | 
						return err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -304,6 +305,7 @@ func (c *Commit) GetFilesChangedSinceCommit(pastCommit string) ([]string, error)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// FileChangedSinceCommit Returns true if the file given has changed since the the past commit
 | 
					// FileChangedSinceCommit Returns true if the file given has changed since the the past commit
 | 
				
			||||||
 | 
					// YOU MUST ENSURE THAT pastCommit is a valid commit ID.
 | 
				
			||||||
func (c *Commit) FileChangedSinceCommit(filename, pastCommit string) (bool, error) {
 | 
					func (c *Commit) FileChangedSinceCommit(filename, pastCommit string) (bool, error) {
 | 
				
			||||||
	return c.repo.FileChangedBetweenCommits(filename, pastCommit, c.ID.String())
 | 
						return c.repo.FileChangedBetweenCommits(filename, pastCommit, c.ID.String())
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -68,7 +68,9 @@ func (tes Entries) GetCommitsInfo(commit *Commit, treePath string, cache LastCom
 | 
				
			|||||||
	// get it for free during the tree traversal and it's used for listing
 | 
						// get it for free during the tree traversal and it's used for listing
 | 
				
			||||||
	// pages to display information about newest commit for a given path.
 | 
						// pages to display information about newest commit for a given path.
 | 
				
			||||||
	var treeCommit *Commit
 | 
						var treeCommit *Commit
 | 
				
			||||||
	if rev, ok := revs[""]; ok {
 | 
						if treePath == "" {
 | 
				
			||||||
 | 
							treeCommit = commit
 | 
				
			||||||
 | 
						} else if rev, ok := revs[""]; ok {
 | 
				
			||||||
		treeCommit = convertCommit(rev)
 | 
							treeCommit = convertCommit(rev)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return commitsInfo, treeCommit, nil
 | 
						return commitsInfo, treeCommit, nil
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -28,21 +28,27 @@ func cloneRepo(url, dir, name string) (string, error) {
 | 
				
			|||||||
func testGetCommitsInfo(t *testing.T, repo1 *Repository) {
 | 
					func testGetCommitsInfo(t *testing.T, repo1 *Repository) {
 | 
				
			||||||
	// these test case are specific to the repo1 test repo
 | 
						// these test case are specific to the repo1 test repo
 | 
				
			||||||
	testCases := []struct {
 | 
						testCases := []struct {
 | 
				
			||||||
		CommitID    string
 | 
							CommitID           string
 | 
				
			||||||
		Path        string
 | 
							Path               string
 | 
				
			||||||
		ExpectedIDs map[string]string
 | 
							ExpectedIDs        map[string]string
 | 
				
			||||||
 | 
							ExpectedTreeCommit string
 | 
				
			||||||
	}{
 | 
						}{
 | 
				
			||||||
		{"8d92fc957a4d7cfd98bc375f0b7bb189a0d6c9f2", "", map[string]string{
 | 
							{"8d92fc957a4d7cfd98bc375f0b7bb189a0d6c9f2", "", map[string]string{
 | 
				
			||||||
			"file1.txt": "95bb4d39648ee7e325106df01a621c530863a653",
 | 
								"file1.txt": "95bb4d39648ee7e325106df01a621c530863a653",
 | 
				
			||||||
			"file2.txt": "8d92fc957a4d7cfd98bc375f0b7bb189a0d6c9f2",
 | 
								"file2.txt": "8d92fc957a4d7cfd98bc375f0b7bb189a0d6c9f2",
 | 
				
			||||||
		}},
 | 
							}, "8d92fc957a4d7cfd98bc375f0b7bb189a0d6c9f2"},
 | 
				
			||||||
		{"2839944139e0de9737a044f78b0e4b40d989a9e3", "", map[string]string{
 | 
							{"2839944139e0de9737a044f78b0e4b40d989a9e3", "", map[string]string{
 | 
				
			||||||
			"file1.txt":   "2839944139e0de9737a044f78b0e4b40d989a9e3",
 | 
								"file1.txt":   "2839944139e0de9737a044f78b0e4b40d989a9e3",
 | 
				
			||||||
			"branch1.txt": "9c9aef8dd84e02bc7ec12641deb4c930a7c30185",
 | 
								"branch1.txt": "9c9aef8dd84e02bc7ec12641deb4c930a7c30185",
 | 
				
			||||||
		}},
 | 
							}, "2839944139e0de9737a044f78b0e4b40d989a9e3"},
 | 
				
			||||||
		{"5c80b0245c1c6f8343fa418ec374b13b5d4ee658", "branch2", map[string]string{
 | 
							{"5c80b0245c1c6f8343fa418ec374b13b5d4ee658", "branch2", map[string]string{
 | 
				
			||||||
			"branch2.txt": "5c80b0245c1c6f8343fa418ec374b13b5d4ee658",
 | 
								"branch2.txt": "5c80b0245c1c6f8343fa418ec374b13b5d4ee658",
 | 
				
			||||||
		}},
 | 
							}, "5c80b0245c1c6f8343fa418ec374b13b5d4ee658"},
 | 
				
			||||||
 | 
							{"feaf4ba6bc635fec442f46ddd4512416ec43c2c2", "", map[string]string{
 | 
				
			||||||
 | 
								"file1.txt": "95bb4d39648ee7e325106df01a621c530863a653",
 | 
				
			||||||
 | 
								"file2.txt": "8d92fc957a4d7cfd98bc375f0b7bb189a0d6c9f2",
 | 
				
			||||||
 | 
								"foo":       "37991dec2c8e592043f47155ce4808d4580f9123",
 | 
				
			||||||
 | 
							}, "feaf4ba6bc635fec442f46ddd4512416ec43c2c2"},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	for _, testCase := range testCases {
 | 
						for _, testCase := range testCases {
 | 
				
			||||||
		commit, err := repo1.GetCommit(testCase.CommitID)
 | 
							commit, err := repo1.GetCommit(testCase.CommitID)
 | 
				
			||||||
@@ -51,7 +57,8 @@ func testGetCommitsInfo(t *testing.T, repo1 *Repository) {
 | 
				
			|||||||
		assert.NoError(t, err)
 | 
							assert.NoError(t, err)
 | 
				
			||||||
		entries, err := tree.ListEntries()
 | 
							entries, err := tree.ListEntries()
 | 
				
			||||||
		assert.NoError(t, err)
 | 
							assert.NoError(t, err)
 | 
				
			||||||
		commitsInfo, _, err := entries.GetCommitsInfo(commit, testCase.Path, nil)
 | 
							commitsInfo, treeCommit, err := entries.GetCommitsInfo(commit, testCase.Path, nil)
 | 
				
			||||||
 | 
							assert.Equal(t, testCase.ExpectedTreeCommit, treeCommit.ID.String())
 | 
				
			||||||
		assert.NoError(t, err)
 | 
							assert.NoError(t, err)
 | 
				
			||||||
		assert.Len(t, commitsInfo, len(testCase.ExpectedIDs))
 | 
							assert.Len(t, commitsInfo, len(testCase.ExpectedIDs))
 | 
				
			||||||
		for _, commitInfo := range commitsInfo {
 | 
							for _, commitInfo := range commitsInfo {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -187,8 +187,7 @@ func Pull(repoPath string, opts PullRemoteOptions) error {
 | 
				
			|||||||
	if opts.All {
 | 
						if opts.All {
 | 
				
			||||||
		cmd.AddArguments("--all")
 | 
							cmd.AddArguments("--all")
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		cmd.AddArguments(opts.Remote)
 | 
							cmd.AddArguments("--", opts.Remote, opts.Branch)
 | 
				
			||||||
		cmd.AddArguments(opts.Branch)
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if opts.Timeout <= 0 {
 | 
						if opts.Timeout <= 0 {
 | 
				
			||||||
@@ -213,7 +212,7 @@ func Push(repoPath string, opts PushOptions) error {
 | 
				
			|||||||
	if opts.Force {
 | 
						if opts.Force {
 | 
				
			||||||
		cmd.AddArguments("-f")
 | 
							cmd.AddArguments("-f")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	cmd.AddArguments(opts.Remote, opts.Branch)
 | 
						cmd.AddArguments("--", opts.Remote, opts.Branch)
 | 
				
			||||||
	_, err := cmd.RunInDirWithEnv(repoPath, opts.Env)
 | 
						_, err := cmd.RunInDirWithEnv(repoPath, opts.Env)
 | 
				
			||||||
	return err
 | 
						return err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -135,7 +135,7 @@ func (repo *Repository) DeleteBranch(name string, opts DeleteBranchOptions) erro
 | 
				
			|||||||
		cmd.AddArguments("-d")
 | 
							cmd.AddArguments("-d")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cmd.AddArguments(name)
 | 
						cmd.AddArguments("--", name)
 | 
				
			||||||
	_, err := cmd.RunInDir(repo.Path)
 | 
						_, err := cmd.RunInDir(repo.Path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return err
 | 
						return err
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -117,20 +117,26 @@ func (repo *Repository) getCommit(id SHA1) (*Commit, error) {
 | 
				
			|||||||
	return commit, nil
 | 
						return commit, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GetCommit returns commit object of by ID string.
 | 
					// ConvertToSHA1 returns a Hash object from a potential ID string
 | 
				
			||||||
func (repo *Repository) GetCommit(commitID string) (*Commit, error) {
 | 
					func (repo *Repository) ConvertToSHA1(commitID string) (SHA1, error) {
 | 
				
			||||||
	if len(commitID) != 40 {
 | 
						if len(commitID) != 40 {
 | 
				
			||||||
		var err error
 | 
							var err error
 | 
				
			||||||
		actualCommitID, err := NewCommand("rev-parse", commitID).RunInDir(repo.Path)
 | 
							actualCommitID, err := NewCommand("rev-parse", "--verify", commitID).RunInDir(repo.Path)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			if strings.Contains(err.Error(), "unknown revision or path") {
 | 
								if strings.Contains(err.Error(), "unknown revision or path") ||
 | 
				
			||||||
				return nil, ErrNotExist{commitID, ""}
 | 
									strings.Contains(err.Error(), "fatal: Needed a single revision") {
 | 
				
			||||||
 | 
									return SHA1{}, ErrNotExist{commitID, ""}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			return nil, err
 | 
								return SHA1{}, err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		commitID = actualCommitID
 | 
							commitID = actualCommitID
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	id, err := NewIDFromString(commitID)
 | 
						return NewIDFromString(commitID)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GetCommit returns commit object of by ID string.
 | 
				
			||||||
 | 
					func (repo *Repository) GetCommit(commitID string) (*Commit, error) {
 | 
				
			||||||
 | 
						id, err := repo.ConvertToSHA1(commitID)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -243,6 +249,7 @@ func (repo *Repository) getFilesChanged(id1, id2 string) ([]string, error) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// FileChangedBetweenCommits Returns true if the file changed between commit IDs id1 and id2
 | 
					// FileChangedBetweenCommits Returns true if the file changed between commit IDs id1 and id2
 | 
				
			||||||
 | 
					// You must ensure that id1 and id2 are valid commit ids.
 | 
				
			||||||
func (repo *Repository) FileChangedBetweenCommits(filename, id1, id2 string) (bool, error) {
 | 
					func (repo *Repository) FileChangedBetweenCommits(filename, id1, id2 string) (bool, error) {
 | 
				
			||||||
	stdout, err := NewCommand("diff", "--name-only", "-z", id1, id2, "--", filename).RunInDirBytes(repo.Path)
 | 
						stdout, err := NewCommand("diff", "--name-only", "-z", id1, id2, "--", filename).RunInDirBytes(repo.Path)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -55,5 +55,5 @@ func TestGetCommitWithBadCommitID(t *testing.T) {
 | 
				
			|||||||
	commit, err := bareRepo1.GetCommit("bad_branch")
 | 
						commit, err := bareRepo1.GetCommit("bad_branch")
 | 
				
			||||||
	assert.Nil(t, commit)
 | 
						assert.Nil(t, commit)
 | 
				
			||||||
	assert.Error(t, err)
 | 
						assert.Error(t, err)
 | 
				
			||||||
	assert.EqualError(t, err, "object does not exist [id: bad_branch, rel_path: ]")
 | 
						assert.True(t, IsErrNotExist(err))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -39,7 +39,7 @@ func (repo *Repository) GetMergeBase(tmpRemote string, base, head string) (strin
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	stdout, err := NewCommand("merge-base", base, head).RunInDir(repo.Path)
 | 
						stdout, err := NewCommand("merge-base", "--", base, head).RunInDir(repo.Path)
 | 
				
			||||||
	return strings.TrimSpace(stdout), base, err
 | 
						return strings.TrimSpace(stdout), base, err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -54,7 +54,7 @@ func (repo *Repository) GetCompareInfo(basePath, baseBranch, headBranch string)
 | 
				
			|||||||
	if repo.Path != basePath {
 | 
						if repo.Path != basePath {
 | 
				
			||||||
		// Add a temporary remote
 | 
							// Add a temporary remote
 | 
				
			||||||
		tmpRemote = strconv.FormatInt(time.Now().UnixNano(), 10)
 | 
							tmpRemote = strconv.FormatInt(time.Now().UnixNano(), 10)
 | 
				
			||||||
		if err = repo.AddRemote(tmpRemote, basePath, true); err != nil {
 | 
							if err = repo.AddRemote(tmpRemote, basePath, false); err != nil {
 | 
				
			||||||
			return nil, fmt.Errorf("AddRemote: %v", err)
 | 
								return nil, fmt.Errorf("AddRemote: %v", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		defer func() {
 | 
							defer func() {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,7 +12,7 @@ import (
 | 
				
			|||||||
// ReadTreeToIndex reads a treeish to the index
 | 
					// ReadTreeToIndex reads a treeish to the index
 | 
				
			||||||
func (repo *Repository) ReadTreeToIndex(treeish string) error {
 | 
					func (repo *Repository) ReadTreeToIndex(treeish string) error {
 | 
				
			||||||
	if len(treeish) != 40 {
 | 
						if len(treeish) != 40 {
 | 
				
			||||||
		res, err := NewCommand("rev-parse", treeish).RunInDir(repo.Path)
 | 
							res, err := NewCommand("rev-parse", "--verify", treeish).RunInDir(repo.Path)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,12 +23,12 @@ func TestRepository_GetCodeActivityStats(t *testing.T) {
 | 
				
			|||||||
	assert.NoError(t, err)
 | 
						assert.NoError(t, err)
 | 
				
			||||||
	assert.NotNil(t, code)
 | 
						assert.NotNil(t, code)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	assert.EqualValues(t, 8, code.CommitCount)
 | 
						assert.EqualValues(t, 9, code.CommitCount)
 | 
				
			||||||
	assert.EqualValues(t, 2, code.AuthorCount)
 | 
						assert.EqualValues(t, 3, code.AuthorCount)
 | 
				
			||||||
	assert.EqualValues(t, 8, code.CommitCountInAllBranches)
 | 
						assert.EqualValues(t, 9, code.CommitCountInAllBranches)
 | 
				
			||||||
	assert.EqualValues(t, 10, code.Additions)
 | 
						assert.EqualValues(t, 10, code.Additions)
 | 
				
			||||||
	assert.EqualValues(t, 1, code.Deletions)
 | 
						assert.EqualValues(t, 1, code.Deletions)
 | 
				
			||||||
	assert.Len(t, code.Authors, 2)
 | 
						assert.Len(t, code.Authors, 3)
 | 
				
			||||||
	assert.Contains(t, code.Authors, "tris.git@shoddynet.org")
 | 
						assert.Contains(t, code.Authors, "tris.git@shoddynet.org")
 | 
				
			||||||
	assert.EqualValues(t, 3, code.Authors["tris.git@shoddynet.org"])
 | 
						assert.EqualValues(t, 3, code.Authors["tris.git@shoddynet.org"])
 | 
				
			||||||
	assert.EqualValues(t, 5, code.Authors[""])
 | 
						assert.EqualValues(t, 5, code.Authors[""])
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,13 +29,13 @@ func (repo *Repository) IsTagExist(name string) bool {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// CreateTag create one tag in the repository
 | 
					// CreateTag create one tag in the repository
 | 
				
			||||||
func (repo *Repository) CreateTag(name, revision string) error {
 | 
					func (repo *Repository) CreateTag(name, revision string) error {
 | 
				
			||||||
	_, err := NewCommand("tag", name, revision).RunInDir(repo.Path)
 | 
						_, err := NewCommand("tag", "--", name, revision).RunInDir(repo.Path)
 | 
				
			||||||
	return err
 | 
						return err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// CreateAnnotatedTag create one annotated tag in the repository
 | 
					// CreateAnnotatedTag create one annotated tag in the repository
 | 
				
			||||||
func (repo *Repository) CreateAnnotatedTag(name, message, revision string) error {
 | 
					func (repo *Repository) CreateAnnotatedTag(name, message, revision string) error {
 | 
				
			||||||
	_, err := NewCommand("tag", "-a", "-m", message, name, revision).RunInDir(repo.Path)
 | 
						_, err := NewCommand("tag", "-a", "-m", message, "--", name, revision).RunInDir(repo.Path)
 | 
				
			||||||
	return err
 | 
						return err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -153,7 +153,7 @@ func (repo *Repository) GetTagNameBySHA(sha string) (string, error) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// GetTagID returns the object ID for a tag (annotated tags have both an object SHA AND a commit SHA)
 | 
					// GetTagID returns the object ID for a tag (annotated tags have both an object SHA AND a commit SHA)
 | 
				
			||||||
func (repo *Repository) GetTagID(name string) (string, error) {
 | 
					func (repo *Repository) GetTagID(name string) (string, error) {
 | 
				
			||||||
	stdout, err := NewCommand("show-ref", name).RunInDir(repo.Path)
 | 
						stdout, err := NewCommand("show-ref", "--", name).RunInDir(repo.Path)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return "", err
 | 
							return "", err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -28,7 +28,7 @@ func (repo *Repository) getTree(id SHA1) (*Tree, error) {
 | 
				
			|||||||
// GetTree find the tree object in the repository.
 | 
					// GetTree find the tree object in the repository.
 | 
				
			||||||
func (repo *Repository) GetTree(idStr string) (*Tree, error) {
 | 
					func (repo *Repository) GetTree(idStr string) (*Tree, error) {
 | 
				
			||||||
	if len(idStr) != 40 {
 | 
						if len(idStr) != 40 {
 | 
				
			||||||
		res, err := NewCommand("rev-parse", idStr).RunInDir(repo.Path)
 | 
							res, err := NewCommand("rev-parse", "--verify", idStr).RunInDir(repo.Path)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return nil, err
 | 
								return nil, err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -63,7 +63,7 @@ type CommitTreeOpts struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// CommitTree creates a commit from a given tree id for the user with provided message
 | 
					// CommitTree creates a commit from a given tree id for the user with provided message
 | 
				
			||||||
func (repo *Repository) CommitTree(sig *Signature, tree *Tree, opts CommitTreeOpts) (SHA1, error) {
 | 
					func (repo *Repository) CommitTree(sig *Signature, tree *Tree, opts CommitTreeOpts) (SHA1, error) {
 | 
				
			||||||
	commitTimeStr := time.Now().Format(time.UnixDate)
 | 
						commitTimeStr := time.Now().Format(time.RFC3339)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Because this may call hooks we should pass in the environment
 | 
						// Because this may call hooks we should pass in the environment
 | 
				
			||||||
	env := append(os.Environ(),
 | 
						env := append(os.Environ(),
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1
									
								
								modules/git/tests/repos/repo1_bare/logs/HEAD
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								modules/git/tests/repos/repo1_bare/logs/HEAD
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					37991dec2c8e592043f47155ce4808d4580f9123 feaf4ba6bc635fec442f46ddd4512416ec43c2c2 silverwind <me@silverwind.io> 1563741799 +0200	push
 | 
				
			||||||
@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					37991dec2c8e592043f47155ce4808d4580f9123 feaf4ba6bc635fec442f46ddd4512416ec43c2c2 silverwind <me@silverwind.io> 1563741799 +0200	push
 | 
				
			||||||
										
											Binary file not shown.
										
									
								
							@@ -1 +1 @@
 | 
				
			|||||||
37991dec2c8e592043f47155ce4808d4580f9123
 | 
					feaf4ba6bc635fec442f46ddd4512416ec43c2c2
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -108,6 +108,11 @@ func (te *TreeEntry) IsRegular() bool {
 | 
				
			|||||||
	return te.gogitTreeEntry.Mode == filemode.Regular
 | 
						return te.gogitTreeEntry.Mode == filemode.Regular
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// IsExecutable if the entry is an executable file (not necessarily binary)
 | 
				
			||||||
 | 
					func (te *TreeEntry) IsExecutable() bool {
 | 
				
			||||||
 | 
						return te.gogitTreeEntry.Mode == filemode.Executable
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Blob returns the blob object the entry
 | 
					// Blob returns the blob object the entry
 | 
				
			||||||
func (te *TreeEntry) Blob() *Blob {
 | 
					func (te *TreeEntry) Blob() *Blob {
 | 
				
			||||||
	encodedObj, err := te.ptree.repo.gogitRepo.Storer.EncodedObject(plumbing.AnyObject, te.gogitTreeEntry.Hash)
 | 
						encodedObj, err := te.ptree.repo.gogitRepo.Storer.EncodedObject(plumbing.AnyObject, te.gogitTreeEntry.Hash)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -153,7 +153,7 @@ func RenderRaw(body []byte, urlPrefix string, wikiMarkdown bool) []byte {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	body = blackfriday.Markdown(body, renderer, exts)
 | 
						body = blackfriday.Markdown(body, renderer, exts)
 | 
				
			||||||
	return body
 | 
						return markup.SanitizeBytes(body)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var (
 | 
					var (
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -111,7 +111,7 @@ func (g *GiteaLocalUploader) CreateMilestones(milestones ...*base.Milestone) err
 | 
				
			|||||||
			RepoID:       g.repo.ID,
 | 
								RepoID:       g.repo.ID,
 | 
				
			||||||
			Name:         milestone.Title,
 | 
								Name:         milestone.Title,
 | 
				
			||||||
			Content:      milestone.Description,
 | 
								Content:      milestone.Description,
 | 
				
			||||||
			IsClosed:     milestone.State == "close",
 | 
								IsClosed:     milestone.State == "closed",
 | 
				
			||||||
			DeadlineUnix: deadline,
 | 
								DeadlineUnix: deadline,
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if ms.IsClosed && milestone.Closed != nil {
 | 
							if ms.IsClosed && milestone.Closed != nil {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -173,6 +173,7 @@ func TestGitHubDownloadRepo(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	var (
 | 
						var (
 | 
				
			||||||
		closed1 = time.Date(2018, 10, 23, 02, 57, 43, 0, time.UTC)
 | 
							closed1 = time.Date(2018, 10, 23, 02, 57, 43, 0, time.UTC)
 | 
				
			||||||
 | 
							closed7 = time.Date(2019, 7, 8, 8, 20, 23, 0, time.UTC)
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
	assert.EqualValues(t, []*base.Issue{
 | 
						assert.EqualValues(t, []*base.Issue{
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
@@ -208,9 +209,9 @@ func TestGitHubDownloadRepo(t *testing.T) {
 | 
				
			|||||||
			Number:     7,
 | 
								Number:     7,
 | 
				
			||||||
			Title:      "display page revisions on wiki",
 | 
								Title:      "display page revisions on wiki",
 | 
				
			||||||
			Content:    "Hi guys,\r\n\r\nWiki on Gogs is very fine, I liked a lot, but I think that is good idea to be possible see other revisions from page as a page history.\r\n\r\nWhat you think?\r\n\r\nReference: https://github.com/gogits/gogs/issues/2991",
 | 
								Content:    "Hi guys,\r\n\r\nWiki on Gogs is very fine, I liked a lot, but I think that is good idea to be possible see other revisions from page as a page history.\r\n\r\nWhat you think?\r\n\r\nReference: https://github.com/gogits/gogs/issues/2991",
 | 
				
			||||||
			Milestone:  "1.x.x",
 | 
								Milestone:  "1.10.0",
 | 
				
			||||||
			PosterName: "joubertredrat",
 | 
								PosterName: "joubertredrat",
 | 
				
			||||||
			State:      "open",
 | 
								State:      "closed",
 | 
				
			||||||
			Created:    time.Date(2016, 11, 02, 18, 57, 32, 0, time.UTC),
 | 
								Created:    time.Date(2016, 11, 02, 18, 57, 32, 0, time.UTC),
 | 
				
			||||||
			Labels: []*base.Label{
 | 
								Labels: []*base.Label{
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
@@ -232,6 +233,7 @@ func TestGitHubDownloadRepo(t *testing.T) {
 | 
				
			|||||||
				Heart:      0,
 | 
									Heart:      0,
 | 
				
			||||||
				Hooray:     0,
 | 
									Hooray:     0,
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
 | 
								Closed: &closed7,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			Number:     8,
 | 
								Number:     8,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,12 +29,13 @@ type HookOptions struct {
 | 
				
			|||||||
	UserName                        string
 | 
						UserName                        string
 | 
				
			||||||
	GitObjectDirectory              string
 | 
						GitObjectDirectory              string
 | 
				
			||||||
	GitAlternativeObjectDirectories string
 | 
						GitAlternativeObjectDirectories string
 | 
				
			||||||
 | 
						GitQuarantinePath               string
 | 
				
			||||||
	ProtectedBranchID               int64
 | 
						ProtectedBranchID               int64
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// HookPreReceive check whether the provided commits are allowed
 | 
					// HookPreReceive check whether the provided commits are allowed
 | 
				
			||||||
func HookPreReceive(ownerName, repoName string, opts HookOptions) (int, string) {
 | 
					func HookPreReceive(ownerName, repoName string, opts HookOptions) (int, string) {
 | 
				
			||||||
	reqURL := setting.LocalURL + fmt.Sprintf("api/internal/hook/pre-receive/%s/%s?old=%s&new=%s&ref=%s&userID=%d&gitObjectDirectory=%s&gitAlternativeObjectDirectories=%s&prID=%d",
 | 
						reqURL := setting.LocalURL + fmt.Sprintf("api/internal/hook/pre-receive/%s/%s?old=%s&new=%s&ref=%s&userID=%d&gitObjectDirectory=%s&gitAlternativeObjectDirectories=%s&gitQuarantinePath=%s&prID=%d",
 | 
				
			||||||
		url.PathEscape(ownerName),
 | 
							url.PathEscape(ownerName),
 | 
				
			||||||
		url.PathEscape(repoName),
 | 
							url.PathEscape(repoName),
 | 
				
			||||||
		url.QueryEscape(opts.OldCommitID),
 | 
							url.QueryEscape(opts.OldCommitID),
 | 
				
			||||||
@@ -43,6 +44,7 @@ func HookPreReceive(ownerName, repoName string, opts HookOptions) (int, string)
 | 
				
			|||||||
		opts.UserID,
 | 
							opts.UserID,
 | 
				
			||||||
		url.QueryEscape(opts.GitObjectDirectory),
 | 
							url.QueryEscape(opts.GitObjectDirectory),
 | 
				
			||||||
		url.QueryEscape(opts.GitAlternativeObjectDirectories),
 | 
							url.QueryEscape(opts.GitAlternativeObjectDirectories),
 | 
				
			||||||
 | 
							url.QueryEscape(opts.GitQuarantinePath),
 | 
				
			||||||
		opts.ProtectedBranchID,
 | 
							opts.ProtectedBranchID,
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -49,7 +49,6 @@ func Merge(pr *models.PullRequest, doer *models.User, baseGitRepo *git.Repositor
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	defer func() {
 | 
						defer func() {
 | 
				
			||||||
		go models.HookQueue.Add(pr.BaseRepo.ID)
 | 
					 | 
				
			||||||
		go models.AddTestPullRequestTask(doer, pr.BaseRepo.ID, pr.BaseBranch, false)
 | 
							go models.AddTestPullRequestTask(doer, pr.BaseRepo.ID, pr.BaseBranch, false)
 | 
				
			||||||
	}()
 | 
						}()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -102,7 +101,7 @@ func Merge(pr *models.PullRequest, doer *models.User, baseGitRepo *git.Repositor
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Fetch head branch
 | 
						// Fetch head branch
 | 
				
			||||||
	if err := git.NewCommand("fetch", remoteRepoName).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil {
 | 
						if err := git.NewCommand("fetch", remoteRepoName, pr.HeadBranch).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil {
 | 
				
			||||||
		return fmt.Errorf("git fetch [%s -> %s]: %s", headRepoPath, tmpBasePath, errbuf.String())
 | 
							return fmt.Errorf("git fetch [%s -> %s]: %s", headRepoPath, tmpBasePath, errbuf.String())
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -241,7 +240,13 @@ func Merge(pr *models.PullRequest, doer *models.User, baseGitRepo *git.Repositor
 | 
				
			|||||||
		headUser = doer
 | 
							headUser = doer
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	env := models.FullPushingEnvironment(headUser, doer, pr.BaseRepo, pr.ID)
 | 
						env := models.FullPushingEnvironment(
 | 
				
			||||||
 | 
							headUser,
 | 
				
			||||||
 | 
							doer,
 | 
				
			||||||
 | 
							pr.BaseRepo,
 | 
				
			||||||
 | 
							pr.BaseRepo.Name,
 | 
				
			||||||
 | 
							pr.ID,
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Push back to upstream.
 | 
						// Push back to upstream.
 | 
				
			||||||
	if err := git.NewCommand("push", "origin", pr.BaseBranch).RunInDirTimeoutEnvPipeline(env, -1, tmpBasePath, nil, &errbuf); err != nil {
 | 
						if err := git.NewCommand("push", "origin", pr.BaseBranch).RunInDirTimeoutEnvPipeline(env, -1, tmpBasePath, nil, &errbuf); err != nil {
 | 
				
			||||||
@@ -287,39 +292,6 @@ func Merge(pr *models.PullRequest, doer *models.User, baseGitRepo *git.Repositor
 | 
				
			|||||||
		go models.HookQueue.Add(pr.Issue.Repo.ID)
 | 
							go models.HookQueue.Add(pr.Issue.Repo.ID)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	l, err := baseGitRepo.CommitsBetweenIDs(pr.MergedCommitID, pr.MergeBase)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		log.Error("CommitsBetweenIDs: %v", err)
 | 
					 | 
				
			||||||
		return nil
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// It is possible that head branch is not fully sync with base branch for merge commits,
 | 
					 | 
				
			||||||
	// so we need to get latest head commit and append merge commit manually
 | 
					 | 
				
			||||||
	// to avoid strange diff commits produced.
 | 
					 | 
				
			||||||
	mergeCommit, err := baseGitRepo.GetBranchCommit(pr.BaseBranch)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		log.Error("GetBranchCommit: %v", err)
 | 
					 | 
				
			||||||
		return nil
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if mergeStyle == models.MergeStyleMerge {
 | 
					 | 
				
			||||||
		l.PushFront(mergeCommit)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	p := &api.PushPayload{
 | 
					 | 
				
			||||||
		Ref:        git.BranchPrefix + pr.BaseBranch,
 | 
					 | 
				
			||||||
		Before:     pr.MergeBase,
 | 
					 | 
				
			||||||
		After:      mergeCommit.ID.String(),
 | 
					 | 
				
			||||||
		CompareURL: setting.AppURL + pr.BaseRepo.ComposeCompareURL(pr.MergeBase, pr.MergedCommitID),
 | 
					 | 
				
			||||||
		Commits:    models.ListToPushCommits(l).ToAPIPayloadCommits(pr.BaseRepo.HTMLURL()),
 | 
					 | 
				
			||||||
		Repo:       pr.BaseRepo.APIFormat(mode),
 | 
					 | 
				
			||||||
		Pusher:     pr.HeadRepo.MustOwner().APIFormat(),
 | 
					 | 
				
			||||||
		Sender:     doer.APIFormat(),
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if err = models.PrepareWebhooks(pr.BaseRepo, models.HookEventPush, p); err != nil {
 | 
					 | 
				
			||||||
		log.Error("PrepareWebhooks: %v", err)
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		go models.HookQueue.Add(pr.BaseRepo.ID)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -92,6 +92,12 @@ func DeleteRepoFile(repo *models.Repository, doer *models.User, opts *DeleteRepo
 | 
				
			|||||||
	// Assigned LastCommitID in opts if it hasn't been set
 | 
						// Assigned LastCommitID in opts if it hasn't been set
 | 
				
			||||||
	if opts.LastCommitID == "" {
 | 
						if opts.LastCommitID == "" {
 | 
				
			||||||
		opts.LastCommitID = commit.ID.String()
 | 
							opts.LastCommitID = commit.ID.String()
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							lastCommitID, err := t.gitRepo.ConvertToSHA1(opts.LastCommitID)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return nil, fmt.Errorf("DeleteRepoFile: Invalid last commit ID: %v", err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							opts.LastCommitID = lastCommitID.String()
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Get the files in the index
 | 
						// Get the files in the index
 | 
				
			||||||
@@ -172,32 +178,6 @@ func DeleteRepoFile(repo *models.Repository, doer *models.User, opts *DeleteRepo
 | 
				
			|||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Simulate push event.
 | 
					 | 
				
			||||||
	oldCommitID := opts.LastCommitID
 | 
					 | 
				
			||||||
	if opts.NewBranch != opts.OldBranch {
 | 
					 | 
				
			||||||
		oldCommitID = git.EmptySHA
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if err = repo.GetOwner(); err != nil {
 | 
					 | 
				
			||||||
		return nil, fmt.Errorf("GetOwner: %v", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	err = PushUpdate(
 | 
					 | 
				
			||||||
		repo,
 | 
					 | 
				
			||||||
		opts.NewBranch,
 | 
					 | 
				
			||||||
		models.PushUpdateOptions{
 | 
					 | 
				
			||||||
			PusherID:     doer.ID,
 | 
					 | 
				
			||||||
			PusherName:   doer.Name,
 | 
					 | 
				
			||||||
			RepoUserName: repo.Owner.Name,
 | 
					 | 
				
			||||||
			RepoName:     repo.Name,
 | 
					 | 
				
			||||||
			RefFullName:  git.BranchPrefix + opts.NewBranch,
 | 
					 | 
				
			||||||
			OldCommitID:  oldCommitID,
 | 
					 | 
				
			||||||
			NewCommitID:  commitHash,
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
	)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return nil, fmt.Errorf("PushUpdate: %v", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	commit, err = t.GetCommit(commitHash)
 | 
						commit, err = t.GetCommit(commitHash)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -249,7 +249,7 @@ func (t *TemporaryUploadRepository) GetLastCommitByRef(ref string) (string, erro
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// CommitTree creates a commit from a given tree for the user with provided message
 | 
					// CommitTree creates a commit from a given tree for the user with provided message
 | 
				
			||||||
func (t *TemporaryUploadRepository) CommitTree(author, committer *models.User, treeHash string, message string) (string, error) {
 | 
					func (t *TemporaryUploadRepository) CommitTree(author, committer *models.User, treeHash string, message string) (string, error) {
 | 
				
			||||||
	commitTimeStr := time.Now().Format(time.UnixDate)
 | 
						commitTimeStr := time.Now().Format(time.RFC3339)
 | 
				
			||||||
	authorSig := author.NewGitSig()
 | 
						authorSig := author.NewGitSig()
 | 
				
			||||||
	committerSig := committer.NewGitSig()
 | 
						committerSig := committer.NewGitSig()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -188,6 +188,13 @@ func CreateOrUpdateRepoFile(repo *models.Repository, doer *models.User, opts *Up
 | 
				
			|||||||
	// Assigned LastCommitID in opts if it hasn't been set
 | 
						// Assigned LastCommitID in opts if it hasn't been set
 | 
				
			||||||
	if opts.LastCommitID == "" {
 | 
						if opts.LastCommitID == "" {
 | 
				
			||||||
		opts.LastCommitID = commit.ID.String()
 | 
							opts.LastCommitID = commit.ID.String()
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							lastCommitID, err := t.gitRepo.ConvertToSHA1(opts.LastCommitID)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return nil, fmt.Errorf("DeleteRepoFile: Invalid last commit ID: %v", err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							opts.LastCommitID = lastCommitID.String()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	encoding := "UTF-8"
 | 
						encoding := "UTF-8"
 | 
				
			||||||
@@ -387,32 +394,6 @@ func CreateOrUpdateRepoFile(repo *models.Repository, doer *models.User, opts *Up
 | 
				
			|||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Simulate push event.
 | 
					 | 
				
			||||||
	oldCommitID := opts.LastCommitID
 | 
					 | 
				
			||||||
	if opts.NewBranch != opts.OldBranch || oldCommitID == "" {
 | 
					 | 
				
			||||||
		oldCommitID = git.EmptySHA
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if err = repo.GetOwner(); err != nil {
 | 
					 | 
				
			||||||
		return nil, fmt.Errorf("GetOwner: %v", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	err = PushUpdate(
 | 
					 | 
				
			||||||
		repo,
 | 
					 | 
				
			||||||
		opts.NewBranch,
 | 
					 | 
				
			||||||
		models.PushUpdateOptions{
 | 
					 | 
				
			||||||
			PusherID:     doer.ID,
 | 
					 | 
				
			||||||
			PusherName:   doer.Name,
 | 
					 | 
				
			||||||
			RepoUserName: repo.Owner.Name,
 | 
					 | 
				
			||||||
			RepoName:     repo.Name,
 | 
					 | 
				
			||||||
			RefFullName:  git.BranchPrefix + opts.NewBranch,
 | 
					 | 
				
			||||||
			OldCommitID:  oldCommitID,
 | 
					 | 
				
			||||||
			NewCommitID:  commitHash,
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
	)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return nil, fmt.Errorf("PushUpdate: %v", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	commit, err = t.GetCommit(commitHash)
 | 
						commit, err = t.GetCommit(commitHash)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,7 +11,6 @@ import (
 | 
				
			|||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"code.gitea.io/gitea/models"
 | 
						"code.gitea.io/gitea/models"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/git"
 | 
					 | 
				
			||||||
	"code.gitea.io/gitea/modules/lfs"
 | 
						"code.gitea.io/gitea/modules/lfs"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/setting"
 | 
						"code.gitea.io/gitea/modules/setting"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -177,31 +176,5 @@ func UploadRepoFiles(repo *models.Repository, doer *models.User, opts *UploadRep
 | 
				
			|||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Simulate push event.
 | 
					 | 
				
			||||||
	oldCommitID := opts.LastCommitID
 | 
					 | 
				
			||||||
	if opts.NewBranch != opts.OldBranch {
 | 
					 | 
				
			||||||
		oldCommitID = git.EmptySHA
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if err = repo.GetOwner(); err != nil {
 | 
					 | 
				
			||||||
		return fmt.Errorf("GetOwner: %v", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	err = PushUpdate(
 | 
					 | 
				
			||||||
		repo,
 | 
					 | 
				
			||||||
		opts.NewBranch,
 | 
					 | 
				
			||||||
		models.PushUpdateOptions{
 | 
					 | 
				
			||||||
			PusherID:     doer.ID,
 | 
					 | 
				
			||||||
			PusherName:   doer.Name,
 | 
					 | 
				
			||||||
			RepoUserName: repo.Owner.Name,
 | 
					 | 
				
			||||||
			RepoName:     repo.Name,
 | 
					 | 
				
			||||||
			RefFullName:  git.BranchPrefix + opts.NewBranch,
 | 
					 | 
				
			||||||
			OldCommitID:  oldCommitID,
 | 
					 | 
				
			||||||
			NewCommitID:  commitHash,
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
	)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return fmt.Errorf("PushUpdate: %v", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return models.DeleteUploads(uploads...)
 | 
						return models.DeleteUploads(uploads...)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,9 +10,9 @@ type FileOptions struct {
 | 
				
			|||||||
	// message (optional) for the commit of this file. if not supplied, a default message will be used
 | 
						// message (optional) for the commit of this file. if not supplied, a default message will be used
 | 
				
			||||||
	Message string `json:"message"`
 | 
						Message string `json:"message"`
 | 
				
			||||||
	// branch (optional) to base this file from. if not given, the default branch is used
 | 
						// branch (optional) to base this file from. if not given, the default branch is used
 | 
				
			||||||
	BranchName string `json:"branch"`
 | 
						BranchName string `json:"branch" binding:"GitRefName;MaxSize(100)"`
 | 
				
			||||||
	// new_branch (optional) will make a new branch from `branch` before creating the file
 | 
						// new_branch (optional) will make a new branch from `branch` before creating the file
 | 
				
			||||||
	NewBranchName string `json:"new_branch"`
 | 
						NewBranchName string `json:"new_branch" binding:"GitRefName;MaxSize(100)"`
 | 
				
			||||||
	// `author` and `committer` are optional (if only one is given, it will be used for the other, otherwise the authenticated user will be used)
 | 
						// `author` and `committer` are optional (if only one is given, it will be used for the other, otherwise the authenticated user will be used)
 | 
				
			||||||
	Author    Identity `json:"author"`
 | 
						Author    Identity `json:"author"`
 | 
				
			||||||
	Committer Identity `json:"committer"`
 | 
						Committer Identity `json:"committer"`
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -694,6 +694,7 @@ editor.delete = Delete '%s'
 | 
				
			|||||||
editor.commit_message_desc = Add an optional extended description…
 | 
					editor.commit_message_desc = Add an optional extended description…
 | 
				
			||||||
editor.commit_directly_to_this_branch = Commit directly to the <strong class="branch-name">%s</strong> branch.
 | 
					editor.commit_directly_to_this_branch = Commit directly to the <strong class="branch-name">%s</strong> branch.
 | 
				
			||||||
editor.create_new_branch = Create a <strong>new branch</strong> for this commit and start a pull request.
 | 
					editor.create_new_branch = Create a <strong>new branch</strong> for this commit and start a pull request.
 | 
				
			||||||
 | 
					editor.propose_file_change = Propose file change
 | 
				
			||||||
editor.new_branch_name_desc = New branch name…
 | 
					editor.new_branch_name_desc = New branch name…
 | 
				
			||||||
editor.cancel = Cancel
 | 
					editor.cancel = Cancel
 | 
				
			||||||
editor.filename_cannot_be_empty = The filename cannot be empty.
 | 
					editor.filename_cannot_be_empty = The filename cannot be empty.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -208,6 +208,9 @@ footer .ui.left,footer .ui.right{line-height:40px}
 | 
				
			|||||||
.ui.tabular.menu .item{color:rgba(0,0,0,.5)}
 | 
					.ui.tabular.menu .item{color:rgba(0,0,0,.5)}
 | 
				
			||||||
.ui.tabular.menu .item:hover{color:rgba(0,0,0,.8)}
 | 
					.ui.tabular.menu .item:hover{color:rgba(0,0,0,.8)}
 | 
				
			||||||
.ui.tabular.menu .item.active{color:rgba(0,0,0,.9)}
 | 
					.ui.tabular.menu .item.active{color:rgba(0,0,0,.9)}
 | 
				
			||||||
 | 
					.inline-grouped-list{display:inline-block;vertical-align:top}
 | 
				
			||||||
 | 
					.inline-grouped-list>.ui{display:block;margin-top:5px;margin-bottom:10px}
 | 
				
			||||||
 | 
					.inline-grouped-list>.ui:first-child{margin-top:1px}
 | 
				
			||||||
.markdown:not(code){overflow:hidden;font-size:16px;line-height:1.6!important;word-wrap:break-word}
 | 
					.markdown:not(code){overflow:hidden;font-size:16px;line-height:1.6!important;word-wrap:break-word}
 | 
				
			||||||
.markdown:not(code).ui.segment{padding:3em}
 | 
					.markdown:not(code).ui.segment{padding:3em}
 | 
				
			||||||
.markdown:not(code).file-view{padding:2em 2em 2em!important}
 | 
					.markdown:not(code).file-view{padding:2em 2em 2em!important}
 | 
				
			||||||
@@ -620,6 +623,7 @@ footer .ui.left,footer .ui.right{line-height:40px}
 | 
				
			|||||||
.repository #commits-table thead .sha{width:140px}
 | 
					.repository #commits-table thead .sha{width:140px}
 | 
				
			||||||
.repository #commits-table thead .shatd{text-align:center}
 | 
					.repository #commits-table thead .shatd{text-align:center}
 | 
				
			||||||
.repository #commits-table td.sha .sha.label{margin:0}
 | 
					.repository #commits-table td.sha .sha.label{margin:0}
 | 
				
			||||||
 | 
					.repository #commits-table td.message{text-overflow:unset}
 | 
				
			||||||
.repository #commits-table.ui.basic.striped.table tbody tr:nth-child(2n){background-color:rgba(0,0,0,.02)!important}
 | 
					.repository #commits-table.ui.basic.striped.table tbody tr:nth-child(2n){background-color:rgba(0,0,0,.02)!important}
 | 
				
			||||||
.repository #commits-table td.sha .sha.label.isSigned,.repository #repo-files-table .sha.label.isSigned{border:1px solid #bbb}
 | 
					.repository #commits-table td.sha .sha.label.isSigned,.repository #repo-files-table .sha.label.isSigned{border:1px solid #bbb}
 | 
				
			||||||
.repository #commits-table td.sha .sha.label.isSigned .detail.icon,.repository #repo-files-table .sha.label.isSigned .detail.icon{background:#fafafa;margin:-6px -10px -4px 0;padding:5px 3px 5px 6px;border-left:1px solid #bbb;border-top-left-radius:0;border-bottom-left-radius:0}
 | 
					.repository #commits-table td.sha .sha.label.isSigned .detail.icon,.repository #repo-files-table .sha.label.isSigned .detail.icon{background:#fafafa;margin:-6px -10px -4px 0;padding:5px 3px 5px 6px;border-left:1px solid #bbb;border-top-left-radius:0;border-bottom-left-radius:0}
 | 
				
			||||||
@@ -744,7 +748,7 @@ footer .ui.left,footer .ui.right{line-height:40px}
 | 
				
			|||||||
.repository .segment.reactions .select-reaction{float:none}
 | 
					.repository .segment.reactions .select-reaction{float:none}
 | 
				
			||||||
.repository .segment.reactions .select-reaction:not(.active) a{display:none}
 | 
					.repository .segment.reactions .select-reaction:not(.active) a{display:none}
 | 
				
			||||||
.repository .segment.reactions:hover .select-reaction a{display:block}
 | 
					.repository .segment.reactions:hover .select-reaction a{display:block}
 | 
				
			||||||
.user-cards .list{padding:0}
 | 
					.user-cards .list{padding:0;display:flex;flex-wrap:wrap}
 | 
				
			||||||
.user-cards .list .item{list-style:none;width:32%;margin:10px 10px 10px 0;padding-bottom:14px;float:left}
 | 
					.user-cards .list .item{list-style:none;width:32%;margin:10px 10px 10px 0;padding-bottom:14px;float:left}
 | 
				
			||||||
.user-cards .list .item .avatar{width:48px;height:48px;float:left;display:block;margin-right:10px}
 | 
					.user-cards .list .item .avatar{width:48px;height:48px;float:left;display:block;margin-right:10px}
 | 
				
			||||||
.user-cards .list .item .name{margin-top:0;margin-bottom:0;font-weight:400}
 | 
					.user-cards .list .item .name{margin-top:0;margin-bottom:0;font-weight:400}
 | 
				
			||||||
@@ -814,8 +818,8 @@ footer .ui.left,footer .ui.right{line-height:40px}
 | 
				
			|||||||
.stats-table .table-cell{display:table-cell}
 | 
					.stats-table .table-cell{display:table-cell}
 | 
				
			||||||
.stats-table .table-cell.tiny{height:.5em}
 | 
					.stats-table .table-cell.tiny{height:.5em}
 | 
				
			||||||
tbody.commit-list{vertical-align:baseline}
 | 
					tbody.commit-list{vertical-align:baseline}
 | 
				
			||||||
.commit-list .message-wrapper{overflow:hidden;text-overflow:ellipsis;max-width:calc(100% - 24px);display:inline-block;vertical-align:middle}
 | 
					.commit-list .message-wrapper{overflow:hidden;text-overflow:ellipsis;max-width:calc(100% - 50px);display:inline-block;vertical-align:middle}
 | 
				
			||||||
.commit-list .message-wrapper .commit-status-link{display:inline-block;vertical-align:middle}
 | 
					.commit-list .commit-status-link{display:inline-block;vertical-align:middle}
 | 
				
			||||||
.commit-body{white-space:pre-wrap}
 | 
					.commit-body{white-space:pre-wrap}
 | 
				
			||||||
.git-notes.top{text-align:left}
 | 
					.git-notes.top{text-align:left}
 | 
				
			||||||
.git-notes .commit-body{margin:0}
 | 
					.git-notes .commit-body{margin:0}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -209,7 +209,7 @@ a.ui.label:hover,a.ui.labels .label:hover{background-color:#505667;color:#dbdbdb
 | 
				
			|||||||
.repository .label.list .item{border-bottom:1px dashed #4c505c}
 | 
					.repository .label.list .item{border-bottom:1px dashed #4c505c}
 | 
				
			||||||
.ui.basic.blue.button,.ui.basic.blue.buttons .button{box-shadow:0 0 0 1px #87ab63 inset!important;color:#87ab63!important}
 | 
					.ui.basic.blue.button,.ui.basic.blue.buttons .button{box-shadow:0 0 0 1px #87ab63 inset!important;color:#87ab63!important}
 | 
				
			||||||
.repository.file.list #file-content .code-view .hljs,.repository.file.list #file-content .code-view .lines-code ol,.repository.file.list #file-content .code-view .lines-code pre,.repository.file.list #file-content .code-view .lines-num .hljs,.repository.file.list #file-content .code-view .lines-num ol,.repository.file.list #file-content .code-view .lines-num pre{background-color:#2a2e3a}
 | 
					.repository.file.list #file-content .code-view .hljs,.repository.file.list #file-content .code-view .lines-code ol,.repository.file.list #file-content .code-view .lines-code pre,.repository.file.list #file-content .code-view .lines-num .hljs,.repository.file.list #file-content .code-view .lines-num ol,.repository.file.list #file-content .code-view .lines-num pre{background-color:#2a2e3a}
 | 
				
			||||||
.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(1),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(2),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(3),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(4),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(5),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(6){background-color:#2a2e3a}
 | 
					.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(1),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(2),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(3),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(4),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(5),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(6){background-color:#2a2e3a}
 | 
				
			||||||
.repository .diff-file-box .code-diff-split tbody tr td.add-code,.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(4),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(5),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(6){background-color:#283e2d!important;border-color:#314a37!important}
 | 
					.repository .diff-file-box .code-diff-split tbody tr td.add-code,.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(4),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(5),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(6){background-color:#283e2d!important;border-color:#314a37!important}
 | 
				
			||||||
.repository .diff-file-box .code-diff-split tbody tr td.del-code,.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(1),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(2),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(3){background-color:#3c2626!important;border-color:#634343!important}
 | 
					.repository .diff-file-box .code-diff-split tbody tr td.del-code,.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(1),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(2),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(3){background-color:#3c2626!important;border-color:#634343!important}
 | 
				
			||||||
.ui.blue.button:active,.ui.blue.buttons .button:active{background-color:#a27558}
 | 
					.ui.blue.button:active,.ui.blue.buttons .button:active{background-color:#a27558}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,6 +10,11 @@ function htmlEncode(text) {
 | 
				
			|||||||
var csrf;
 | 
					var csrf;
 | 
				
			||||||
var suburl;
 | 
					var suburl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Disable Dropzone auto-discover because it's manually initialized
 | 
				
			||||||
 | 
					if (typeof(Dropzone) !== "undefined") {
 | 
				
			||||||
 | 
					    Dropzone.autoDiscover = false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Polyfill for IE9+ support (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from)
 | 
					// Polyfill for IE9+ support (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from)
 | 
				
			||||||
if (!Array.from) {
 | 
					if (!Array.from) {
 | 
				
			||||||
    Array.from = (function () {
 | 
					    Array.from = (function () {
 | 
				
			||||||
@@ -1270,6 +1275,7 @@ function initEditor() {
 | 
				
			|||||||
            $('.quick-pull-branch-name').hide();
 | 
					            $('.quick-pull-branch-name').hide();
 | 
				
			||||||
            $('.quick-pull-branch-name input').prop('required',false);
 | 
					            $('.quick-pull-branch-name input').prop('required',false);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        $('#commit-button').text($(this).attr('button_text'));
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    var $editFilename = $("#file-name");
 | 
					    var $editFilename = $("#file-name");
 | 
				
			||||||
@@ -1968,17 +1974,18 @@ $(document).ready(function () {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    // Highlight JS
 | 
					    // Highlight JS
 | 
				
			||||||
    if (typeof hljs != 'undefined') {
 | 
					    if (typeof hljs != 'undefined') {
 | 
				
			||||||
        hljs.initHighlightingOnLoad();
 | 
					        const nodes = [].slice.call(document.querySelectorAll('pre code') || []);
 | 
				
			||||||
 | 
					        for (let i = 0; i < nodes.length; i++) {
 | 
				
			||||||
 | 
					            hljs.highlightBlock(nodes[i]);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Dropzone
 | 
					    // Dropzone
 | 
				
			||||||
    var $dropzone = $('#dropzone');
 | 
					    const $dropzone = $('#dropzone');
 | 
				
			||||||
    if ($dropzone.length > 0) {
 | 
					    if ($dropzone.length > 0) {
 | 
				
			||||||
        // Disable auto discover for all elements:
 | 
					        const filenameDict = {};
 | 
				
			||||||
        Dropzone.autoDiscover = false;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        var filenameDict = {};
 | 
					        new Dropzone("#dropzone", {
 | 
				
			||||||
        $dropzone.dropzone({
 | 
					 | 
				
			||||||
            url: $dropzone.data('upload-url'),
 | 
					            url: $dropzone.data('upload-url'),
 | 
				
			||||||
            headers: {"X-Csrf-Token": csrf},
 | 
					            headers: {"X-Csrf-Token": csrf},
 | 
				
			||||||
            maxFiles: $dropzone.data('max-file'),
 | 
					            maxFiles: $dropzone.data('max-file'),
 | 
				
			||||||
@@ -2006,7 +2013,7 @@ $(document).ready(function () {
 | 
				
			|||||||
                        });
 | 
					                        });
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                })
 | 
					                })
 | 
				
			||||||
            }
 | 
					            },
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -2104,12 +2111,16 @@ $(document).ready(function () {
 | 
				
			|||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    $('.issue-action').click(function () {
 | 
					    $('.issue-action').click(function () {
 | 
				
			||||||
        var action = this.dataset.action
 | 
					        let action = this.dataset.action;
 | 
				
			||||||
        var elementId = this.dataset.elementId
 | 
					        let elementId = this.dataset.elementId;
 | 
				
			||||||
        var issueIDs = $('.issue-checkbox').children('input:checked').map(function() {
 | 
					        let issueIDs = $('.issue-checkbox').children('input:checked').map(function() {
 | 
				
			||||||
            return this.dataset.issueId;
 | 
					            return this.dataset.issueId;
 | 
				
			||||||
        }).get().join();
 | 
					        }).get().join();
 | 
				
			||||||
        var url = this.dataset.url
 | 
					        let url = this.dataset.url;
 | 
				
			||||||
 | 
					        if (elementId === '0' && url.substr(-9) === '/assignee'){
 | 
				
			||||||
 | 
					            elementId = '';
 | 
				
			||||||
 | 
					            action = 'clear';
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        updateIssuesMeta(url, action, issueIDs, elementId).then(reload);
 | 
					        updateIssuesMeta(url, action, issueIDs, elementId).then(reload);
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -605,7 +605,6 @@ code,
 | 
				
			|||||||
.file-comment {
 | 
					.file-comment {
 | 
				
			||||||
    font: 12px @monospaced-fonts, monospace;
 | 
					    font: 12px @monospaced-fonts, monospace;
 | 
				
			||||||
    color: rgba(0, 0, 0, 0.87);
 | 
					    color: rgba(0, 0, 0, 0.87);
 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.ui.floating.dropdown {
 | 
					.ui.floating.dropdown {
 | 
				
			||||||
@@ -877,3 +876,19 @@ footer {
 | 
				
			|||||||
.ui.tabular.menu .item.active {
 | 
					.ui.tabular.menu .item.active {
 | 
				
			||||||
    color: rgba(0, 0, 0, 0.9);
 | 
					    color: rgba(0, 0, 0, 0.9);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* multiple radio or checkboxes as inline element */
 | 
				
			||||||
 | 
					.inline-grouped-list {
 | 
				
			||||||
 | 
					    display: inline-block;
 | 
				
			||||||
 | 
					    vertical-align: top;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    > .ui {
 | 
				
			||||||
 | 
					        display: block;
 | 
				
			||||||
 | 
					        margin-top: 5px;
 | 
				
			||||||
 | 
					        margin-bottom: 10px;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        &:first-child {
 | 
				
			||||||
 | 
					            margin-top: 1px;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1265,6 +1265,10 @@
 | 
				
			|||||||
            margin: 0;
 | 
					            margin: 0;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        td.message {
 | 
				
			||||||
 | 
					            text-overflow: unset;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        &.ui.basic.striped.table tbody tr:nth-child(2n) {
 | 
					        &.ui.basic.striped.table tbody tr:nth-child(2n) {
 | 
				
			||||||
            background-color: rgba(0, 0, 0, 0.02) !important;
 | 
					            background-color: rgba(0, 0, 0, 0.02) !important;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -1971,6 +1975,8 @@
 | 
				
			|||||||
&.user-cards {
 | 
					&.user-cards {
 | 
				
			||||||
    .list {
 | 
					    .list {
 | 
				
			||||||
        padding: 0;
 | 
					        padding: 0;
 | 
				
			||||||
 | 
					        display: flex;
 | 
				
			||||||
 | 
					        flex-wrap: wrap;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        .item {
 | 
					        .item {
 | 
				
			||||||
            list-style: none;
 | 
					            list-style: none;
 | 
				
			||||||
@@ -2300,12 +2306,12 @@ tbody.commit-list {
 | 
				
			|||||||
.commit-list .message-wrapper {
 | 
					.commit-list .message-wrapper {
 | 
				
			||||||
    overflow: hidden;
 | 
					    overflow: hidden;
 | 
				
			||||||
    text-overflow: ellipsis;
 | 
					    text-overflow: ellipsis;
 | 
				
			||||||
    max-width: calc(100% - 24px);
 | 
					    max-width: calc(100% - 50px);
 | 
				
			||||||
    display: inline-block;
 | 
					    display: inline-block;
 | 
				
			||||||
    vertical-align: middle;
 | 
					    vertical-align: middle;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.commit-list .message-wrapper .commit-status-link {
 | 
					.commit-list .commit-status-link {
 | 
				
			||||||
    display: inline-block;
 | 
					    display: inline-block;
 | 
				
			||||||
    vertical-align: middle;
 | 
					    vertical-align: middle;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1082,7 +1082,7 @@ a.ui.labels .label:hover {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(1),
 | 
					.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(1),
 | 
				
			||||||
.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(2),
 | 
					.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(2),
 | 
				
			||||||
.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(3),
 | 
					.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(3),
 | 
				
			||||||
.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(4),
 | 
					.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(4),
 | 
				
			||||||
.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(5),
 | 
					.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(5),
 | 
				
			||||||
.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(6) {
 | 
					.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(6) {
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										5
									
								
								public/vendor/VERSIONS
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								public/vendor/VERSIONS
									
									
									
									
										vendored
									
									
								
							@@ -6,7 +6,10 @@ File(s): /vendor/plugins/jquery.areyousure/jquery.are-you-sure.js
 | 
				
			|||||||
Version: 1.9.0
 | 
					Version: 1.9.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
File(s): /vendor/plugins/jquery/jquery.min.js
 | 
					File(s): /vendor/plugins/jquery/jquery.min.js
 | 
				
			||||||
Version: 1.12.4
 | 
					Version: 3.4.1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					File(s): /vendor/plugins/jquery-migrate/jquery-migrate.min.js
 | 
				
			||||||
 | 
					Version: 3.0.1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
File(s): /vendor/plugins/semantic/semantic.min.js
 | 
					File(s): /vendor/plugins/semantic/semantic.min.js
 | 
				
			||||||
Version: 2.3.1
 | 
					Version: 2.3.1
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										9
									
								
								public/vendor/librejs.html
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										9
									
								
								public/vendor/librejs.html
									
									
									
									
										vendored
									
									
								
							@@ -17,8 +17,13 @@
 | 
				
			|||||||
        </tr>
 | 
					        </tr>
 | 
				
			||||||
        <tr>
 | 
					        <tr>
 | 
				
			||||||
          <td><a href="./plugins/jquery/jquery.min.js">jquery.min.js</a></td>
 | 
					          <td><a href="./plugins/jquery/jquery.min.js">jquery.min.js</a></td>
 | 
				
			||||||
          <td><a href="http://www.freebsd.org/copyright/freebsd-license.html">Expat</a></td>
 | 
					          <td><a href="https://jquery.org/license/">MIT</a></td>
 | 
				
			||||||
          <td><a href="https://code.jquery.com/jquery-1.12.4.min.js">jquery-1.12.4.min.js</a></td>
 | 
					          <td><a href="https://code.jquery.com/jquery-3.4.1.min.js">jquery-3.4.1.min.js</a></td>
 | 
				
			||||||
 | 
					        </tr>
 | 
				
			||||||
 | 
					        <tr>
 | 
				
			||||||
 | 
					          <td><a href="./plugins/jquery-migrate/jquery-migrate.min.js">jquery-migrate.min.js</a></td>
 | 
				
			||||||
 | 
					          <td><a href="https://jquery.org/license/">MIT</a></td>
 | 
				
			||||||
 | 
					          <td><a href="https://code.jquery.com/jquery-migrate-3.0.1.min.js">jquery-migrate-3.0.1.min.js</a></td>
 | 
				
			||||||
        </tr>
 | 
					        </tr>
 | 
				
			||||||
        <tr>
 | 
					        <tr>
 | 
				
			||||||
          <td><a href="./plugins/semantic/semantic.min.js">semantic.min.js</a></td>
 | 
					          <td><a href="./plugins/semantic/semantic.min.js">semantic.min.js</a></td>
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										215
									
								
								public/vendor/plugins/jquery-migrate/jquery-migrate.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										215
									
								
								public/vendor/plugins/jquery-migrate/jquery-migrate.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,215 @@
 | 
				
			|||||||
 | 
					/*! jQuery Migrate v3.0.1 | (c) jQuery Foundation and other contributors | jquery.org/license */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void 0 === jQuery.migrateMute && (jQuery.migrateMute = !0), function(e) {
 | 
				
			||||||
 | 
					    "function" == typeof define && define.amd ? define([ "jquery" ], window, e) : "object" == typeof module && module.exports ? module.exports = e(require("jquery"), window) : e(jQuery, window);
 | 
				
			||||||
 | 
					}(function(e, t) {
 | 
				
			||||||
 | 
					    "use strict";
 | 
				
			||||||
 | 
					    function r(r) {
 | 
				
			||||||
 | 
					        var n = t.console;
 | 
				
			||||||
 | 
					        o[r] || (o[r] = !0, e.migrateWarnings.push(r), n && n.warn && !e.migrateMute && (n.warn("JQMIGRATE: " + r), 
 | 
				
			||||||
 | 
					        e.migrateTrace && n.trace && n.trace()));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    function n(e, t, n, a) {
 | 
				
			||||||
 | 
					        Object.defineProperty(e, t, {
 | 
				
			||||||
 | 
					            configurable: !0,
 | 
				
			||||||
 | 
					            enumerable: !0,
 | 
				
			||||||
 | 
					            get: function() {
 | 
				
			||||||
 | 
					                return r(a), n;
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            set: function(e) {
 | 
				
			||||||
 | 
					                r(a), n = e;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    function a(e, t, n, a) {
 | 
				
			||||||
 | 
					        e[t] = function() {
 | 
				
			||||||
 | 
					            return r(a), n.apply(this, arguments);
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    e.migrateVersion = "3.0.1", function() {
 | 
				
			||||||
 | 
					        var r = /^[12]\./;
 | 
				
			||||||
 | 
					        t.console && t.console.log && (e && !r.test(e.fn.jquery) || t.console.log("JQMIGRATE: jQuery 3.0.0+ REQUIRED"), 
 | 
				
			||||||
 | 
					        e.migrateWarnings && t.console.log("JQMIGRATE: Migrate plugin loaded multiple times"), 
 | 
				
			||||||
 | 
					        t.console.log("JQMIGRATE: Migrate is installed" + (e.migrateMute ? "" : " with logging active") + ", version " + e.migrateVersion));
 | 
				
			||||||
 | 
					    }();
 | 
				
			||||||
 | 
					    var o = {};
 | 
				
			||||||
 | 
					    e.migrateWarnings = [], void 0 === e.migrateTrace && (e.migrateTrace = !0), e.migrateReset = function() {
 | 
				
			||||||
 | 
					        o = {}, e.migrateWarnings.length = 0;
 | 
				
			||||||
 | 
					    }, "BackCompat" === t.document.compatMode && r("jQuery is not compatible with Quirks Mode");
 | 
				
			||||||
 | 
					    var i = e.fn.init, s = e.isNumeric, u = e.find, c = /\[(\s*[-\w]+\s*)([~|^$*]?=)\s*([-\w#]*?#[-\w#]*)\s*\]/, l = /\[(\s*[-\w]+\s*)([~|^$*]?=)\s*([-\w#]*?#[-\w#]*)\s*\]/g;
 | 
				
			||||||
 | 
					    e.fn.init = function(e) {
 | 
				
			||||||
 | 
					        var t = Array.prototype.slice.call(arguments);
 | 
				
			||||||
 | 
					        return "string" == typeof e && "#" === e && (r("jQuery( '#' ) is not a valid selector"), 
 | 
				
			||||||
 | 
					        t[0] = []), i.apply(this, t);
 | 
				
			||||||
 | 
					    }, e.fn.init.prototype = e.fn, e.find = function(e) {
 | 
				
			||||||
 | 
					        var n = Array.prototype.slice.call(arguments);
 | 
				
			||||||
 | 
					        if ("string" == typeof e && c.test(e)) try {
 | 
				
			||||||
 | 
					            t.document.querySelector(e);
 | 
				
			||||||
 | 
					        } catch (a) {
 | 
				
			||||||
 | 
					            e = e.replace(l, function(e, t, r, n) {
 | 
				
			||||||
 | 
					                return "[" + t + r + '"' + n + '"]';
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            try {
 | 
				
			||||||
 | 
					                t.document.querySelector(e), r("Attribute selector with '#' must be quoted: " + n[0]), 
 | 
				
			||||||
 | 
					                n[0] = e;
 | 
				
			||||||
 | 
					            } catch (e) {
 | 
				
			||||||
 | 
					                r("Attribute selector with '#' was not fixed: " + n[0]);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return u.apply(this, n);
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    var d;
 | 
				
			||||||
 | 
					    for (d in u) Object.prototype.hasOwnProperty.call(u, d) && (e.find[d] = u[d]);
 | 
				
			||||||
 | 
					    e.fn.size = function() {
 | 
				
			||||||
 | 
					        return r("jQuery.fn.size() is deprecated and removed; use the .length property"), 
 | 
				
			||||||
 | 
					        this.length;
 | 
				
			||||||
 | 
					    }, e.parseJSON = function() {
 | 
				
			||||||
 | 
					        return r("jQuery.parseJSON is deprecated; use JSON.parse"), JSON.parse.apply(null, arguments);
 | 
				
			||||||
 | 
					    }, e.isNumeric = function(t) {
 | 
				
			||||||
 | 
					        var n = s(t), a = function(t) {
 | 
				
			||||||
 | 
					            var r = t && t.toString();
 | 
				
			||||||
 | 
					            return !e.isArray(t) && r - parseFloat(r) + 1 >= 0;
 | 
				
			||||||
 | 
					        }(t);
 | 
				
			||||||
 | 
					        return n !== a && r("jQuery.isNumeric() should not be called on constructed objects"), 
 | 
				
			||||||
 | 
					        a;
 | 
				
			||||||
 | 
					    }, a(e, "holdReady", e.holdReady, "jQuery.holdReady is deprecated"), a(e, "unique", e.uniqueSort, "jQuery.unique is deprecated; use jQuery.uniqueSort"), 
 | 
				
			||||||
 | 
					    n(e.expr, "filters", e.expr.pseudos, "jQuery.expr.filters is deprecated; use jQuery.expr.pseudos"), 
 | 
				
			||||||
 | 
					    n(e.expr, ":", e.expr.pseudos, "jQuery.expr[':'] is deprecated; use jQuery.expr.pseudos");
 | 
				
			||||||
 | 
					    var p = e.ajax;
 | 
				
			||||||
 | 
					    e.ajax = function() {
 | 
				
			||||||
 | 
					        var e = p.apply(this, arguments);
 | 
				
			||||||
 | 
					        return e.promise && (a(e, "success", e.done, "jQXHR.success is deprecated and removed"), 
 | 
				
			||||||
 | 
					        a(e, "error", e.fail, "jQXHR.error is deprecated and removed"), a(e, "complete", e.always, "jQXHR.complete is deprecated and removed")), 
 | 
				
			||||||
 | 
					        e;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    var f = e.fn.removeAttr, y = e.fn.toggleClass, m = /\S+/g;
 | 
				
			||||||
 | 
					    e.fn.removeAttr = function(t) {
 | 
				
			||||||
 | 
					        var n = this;
 | 
				
			||||||
 | 
					        return e.each(t.match(m), function(t, a) {
 | 
				
			||||||
 | 
					            e.expr.match.bool.test(a) && (r("jQuery.fn.removeAttr no longer sets boolean properties: " + a), 
 | 
				
			||||||
 | 
					            n.prop(a, !1));
 | 
				
			||||||
 | 
					        }), f.apply(this, arguments);
 | 
				
			||||||
 | 
					    }, e.fn.toggleClass = function(t) {
 | 
				
			||||||
 | 
					        return void 0 !== t && "boolean" != typeof t ? y.apply(this, arguments) : (r("jQuery.fn.toggleClass( boolean ) is deprecated"), 
 | 
				
			||||||
 | 
					        this.each(function() {
 | 
				
			||||||
 | 
					            var r = this.getAttribute && this.getAttribute("class") || "";
 | 
				
			||||||
 | 
					            r && e.data(this, "__className__", r), this.setAttribute && this.setAttribute("class", r || !1 === t ? "" : e.data(this, "__className__") || "");
 | 
				
			||||||
 | 
					        }));
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    var h = !1;
 | 
				
			||||||
 | 
					    e.swap && e.each([ "height", "width", "reliableMarginRight" ], function(t, r) {
 | 
				
			||||||
 | 
					        var n = e.cssHooks[r] && e.cssHooks[r].get;
 | 
				
			||||||
 | 
					        n && (e.cssHooks[r].get = function() {
 | 
				
			||||||
 | 
					            var e;
 | 
				
			||||||
 | 
					            return h = !0, e = n.apply(this, arguments), h = !1, e;
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }), e.swap = function(e, t, n, a) {
 | 
				
			||||||
 | 
					        var o, i, s = {};
 | 
				
			||||||
 | 
					        h || r("jQuery.swap() is undocumented and deprecated");
 | 
				
			||||||
 | 
					        for (i in t) s[i] = e.style[i], e.style[i] = t[i];
 | 
				
			||||||
 | 
					        o = n.apply(e, a || []);
 | 
				
			||||||
 | 
					        for (i in t) e.style[i] = s[i];
 | 
				
			||||||
 | 
					        return o;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    var g = e.data;
 | 
				
			||||||
 | 
					    e.data = function(t, n, a) {
 | 
				
			||||||
 | 
					        var o;
 | 
				
			||||||
 | 
					        if (n && "object" == typeof n && 2 === arguments.length) {
 | 
				
			||||||
 | 
					            o = e.hasData(t) && g.call(this, t);
 | 
				
			||||||
 | 
					            var i = {};
 | 
				
			||||||
 | 
					            for (var s in n) s !== e.camelCase(s) ? (r("jQuery.data() always sets/gets camelCased names: " + s), 
 | 
				
			||||||
 | 
					            o[s] = n[s]) : i[s] = n[s];
 | 
				
			||||||
 | 
					            return g.call(this, t, i), n;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return n && "string" == typeof n && n !== e.camelCase(n) && (o = e.hasData(t) && g.call(this, t)) && n in o ? (r("jQuery.data() always sets/gets camelCased names: " + n), 
 | 
				
			||||||
 | 
					        arguments.length > 2 && (o[n] = a), o[n]) : g.apply(this, arguments);
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    var v = e.Tween.prototype.run, j = function(e) {
 | 
				
			||||||
 | 
					        return e;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    e.Tween.prototype.run = function() {
 | 
				
			||||||
 | 
					        e.easing[this.easing].length > 1 && (r("'jQuery.easing." + this.easing.toString() + "' should use only one argument"), 
 | 
				
			||||||
 | 
					        e.easing[this.easing] = j), v.apply(this, arguments);
 | 
				
			||||||
 | 
					    }, e.fx.interval = e.fx.interval || 13, t.requestAnimationFrame && n(e.fx, "interval", e.fx.interval, "jQuery.fx.interval is deprecated");
 | 
				
			||||||
 | 
					    var Q = e.fn.load, b = e.event.add, w = e.event.fix;
 | 
				
			||||||
 | 
					    e.event.props = [], e.event.fixHooks = {}, n(e.event.props, "concat", e.event.props.concat, "jQuery.event.props.concat() is deprecated and removed"), 
 | 
				
			||||||
 | 
					    e.event.fix = function(t) {
 | 
				
			||||||
 | 
					        var n, a = t.type, o = this.fixHooks[a], i = e.event.props;
 | 
				
			||||||
 | 
					        if (i.length) for (r("jQuery.event.props are deprecated and removed: " + i.join()); i.length; ) e.event.addProp(i.pop());
 | 
				
			||||||
 | 
					        if (o && !o._migrated_ && (o._migrated_ = !0, r("jQuery.event.fixHooks are deprecated and removed: " + a), 
 | 
				
			||||||
 | 
					        (i = o.props) && i.length)) for (;i.length; ) e.event.addProp(i.pop());
 | 
				
			||||||
 | 
					        return n = w.call(this, t), o && o.filter ? o.filter(n, t) : n;
 | 
				
			||||||
 | 
					    }, e.event.add = function(e, n) {
 | 
				
			||||||
 | 
					        return e === t && "load" === n && "complete" === t.document.readyState && r("jQuery(window).on('load'...) called after load event occurred"), 
 | 
				
			||||||
 | 
					        b.apply(this, arguments);
 | 
				
			||||||
 | 
					    }, e.each([ "load", "unload", "error" ], function(t, n) {
 | 
				
			||||||
 | 
					        e.fn[n] = function() {
 | 
				
			||||||
 | 
					            var e = Array.prototype.slice.call(arguments, 0);
 | 
				
			||||||
 | 
					            return "load" === n && "string" == typeof e[0] ? Q.apply(this, e) : (r("jQuery.fn." + n + "() is deprecated"), 
 | 
				
			||||||
 | 
					            e.splice(0, 0, n), arguments.length ? this.on.apply(this, e) : (this.triggerHandler.apply(this, e), 
 | 
				
			||||||
 | 
					            this));
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					    }), e.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "), function(t, n) {
 | 
				
			||||||
 | 
					        e.fn[n] = function(e, t) {
 | 
				
			||||||
 | 
					            return r("jQuery.fn." + n + "() event shorthand is deprecated"), arguments.length > 0 ? this.on(n, null, e, t) : this.trigger(n);
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					    }), e(function() {
 | 
				
			||||||
 | 
					        e(t.document).triggerHandler("ready");
 | 
				
			||||||
 | 
					    }), e.event.special.ready = {
 | 
				
			||||||
 | 
					        setup: function() {
 | 
				
			||||||
 | 
					            this === t.document && r("'ready' event is deprecated");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }, e.fn.extend({
 | 
				
			||||||
 | 
					        bind: function(e, t, n) {
 | 
				
			||||||
 | 
					            return r("jQuery.fn.bind() is deprecated"), this.on(e, null, t, n);
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        unbind: function(e, t) {
 | 
				
			||||||
 | 
					            return r("jQuery.fn.unbind() is deprecated"), this.off(e, null, t);
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        delegate: function(e, t, n, a) {
 | 
				
			||||||
 | 
					            return r("jQuery.fn.delegate() is deprecated"), this.on(t, e, n, a);
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        undelegate: function(e, t, n) {
 | 
				
			||||||
 | 
					            return r("jQuery.fn.undelegate() is deprecated"), 1 === arguments.length ? this.off(e, "**") : this.off(t, e || "**", n);
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        hover: function(e, t) {
 | 
				
			||||||
 | 
					            return r("jQuery.fn.hover() is deprecated"), this.on("mouseenter", e).on("mouseleave", t || e);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    var x = e.fn.offset;
 | 
				
			||||||
 | 
					    e.fn.offset = function() {
 | 
				
			||||||
 | 
					        var n, a = this[0], o = {
 | 
				
			||||||
 | 
					            top: 0,
 | 
				
			||||||
 | 
					            left: 0
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        return a && a.nodeType ? (n = (a.ownerDocument || t.document).documentElement, e.contains(n, a) ? x.apply(this, arguments) : (r("jQuery.fn.offset() requires an element connected to a document"), 
 | 
				
			||||||
 | 
					        o)) : (r("jQuery.fn.offset() requires a valid DOM element"), o);
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    var k = e.param;
 | 
				
			||||||
 | 
					    e.param = function(t, n) {
 | 
				
			||||||
 | 
					        var a = e.ajaxSettings && e.ajaxSettings.traditional;
 | 
				
			||||||
 | 
					        return void 0 === n && a && (r("jQuery.param() no longer uses jQuery.ajaxSettings.traditional"), 
 | 
				
			||||||
 | 
					        n = a), k.call(this, t, n);
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    var A = e.fn.andSelf || e.fn.addBack;
 | 
				
			||||||
 | 
					    e.fn.andSelf = function() {
 | 
				
			||||||
 | 
					        return r("jQuery.fn.andSelf() is deprecated and removed, use jQuery.fn.addBack()"), 
 | 
				
			||||||
 | 
					        A.apply(this, arguments);
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    var S = e.Deferred, q = [ [ "resolve", "done", e.Callbacks("once memory"), e.Callbacks("once memory"), "resolved" ], [ "reject", "fail", e.Callbacks("once memory"), e.Callbacks("once memory"), "rejected" ], [ "notify", "progress", e.Callbacks("memory"), e.Callbacks("memory") ] ];
 | 
				
			||||||
 | 
					    return e.Deferred = function(t) {
 | 
				
			||||||
 | 
					        var n = S(), a = n.promise();
 | 
				
			||||||
 | 
					        return n.pipe = a.pipe = function() {
 | 
				
			||||||
 | 
					            var t = arguments;
 | 
				
			||||||
 | 
					            return r("deferred.pipe() is deprecated"), e.Deferred(function(r) {
 | 
				
			||||||
 | 
					                e.each(q, function(o, i) {
 | 
				
			||||||
 | 
					                    var s = e.isFunction(t[o]) && t[o];
 | 
				
			||||||
 | 
					                    n[i[1]](function() {
 | 
				
			||||||
 | 
					                        var t = s && s.apply(this, arguments);
 | 
				
			||||||
 | 
					                        t && e.isFunction(t.promise) ? t.promise().done(r.resolve).fail(r.reject).progress(r.notify) : r[i[0] + "With"](this === a ? r.promise() : this, s ? [ t ] : arguments);
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					                }), t = null;
 | 
				
			||||||
 | 
					            }).promise();
 | 
				
			||||||
 | 
					        }, t && t.call(n, n), n;
 | 
				
			||||||
 | 
					    }, e.Deferred.exceptionHook = S.exceptionHook, e;
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
							
								
								
									
										7
									
								
								public/vendor/plugins/jquery/jquery.min.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								public/vendor/plugins/jquery/jquery.min.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							@@ -82,6 +82,15 @@ func GetAllOrgs(ctx *context.APIContext) {
 | 
				
			|||||||
	// summary: List all organizations
 | 
						// summary: List all organizations
 | 
				
			||||||
	// produces:
 | 
						// produces:
 | 
				
			||||||
	// - application/json
 | 
						// - application/json
 | 
				
			||||||
 | 
						// parameters:
 | 
				
			||||||
 | 
						// - name: page
 | 
				
			||||||
 | 
						//   in: query
 | 
				
			||||||
 | 
						//   description: page number of results to return (1-based)
 | 
				
			||||||
 | 
						//   type: integer
 | 
				
			||||||
 | 
						// - name: limit
 | 
				
			||||||
 | 
						//   in: query
 | 
				
			||||||
 | 
						//   description: page size of results, maximum page size is 50
 | 
				
			||||||
 | 
						//   type: integer
 | 
				
			||||||
	// responses:
 | 
						// responses:
 | 
				
			||||||
	//   "200":
 | 
						//   "200":
 | 
				
			||||||
	//     "$ref": "#/responses/OrganizationList"
 | 
						//     "$ref": "#/responses/OrganizationList"
 | 
				
			||||||
@@ -90,7 +99,9 @@ func GetAllOrgs(ctx *context.APIContext) {
 | 
				
			|||||||
	users, _, err := models.SearchUsers(&models.SearchUserOptions{
 | 
						users, _, err := models.SearchUsers(&models.SearchUserOptions{
 | 
				
			||||||
		Type:     models.UserTypeOrganization,
 | 
							Type:     models.UserTypeOrganization,
 | 
				
			||||||
		OrderBy:  models.SearchOrderByAlphabetically,
 | 
							OrderBy:  models.SearchOrderByAlphabetically,
 | 
				
			||||||
		PageSize: -1,
 | 
							Page:     ctx.QueryInt("page"),
 | 
				
			||||||
 | 
							PageSize: convert.ToCorrectPageSize(ctx.QueryInt("limit")),
 | 
				
			||||||
 | 
							Private:  true,
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		ctx.Error(500, "SearchOrganizations", err)
 | 
							ctx.Error(500, "SearchOrganizations", err)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -91,8 +91,7 @@ func CreateUser(ctx *context.APIContext, form api.CreateUserOption) {
 | 
				
			|||||||
	if form.SendNotify && setting.MailService != nil {
 | 
						if form.SendNotify && setting.MailService != nil {
 | 
				
			||||||
		models.SendRegisterNotifyMail(ctx.Context.Context, u)
 | 
							models.SendRegisterNotifyMail(ctx.Context.Context, u)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						ctx.JSON(201, convert.ToUser(u, ctx.IsSigned, ctx.User.IsAdmin))
 | 
				
			||||||
	ctx.JSON(201, u.APIFormat())
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// EditUser api for modifying a user's information
 | 
					// EditUser api for modifying a user's information
 | 
				
			||||||
@@ -181,7 +180,7 @@ func EditUser(ctx *context.APIContext, form api.EditUserOption) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	log.Trace("Account profile updated by admin (%s): %s", ctx.User.Name, u.Name)
 | 
						log.Trace("Account profile updated by admin (%s): %s", ctx.User.Name, u.Name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ctx.JSON(200, u.APIFormat())
 | 
						ctx.JSON(200, convert.ToUser(u, ctx.IsSigned, ctx.User.IsAdmin))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// DeleteUser api for deleting a user
 | 
					// DeleteUser api for deleting a user
 | 
				
			||||||
@@ -326,7 +325,7 @@ func GetAllUsers(ctx *context.APIContext) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	results := make([]*api.User, len(users))
 | 
						results := make([]*api.User, len(users))
 | 
				
			||||||
	for i := range users {
 | 
						for i := range users {
 | 
				
			||||||
		results[i] = convert.ToUser(users[i], ctx.IsSigned, ctx.User != nil && ctx.User.IsAdmin)
 | 
							results[i] = convert.ToUser(users[i], ctx.IsSigned, ctx.User.IsAdmin)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ctx.JSON(200, &results)
 | 
						ctx.JSON(200, &results)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -229,7 +229,7 @@ func ToTeam(team *models.Team) *api.Team {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ToUser convert models.User to api.User
 | 
					// ToUser convert models.User to api.User
 | 
				
			||||||
func ToUser(user *models.User, signed, admin bool) *api.User {
 | 
					func ToUser(user *models.User, signed, authed bool) *api.User {
 | 
				
			||||||
	result := &api.User{
 | 
						result := &api.User{
 | 
				
			||||||
		ID:        user.ID,
 | 
							ID:        user.ID,
 | 
				
			||||||
		UserName:  user.Name,
 | 
							UserName:  user.Name,
 | 
				
			||||||
@@ -239,7 +239,12 @@ func ToUser(user *models.User, signed, admin bool) *api.User {
 | 
				
			|||||||
		LastLogin: user.LastLoginUnix.AsTime(),
 | 
							LastLogin: user.LastLoginUnix.AsTime(),
 | 
				
			||||||
		Created:   user.CreatedUnix.AsTime(),
 | 
							Created:   user.CreatedUnix.AsTime(),
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if signed && (!user.KeepEmailPrivate || admin) {
 | 
						// hide primary email if API caller isn't user itself or an admin
 | 
				
			||||||
 | 
						if !signed {
 | 
				
			||||||
 | 
							result.Email = ""
 | 
				
			||||||
 | 
						} else if user.KeepEmailPrivate && !authed {
 | 
				
			||||||
 | 
							result.Email = user.GetEmail()
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
		result.Email = user.Email
 | 
							result.Email = user.Email
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return result
 | 
						return result
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,6 +12,7 @@ import (
 | 
				
			|||||||
	"code.gitea.io/gitea/models"
 | 
						"code.gitea.io/gitea/models"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/context"
 | 
						"code.gitea.io/gitea/modules/context"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/setting"
 | 
						"code.gitea.io/gitea/modules/setting"
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/routers/api/v1/convert"
 | 
				
			||||||
	"code.gitea.io/gitea/routers/api/v1/user"
 | 
						"code.gitea.io/gitea/routers/api/v1/user"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -46,7 +47,7 @@ func listMembers(ctx *context.APIContext, publicOnly bool) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	apiMembers := make([]*api.User, len(members))
 | 
						apiMembers := make([]*api.User, len(members))
 | 
				
			||||||
	for i, member := range members {
 | 
						for i, member := range members {
 | 
				
			||||||
		apiMembers[i] = member.APIFormat()
 | 
							apiMembers[i] = convert.ToUser(member, ctx.IsSigned, ctx.User != nil && ctx.User.IsAdmin)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	ctx.JSON(200, apiMembers)
 | 
						ctx.JSON(200, apiMembers)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -257,7 +257,7 @@ func GetTeamMembers(ctx *context.APIContext) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	members := make([]*api.User, len(team.Members))
 | 
						members := make([]*api.User, len(team.Members))
 | 
				
			||||||
	for i, member := range team.Members {
 | 
						for i, member := range team.Members {
 | 
				
			||||||
		members[i] = member.APIFormat()
 | 
							members[i] = convert.ToUser(member, ctx.IsSigned, ctx.User.IsAdmin)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	ctx.JSON(200, members)
 | 
						ctx.JSON(200, members)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -288,7 +288,7 @@ func GetTeamMember(ctx *context.APIContext) {
 | 
				
			|||||||
	if ctx.Written() {
 | 
						if ctx.Written() {
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	ctx.JSON(200, u.APIFormat())
 | 
						ctx.JSON(200, convert.ToUser(u, ctx.IsSigned, ctx.User.IsAdmin))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// AddTeamMember api for add a member to a team
 | 
					// AddTeamMember api for add a member to a team
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,6 +12,7 @@ import (
 | 
				
			|||||||
	"code.gitea.io/gitea/modules/context"
 | 
						"code.gitea.io/gitea/modules/context"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	api "code.gitea.io/gitea/modules/structs"
 | 
						api "code.gitea.io/gitea/modules/structs"
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/routers/api/v1/convert"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ListCollaborators list a repository's collaborators
 | 
					// ListCollaborators list a repository's collaborators
 | 
				
			||||||
@@ -42,7 +43,7 @@ func ListCollaborators(ctx *context.APIContext) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	users := make([]*api.User, len(collaborators))
 | 
						users := make([]*api.User, len(collaborators))
 | 
				
			||||||
	for i, collaborator := range collaborators {
 | 
						for i, collaborator := range collaborators {
 | 
				
			||||||
		users[i] = collaborator.APIFormat()
 | 
							users[i] = convert.ToUser(collaborator.User, ctx.IsSigned, ctx.User != nil && ctx.User.IsAdmin)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	ctx.JSON(200, users)
 | 
						ctx.JSON(200, users)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -92,7 +92,7 @@ func GetSingleCommit(ctx *context.APIContext) {
 | 
				
			|||||||
			URL: setting.AppURL + ctx.Link[1:],
 | 
								URL: setting.AppURL + ctx.Link[1:],
 | 
				
			||||||
			SHA: commit.ID.String(),
 | 
								SHA: commit.ID.String(),
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		HTMLURL: ctx.Repo.Repository.HTMLURL() + "/commits/" + commit.ID.String(),
 | 
							HTMLURL: ctx.Repo.Repository.HTMLURL() + "/commit/" + commit.ID.String(),
 | 
				
			||||||
		RepoCommit: &api.RepoCommit{
 | 
							RepoCommit: &api.RepoCommit{
 | 
				
			||||||
			URL: setting.AppURL + ctx.Link[1:],
 | 
								URL: setting.AppURL + ctx.Link[1:],
 | 
				
			||||||
			Author: &api.CommitUser{
 | 
								Author: &api.CommitUser{
 | 
				
			||||||
@@ -111,7 +111,7 @@ func GetSingleCommit(ctx *context.APIContext) {
 | 
				
			|||||||
			},
 | 
								},
 | 
				
			||||||
			Message: commit.Message(),
 | 
								Message: commit.Message(),
 | 
				
			||||||
			Tree: &api.CommitMeta{
 | 
								Tree: &api.CommitMeta{
 | 
				
			||||||
				URL: ctx.Repo.Repository.APIURL() + "/trees/" + commit.ID.String(),
 | 
									URL: ctx.Repo.Repository.APIURL() + "/git/trees/" + commit.ID.String(),
 | 
				
			||||||
				SHA: commit.ID.String(),
 | 
									SHA: commit.ID.String(),
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -71,19 +71,22 @@ func GetGitRefs(ctx *context.APIContext) {
 | 
				
			|||||||
	getGitRefsInternal(ctx, ctx.Params("*"))
 | 
						getGitRefsInternal(ctx, ctx.Params("*"))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func getGitRefsInternal(ctx *context.APIContext, filter string) {
 | 
					func getGitRefs(ctx *context.APIContext, filter string) ([]*git.Reference, string, error) {
 | 
				
			||||||
	gitRepo, err := git.OpenRepository(ctx.Repo.Repository.RepoPath())
 | 
						gitRepo, err := git.OpenRepository(ctx.Repo.Repository.RepoPath())
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		ctx.Error(500, "OpenRepository", err)
 | 
							return nil, "OpenRepository", err
 | 
				
			||||||
		return
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if len(filter) > 0 {
 | 
						if len(filter) > 0 {
 | 
				
			||||||
		filter = "refs/" + filter
 | 
							filter = "refs/" + filter
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					 | 
				
			||||||
	refs, err := gitRepo.GetRefsFiltered(filter)
 | 
						refs, err := gitRepo.GetRefsFiltered(filter)
 | 
				
			||||||
 | 
						return refs, "GetRefsFiltered", err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func getGitRefsInternal(ctx *context.APIContext, filter string) {
 | 
				
			||||||
 | 
						refs, lastMethodName, err := getGitRefs(ctx, filter)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		ctx.Error(500, "GetRefsFiltered", err)
 | 
							ctx.Error(500, lastMethodName, err)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -130,8 +130,8 @@ func TestHook(ctx *context.APIContext) {
 | 
				
			|||||||
			convert.ToCommit(ctx.Repo.Repository, ctx.Repo.Commit),
 | 
								convert.ToCommit(ctx.Repo.Repository, ctx.Repo.Commit),
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		Repo:   ctx.Repo.Repository.APIFormat(models.AccessModeNone),
 | 
							Repo:   ctx.Repo.Repository.APIFormat(models.AccessModeNone),
 | 
				
			||||||
		Pusher: ctx.User.APIFormat(),
 | 
							Pusher: convert.ToUser(ctx.User, ctx.IsSigned, false),
 | 
				
			||||||
		Sender: ctx.User.APIFormat(),
 | 
							Sender: convert.ToUser(ctx.User, ctx.IsSigned, false),
 | 
				
			||||||
	}); err != nil {
 | 
						}); err != nil {
 | 
				
			||||||
		ctx.Error(500, "PrepareWebhook: ", err)
 | 
							ctx.Error(500, "PrepareWebhook: ", err)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -183,7 +183,8 @@ func CreateReleaseAttachment(ctx *context.APIContext) {
 | 
				
			|||||||
	allowed := false
 | 
						allowed := false
 | 
				
			||||||
	for _, t := range allowedTypes {
 | 
						for _, t := range allowedTypes {
 | 
				
			||||||
		t := strings.Trim(t, " ")
 | 
							t := strings.Trim(t, " ")
 | 
				
			||||||
		if t == "*/*" || t == fileType {
 | 
							if t == "*/*" || t == fileType ||
 | 
				
			||||||
 | 
								strings.HasPrefix(fileType, t+";") {
 | 
				
			||||||
			allowed = true
 | 
								allowed = true
 | 
				
			||||||
			break
 | 
								break
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -646,89 +646,102 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error {
 | 
				
			|||||||
		})
 | 
							})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if opts.HasIssues != nil {
 | 
						if opts.HasIssues == nil {
 | 
				
			||||||
		if *opts.HasIssues {
 | 
							// If HasIssues setting not touched, rewrite existing repo unit
 | 
				
			||||||
			// We don't currently allow setting individual issue settings through the API,
 | 
							if unit, err := repo.GetUnit(models.UnitTypeIssues); err == nil {
 | 
				
			||||||
			// only can enable/disable issues, so when enabling issues,
 | 
								units = append(units, *unit)
 | 
				
			||||||
			// we either get the existing config which means it was already enabled,
 | 
							} else if unit, err := repo.GetUnit(models.UnitTypeExternalTracker); err == nil {
 | 
				
			||||||
			// or create a new config since it doesn't exist.
 | 
								units = append(units, *unit)
 | 
				
			||||||
			unit, err := repo.GetUnit(models.UnitTypeIssues)
 | 
					 | 
				
			||||||
			var config *models.IssuesConfig
 | 
					 | 
				
			||||||
			if err != nil {
 | 
					 | 
				
			||||||
				// Unit type doesn't exist so we make a new config file with default values
 | 
					 | 
				
			||||||
				config = &models.IssuesConfig{
 | 
					 | 
				
			||||||
					EnableTimetracker:                true,
 | 
					 | 
				
			||||||
					AllowOnlyContributorsToTrackTime: true,
 | 
					 | 
				
			||||||
					EnableDependencies:               true,
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			} else {
 | 
					 | 
				
			||||||
				config = unit.IssuesConfig()
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			units = append(units, models.RepoUnit{
 | 
					 | 
				
			||||||
				RepoID: repo.ID,
 | 
					 | 
				
			||||||
				Type:   models.UnitTypeIssues,
 | 
					 | 
				
			||||||
				Config: config,
 | 
					 | 
				
			||||||
			})
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
						} else if *opts.HasIssues {
 | 
				
			||||||
 | 
							// We don't currently allow setting individual issue settings through the API,
 | 
				
			||||||
 | 
							// only can enable/disable issues, so when enabling issues,
 | 
				
			||||||
 | 
							// we either get the existing config which means it was already enabled,
 | 
				
			||||||
 | 
							// or create a new config since it doesn't exist.
 | 
				
			||||||
 | 
							unit, err := repo.GetUnit(models.UnitTypeIssues)
 | 
				
			||||||
 | 
							var config *models.IssuesConfig
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								// Unit type doesn't exist so we make a new config file with default values
 | 
				
			||||||
 | 
								config = &models.IssuesConfig{
 | 
				
			||||||
 | 
									EnableTimetracker:                true,
 | 
				
			||||||
 | 
									AllowOnlyContributorsToTrackTime: true,
 | 
				
			||||||
 | 
									EnableDependencies:               true,
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								config = unit.IssuesConfig()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							units = append(units, models.RepoUnit{
 | 
				
			||||||
 | 
								RepoID: repo.ID,
 | 
				
			||||||
 | 
								Type:   models.UnitTypeIssues,
 | 
				
			||||||
 | 
								Config: config,
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if opts.HasWiki != nil {
 | 
						if opts.HasWiki == nil {
 | 
				
			||||||
		if *opts.HasWiki {
 | 
							// If HasWiki setting not touched, rewrite existing repo unit
 | 
				
			||||||
			// We don't currently allow setting individual wiki settings through the API,
 | 
							if unit, err := repo.GetUnit(models.UnitTypeWiki); err == nil {
 | 
				
			||||||
			// only can enable/disable the wiki, so when enabling the wiki,
 | 
								units = append(units, *unit)
 | 
				
			||||||
			// we either get the existing config which means it was already enabled,
 | 
							} else if unit, err := repo.GetUnit(models.UnitTypeExternalWiki); err == nil {
 | 
				
			||||||
			// or create a new config since it doesn't exist.
 | 
								units = append(units, *unit)
 | 
				
			||||||
			config := &models.UnitConfig{}
 | 
					 | 
				
			||||||
			units = append(units, models.RepoUnit{
 | 
					 | 
				
			||||||
				RepoID: repo.ID,
 | 
					 | 
				
			||||||
				Type:   models.UnitTypeWiki,
 | 
					 | 
				
			||||||
				Config: config,
 | 
					 | 
				
			||||||
			})
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
						} else if *opts.HasWiki {
 | 
				
			||||||
 | 
							// We don't currently allow setting individual wiki settings through the API,
 | 
				
			||||||
 | 
							// only can enable/disable the wiki, so when enabling the wiki,
 | 
				
			||||||
 | 
							// we either get the existing config which means it was already enabled,
 | 
				
			||||||
 | 
							// or create a new config since it doesn't exist.
 | 
				
			||||||
 | 
							config := &models.UnitConfig{}
 | 
				
			||||||
 | 
							units = append(units, models.RepoUnit{
 | 
				
			||||||
 | 
								RepoID: repo.ID,
 | 
				
			||||||
 | 
								Type:   models.UnitTypeWiki,
 | 
				
			||||||
 | 
								Config: config,
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if opts.HasPullRequests != nil {
 | 
						if opts.HasPullRequests == nil {
 | 
				
			||||||
		if *opts.HasPullRequests {
 | 
							// If HasPullRequest setting not touched, rewrite existing repo unit
 | 
				
			||||||
			// We do allow setting individual PR settings through the API, so
 | 
							if unit, err := repo.GetUnit(models.UnitTypePullRequests); err == nil {
 | 
				
			||||||
			// we get the config settings and then set them
 | 
								units = append(units, *unit)
 | 
				
			||||||
			// if those settings were provided in the opts.
 | 
					 | 
				
			||||||
			unit, err := repo.GetUnit(models.UnitTypePullRequests)
 | 
					 | 
				
			||||||
			var config *models.PullRequestsConfig
 | 
					 | 
				
			||||||
			if err != nil {
 | 
					 | 
				
			||||||
				// Unit type doesn't exist so we make a new config file with default values
 | 
					 | 
				
			||||||
				config = &models.PullRequestsConfig{
 | 
					 | 
				
			||||||
					IgnoreWhitespaceConflicts: false,
 | 
					 | 
				
			||||||
					AllowMerge:                true,
 | 
					 | 
				
			||||||
					AllowRebase:               true,
 | 
					 | 
				
			||||||
					AllowRebaseMerge:          true,
 | 
					 | 
				
			||||||
					AllowSquash:               true,
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			} else {
 | 
					 | 
				
			||||||
				config = unit.PullRequestsConfig()
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if opts.IgnoreWhitespaceConflicts != nil {
 | 
					 | 
				
			||||||
				config.IgnoreWhitespaceConflicts = *opts.IgnoreWhitespaceConflicts
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			if opts.AllowMerge != nil {
 | 
					 | 
				
			||||||
				config.AllowMerge = *opts.AllowMerge
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			if opts.AllowRebase != nil {
 | 
					 | 
				
			||||||
				config.AllowRebase = *opts.AllowRebase
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			if opts.AllowRebaseMerge != nil {
 | 
					 | 
				
			||||||
				config.AllowRebaseMerge = *opts.AllowRebaseMerge
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			if opts.AllowSquash != nil {
 | 
					 | 
				
			||||||
				config.AllowSquash = *opts.AllowSquash
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			units = append(units, models.RepoUnit{
 | 
					 | 
				
			||||||
				RepoID: repo.ID,
 | 
					 | 
				
			||||||
				Type:   models.UnitTypePullRequests,
 | 
					 | 
				
			||||||
				Config: config,
 | 
					 | 
				
			||||||
			})
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
						} else if *opts.HasPullRequests {
 | 
				
			||||||
 | 
							// We do allow setting individual PR settings through the API, so
 | 
				
			||||||
 | 
							// we get the config settings and then set them
 | 
				
			||||||
 | 
							// if those settings were provided in the opts.
 | 
				
			||||||
 | 
							unit, err := repo.GetUnit(models.UnitTypePullRequests)
 | 
				
			||||||
 | 
							var config *models.PullRequestsConfig
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								// Unit type doesn't exist so we make a new config file with default values
 | 
				
			||||||
 | 
								config = &models.PullRequestsConfig{
 | 
				
			||||||
 | 
									IgnoreWhitespaceConflicts: false,
 | 
				
			||||||
 | 
									AllowMerge:                true,
 | 
				
			||||||
 | 
									AllowRebase:               true,
 | 
				
			||||||
 | 
									AllowRebaseMerge:          true,
 | 
				
			||||||
 | 
									AllowSquash:               true,
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								config = unit.PullRequestsConfig()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if opts.IgnoreWhitespaceConflicts != nil {
 | 
				
			||||||
 | 
								config.IgnoreWhitespaceConflicts = *opts.IgnoreWhitespaceConflicts
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if opts.AllowMerge != nil {
 | 
				
			||||||
 | 
								config.AllowMerge = *opts.AllowMerge
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if opts.AllowRebase != nil {
 | 
				
			||||||
 | 
								config.AllowRebase = *opts.AllowRebase
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if opts.AllowRebaseMerge != nil {
 | 
				
			||||||
 | 
								config.AllowRebaseMerge = *opts.AllowRebaseMerge
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if opts.AllowSquash != nil {
 | 
				
			||||||
 | 
								config.AllowSquash = *opts.AllowSquash
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							units = append(units, models.RepoUnit{
 | 
				
			||||||
 | 
								RepoID: repo.ID,
 | 
				
			||||||
 | 
								Type:   models.UnitTypePullRequests,
 | 
				
			||||||
 | 
								Config: config,
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := models.UpdateRepositoryUnits(repo, units); err != nil {
 | 
						if err := models.UpdateRepositoryUnits(repo, units); err != nil {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,7 @@ import (
 | 
				
			|||||||
	"code.gitea.io/gitea/modules/context"
 | 
						"code.gitea.io/gitea/modules/context"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	api "code.gitea.io/gitea/modules/structs"
 | 
						api "code.gitea.io/gitea/modules/structs"
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/routers/api/v1/convert"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ListStargazers list a repository's stargazers
 | 
					// ListStargazers list a repository's stargazers
 | 
				
			||||||
@@ -38,7 +39,7 @@ func ListStargazers(ctx *context.APIContext) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	users := make([]*api.User, len(stargazers))
 | 
						users := make([]*api.User, len(stargazers))
 | 
				
			||||||
	for i, stargazer := range stargazers {
 | 
						for i, stargazer := range stargazers {
 | 
				
			||||||
		users[i] = stargazer.APIFormat()
 | 
							users[i] = convert.ToUser(stargazer, ctx.IsSigned, ctx.User != nil && ctx.User.IsAdmin)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	ctx.JSON(200, users)
 | 
						ctx.JSON(200, users)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -46,10 +46,7 @@ func NewCommitStatus(ctx *context.APIContext, form api.CreateStatusOption) {
 | 
				
			|||||||
	//     "$ref": "#/responses/StatusList"
 | 
						//     "$ref": "#/responses/StatusList"
 | 
				
			||||||
	sha := ctx.Params("sha")
 | 
						sha := ctx.Params("sha")
 | 
				
			||||||
	if len(sha) == 0 {
 | 
						if len(sha) == 0 {
 | 
				
			||||||
		sha = ctx.Params("ref")
 | 
							ctx.Error(400, "sha not given", nil)
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if len(sha) == 0 {
 | 
					 | 
				
			||||||
		ctx.Error(400, "ref/sha not given", nil)
 | 
					 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	status := &models.CommitStatus{
 | 
						status := &models.CommitStatus{
 | 
				
			||||||
@@ -121,7 +118,38 @@ func GetCommitStatusesByRef(ctx *context.APIContext) {
 | 
				
			|||||||
	// responses:
 | 
						// responses:
 | 
				
			||||||
	//   "200":
 | 
						//   "200":
 | 
				
			||||||
	//     "$ref": "#/responses/StatusList"
 | 
						//     "$ref": "#/responses/StatusList"
 | 
				
			||||||
	getCommitStatuses(ctx, ctx.Params("ref"))
 | 
					
 | 
				
			||||||
 | 
						filter := ctx.Params("ref")
 | 
				
			||||||
 | 
						if len(filter) == 0 {
 | 
				
			||||||
 | 
							ctx.Error(400, "ref not given", nil)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, reftype := range []string{"heads", "tags"} { //Search branches and tags
 | 
				
			||||||
 | 
							refSHA, lastMethodName, err := searchRefCommitByType(ctx, reftype, filter)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								ctx.Error(500, lastMethodName, err)
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if refSHA != "" {
 | 
				
			||||||
 | 
								filter = refSHA
 | 
				
			||||||
 | 
								break
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						getCommitStatuses(ctx, filter) //By default filter is maybe the raw SHA
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func searchRefCommitByType(ctx *context.APIContext, refType, filter string) (string, string, error) {
 | 
				
			||||||
 | 
						refs, lastMethodName, err := getGitRefs(ctx, refType+"/"+filter) //Search by type
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return "", lastMethodName, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if len(refs) > 0 {
 | 
				
			||||||
 | 
							return refs[0].Object.String(), "", nil //Return found SHA
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return "", "", nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func getCommitStatuses(ctx *context.APIContext, sha string) {
 | 
					func getCommitStatuses(ctx *context.APIContext, sha string) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,7 @@ import (
 | 
				
			|||||||
	"code.gitea.io/gitea/modules/context"
 | 
						"code.gitea.io/gitea/modules/context"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	api "code.gitea.io/gitea/modules/structs"
 | 
						api "code.gitea.io/gitea/modules/structs"
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/routers/api/v1/convert"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ListSubscribers list a repo's subscribers (i.e. watchers)
 | 
					// ListSubscribers list a repo's subscribers (i.e. watchers)
 | 
				
			||||||
@@ -38,7 +39,7 @@ func ListSubscribers(ctx *context.APIContext) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	users := make([]*api.User, len(subscribers))
 | 
						users := make([]*api.User, len(subscribers))
 | 
				
			||||||
	for i, subscriber := range subscribers {
 | 
						for i, subscriber := range subscribers {
 | 
				
			||||||
		users[i] = subscriber.APIFormat()
 | 
							users[i] = convert.ToUser(subscriber, ctx.IsSigned, ctx.User != nil && ctx.User.IsAdmin)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	ctx.JSON(200, users)
 | 
						ctx.JSON(200, users)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,12 +9,13 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	"code.gitea.io/gitea/models"
 | 
						"code.gitea.io/gitea/models"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/context"
 | 
						"code.gitea.io/gitea/modules/context"
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/routers/api/v1/convert"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func responseAPIUsers(ctx *context.APIContext, users []*models.User) {
 | 
					func responseAPIUsers(ctx *context.APIContext, users []*models.User) {
 | 
				
			||||||
	apiUsers := make([]*api.User, len(users))
 | 
						apiUsers := make([]*api.User, len(users))
 | 
				
			||||||
	for i := range users {
 | 
						for i := range users {
 | 
				
			||||||
		apiUsers[i] = users[i].APIFormat()
 | 
							apiUsers[i] = convert.ToUser(users[i], ctx.IsSigned, ctx.User != nil && ctx.User.IsAdmin)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	ctx.JSON(200, &apiUsers)
 | 
						ctx.JSON(200, &apiUsers)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,13 +22,13 @@ func appendPrivateInformation(apiKey *api.PublicKey, key *models.PublicKey, defa
 | 
				
			|||||||
		apiKey.KeyType = "user"
 | 
							apiKey.KeyType = "user"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if defaultUser.ID == key.OwnerID {
 | 
							if defaultUser.ID == key.OwnerID {
 | 
				
			||||||
			apiKey.Owner = defaultUser.APIFormat()
 | 
								apiKey.Owner = convert.ToUser(defaultUser, true, true)
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			user, err := models.GetUserByID(key.OwnerID)
 | 
								user, err := models.GetUserByID(key.OwnerID)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return apiKey, err
 | 
									return apiKey, err
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			apiKey.Owner = user.APIFormat()
 | 
								apiKey.Owner = convert.ToUser(user, true, true)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		apiKey.KeyType = "unknown"
 | 
							apiKey.KeyType = "unknown"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -104,11 +104,7 @@ func GetInfo(ctx *context.APIContext) {
 | 
				
			|||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Hide user e-mail when API caller isn't signed in.
 | 
						ctx.JSON(200, convert.ToUser(u, ctx.IsSigned, ctx.User.ID == u.ID || ctx.User.IsAdmin))
 | 
				
			||||||
	if !ctx.IsSigned {
 | 
					 | 
				
			||||||
		u.Email = ""
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	ctx.JSON(200, u.APIFormat())
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GetAuthenticatedUser get current user's information
 | 
					// GetAuthenticatedUser get current user's information
 | 
				
			||||||
@@ -121,7 +117,7 @@ func GetAuthenticatedUser(ctx *context.APIContext) {
 | 
				
			|||||||
	// responses:
 | 
						// responses:
 | 
				
			||||||
	//   "200":
 | 
						//   "200":
 | 
				
			||||||
	//     "$ref": "#/responses/User"
 | 
						//     "$ref": "#/responses/User"
 | 
				
			||||||
	ctx.JSON(200, ctx.User.APIFormat())
 | 
						ctx.JSON(200, convert.ToUser(ctx.User, ctx.IsSigned, ctx.User != nil))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GetUserHeatmapData is the handler to get a users heatmap
 | 
					// GetUserHeatmapData is the handler to get a users heatmap
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -39,6 +39,7 @@ func Settings(ctx *context.Context) {
 | 
				
			|||||||
func SettingsPost(ctx *context.Context, form auth.UpdateOrgSettingForm) {
 | 
					func SettingsPost(ctx *context.Context, form auth.UpdateOrgSettingForm) {
 | 
				
			||||||
	ctx.Data["Title"] = ctx.Tr("org.settings")
 | 
						ctx.Data["Title"] = ctx.Tr("org.settings")
 | 
				
			||||||
	ctx.Data["PageIsSettingsOptions"] = true
 | 
						ctx.Data["PageIsSettingsOptions"] = true
 | 
				
			||||||
 | 
						ctx.Data["CurrentVisibility"] = structs.VisibleType(ctx.Org.Organization.Visibility)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ctx.HasError() {
 | 
						if ctx.HasError() {
 | 
				
			||||||
		ctx.HTML(200, tplSettingsOptions)
 | 
							ctx.HTML(200, tplSettingsOptions)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -31,6 +31,7 @@ func HookPreReceive(ctx *macaron.Context) {
 | 
				
			|||||||
	userID := ctx.QueryInt64("userID")
 | 
						userID := ctx.QueryInt64("userID")
 | 
				
			||||||
	gitObjectDirectory := ctx.QueryTrim("gitObjectDirectory")
 | 
						gitObjectDirectory := ctx.QueryTrim("gitObjectDirectory")
 | 
				
			||||||
	gitAlternativeObjectDirectories := ctx.QueryTrim("gitAlternativeObjectDirectories")
 | 
						gitAlternativeObjectDirectories := ctx.QueryTrim("gitAlternativeObjectDirectories")
 | 
				
			||||||
 | 
						gitQuarantinePath := ctx.QueryTrim("gitQuarantinePath")
 | 
				
			||||||
	prID := ctx.QueryInt64("prID")
 | 
						prID := ctx.QueryInt64("prID")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	branchName := strings.TrimPrefix(refFullName, git.BranchPrefix)
 | 
						branchName := strings.TrimPrefix(refFullName, git.BranchPrefix)
 | 
				
			||||||
@@ -63,11 +64,19 @@ func HookPreReceive(ctx *macaron.Context) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		// detect force push
 | 
							// detect force push
 | 
				
			||||||
		if git.EmptySHA != oldCommitID {
 | 
							if git.EmptySHA != oldCommitID {
 | 
				
			||||||
			env := append(os.Environ(),
 | 
								env := os.Environ()
 | 
				
			||||||
				private.GitAlternativeObjectDirectories+"="+gitAlternativeObjectDirectories,
 | 
								if gitAlternativeObjectDirectories != "" {
 | 
				
			||||||
				private.GitObjectDirectory+"="+gitObjectDirectory,
 | 
									env = append(env,
 | 
				
			||||||
				private.GitQuarantinePath+"="+gitObjectDirectory,
 | 
										private.GitAlternativeObjectDirectories+"="+gitAlternativeObjectDirectories)
 | 
				
			||||||
			)
 | 
								}
 | 
				
			||||||
 | 
								if gitObjectDirectory != "" {
 | 
				
			||||||
 | 
									env = append(env,
 | 
				
			||||||
 | 
										private.GitObjectDirectory+"="+gitObjectDirectory)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if gitQuarantinePath != "" {
 | 
				
			||||||
 | 
									env = append(env,
 | 
				
			||||||
 | 
										private.GitQuarantinePath+"="+gitQuarantinePath)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			output, err := git.NewCommand("rev-list", "--max-count=1", oldCommitID, "^"+newCommitID).RunInDirWithEnv(repo.RepoPath(), env)
 | 
								output, err := git.NewCommand("rev-list", "--max-count=1", oldCommitID, "^"+newCommitID).RunInDirWithEnv(repo.RepoPath(), env)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -48,7 +48,8 @@ func UploadAttachment(ctx *context.Context) {
 | 
				
			|||||||
	allowed := false
 | 
						allowed := false
 | 
				
			||||||
	for _, t := range allowedTypes {
 | 
						for _, t := range allowedTypes {
 | 
				
			||||||
		t := strings.Trim(t, " ")
 | 
							t := strings.Trim(t, " ")
 | 
				
			||||||
		if t == "*/*" || t == fileType {
 | 
							if t == "*/*" || t == fileType ||
 | 
				
			||||||
 | 
								strings.HasPrefix(fileType, t+";") {
 | 
				
			||||||
			allowed = true
 | 
								allowed = true
 | 
				
			||||||
			break
 | 
								break
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -39,6 +39,7 @@ func Branches(ctx *context.Context) {
 | 
				
			|||||||
	ctx.Data["Title"] = "Branches"
 | 
						ctx.Data["Title"] = "Branches"
 | 
				
			||||||
	ctx.Data["IsRepoToolbarBranches"] = true
 | 
						ctx.Data["IsRepoToolbarBranches"] = true
 | 
				
			||||||
	ctx.Data["DefaultBranch"] = ctx.Repo.Repository.DefaultBranch
 | 
						ctx.Data["DefaultBranch"] = ctx.Repo.Repository.DefaultBranch
 | 
				
			||||||
 | 
						ctx.Data["AllowsPulls"] = ctx.Repo.Repository.AllowsPulls()
 | 
				
			||||||
	ctx.Data["IsWriter"] = ctx.Repo.CanWrite(models.UnitTypeCode)
 | 
						ctx.Data["IsWriter"] = ctx.Repo.CanWrite(models.UnitTypeCode)
 | 
				
			||||||
	ctx.Data["IsMirror"] = ctx.Repo.Repository.IsMirror
 | 
						ctx.Data["IsMirror"] = ctx.Repo.Repository.IsMirror
 | 
				
			||||||
	ctx.Data["PageIsViewCode"] = true
 | 
						ctx.Data["PageIsViewCode"] = true
 | 
				
			||||||
@@ -161,6 +162,12 @@ func loadBranches(ctx *context.Context) []*Branch {
 | 
				
			|||||||
		return nil
 | 
							return nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						protectedBranches, err := ctx.Repo.Repository.GetProtectedBranches()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							ctx.ServerError("GetProtectedBranches", err)
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	branches := make([]*Branch, len(rawBranches))
 | 
						branches := make([]*Branch, len(rawBranches))
 | 
				
			||||||
	for i := range rawBranches {
 | 
						for i := range rawBranches {
 | 
				
			||||||
		commit, err := rawBranches[i].GetCommit()
 | 
							commit, err := rawBranches[i].GetCommit()
 | 
				
			||||||
@@ -169,11 +176,13 @@ func loadBranches(ctx *context.Context) []*Branch {
 | 
				
			|||||||
			return nil
 | 
								return nil
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							var isProtected bool
 | 
				
			||||||
		branchName := rawBranches[i].Name
 | 
							branchName := rawBranches[i].Name
 | 
				
			||||||
		isProtected, err := ctx.Repo.Repository.IsProtectedBranch(branchName, ctx.User)
 | 
							for _, b := range protectedBranches {
 | 
				
			||||||
		if err != nil {
 | 
								if b.BranchName == branchName {
 | 
				
			||||||
			ctx.ServerError("IsProtectedBranch", err)
 | 
									isProtected = true
 | 
				
			||||||
			return nil
 | 
									break
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		divergence, divergenceError := repofiles.CountDivergingCommits(ctx.Repo.Repository, branchName)
 | 
							divergence, divergenceError := repofiles.CountDivergingCommits(ctx.Repo.Repository, branchName)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -292,6 +292,13 @@ func CompareDiff(ctx *context.Context) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ctx.Data["PageIsComparePull"] == true {
 | 
						if ctx.Data["PageIsComparePull"] == true {
 | 
				
			||||||
 | 
							headBranches, err := headGitRepo.GetBranches()
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								ctx.ServerError("GetBranches", err)
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							ctx.Data["HeadBranches"] = headBranches
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		pr, err := models.GetUnmergedPullRequest(headRepo.ID, ctx.Repo.Repository.ID, headBranch, baseBranch)
 | 
							pr, err := models.GetUnmergedPullRequest(headRepo.ID, ctx.Repo.Repository.ID, headBranch, baseBranch)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			if !models.IsErrPullRequestNotExist(err) {
 | 
								if !models.IsErrPullRequestNotExist(err) {
 | 
				
			||||||
@@ -312,13 +319,6 @@ func CompareDiff(ctx *context.Context) {
 | 
				
			|||||||
				return
 | 
									return
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					 | 
				
			||||||
		headBranches, err := headGitRepo.GetBranches()
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			ctx.ServerError("GetBranches", err)
 | 
					 | 
				
			||||||
			return
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		ctx.Data["HeadBranches"] = headBranches
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	beforeCommitID := ctx.Data["BeforeCommitID"].(string)
 | 
						beforeCommitID := ctx.Data["BeforeCommitID"].(string)
 | 
				
			||||||
	afterCommitID := ctx.Data["AfterCommitID"].(string)
 | 
						afterCommitID := ctx.Data["AfterCommitID"].(string)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,6 +9,7 @@ import (
 | 
				
			|||||||
	"io/ioutil"
 | 
						"io/ioutil"
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
	"path"
 | 
						"path"
 | 
				
			||||||
 | 
						"path/filepath"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"code.gitea.io/gitea/models"
 | 
						"code.gitea.io/gitea/models"
 | 
				
			||||||
@@ -137,7 +138,7 @@ func editFile(ctx *context.Context, isNewFile bool) {
 | 
				
			|||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		ctx.Data["commit_choice"] = frmCommitChoiceNewBranch
 | 
							ctx.Data["commit_choice"] = frmCommitChoiceNewBranch
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	ctx.Data["new_branch_name"] = ""
 | 
						ctx.Data["new_branch_name"] = GetUniquePatchBranchName(ctx)
 | 
				
			||||||
	ctx.Data["last_commit"] = ctx.Repo.CommitID
 | 
						ctx.Data["last_commit"] = ctx.Repo.CommitID
 | 
				
			||||||
	ctx.Data["MarkdownFileExts"] = strings.Join(setting.Markdown.FileExtensions, ",")
 | 
						ctx.Data["MarkdownFileExts"] = strings.Join(setting.Markdown.FileExtensions, ",")
 | 
				
			||||||
	ctx.Data["LineWrapExtensions"] = strings.Join(setting.Repository.Editor.LineWrapExtensions, ",")
 | 
						ctx.Data["LineWrapExtensions"] = strings.Join(setting.Repository.Editor.LineWrapExtensions, ",")
 | 
				
			||||||
@@ -266,6 +267,10 @@ func editFilePost(ctx *context.Context, form auth.EditRepoFileForm, isNewFile bo
 | 
				
			|||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			ctx.RenderWithErr(ctx.Tr("repo.editor.fail_to_update_file", form.TreePath, err), tplEditFile, &form)
 | 
								ctx.RenderWithErr(ctx.Tr("repo.editor.fail_to_update_file", form.TreePath, err), tplEditFile, &form)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if form.CommitChoice == frmCommitChoiceNewBranch {
 | 
				
			||||||
 | 
							ctx.Redirect(ctx.Repo.RepoLink + "/compare/" + ctx.Repo.BranchName + "..." + form.NewBranchName)
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		ctx.Redirect(ctx.Repo.RepoLink + "/src/branch/" + util.PathEscapeSegments(branchName) + "/" + util.PathEscapeSegments(form.TreePath))
 | 
							ctx.Redirect(ctx.Repo.RepoLink + "/src/branch/" + util.PathEscapeSegments(branchName) + "/" + util.PathEscapeSegments(form.TreePath))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -335,7 +340,7 @@ func DeleteFile(ctx *context.Context) {
 | 
				
			|||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		ctx.Data["commit_choice"] = frmCommitChoiceNewBranch
 | 
							ctx.Data["commit_choice"] = frmCommitChoiceNewBranch
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	ctx.Data["new_branch_name"] = ""
 | 
						ctx.Data["new_branch_name"] = GetUniquePatchBranchName(ctx)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ctx.HTML(200, tplDeleteFile)
 | 
						ctx.HTML(200, tplDeleteFile)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -362,7 +367,7 @@ func DeleteFilePost(ctx *context.Context, form auth.DeleteRepoFileForm) {
 | 
				
			|||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if branchName != ctx.Repo.BranchName && !canCommit {
 | 
						if branchName == ctx.Repo.BranchName && !canCommit {
 | 
				
			||||||
		ctx.Data["Err_NewBranchName"] = true
 | 
							ctx.Data["Err_NewBranchName"] = true
 | 
				
			||||||
		ctx.Data["commit_choice"] = frmCommitChoiceNewBranch
 | 
							ctx.Data["commit_choice"] = frmCommitChoiceNewBranch
 | 
				
			||||||
		ctx.RenderWithErr(ctx.Tr("repo.editor.cannot_commit_to_protected_branch", branchName), tplDeleteFile, &form)
 | 
							ctx.RenderWithErr(ctx.Tr("repo.editor.cannot_commit_to_protected_branch", branchName), tplDeleteFile, &form)
 | 
				
			||||||
@@ -387,20 +392,20 @@ func DeleteFilePost(ctx *context.Context, form auth.DeleteRepoFileForm) {
 | 
				
			|||||||
	}); err != nil {
 | 
						}); err != nil {
 | 
				
			||||||
		// This is where we handle all the errors thrown by repofiles.DeleteRepoFile
 | 
							// This is where we handle all the errors thrown by repofiles.DeleteRepoFile
 | 
				
			||||||
		if git.IsErrNotExist(err) || models.IsErrRepoFileDoesNotExist(err) {
 | 
							if git.IsErrNotExist(err) || models.IsErrRepoFileDoesNotExist(err) {
 | 
				
			||||||
			ctx.RenderWithErr(ctx.Tr("repo.editor.file_deleting_no_longer_exists", ctx.Repo.TreePath), tplEditFile, &form)
 | 
								ctx.RenderWithErr(ctx.Tr("repo.editor.file_deleting_no_longer_exists", ctx.Repo.TreePath), tplDeleteFile, &form)
 | 
				
			||||||
		} else if models.IsErrFilenameInvalid(err) {
 | 
							} else if models.IsErrFilenameInvalid(err) {
 | 
				
			||||||
			ctx.Data["Err_TreePath"] = true
 | 
								ctx.Data["Err_TreePath"] = true
 | 
				
			||||||
			ctx.RenderWithErr(ctx.Tr("repo.editor.filename_is_invalid", ctx.Repo.TreePath), tplEditFile, &form)
 | 
								ctx.RenderWithErr(ctx.Tr("repo.editor.filename_is_invalid", ctx.Repo.TreePath), tplDeleteFile, &form)
 | 
				
			||||||
		} else if models.IsErrFilePathInvalid(err) {
 | 
							} else if models.IsErrFilePathInvalid(err) {
 | 
				
			||||||
			ctx.Data["Err_TreePath"] = true
 | 
								ctx.Data["Err_TreePath"] = true
 | 
				
			||||||
			if fileErr, ok := err.(models.ErrFilePathInvalid); ok {
 | 
								if fileErr, ok := err.(models.ErrFilePathInvalid); ok {
 | 
				
			||||||
				switch fileErr.Type {
 | 
									switch fileErr.Type {
 | 
				
			||||||
				case git.EntryModeSymlink:
 | 
									case git.EntryModeSymlink:
 | 
				
			||||||
					ctx.RenderWithErr(ctx.Tr("repo.editor.file_is_a_symlink", fileErr.Path), tplEditFile, &form)
 | 
										ctx.RenderWithErr(ctx.Tr("repo.editor.file_is_a_symlink", fileErr.Path), tplDeleteFile, &form)
 | 
				
			||||||
				case git.EntryModeTree:
 | 
									case git.EntryModeTree:
 | 
				
			||||||
					ctx.RenderWithErr(ctx.Tr("repo.editor.filename_is_a_directory", fileErr.Path), tplEditFile, &form)
 | 
										ctx.RenderWithErr(ctx.Tr("repo.editor.filename_is_a_directory", fileErr.Path), tplDeleteFile, &form)
 | 
				
			||||||
				case git.EntryModeBlob:
 | 
									case git.EntryModeBlob:
 | 
				
			||||||
					ctx.RenderWithErr(ctx.Tr("repo.editor.directory_is_a_file", fileErr.Path), tplEditFile, &form)
 | 
										ctx.RenderWithErr(ctx.Tr("repo.editor.directory_is_a_file", fileErr.Path), tplDeleteFile, &form)
 | 
				
			||||||
				default:
 | 
									default:
 | 
				
			||||||
					ctx.ServerError("DeleteRepoFile", err)
 | 
										ctx.ServerError("DeleteRepoFile", err)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
@@ -410,25 +415,44 @@ func DeleteFilePost(ctx *context.Context, form auth.DeleteRepoFileForm) {
 | 
				
			|||||||
		} else if git.IsErrBranchNotExist(err) {
 | 
							} else if git.IsErrBranchNotExist(err) {
 | 
				
			||||||
			// For when a user deletes a file to a branch that no longer exists
 | 
								// For when a user deletes a file to a branch that no longer exists
 | 
				
			||||||
			if branchErr, ok := err.(git.ErrBranchNotExist); ok {
 | 
								if branchErr, ok := err.(git.ErrBranchNotExist); ok {
 | 
				
			||||||
				ctx.RenderWithErr(ctx.Tr("repo.editor.branch_does_not_exist", branchErr.Name), tplEditFile, &form)
 | 
									ctx.RenderWithErr(ctx.Tr("repo.editor.branch_does_not_exist", branchErr.Name), tplDeleteFile, &form)
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
				ctx.Error(500, err.Error())
 | 
									ctx.Error(500, err.Error())
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		} else if models.IsErrBranchAlreadyExists(err) {
 | 
							} else if models.IsErrBranchAlreadyExists(err) {
 | 
				
			||||||
			// For when a user specifies a new branch that already exists
 | 
								// For when a user specifies a new branch that already exists
 | 
				
			||||||
			if branchErr, ok := err.(models.ErrBranchAlreadyExists); ok {
 | 
								if branchErr, ok := err.(models.ErrBranchAlreadyExists); ok {
 | 
				
			||||||
				ctx.RenderWithErr(ctx.Tr("repo.editor.branch_already_exists", branchErr.BranchName), tplEditFile, &form)
 | 
									ctx.RenderWithErr(ctx.Tr("repo.editor.branch_already_exists", branchErr.BranchName), tplDeleteFile, &form)
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
				ctx.Error(500, err.Error())
 | 
									ctx.Error(500, err.Error())
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		} else if models.IsErrCommitIDDoesNotMatch(err) {
 | 
							} else if models.IsErrCommitIDDoesNotMatch(err) {
 | 
				
			||||||
			ctx.RenderWithErr(ctx.Tr("repo.editor.file_changed_while_editing", ctx.Repo.RepoLink+"/compare/"+form.LastCommit+"..."+ctx.Repo.CommitID), tplEditFile, &form)
 | 
								ctx.RenderWithErr(ctx.Tr("repo.editor.file_changed_while_deleting", ctx.Repo.RepoLink+"/compare/"+form.LastCommit+"..."+ctx.Repo.CommitID), tplDeleteFile, &form)
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			ctx.ServerError("DeleteRepoFile", err)
 | 
								ctx.ServerError("DeleteRepoFile", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ctx.Flash.Success(ctx.Tr("repo.editor.file_delete_success", ctx.Repo.TreePath))
 | 
				
			||||||
 | 
						if form.CommitChoice == frmCommitChoiceNewBranch {
 | 
				
			||||||
 | 
							ctx.Redirect(ctx.Repo.RepoLink + "/compare/" + ctx.Repo.BranchName + "..." + form.NewBranchName)
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		ctx.Flash.Success(ctx.Tr("repo.editor.file_delete_success", ctx.Repo.TreePath))
 | 
							treePath := filepath.Dir(ctx.Repo.TreePath)
 | 
				
			||||||
		ctx.Redirect(ctx.Repo.RepoLink + "/src/branch/" + util.PathEscapeSegments(branchName))
 | 
							if treePath == "." {
 | 
				
			||||||
 | 
								treePath = "" // the file deleted was in the root, so we return the user to the root directory
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if len(treePath) > 0 {
 | 
				
			||||||
 | 
								// Need to get the latest commit since it changed
 | 
				
			||||||
 | 
								commit, err := ctx.Repo.GitRepo.GetBranchCommit(ctx.Repo.BranchName)
 | 
				
			||||||
 | 
								if err == nil && commit != nil {
 | 
				
			||||||
 | 
									// We have the comment, now find what directory we can return the user to
 | 
				
			||||||
 | 
									// (must have entries)
 | 
				
			||||||
 | 
									treePath = GetClosestParentWithFiles(treePath, commit)
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									treePath = "" // otherwise return them to the root of the repo
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							ctx.Redirect(ctx.Repo.RepoLink + "/src/branch/" + util.PathEscapeSegments(branchName) + "/" + util.PathEscapeSegments(treePath))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -467,7 +491,7 @@ func UploadFile(ctx *context.Context) {
 | 
				
			|||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		ctx.Data["commit_choice"] = frmCommitChoiceNewBranch
 | 
							ctx.Data["commit_choice"] = frmCommitChoiceNewBranch
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	ctx.Data["new_branch_name"] = ""
 | 
						ctx.Data["new_branch_name"] = GetUniquePatchBranchName(ctx)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ctx.HTML(200, tplUploadFile)
 | 
						ctx.HTML(200, tplUploadFile)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -565,7 +589,11 @@ func UploadFilePost(ctx *context.Context, form auth.UploadRepoFileForm) {
 | 
				
			|||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ctx.Redirect(ctx.Repo.RepoLink + "/src/branch/" + util.PathEscapeSegments(branchName) + "/" + util.PathEscapeSegments(form.TreePath))
 | 
						if form.CommitChoice == frmCommitChoiceNewBranch {
 | 
				
			||||||
 | 
							ctx.Redirect(ctx.Repo.RepoLink + "/compare/" + ctx.Repo.BranchName + "..." + form.NewBranchName)
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							ctx.Redirect(ctx.Repo.RepoLink + "/src/branch/" + util.PathEscapeSegments(branchName) + "/" + util.PathEscapeSegments(form.TreePath))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func cleanUploadFileName(name string) string {
 | 
					func cleanUploadFileName(name string) string {
 | 
				
			||||||
@@ -600,7 +628,8 @@ func UploadFileToServer(ctx *context.Context) {
 | 
				
			|||||||
		allowed := false
 | 
							allowed := false
 | 
				
			||||||
		for _, t := range setting.Repository.Upload.AllowedTypes {
 | 
							for _, t := range setting.Repository.Upload.AllowedTypes {
 | 
				
			||||||
			t := strings.Trim(t, " ")
 | 
								t := strings.Trim(t, " ")
 | 
				
			||||||
			if t == "*/*" || t == fileType {
 | 
								if t == "*/*" || t == fileType ||
 | 
				
			||||||
 | 
									strings.HasPrefix(fileType, t+";") {
 | 
				
			||||||
				allowed = true
 | 
									allowed = true
 | 
				
			||||||
				break
 | 
									break
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@@ -645,3 +674,40 @@ func RemoveUploadFileFromServer(ctx *context.Context, form auth.RemoveUploadFile
 | 
				
			|||||||
	log.Trace("Upload file removed: %s", form.File)
 | 
						log.Trace("Upload file removed: %s", form.File)
 | 
				
			||||||
	ctx.Status(204)
 | 
						ctx.Status(204)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GetUniquePatchBranchName Gets a unique branch name for a new patch branch
 | 
				
			||||||
 | 
					// It will be in the form of <username>-patch-<num> where <num> is the first branch of this format
 | 
				
			||||||
 | 
					// that doesn't already exist. If we exceed 1000 tries or an error is thrown, we just return "" so the user has to
 | 
				
			||||||
 | 
					// type in the branch name themselves (will be an empty field)
 | 
				
			||||||
 | 
					func GetUniquePatchBranchName(ctx *context.Context) string {
 | 
				
			||||||
 | 
						prefix := ctx.User.LowerName + "-patch-"
 | 
				
			||||||
 | 
						for i := 1; i <= 1000; i++ {
 | 
				
			||||||
 | 
							branchName := fmt.Sprintf("%s%d", prefix, i)
 | 
				
			||||||
 | 
							if _, err := ctx.Repo.Repository.GetBranch(branchName); err != nil {
 | 
				
			||||||
 | 
								if git.IsErrBranchNotExist(err) {
 | 
				
			||||||
 | 
									return branchName
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								log.Error("GetUniquePatchBranchName: %v", err)
 | 
				
			||||||
 | 
								return ""
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return ""
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GetClosestParentWithFiles Recursively gets the path of parent in a tree that has files (used when file in a tree is
 | 
				
			||||||
 | 
					// deleted). Returns "" for the root if no parents other than the root have files. If the given treePath isn't a
 | 
				
			||||||
 | 
					// SubTree or it has no entries, we go up one dir and see if we can return the user to that listing.
 | 
				
			||||||
 | 
					func GetClosestParentWithFiles(treePath string, commit *git.Commit) string {
 | 
				
			||||||
 | 
						if len(treePath) == 0 || treePath == "." {
 | 
				
			||||||
 | 
							return ""
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// see if the tree has entries
 | 
				
			||||||
 | 
						if tree, err := commit.SubTree(treePath); err != nil {
 | 
				
			||||||
 | 
							// failed to get tree, going up a dir
 | 
				
			||||||
 | 
							return GetClosestParentWithFiles(filepath.Dir(treePath), commit)
 | 
				
			||||||
 | 
						} else if entries, err := tree.ListEntries(); err != nil || len(entries) == 0 {
 | 
				
			||||||
 | 
							// no files in this dir, going up a dir
 | 
				
			||||||
 | 
							return GetClosestParentWithFiles(filepath.Dir(treePath), commit)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return treePath
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user