mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-11-03 08:02:36 +09:00 
			
		
		
		
	Compare commits
	
		
			62 Commits
		
	
	
		
			v1.13.0-de
			...
			v1.9.1
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					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 | 
							
								
								
									
										67
									
								
								.drone.yml
									
									
									
									
									
								
							
							
						
						
									
										67
									
								
								.drone.yml
									
									
									
									
									
								
							@@ -114,6 +114,17 @@ steps:
 | 
			
		||||
        - push
 | 
			
		||||
        - pull_request
 | 
			
		||||
 | 
			
		||||
  - name: tag-pre-condition
 | 
			
		||||
    pull: always
 | 
			
		||||
    image: alpine/git
 | 
			
		||||
    commands:
 | 
			
		||||
      - git update-ref refs/heads/tag_test ${DRONE_COMMIT_SHA}
 | 
			
		||||
    depends_on:
 | 
			
		||||
      - build
 | 
			
		||||
    when:
 | 
			
		||||
      event:
 | 
			
		||||
        - tag
 | 
			
		||||
 | 
			
		||||
  - name: tag-test
 | 
			
		||||
    pull: always
 | 
			
		||||
    image: golang:1.12
 | 
			
		||||
@@ -122,7 +133,7 @@ steps:
 | 
			
		||||
    environment:
 | 
			
		||||
      TAGS: bindata
 | 
			
		||||
    depends_on:
 | 
			
		||||
      - build
 | 
			
		||||
      - tag-pre-condition
 | 
			
		||||
    when:
 | 
			
		||||
      event:
 | 
			
		||||
        - tag
 | 
			
		||||
@@ -442,7 +453,6 @@ trigger:
 | 
			
		||||
 | 
			
		||||
depends_on:
 | 
			
		||||
  - testing
 | 
			
		||||
  - translations
 | 
			
		||||
 | 
			
		||||
steps:
 | 
			
		||||
  - name: fetch-tags
 | 
			
		||||
@@ -558,6 +568,15 @@ workspace:
 | 
			
		||||
  base: /go
 | 
			
		||||
  path: src/code.gitea.io/gitea
 | 
			
		||||
 | 
			
		||||
depends_on:
 | 
			
		||||
  - testing
 | 
			
		||||
 | 
			
		||||
trigger:
 | 
			
		||||
  ref:
 | 
			
		||||
  - refs/heads/master
 | 
			
		||||
  - "refs/tags/**"
 | 
			
		||||
  - "refs/pull/**"
 | 
			
		||||
 | 
			
		||||
steps:
 | 
			
		||||
  - name: fetch-tags
 | 
			
		||||
    pull: default
 | 
			
		||||
@@ -571,56 +590,28 @@ steps:
 | 
			
		||||
 | 
			
		||||
  - name: dryrun
 | 
			
		||||
    pull: always
 | 
			
		||||
    image: plugins/docker:18.09
 | 
			
		||||
    image: plugins/docker:linux-amd64
 | 
			
		||||
    settings:
 | 
			
		||||
      cache_from: gitea/gitea
 | 
			
		||||
      dry_run: true
 | 
			
		||||
      repo: gitea/gitea
 | 
			
		||||
    when:
 | 
			
		||||
      event:
 | 
			
		||||
        - pull_request
 | 
			
		||||
 | 
			
		||||
  - name: release
 | 
			
		||||
  - name: publish
 | 
			
		||||
    pull: always
 | 
			
		||||
    image: plugins/docker:18.09
 | 
			
		||||
    image: plugins/docker:linux-amd64
 | 
			
		||||
    settings:
 | 
			
		||||
      cache_from: gitea/gitea
 | 
			
		||||
      auto_tag: true
 | 
			
		||||
      repo: gitea/gitea
 | 
			
		||||
      tags:
 | 
			
		||||
        - "${DRONE_BRANCH##release/v}"
 | 
			
		||||
    environment:
 | 
			
		||||
      DOCKER_PASSWORD:
 | 
			
		||||
      password:
 | 
			
		||||
        from_secret: docker_password
 | 
			
		||||
      DOCKER_USERNAME:
 | 
			
		||||
      username:
 | 
			
		||||
        from_secret: docker_username
 | 
			
		||||
    depends_on:
 | 
			
		||||
      - dryrun
 | 
			
		||||
    when:
 | 
			
		||||
      branch:
 | 
			
		||||
        - "release/*"
 | 
			
		||||
      event:
 | 
			
		||||
        - push
 | 
			
		||||
 | 
			
		||||
  - name: latest
 | 
			
		||||
    pull: always
 | 
			
		||||
    image: plugins/docker:18.09
 | 
			
		||||
    settings:
 | 
			
		||||
      cache_from: gitea/gitea
 | 
			
		||||
      default_tags: true
 | 
			
		||||
      repo: gitea/gitea
 | 
			
		||||
    environment:
 | 
			
		||||
      DOCKER_PASSWORD:
 | 
			
		||||
        from_secret: docker_password
 | 
			
		||||
      DOCKER_USERNAME:
 | 
			
		||||
        from_secret: docker_username
 | 
			
		||||
    depends_on:
 | 
			
		||||
      - dryrun
 | 
			
		||||
    when:
 | 
			
		||||
      branch:
 | 
			
		||||
        - master
 | 
			
		||||
      event:
 | 
			
		||||
        - push
 | 
			
		||||
        - tag
 | 
			
		||||
        exclude:
 | 
			
		||||
        - pull_request
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
kind: pipeline
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										71
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										71
									
								
								CHANGELOG.md
									
									
									
									
									
								
							@@ -4,9 +4,42 @@ This changelog goes through all the changes that have been made in each release
 | 
			
		||||
without substantial changes to our git log; to see the highlights of what has
 | 
			
		||||
been added to each release, please refer to the [blog](https://blog.gitea.io).
 | 
			
		||||
 | 
			
		||||
## [1.9.0-RC1](https://github.com/go-gitea/gitea/releases/tag/v1.9.0-rc1) - 2019-07-06
 | 
			
		||||
## [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
 | 
			
		||||
  * 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
 | 
			
		||||
  * Content API for Creating, Updating, Deleting Files (#6314)
 | 
			
		||||
  * Enable tls-alpn-01: Use certmanager provided TLSConfig for LetsEncrypt (#7229)
 | 
			
		||||
@@ -29,6 +62,39 @@ been added to each release, please refer to the [blog](https://blog.gitea.io).
 | 
			
		||||
  * Implement Default Webhooks (#4299)
 | 
			
		||||
  * Telegram webhook (#4227)
 | 
			
		||||
* 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)
 | 
			
		||||
  * Handle early git version's lack of get-url (#7065)
 | 
			
		||||
  * Fix icon position in issue view (#7354)
 | 
			
		||||
@@ -166,6 +232,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.io).
 | 
			
		||||
  * Disable benchmarking during tag events on DroneIO (#6365)
 | 
			
		||||
  * Comments list performance optimization (#5305)
 | 
			
		||||
* ENHANCEMENT
 | 
			
		||||
  * Update Drone docker generation to standard format (#7480) (#7496) (#7504)
 | 
			
		||||
  * Add API Endpoint for Repo Edit (#7006)
 | 
			
		||||
  * Add state param to milestone listing API (#7131)
 | 
			
		||||
  * Make captcha and password optional for external accounts (#6606)
 | 
			
		||||
@@ -285,8 +352,6 @@ been added to each release, please refer to the [blog](https://blog.gitea.io).
 | 
			
		||||
  * Refactor: append, build variable and type switch (#4940)
 | 
			
		||||
  * Git statistics in Activity tab (#4724)
 | 
			
		||||
  * Drop the bits argument when generating an ed25519 key (#6504)
 | 
			
		||||
* SECURITY
 | 
			
		||||
  * Shadow the password on cache and session config on admin panel (#7300)
 | 
			
		||||
* TESTING
 | 
			
		||||
  * Exclude pull_request from fetch-tags step, fixes #7108 (#7120)
 | 
			
		||||
  * Refactor and improve git test (#7086)
 | 
			
		||||
 
 | 
			
		||||
@@ -96,6 +96,7 @@ func runHookPreReceive(c *cli.Context) error {
 | 
			
		||||
				UserID:                          userID,
 | 
			
		||||
				GitAlternativeObjectDirectories: os.Getenv(private.GitAlternativeObjectDirectories),
 | 
			
		||||
				GitObjectDirectory:              os.Getenv(private.GitObjectDirectory),
 | 
			
		||||
				GitQuarantinePath:               os.Getenv(private.GitQuarantinePath),
 | 
			
		||||
				ProtectedBranchID:               prID,
 | 
			
		||||
			})
 | 
			
		||||
			switch statusCode {
 | 
			
		||||
 
 | 
			
		||||
@@ -73,7 +73,6 @@ func fail(userMessage, logMessage string, args ...interface{}) {
 | 
			
		||||
		if !setting.ProdMode {
 | 
			
		||||
			fmt.Fprintf(os.Stderr, logMessage+"\n", args...)
 | 
			
		||||
		}
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	os.Exit(1)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										4
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								go.mod
									
									
									
									
									
								
							@@ -45,7 +45,7 @@ require (
 | 
			
		||||
	github.com/glycerine/goconvey v0.0.0-20190315024820-982ee783a72e // indirect
 | 
			
		||||
	github.com/go-macaron/binding v0.0.0-20160711225916-9440f336b443
 | 
			
		||||
	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/csrf v0.0.0-20180426211211-503617c6b372
 | 
			
		||||
	github.com/go-macaron/i18n v0.0.0-20160612092837-ef57533c3b0f
 | 
			
		||||
@@ -135,4 +135,4 @@ require (
 | 
			
		||||
	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.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 | 
			
		||||
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-20180314172330-6a30f4e59a44/go.mod h1:xN/JuLBIz4bjkxNmByTiV1IbhfnYb6oo99phBn4Eqhc=
 | 
			
		||||
github.com/denisenkom/go-mssqldb v0.0.0-20180315180555-6a30f4e59a44 h1:DWxZh2sImfCFn/79OUBhzFkPTKnsdDzXH/JTxpw5n6w=
 | 
			
		||||
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/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
 | 
			
		||||
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/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/captcha v0.0.0-20151123225153-8aa5919789ab h1:4VFhsA3GE5Wwq1Ymr8KWCmrOWi1wRLEgdj48LPfQjxI=
 | 
			
		||||
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 h1:MdgvtI3Y1u/DHNj7xUGOqAv+KGoTikjy8xQtCm12L78=
 | 
			
		||||
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/go.mod h1:utmMRnVIrXPSfA9MFcpIYKEpKawjKxf62vv62k4707E=
 | 
			
		||||
github.com/go-macaron/csrf v0.0.0-20180426211211-503617c6b372 h1:acrx8CnDmlKl+BPoOOLEK9Ko+SrWFB5pxRuGkKj4iqo=
 | 
			
		||||
 
 | 
			
		||||
@@ -24,20 +24,24 @@ import (
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
 | 
			
		||||
	//Setup ssh wrapper
 | 
			
		||||
	os.Setenv("GIT_SSH_COMMAND",
 | 
			
		||||
		"ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i "+
 | 
			
		||||
			filepath.Join(setting.AppWorkPath, keyFile))
 | 
			
		||||
		"ssh -o \"UserKnownHostsFile=/dev/null\" -o \"StrictHostKeyChecking=no\" -o \"IdentitiesOnly=yes\" -i \""+keyFile+"\"")
 | 
			
		||||
	os.Setenv("GIT_SSH_VARIANT", "ssh")
 | 
			
		||||
 | 
			
		||||
	callback(keyFile)
 | 
			
		||||
 | 
			
		||||
	defer os.RemoveAll(keyFile)
 | 
			
		||||
	defer os.RemoveAll(keyFile + ".pub")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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) {
 | 
			
		||||
	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")
 | 
			
		||||
		testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
 | 
			
		||||
		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), "/")
 | 
			
		||||
		assert.EqualValues(t, "pulls", elem[3])
 | 
			
		||||
		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) {
 | 
			
		||||
	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")
 | 
			
		||||
		testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
 | 
			
		||||
		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), "/")
 | 
			
		||||
		assert.EqualValues(t, "pulls", elem[3])
 | 
			
		||||
		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) {
 | 
			
		||||
	onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
 | 
			
		||||
		prepareTestEnv(t)
 | 
			
		||||
 | 
			
		||||
		hookTasks, err := models.HookTasks(1, 1) //Retrieve previous hook number
 | 
			
		||||
		assert.NoError(t, err)
 | 
			
		||||
		hookTasksLenBefore := len(hookTasks)
 | 
			
		||||
 | 
			
		||||
		session := loginUser(t, "user1")
 | 
			
		||||
		testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
 | 
			
		||||
		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), "/")
 | 
			
		||||
		assert.EqualValues(t, "pulls", elem[3])
 | 
			
		||||
		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) {
 | 
			
		||||
	onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
 | 
			
		||||
		prepareTestEnv(t)
 | 
			
		||||
 | 
			
		||||
		hookTasks, err := models.HookTasks(1, 1) //Retrieve previous hook number
 | 
			
		||||
		assert.NoError(t, err)
 | 
			
		||||
		hookTasksLenBefore := len(hookTasks)
 | 
			
		||||
 | 
			
		||||
		session := loginUser(t, "user1")
 | 
			
		||||
		testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
 | 
			
		||||
		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), "/")
 | 
			
		||||
		assert.EqualValues(t, "pulls", elem[3])
 | 
			
		||||
		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)
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -5,10 +5,13 @@
 | 
			
		||||
package integrations
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"net/http/httptest"
 | 
			
		||||
	"path"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/modules/setting"
 | 
			
		||||
	api "code.gitea.io/gitea/modules/structs"
 | 
			
		||||
 | 
			
		||||
	"github.com/stretchr/testify/assert"
 | 
			
		||||
@@ -67,6 +70,29 @@ func doTestRepoCommitWithStatus(t *testing.T, state string, classes ...string) {
 | 
			
		||||
	for _, class := range classes {
 | 
			
		||||
		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) {
 | 
			
		||||
 
 | 
			
		||||
@@ -65,6 +65,7 @@ var (
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
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 {
 | 
			
		||||
	return fmt.Sprintf(`(?i)(?:%s)(?::?) %s`, strings.Join(words, "|"), issueRefRegexpStr)
 | 
			
		||||
@@ -73,7 +74,7 @@ func assembleKeywordsPattern(words []string) string {
 | 
			
		||||
func init() {
 | 
			
		||||
	issueCloseKeywordsPat = regexp.MustCompile(assembleKeywordsPattern(issueCloseKeywords))
 | 
			
		||||
	issueReopenKeywordsPat = regexp.MustCompile(assembleKeywordsPattern(issueReopenKeywords))
 | 
			
		||||
	issueReferenceKeywordsPat = regexp.MustCompile(issueRefRegexpStr)
 | 
			
		||||
	issueReferenceKeywordsPat = regexp.MustCompile(issueRefRegexpStrNoKeyword)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Action represents user operation type and other information to
 | 
			
		||||
 
 | 
			
		||||
@@ -155,6 +155,25 @@ func TestPushCommits_AvatarLink(t *testing.T) {
 | 
			
		||||
		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) {
 | 
			
		||||
	assert.NoError(t, PrepareTestDatabase())
 | 
			
		||||
	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.
 | 
			
		||||
func (protectBranch *ProtectedBranch) GetGrantedApprovalsCount(pr *PullRequest) int64 {
 | 
			
		||||
	reviews, err := GetReviewersByPullID(pr.Issue.ID)
 | 
			
		||||
	reviews, err := GetReviewersByPullID(pr.IssueID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Error("GetReviewersByPullID: %v", err)
 | 
			
		||||
		return 0
 | 
			
		||||
 
 | 
			
		||||
@@ -87,7 +87,7 @@ func (status *CommitStatus) loadRepo(e Engine) (err error) {
 | 
			
		||||
// APIURL returns the absolute APIURL to this commit-status.
 | 
			
		||||
func (status *CommitStatus) APIURL() string {
 | 
			
		||||
	_ = 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)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -19,20 +19,25 @@ func TestGetCommitStatuses(t *testing.T) {
 | 
			
		||||
 | 
			
		||||
	statuses, err := GetCommitStatuses(repo1, sha1, 0)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	if assert.Len(t, statuses, 5) {
 | 
			
		||||
		assert.Equal(t, statuses[0].Context, "ci/awesomeness")
 | 
			
		||||
		assert.Equal(t, statuses[0].State, CommitStatusPending)
 | 
			
		||||
	assert.Len(t, statuses, 5)
 | 
			
		||||
 | 
			
		||||
		assert.Equal(t, statuses[1].Context, "cov/awesomeness")
 | 
			
		||||
		assert.Equal(t, statuses[1].State, CommitStatusWarning)
 | 
			
		||||
	assert.Equal(t, "ci/awesomeness", statuses[0].Context)
 | 
			
		||||
	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, statuses[2].State, CommitStatusSuccess)
 | 
			
		||||
	assert.Equal(t, "cov/awesomeness", statuses[1].Context)
 | 
			
		||||
	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, statuses[3].State, CommitStatusFailure)
 | 
			
		||||
	assert.Equal(t, "cov/awesomeness", statuses[2].Context)
 | 
			
		||||
	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, statuses[4].State, CommitStatusError)
 | 
			
		||||
	}
 | 
			
		||||
	assert.Equal(t, "ci/awesomeness", statuses[3].Context)
 | 
			
		||||
	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
 | 
			
		||||
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
 | 
			
		||||
func FullPushingEnvironment(author, committer *User, repo *Repository, prID int64) []string {
 | 
			
		||||
func FullPushingEnvironment(author, committer *User, repo *Repository, repoName string, prID int64) []string {
 | 
			
		||||
	isWiki := "false"
 | 
			
		||||
	if strings.HasSuffix(repo.Name, ".wiki") {
 | 
			
		||||
	if strings.HasSuffix(repoName, ".wiki") {
 | 
			
		||||
		isWiki = "true"
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -32,7 +32,7 @@ func FullPushingEnvironment(author, committer *User, repo *Repository, prID int6
 | 
			
		||||
		"GIT_AUTHOR_EMAIL="+authorSig.Email,
 | 
			
		||||
		"GIT_COMMITTER_NAME="+committerSig.Name,
 | 
			
		||||
		"GIT_COMMITTER_EMAIL="+committerSig.Email,
 | 
			
		||||
		EnvRepoName+"="+repo.Name,
 | 
			
		||||
		EnvRepoName+"="+repoName,
 | 
			
		||||
		EnvRepoUsername+"="+repo.MustOwnerName(),
 | 
			
		||||
		EnvRepoIsWiki+"="+isWiki,
 | 
			
		||||
		EnvPusherName+"="+committer.Name,
 | 
			
		||||
 
 | 
			
		||||
@@ -1835,3 +1835,22 @@ func (issue *Issue) BlockedByDependencies() ([]*Issue, error) {
 | 
			
		||||
func (issue *Issue) BlockingDependencies() ([]*Issue, error) {
 | 
			
		||||
	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 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) {
 | 
			
		||||
 | 
			
		||||
	// Update the assignee
 | 
			
		||||
	removed, err := updateIssueAssignee(sess, issue, assigneeID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
@@ -209,7 +213,6 @@ func (issue *Issue) changeAssignee(sess *xorm.Session, doer *User, assigneeID in
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	go HookQueue.Add(issue.RepoID)
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -632,12 +632,7 @@ func sendCreateCommentAction(e *xorm.Session, opts *CreateCommentOptions, commen
 | 
			
		||||
			act.OpType = ActionReopenPullRequest
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if opts.Issue.IsPull {
 | 
			
		||||
			_, 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 {
 | 
			
		||||
		if err = opts.Issue.updateClosedNum(e); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@@ -647,12 +642,7 @@ func sendCreateCommentAction(e *xorm.Session, opts *CreateCommentOptions, commen
 | 
			
		||||
			act.OpType = ActionClosePullRequest
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if opts.Issue.IsPull {
 | 
			
		||||
			_, 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 {
 | 
			
		||||
		if err = opts.Issue.updateClosedNum(e); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -62,38 +62,50 @@ func insertIssue(sess *xorm.Session, issue *Issue) error {
 | 
			
		||||
	if _, err := sess.Insert(issueLabels); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cols := make([]string, 0)
 | 
			
		||||
	if !issue.IsPull {
 | 
			
		||||
		sess.ID(issue.RepoID).Incr("num_issues")
 | 
			
		||||
		cols = append(cols, "num_issues")
 | 
			
		||||
		if issue.IsClosed {
 | 
			
		||||
			sess.Incr("num_closed_issues")
 | 
			
		||||
			cols = append(cols, "num_closed_issues")
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		sess.ID(issue.RepoID).Incr("num_pulls")
 | 
			
		||||
		cols = append(cols, "num_pulls")
 | 
			
		||||
		if issue.IsClosed {
 | 
			
		||||
			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
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cols = []string{"num_issues"}
 | 
			
		||||
	sess.Incr("num_issues")
 | 
			
		||||
	if issue.IsClosed {
 | 
			
		||||
		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
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if issue.MilestoneID > 0 {
 | 
			
		||||
		cols = []string{"num_issues"}
 | 
			
		||||
		sess.Incr("num_issues")
 | 
			
		||||
		cl := "num_closed_issues"
 | 
			
		||||
		if issue.IsClosed {
 | 
			
		||||
			sess.Incr("num_closed_issues")
 | 
			
		||||
			cols = append(cols, "num_closed_issues")
 | 
			
		||||
			cl = "(num_closed_issues + 1)"
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if _, err := sess.ID(issue.MilestoneID).
 | 
			
		||||
			SetExpr("completeness", "num_closed_issues * 100 / num_issues").
 | 
			
		||||
			NoAutoTime().
 | 
			
		||||
			SetExpr("completeness", cl+" * 100 / (num_issues + 1)").
 | 
			
		||||
			NoAutoTime().Cols(cols...).
 | 
			
		||||
			Update(new(Milestone)); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
@@ -321,11 +321,25 @@ func dropTableColumns(sess *xorm.Session, tableName string, columnNames ...strin
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		tableSQL := string(res[0]["sql"])
 | 
			
		||||
 | 
			
		||||
		// Separate out the column definitions
 | 
			
		||||
		tableSQL = tableSQL[strings.Index(tableSQL, "("):]
 | 
			
		||||
 | 
			
		||||
		// Remove the required 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)
 | 
			
		||||
 | 
			
		||||
		tableSQL = fmt.Sprintf("CREATE TABLE `new_%s_new` ", tableName) + tableSQL
 | 
			
		||||
 
 | 
			
		||||
@@ -5,13 +5,7 @@
 | 
			
		||||
package migrations
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/models"
 | 
			
		||||
	"code.gitea.io/gitea/modules/log"
 | 
			
		||||
 | 
			
		||||
	"github.com/go-xorm/xorm"
 | 
			
		||||
	"xorm.io/core"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func renameRepoIsBareToIsEmpty(x *xorm.Engine) error {
 | 
			
		||||
@@ -21,73 +15,28 @@ func renameRepoIsBareToIsEmpty(x *xorm.Engine) error {
 | 
			
		||||
		IsEmpty bool `xorm:"INDEX"`
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// First remove the index
 | 
			
		||||
	sess := x.NewSession()
 | 
			
		||||
	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 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 {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if _, err := sess.Exec("UPDATE repository SET is_empty = is_bare;"); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	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 {
 | 
			
		||||
	if err := sess.Commit(); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if models.DbCfg.Type == core.SQLITE {
 | 
			
		||||
		log.Warn("TABLE repository's COLUMN is_bare should be DROP but sqlite is not supported, you could manually do that.")
 | 
			
		||||
	if err := sess.Begin(); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
	if err := dropTableColumns(sess, "repository", "is_bare"); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return sess.Commit()
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -8,9 +8,7 @@ import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
 | 
			
		||||
	"github.com/go-xorm/xorm"
 | 
			
		||||
	"xorm.io/core"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/models"
 | 
			
		||||
	"code.gitea.io/gitea/modules/generate"
 | 
			
		||||
	"code.gitea.io/gitea/modules/log"
 | 
			
		||||
	"code.gitea.io/gitea/modules/util"
 | 
			
		||||
@@ -37,41 +35,6 @@ func hashAppToken(x *xorm.Engine) error {
 | 
			
		||||
	// First remove the index
 | 
			
		||||
	sess := x.NewSession()
 | 
			
		||||
	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 {
 | 
			
		||||
		return err
 | 
			
		||||
@@ -81,7 +44,7 @@ func hashAppToken(x *xorm.Engine) error {
 | 
			
		||||
		return fmt.Errorf("Sync2: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err = sess.Commit(); err != nil {
 | 
			
		||||
	if err := sess.Commit(); err != nil {
 | 
			
		||||
		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
 | 
			
		||||
func UsersInTeamsCount(userIDs []int64, teamIDs []int64) (count int64, err error) {
 | 
			
		||||
	if count, err = x.In("uid", userIDs).In("team_id", teamIDs).Count(new(TeamUser)); err != nil {
 | 
			
		||||
func UsersInTeamsCount(userIDs []int64, teamIDs []int64) (int64, error) {
 | 
			
		||||
	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
 | 
			
		||||
	return int64(len(ids)), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ___________                  __________
 | 
			
		||||
 
 | 
			
		||||
@@ -370,7 +370,7 @@ func TestUsersInTeamsCount(t *testing.T) {
 | 
			
		||||
		assert.Equal(t, expected, count)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	test([]int64{2}, []int64{1, 2, 3, 4}, 2)
 | 
			
		||||
	test([]int64{1, 2, 3, 4, 5}, []int64{2, 5}, 2)
 | 
			
		||||
	test([]int64{1, 2, 3, 4, 5}, []int64{2, 3, 5}, 3)
 | 
			
		||||
	test([]int64{2}, []int64{1, 2, 3, 4}, 1)          // only userid 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) // userid 2,4,5
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -189,36 +189,6 @@ func (pr *PullRequest) apiFormat(e Engine) *api.PullRequest {
 | 
			
		||||
			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 {
 | 
			
		||||
		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{
 | 
			
		||||
		ID:        pr.ID,
 | 
			
		||||
		URL:       pr.Issue.HTMLURL(),
 | 
			
		||||
		Index:     pr.Index,
 | 
			
		||||
		Poster:    apiIssue.Poster,
 | 
			
		||||
		Title:     apiIssue.Title,
 | 
			
		||||
@@ -241,13 +212,68 @@ func (pr *PullRequest) apiFormat(e Engine) *api.PullRequest {
 | 
			
		||||
		DiffURL:   pr.Issue.DiffURL(),
 | 
			
		||||
		PatchURL:  pr.Issue.PatchURL(),
 | 
			
		||||
		HasMerged: pr.HasMerged,
 | 
			
		||||
		Base:      apiBaseBranchInfo,
 | 
			
		||||
		Head:      apiHeadBranchInfo,
 | 
			
		||||
		MergeBase: pr.MergeBase,
 | 
			
		||||
		Deadline:  apiIssue.Deadline,
 | 
			
		||||
		Created:   pr.Issue.CreatedUnix.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 {
 | 
			
		||||
		mergeable := pr.Status != PullRequestStatusConflict && !pr.IsWorkInProgress()
 | 
			
		||||
 
 | 
			
		||||
@@ -31,7 +31,15 @@ func TestPullRequest_LoadIssue(t *testing.T) {
 | 
			
		||||
	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) {
 | 
			
		||||
	assert.NoError(t, PrepareTestDatabase())
 | 
			
		||||
 
 | 
			
		||||
@@ -134,8 +134,8 @@ type Repository struct {
 | 
			
		||||
	Owner         *User  `xorm:"-"`
 | 
			
		||||
	LowerName     string `xorm:"UNIQUE(s) INDEX NOT NULL"`
 | 
			
		||||
	Name          string `xorm:"INDEX NOT NULL"`
 | 
			
		||||
	Description   string
 | 
			
		||||
	Website       string
 | 
			
		||||
	Description   string `xorm:"TEXT"`
 | 
			
		||||
	Website       string `xorm:"VARCHAR(2048)"`
 | 
			
		||||
	DefaultBranch string
 | 
			
		||||
 | 
			
		||||
	NumWatches          int
 | 
			
		||||
@@ -1324,7 +1324,6 @@ func createRepository(e *xorm.Session, doer, u *User, repo *Repository) (err err
 | 
			
		||||
		}); err != nil {
 | 
			
		||||
			return fmt.Errorf("prepareWebhooks: %v", err)
 | 
			
		||||
		}
 | 
			
		||||
		go HookQueue.Add(repo.ID)
 | 
			
		||||
	} else if err = repo.recalculateAccesses(e); err != nil {
 | 
			
		||||
		// Organization automatically called this in addRepository method.
 | 
			
		||||
		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 {
 | 
			
		||||
@@ -1783,6 +1791,7 @@ func DeleteRepository(doer *User, uid, repoID int64) error {
 | 
			
		||||
		&HookTask{RepoID: repoID},
 | 
			
		||||
		&Notification{RepoID: repoID},
 | 
			
		||||
		&CommitStatus{RepoID: repoID},
 | 
			
		||||
		&RepoIndexerStatus{RepoID: repoID},
 | 
			
		||||
	); err != nil {
 | 
			
		||||
		return fmt.Errorf("deleteBeans: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
@@ -2327,6 +2336,23 @@ func CheckRepoStats() {
 | 
			
		||||
	}
 | 
			
		||||
	// ***** 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.
 | 
			
		||||
	// ***** 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)")
 | 
			
		||||
@@ -2461,6 +2487,11 @@ func ForkRepository(doer, u *User, oldRepo *Repository, name, desc string) (_ *R
 | 
			
		||||
		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 {
 | 
			
		||||
		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 {
 | 
			
		||||
		return fmt.Errorf("Misformatted git cat-file output: %v", err)
 | 
			
		||||
	} else if int64(size) > setting.Indexer.MaxIndexerFileSize {
 | 
			
		||||
		return nil
 | 
			
		||||
		return addDelete(update.Filename, repo, batch)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	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)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func isIndexable(entry *git.TreeEntry) bool {
 | 
			
		||||
	return entry.IsRegular() || entry.IsExecutable()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// parseGitLsTreeOutput parses the output of a `git ls-tree -r --full-name` command
 | 
			
		||||
func parseGitLsTreeOutput(stdout []byte) ([]fileUpdate, error) {
 | 
			
		||||
	entries, err := git.ParseTreeEntries(stdout)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	var idxCount = 0
 | 
			
		||||
	updates := make([]fileUpdate, len(entries))
 | 
			
		||||
	for i, entry := range entries {
 | 
			
		||||
		updates[i] = fileUpdate{
 | 
			
		||||
			Filename: entry.Name(),
 | 
			
		||||
			BlobSha:  entry.ID.String(),
 | 
			
		||||
	for _, entry := range entries {
 | 
			
		||||
		if isIndexable(entry) {
 | 
			
		||||
			updates[idxCount] = fileUpdate{
 | 
			
		||||
				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
 | 
			
		||||
 
 | 
			
		||||
@@ -642,12 +642,14 @@ func rewriteAllPublicKeys(e Engine) error {
 | 
			
		||||
			}
 | 
			
		||||
			_, err = t.WriteString(line + "\n")
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				f.Close()
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		defer f.Close()
 | 
			
		||||
		f.Close()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	t.Close()
 | 
			
		||||
	return os.Rename(tmpPath, fPath)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -195,9 +195,9 @@ func (u *User) UpdateTheme(themeName string) error {
 | 
			
		||||
	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.
 | 
			
		||||
func (u *User) getEmail() string {
 | 
			
		||||
func (u *User) GetEmail() string {
 | 
			
		||||
	if u.KeepEmailPrivate {
 | 
			
		||||
		return fmt.Sprintf("%s@%s", u.LowerName, setting.Service.NoReplyAddress)
 | 
			
		||||
	}
 | 
			
		||||
@@ -210,7 +210,7 @@ func (u *User) APIFormat() *api.User {
 | 
			
		||||
		ID:        u.ID,
 | 
			
		||||
		UserName:  u.Name,
 | 
			
		||||
		FullName:  u.FullName,
 | 
			
		||||
		Email:     u.getEmail(),
 | 
			
		||||
		Email:     u.GetEmail(),
 | 
			
		||||
		AvatarURL: u.AvatarLink(),
 | 
			
		||||
		Language:  u.Language,
 | 
			
		||||
		IsAdmin:   u.IsAdmin,
 | 
			
		||||
@@ -425,7 +425,7 @@ func (u *User) GetFollowing(page int) ([]*User, error) {
 | 
			
		||||
func (u *User) NewGitSig() *git.Signature {
 | 
			
		||||
	return &git.Signature{
 | 
			
		||||
		Name:  u.GitName(),
 | 
			
		||||
		Email: u.getEmail(),
 | 
			
		||||
		Email: u.GetEmail(),
 | 
			
		||||
		When:  time.Now(),
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -751,6 +751,7 @@ var (
 | 
			
		||||
		"robots.txt",
 | 
			
		||||
		".",
 | 
			
		||||
		"..",
 | 
			
		||||
		".well-known",
 | 
			
		||||
	}
 | 
			
		||||
	reservedUserPatterns = []string{"*.keys", "*.gpg"}
 | 
			
		||||
)
 | 
			
		||||
@@ -1375,9 +1376,7 @@ type SearchUserOptions struct {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (opts *SearchUserOptions) toConds() builder.Cond {
 | 
			
		||||
 | 
			
		||||
	var cond = builder.NewCond()
 | 
			
		||||
	cond = cond.And(builder.Eq{"type": opts.Type})
 | 
			
		||||
	var cond builder.Cond = builder.Eq{"type": opts.Type}
 | 
			
		||||
 | 
			
		||||
	if len(opts.Keyword) > 0 {
 | 
			
		||||
		lowerKeyword := strings.ToLower(opts.Keyword)
 | 
			
		||||
 
 | 
			
		||||
@@ -890,7 +890,6 @@ func DeliverHooks() {
 | 
			
		||||
	for _, t := range tasks {
 | 
			
		||||
		if err = t.deliver(); err != nil {
 | 
			
		||||
			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.
 | 
			
		||||
func getSlackForkPayload(p *api.ForkPayload, slack *SlackMeta) (*SlackPayload, error) {
 | 
			
		||||
	baseLink := SlackLinkFormatter(p.Repo.HTMLURL, p.Repo.Name)
 | 
			
		||||
	forkLink := SlackLinkFormatter(p.Forkee.HTMLURL, p.Forkee.FullName)
 | 
			
		||||
	baseLink := 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)
 | 
			
		||||
	return &SlackPayload{
 | 
			
		||||
		Channel:  slack.Channel,
 | 
			
		||||
 
 | 
			
		||||
@@ -217,7 +217,13 @@ func (repo *Repository) updateWikiPage(doer *User, oldWikiName, newWikiName, con
 | 
			
		||||
	if err := git.Push(basePath, git.PushOptions{
 | 
			
		||||
		Remote: "origin",
 | 
			
		||||
		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 {
 | 
			
		||||
		log.Error("%v", err)
 | 
			
		||||
		return fmt.Errorf("Push: %v", err)
 | 
			
		||||
 
 | 
			
		||||
@@ -169,6 +169,7 @@ func AddChanges(repoPath string, all bool, files ...string) error {
 | 
			
		||||
	if all {
 | 
			
		||||
		cmd.AddArguments("--all")
 | 
			
		||||
	}
 | 
			
		||||
	cmd.AddArguments("--")
 | 
			
		||||
	_, err := cmd.AddArguments(files...).RunInDir(repoPath)
 | 
			
		||||
	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
 | 
			
		||||
// YOU MUST ENSURE THAT pastCommit is a valid commit ID.
 | 
			
		||||
func (c *Commit) FileChangedSinceCommit(filename, pastCommit string) (bool, error) {
 | 
			
		||||
	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
 | 
			
		||||
	// pages to display information about newest commit for a given path.
 | 
			
		||||
	var treeCommit *Commit
 | 
			
		||||
	if rev, ok := revs[""]; ok {
 | 
			
		||||
	if treePath == "" {
 | 
			
		||||
		treeCommit = commit
 | 
			
		||||
	} else if rev, ok := revs[""]; ok {
 | 
			
		||||
		treeCommit = convertCommit(rev)
 | 
			
		||||
	}
 | 
			
		||||
	return commitsInfo, treeCommit, nil
 | 
			
		||||
 
 | 
			
		||||
@@ -28,21 +28,27 @@ func cloneRepo(url, dir, name string) (string, error) {
 | 
			
		||||
func testGetCommitsInfo(t *testing.T, repo1 *Repository) {
 | 
			
		||||
	// these test case are specific to the repo1 test repo
 | 
			
		||||
	testCases := []struct {
 | 
			
		||||
		CommitID    string
 | 
			
		||||
		Path        string
 | 
			
		||||
		ExpectedIDs map[string]string
 | 
			
		||||
		CommitID           string
 | 
			
		||||
		Path               string
 | 
			
		||||
		ExpectedIDs        map[string]string
 | 
			
		||||
		ExpectedTreeCommit string
 | 
			
		||||
	}{
 | 
			
		||||
		{"8d92fc957a4d7cfd98bc375f0b7bb189a0d6c9f2", "", map[string]string{
 | 
			
		||||
			"file1.txt": "95bb4d39648ee7e325106df01a621c530863a653",
 | 
			
		||||
			"file2.txt": "8d92fc957a4d7cfd98bc375f0b7bb189a0d6c9f2",
 | 
			
		||||
		}},
 | 
			
		||||
		}, "8d92fc957a4d7cfd98bc375f0b7bb189a0d6c9f2"},
 | 
			
		||||
		{"2839944139e0de9737a044f78b0e4b40d989a9e3", "", map[string]string{
 | 
			
		||||
			"file1.txt":   "2839944139e0de9737a044f78b0e4b40d989a9e3",
 | 
			
		||||
			"branch1.txt": "9c9aef8dd84e02bc7ec12641deb4c930a7c30185",
 | 
			
		||||
		}},
 | 
			
		||||
		}, "2839944139e0de9737a044f78b0e4b40d989a9e3"},
 | 
			
		||||
		{"5c80b0245c1c6f8343fa418ec374b13b5d4ee658", "branch2", map[string]string{
 | 
			
		||||
			"branch2.txt": "5c80b0245c1c6f8343fa418ec374b13b5d4ee658",
 | 
			
		||||
		}},
 | 
			
		||||
		}, "5c80b0245c1c6f8343fa418ec374b13b5d4ee658"},
 | 
			
		||||
		{"feaf4ba6bc635fec442f46ddd4512416ec43c2c2", "", map[string]string{
 | 
			
		||||
			"file1.txt": "95bb4d39648ee7e325106df01a621c530863a653",
 | 
			
		||||
			"file2.txt": "8d92fc957a4d7cfd98bc375f0b7bb189a0d6c9f2",
 | 
			
		||||
			"foo":       "37991dec2c8e592043f47155ce4808d4580f9123",
 | 
			
		||||
		}, "feaf4ba6bc635fec442f46ddd4512416ec43c2c2"},
 | 
			
		||||
	}
 | 
			
		||||
	for _, testCase := range testCases {
 | 
			
		||||
		commit, err := repo1.GetCommit(testCase.CommitID)
 | 
			
		||||
@@ -51,7 +57,8 @@ func testGetCommitsInfo(t *testing.T, repo1 *Repository) {
 | 
			
		||||
		assert.NoError(t, err)
 | 
			
		||||
		entries, err := tree.ListEntries()
 | 
			
		||||
		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.Len(t, commitsInfo, len(testCase.ExpectedIDs))
 | 
			
		||||
		for _, commitInfo := range commitsInfo {
 | 
			
		||||
 
 | 
			
		||||
@@ -187,8 +187,7 @@ func Pull(repoPath string, opts PullRemoteOptions) error {
 | 
			
		||||
	if opts.All {
 | 
			
		||||
		cmd.AddArguments("--all")
 | 
			
		||||
	} else {
 | 
			
		||||
		cmd.AddArguments(opts.Remote)
 | 
			
		||||
		cmd.AddArguments(opts.Branch)
 | 
			
		||||
		cmd.AddArguments("--", opts.Remote, opts.Branch)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if opts.Timeout <= 0 {
 | 
			
		||||
@@ -213,7 +212,7 @@ func Push(repoPath string, opts PushOptions) error {
 | 
			
		||||
	if opts.Force {
 | 
			
		||||
		cmd.AddArguments("-f")
 | 
			
		||||
	}
 | 
			
		||||
	cmd.AddArguments(opts.Remote, opts.Branch)
 | 
			
		||||
	cmd.AddArguments("--", opts.Remote, opts.Branch)
 | 
			
		||||
	_, err := cmd.RunInDirWithEnv(repoPath, opts.Env)
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -135,7 +135,7 @@ func (repo *Repository) DeleteBranch(name string, opts DeleteBranchOptions) erro
 | 
			
		||||
		cmd.AddArguments("-d")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cmd.AddArguments(name)
 | 
			
		||||
	cmd.AddArguments("--", name)
 | 
			
		||||
	_, err := cmd.RunInDir(repo.Path)
 | 
			
		||||
 | 
			
		||||
	return err
 | 
			
		||||
 
 | 
			
		||||
@@ -117,20 +117,26 @@ func (repo *Repository) getCommit(id SHA1) (*Commit, error) {
 | 
			
		||||
	return commit, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetCommit returns commit object of by ID string.
 | 
			
		||||
func (repo *Repository) GetCommit(commitID string) (*Commit, error) {
 | 
			
		||||
// ConvertToSHA1 returns a Hash object from a potential ID string
 | 
			
		||||
func (repo *Repository) ConvertToSHA1(commitID string) (SHA1, error) {
 | 
			
		||||
	if len(commitID) != 40 {
 | 
			
		||||
		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 strings.Contains(err.Error(), "unknown revision or path") {
 | 
			
		||||
				return nil, ErrNotExist{commitID, ""}
 | 
			
		||||
			if strings.Contains(err.Error(), "unknown revision or path") ||
 | 
			
		||||
				strings.Contains(err.Error(), "fatal: Needed a single revision") {
 | 
			
		||||
				return SHA1{}, ErrNotExist{commitID, ""}
 | 
			
		||||
			}
 | 
			
		||||
			return nil, err
 | 
			
		||||
			return SHA1{}, err
 | 
			
		||||
		}
 | 
			
		||||
		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 {
 | 
			
		||||
		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
 | 
			
		||||
// You must ensure that id1 and id2 are valid commit ids.
 | 
			
		||||
func (repo *Repository) FileChangedBetweenCommits(filename, id1, id2 string) (bool, error) {
 | 
			
		||||
	stdout, err := NewCommand("diff", "--name-only", "-z", id1, id2, "--", filename).RunInDirBytes(repo.Path)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
 
 | 
			
		||||
@@ -55,5 +55,5 @@ func TestGetCommitWithBadCommitID(t *testing.T) {
 | 
			
		||||
	commit, err := bareRepo1.GetCommit("bad_branch")
 | 
			
		||||
	assert.Nil(t, commit)
 | 
			
		||||
	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
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -54,7 +54,7 @@ func (repo *Repository) GetCompareInfo(basePath, baseBranch, headBranch string)
 | 
			
		||||
	if repo.Path != basePath {
 | 
			
		||||
		// Add a temporary remote
 | 
			
		||||
		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)
 | 
			
		||||
		}
 | 
			
		||||
		defer func() {
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,7 @@ import (
 | 
			
		||||
// ReadTreeToIndex reads a treeish to the index
 | 
			
		||||
func (repo *Repository) ReadTreeToIndex(treeish string) error {
 | 
			
		||||
	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 {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
@@ -23,12 +23,12 @@ func TestRepository_GetCodeActivityStats(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.NotNil(t, code)
 | 
			
		||||
 | 
			
		||||
	assert.EqualValues(t, 8, code.CommitCount)
 | 
			
		||||
	assert.EqualValues(t, 2, code.AuthorCount)
 | 
			
		||||
	assert.EqualValues(t, 8, code.CommitCountInAllBranches)
 | 
			
		||||
	assert.EqualValues(t, 9, code.CommitCount)
 | 
			
		||||
	assert.EqualValues(t, 3, code.AuthorCount)
 | 
			
		||||
	assert.EqualValues(t, 9, code.CommitCountInAllBranches)
 | 
			
		||||
	assert.EqualValues(t, 10, code.Additions)
 | 
			
		||||
	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.EqualValues(t, 3, code.Authors["tris.git@shoddynet.org"])
 | 
			
		||||
	assert.EqualValues(t, 5, code.Authors[""])
 | 
			
		||||
 
 | 
			
		||||
@@ -29,13 +29,13 @@ func (repo *Repository) IsTagExist(name string) bool {
 | 
			
		||||
 | 
			
		||||
// CreateTag create one tag in the repository
 | 
			
		||||
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
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CreateAnnotatedTag create one annotated tag in the repository
 | 
			
		||||
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
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -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)
 | 
			
		||||
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 {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -28,7 +28,7 @@ func (repo *Repository) getTree(id SHA1) (*Tree, error) {
 | 
			
		||||
// GetTree find the tree object in the repository.
 | 
			
		||||
func (repo *Repository) GetTree(idStr string) (*Tree, error) {
 | 
			
		||||
	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 {
 | 
			
		||||
			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
 | 
			
		||||
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
 | 
			
		||||
	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
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 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
 | 
			
		||||
func (te *TreeEntry) Blob() *Blob {
 | 
			
		||||
	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)
 | 
			
		||||
	return body
 | 
			
		||||
	return markup.SanitizeBytes(body)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
 
 | 
			
		||||
@@ -111,7 +111,7 @@ func (g *GiteaLocalUploader) CreateMilestones(milestones ...*base.Milestone) err
 | 
			
		||||
			RepoID:       g.repo.ID,
 | 
			
		||||
			Name:         milestone.Title,
 | 
			
		||||
			Content:      milestone.Description,
 | 
			
		||||
			IsClosed:     milestone.State == "close",
 | 
			
		||||
			IsClosed:     milestone.State == "closed",
 | 
			
		||||
			DeadlineUnix: deadline,
 | 
			
		||||
		}
 | 
			
		||||
		if ms.IsClosed && milestone.Closed != nil {
 | 
			
		||||
 
 | 
			
		||||
@@ -173,6 +173,7 @@ func TestGitHubDownloadRepo(t *testing.T) {
 | 
			
		||||
 | 
			
		||||
	var (
 | 
			
		||||
		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{
 | 
			
		||||
		{
 | 
			
		||||
@@ -208,9 +209,9 @@ func TestGitHubDownloadRepo(t *testing.T) {
 | 
			
		||||
			Number:     7,
 | 
			
		||||
			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",
 | 
			
		||||
			Milestone:  "1.x.x",
 | 
			
		||||
			Milestone:  "1.10.0",
 | 
			
		||||
			PosterName: "joubertredrat",
 | 
			
		||||
			State:      "open",
 | 
			
		||||
			State:      "closed",
 | 
			
		||||
			Created:    time.Date(2016, 11, 02, 18, 57, 32, 0, time.UTC),
 | 
			
		||||
			Labels: []*base.Label{
 | 
			
		||||
				{
 | 
			
		||||
@@ -232,6 +233,7 @@ func TestGitHubDownloadRepo(t *testing.T) {
 | 
			
		||||
				Heart:      0,
 | 
			
		||||
				Hooray:     0,
 | 
			
		||||
			},
 | 
			
		||||
			Closed: &closed7,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			Number:     8,
 | 
			
		||||
 
 | 
			
		||||
@@ -29,12 +29,13 @@ type HookOptions struct {
 | 
			
		||||
	UserName                        string
 | 
			
		||||
	GitObjectDirectory              string
 | 
			
		||||
	GitAlternativeObjectDirectories string
 | 
			
		||||
	GitQuarantinePath               string
 | 
			
		||||
	ProtectedBranchID               int64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// HookPreReceive check whether the provided commits are allowed
 | 
			
		||||
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(repoName),
 | 
			
		||||
		url.QueryEscape(opts.OldCommitID),
 | 
			
		||||
@@ -43,6 +44,7 @@ func HookPreReceive(ownerName, repoName string, opts HookOptions) (int, string)
 | 
			
		||||
		opts.UserID,
 | 
			
		||||
		url.QueryEscape(opts.GitObjectDirectory),
 | 
			
		||||
		url.QueryEscape(opts.GitAlternativeObjectDirectories),
 | 
			
		||||
		url.QueryEscape(opts.GitQuarantinePath),
 | 
			
		||||
		opts.ProtectedBranchID,
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -49,7 +49,6 @@ func Merge(pr *models.PullRequest, doer *models.User, baseGitRepo *git.Repositor
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	defer func() {
 | 
			
		||||
		go models.HookQueue.Add(pr.BaseRepo.ID)
 | 
			
		||||
		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
 | 
			
		||||
	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())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -241,7 +240,13 @@ func Merge(pr *models.PullRequest, doer *models.User, baseGitRepo *git.Repositor
 | 
			
		||||
		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.
 | 
			
		||||
	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)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	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
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -92,6 +92,12 @@ func DeleteRepoFile(repo *models.Repository, doer *models.User, opts *DeleteRepo
 | 
			
		||||
	// Assigned LastCommitID in opts if it hasn't been set
 | 
			
		||||
	if opts.LastCommitID == "" {
 | 
			
		||||
		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
 | 
			
		||||
@@ -172,32 +178,6 @@ func DeleteRepoFile(repo *models.Repository, doer *models.User, opts *DeleteRepo
 | 
			
		||||
		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)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		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
 | 
			
		||||
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()
 | 
			
		||||
	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
 | 
			
		||||
	if opts.LastCommitID == "" {
 | 
			
		||||
		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"
 | 
			
		||||
@@ -387,32 +394,6 @@ func CreateOrUpdateRepoFile(repo *models.Repository, doer *models.User, opts *Up
 | 
			
		||||
		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)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,6 @@ import (
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/models"
 | 
			
		||||
	"code.gitea.io/gitea/modules/git"
 | 
			
		||||
	"code.gitea.io/gitea/modules/lfs"
 | 
			
		||||
	"code.gitea.io/gitea/modules/setting"
 | 
			
		||||
)
 | 
			
		||||
@@ -177,31 +176,5 @@ func UploadRepoFiles(repo *models.Repository, doer *models.User, opts *UploadRep
 | 
			
		||||
		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...)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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 string `json:"message"`
 | 
			
		||||
	// 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
 | 
			
		||||
	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    Identity `json:"author"`
 | 
			
		||||
	Committer Identity `json:"committer"`
 | 
			
		||||
 
 | 
			
		||||
@@ -694,6 +694,7 @@ editor.delete = Delete '%s'
 | 
			
		||||
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.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.cancel = Cancel
 | 
			
		||||
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:hover{color:rgba(0,0,0,.8)}
 | 
			
		||||
.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).ui.segment{padding:3em}
 | 
			
		||||
.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 .shatd{text-align:center}
 | 
			
		||||
.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 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}
 | 
			
		||||
@@ -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:not(.active) a{display:none}
 | 
			
		||||
.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 .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}
 | 
			
		||||
@@ -814,8 +818,8 @@ footer .ui.left,footer .ui.right{line-height:40px}
 | 
			
		||||
.stats-table .table-cell{display:table-cell}
 | 
			
		||||
.stats-table .table-cell.tiny{height:.5em}
 | 
			
		||||
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 .commit-status-link{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 .commit-status-link{display:inline-block;vertical-align:middle}
 | 
			
		||||
.commit-body{white-space:pre-wrap}
 | 
			
		||||
.git-notes.top{text-align:left}
 | 
			
		||||
.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}
 | 
			
		||||
.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 .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.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}
 | 
			
		||||
 
 | 
			
		||||
@@ -10,6 +10,11 @@ function htmlEncode(text) {
 | 
			
		||||
var csrf;
 | 
			
		||||
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)
 | 
			
		||||
if (!Array.from) {
 | 
			
		||||
    Array.from = (function () {
 | 
			
		||||
@@ -1270,6 +1275,7 @@ function initEditor() {
 | 
			
		||||
            $('.quick-pull-branch-name').hide();
 | 
			
		||||
            $('.quick-pull-branch-name input').prop('required',false);
 | 
			
		||||
        }
 | 
			
		||||
        $('#commit-button').text($(this).attr('button_text'));
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    var $editFilename = $("#file-name");
 | 
			
		||||
@@ -1968,17 +1974,18 @@ $(document).ready(function () {
 | 
			
		||||
 | 
			
		||||
    // Highlight JS
 | 
			
		||||
    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
 | 
			
		||||
    var $dropzone = $('#dropzone');
 | 
			
		||||
    const $dropzone = $('#dropzone');
 | 
			
		||||
    if ($dropzone.length > 0) {
 | 
			
		||||
        // Disable auto discover for all elements:
 | 
			
		||||
        Dropzone.autoDiscover = false;
 | 
			
		||||
        const filenameDict = {};
 | 
			
		||||
 | 
			
		||||
        var filenameDict = {};
 | 
			
		||||
        $dropzone.dropzone({
 | 
			
		||||
        new Dropzone("#dropzone", {
 | 
			
		||||
            url: $dropzone.data('upload-url'),
 | 
			
		||||
            headers: {"X-Csrf-Token": csrf},
 | 
			
		||||
            maxFiles: $dropzone.data('max-file'),
 | 
			
		||||
@@ -2006,7 +2013,7 @@ $(document).ready(function () {
 | 
			
		||||
                        });
 | 
			
		||||
                    }
 | 
			
		||||
                })
 | 
			
		||||
            }
 | 
			
		||||
            },
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -2104,12 +2111,16 @@ $(document).ready(function () {
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    $('.issue-action').click(function () {
 | 
			
		||||
        var action = this.dataset.action
 | 
			
		||||
        var elementId = this.dataset.elementId
 | 
			
		||||
        var issueIDs = $('.issue-checkbox').children('input:checked').map(function() {
 | 
			
		||||
        let action = this.dataset.action;
 | 
			
		||||
        let elementId = this.dataset.elementId;
 | 
			
		||||
        let issueIDs = $('.issue-checkbox').children('input:checked').map(function() {
 | 
			
		||||
            return this.dataset.issueId;
 | 
			
		||||
        }).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);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -605,7 +605,6 @@ code,
 | 
			
		||||
.file-comment {
 | 
			
		||||
    font: 12px @monospaced-fonts, monospace;
 | 
			
		||||
    color: rgba(0, 0, 0, 0.87);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.ui.floating.dropdown {
 | 
			
		||||
@@ -877,3 +876,19 @@ footer {
 | 
			
		||||
.ui.tabular.menu .item.active {
 | 
			
		||||
    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;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        td.message {
 | 
			
		||||
            text-overflow: unset;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        &.ui.basic.striped.table tbody tr:nth-child(2n) {
 | 
			
		||||
            background-color: rgba(0, 0, 0, 0.02) !important;
 | 
			
		||||
        }
 | 
			
		||||
@@ -1971,6 +1975,8 @@
 | 
			
		||||
&.user-cards {
 | 
			
		||||
    .list {
 | 
			
		||||
        padding: 0;
 | 
			
		||||
        display: flex;
 | 
			
		||||
        flex-wrap: wrap;
 | 
			
		||||
 | 
			
		||||
        .item {
 | 
			
		||||
            list-style: none;
 | 
			
		||||
@@ -2300,12 +2306,12 @@ tbody.commit-list {
 | 
			
		||||
.commit-list .message-wrapper {
 | 
			
		||||
    overflow: hidden;
 | 
			
		||||
    text-overflow: ellipsis;
 | 
			
		||||
    max-width: calc(100% - 24px);
 | 
			
		||||
    max-width: calc(100% - 50px);
 | 
			
		||||
    display: inline-block;
 | 
			
		||||
    vertical-align: middle;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.commit-list .message-wrapper .commit-status-link {
 | 
			
		||||
.commit-list .commit-status-link {
 | 
			
		||||
    display: inline-block;
 | 
			
		||||
    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(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(5),
 | 
			
		||||
.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
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
Version: 2.3.1
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										9
									
								
								public/vendor/librejs.html
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										9
									
								
								public/vendor/librejs.html
									
									
									
									
										vendored
									
									
								
							@@ -17,8 +17,13 @@
 | 
			
		||||
        </tr>
 | 
			
		||||
        <tr>
 | 
			
		||||
          <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://code.jquery.com/jquery-1.12.4.min.js">jquery-1.12.4.min.js</a></td>
 | 
			
		||||
          <td><a href="https://jquery.org/license/">MIT</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>
 | 
			
		||||
          <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
 | 
			
		||||
	// produces:
 | 
			
		||||
	// - 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:
 | 
			
		||||
	//   "200":
 | 
			
		||||
	//     "$ref": "#/responses/OrganizationList"
 | 
			
		||||
@@ -90,7 +99,9 @@ func GetAllOrgs(ctx *context.APIContext) {
 | 
			
		||||
	users, _, err := models.SearchUsers(&models.SearchUserOptions{
 | 
			
		||||
		Type:     models.UserTypeOrganization,
 | 
			
		||||
		OrderBy:  models.SearchOrderByAlphabetically,
 | 
			
		||||
		PageSize: -1,
 | 
			
		||||
		Page:     ctx.QueryInt("page"),
 | 
			
		||||
		PageSize: convert.ToCorrectPageSize(ctx.QueryInt("limit")),
 | 
			
		||||
		Private:  true,
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		ctx.Error(500, "SearchOrganizations", err)
 | 
			
		||||
 
 | 
			
		||||
@@ -91,8 +91,7 @@ func CreateUser(ctx *context.APIContext, form api.CreateUserOption) {
 | 
			
		||||
	if form.SendNotify && setting.MailService != nil {
 | 
			
		||||
		models.SendRegisterNotifyMail(ctx.Context.Context, u)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ctx.JSON(201, u.APIFormat())
 | 
			
		||||
	ctx.JSON(201, convert.ToUser(u, ctx.IsSigned, ctx.User.IsAdmin))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 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)
 | 
			
		||||
 | 
			
		||||
	ctx.JSON(200, u.APIFormat())
 | 
			
		||||
	ctx.JSON(200, convert.ToUser(u, ctx.IsSigned, ctx.User.IsAdmin))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeleteUser api for deleting a user
 | 
			
		||||
@@ -326,7 +325,7 @@ func GetAllUsers(ctx *context.APIContext) {
 | 
			
		||||
 | 
			
		||||
	results := make([]*api.User, len(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)
 | 
			
		||||
 
 | 
			
		||||
@@ -229,7 +229,7 @@ func ToTeam(team *models.Team) *api.Team {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 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{
 | 
			
		||||
		ID:        user.ID,
 | 
			
		||||
		UserName:  user.Name,
 | 
			
		||||
@@ -239,7 +239,12 @@ func ToUser(user *models.User, signed, admin bool) *api.User {
 | 
			
		||||
		LastLogin: user.LastLoginUnix.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
 | 
			
		||||
	}
 | 
			
		||||
	return result
 | 
			
		||||
 
 | 
			
		||||
@@ -12,6 +12,7 @@ import (
 | 
			
		||||
	"code.gitea.io/gitea/models"
 | 
			
		||||
	"code.gitea.io/gitea/modules/context"
 | 
			
		||||
	"code.gitea.io/gitea/modules/setting"
 | 
			
		||||
	"code.gitea.io/gitea/routers/api/v1/convert"
 | 
			
		||||
	"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))
 | 
			
		||||
	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)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -257,7 +257,7 @@ func GetTeamMembers(ctx *context.APIContext) {
 | 
			
		||||
	}
 | 
			
		||||
	members := make([]*api.User, len(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)
 | 
			
		||||
}
 | 
			
		||||
@@ -288,7 +288,7 @@ func GetTeamMember(ctx *context.APIContext) {
 | 
			
		||||
	if ctx.Written() {
 | 
			
		||||
		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
 | 
			
		||||
 
 | 
			
		||||
@@ -12,6 +12,7 @@ import (
 | 
			
		||||
	"code.gitea.io/gitea/modules/context"
 | 
			
		||||
 | 
			
		||||
	api "code.gitea.io/gitea/modules/structs"
 | 
			
		||||
	"code.gitea.io/gitea/routers/api/v1/convert"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ListCollaborators list a repository's collaborators
 | 
			
		||||
@@ -42,7 +43,7 @@ func ListCollaborators(ctx *context.APIContext) {
 | 
			
		||||
	}
 | 
			
		||||
	users := make([]*api.User, len(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)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -92,7 +92,7 @@ func GetSingleCommit(ctx *context.APIContext) {
 | 
			
		||||
			URL: setting.AppURL + ctx.Link[1:],
 | 
			
		||||
			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{
 | 
			
		||||
			URL: setting.AppURL + ctx.Link[1:],
 | 
			
		||||
			Author: &api.CommitUser{
 | 
			
		||||
@@ -111,7 +111,7 @@ func GetSingleCommit(ctx *context.APIContext) {
 | 
			
		||||
			},
 | 
			
		||||
			Message: commit.Message(),
 | 
			
		||||
			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(),
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
 
 | 
			
		||||
@@ -71,19 +71,22 @@ func GetGitRefs(ctx *context.APIContext) {
 | 
			
		||||
	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())
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		ctx.Error(500, "OpenRepository", err)
 | 
			
		||||
		return
 | 
			
		||||
		return nil, "OpenRepository", err
 | 
			
		||||
	}
 | 
			
		||||
	if len(filter) > 0 {
 | 
			
		||||
		filter = "refs/" + 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 {
 | 
			
		||||
		ctx.Error(500, "GetRefsFiltered", err)
 | 
			
		||||
		ctx.Error(500, lastMethodName, err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -130,8 +130,8 @@ func TestHook(ctx *context.APIContext) {
 | 
			
		||||
			convert.ToCommit(ctx.Repo.Repository, ctx.Repo.Commit),
 | 
			
		||||
		},
 | 
			
		||||
		Repo:   ctx.Repo.Repository.APIFormat(models.AccessModeNone),
 | 
			
		||||
		Pusher: ctx.User.APIFormat(),
 | 
			
		||||
		Sender: ctx.User.APIFormat(),
 | 
			
		||||
		Pusher: convert.ToUser(ctx.User, ctx.IsSigned, false),
 | 
			
		||||
		Sender: convert.ToUser(ctx.User, ctx.IsSigned, false),
 | 
			
		||||
	}); err != nil {
 | 
			
		||||
		ctx.Error(500, "PrepareWebhook: ", err)
 | 
			
		||||
		return
 | 
			
		||||
 
 | 
			
		||||
@@ -646,89 +646,102 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error {
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if opts.HasIssues != nil {
 | 
			
		||||
		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.HasIssues == nil {
 | 
			
		||||
		// If HasIssues setting not touched, rewrite existing repo unit
 | 
			
		||||
		if unit, err := repo.GetUnit(models.UnitTypeIssues); err == nil {
 | 
			
		||||
			units = append(units, *unit)
 | 
			
		||||
		} else if unit, err := repo.GetUnit(models.UnitTypeExternalTracker); err == nil {
 | 
			
		||||
			units = append(units, *unit)
 | 
			
		||||
		}
 | 
			
		||||
	} 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 {
 | 
			
		||||
			// 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.HasWiki == nil {
 | 
			
		||||
		// If HasWiki setting not touched, rewrite existing repo unit
 | 
			
		||||
		if unit, err := repo.GetUnit(models.UnitTypeWiki); err == nil {
 | 
			
		||||
			units = append(units, *unit)
 | 
			
		||||
		} else if unit, err := repo.GetUnit(models.UnitTypeExternalWiki); err == nil {
 | 
			
		||||
			units = append(units, *unit)
 | 
			
		||||
		}
 | 
			
		||||
	} 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 {
 | 
			
		||||
			// 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 opts.HasPullRequests == nil {
 | 
			
		||||
		// If HasPullRequest setting not touched, rewrite existing repo unit
 | 
			
		||||
		if unit, err := repo.GetUnit(models.UnitTypePullRequests); err == nil {
 | 
			
		||||
			units = append(units, *unit)
 | 
			
		||||
		}
 | 
			
		||||
	} 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 {
 | 
			
		||||
 
 | 
			
		||||
@@ -8,6 +8,7 @@ import (
 | 
			
		||||
	"code.gitea.io/gitea/modules/context"
 | 
			
		||||
 | 
			
		||||
	api "code.gitea.io/gitea/modules/structs"
 | 
			
		||||
	"code.gitea.io/gitea/routers/api/v1/convert"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ListStargazers list a repository's stargazers
 | 
			
		||||
@@ -38,7 +39,7 @@ func ListStargazers(ctx *context.APIContext) {
 | 
			
		||||
	}
 | 
			
		||||
	users := make([]*api.User, len(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)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -46,10 +46,7 @@ func NewCommitStatus(ctx *context.APIContext, form api.CreateStatusOption) {
 | 
			
		||||
	//     "$ref": "#/responses/StatusList"
 | 
			
		||||
	sha := ctx.Params("sha")
 | 
			
		||||
	if len(sha) == 0 {
 | 
			
		||||
		sha = ctx.Params("ref")
 | 
			
		||||
	}
 | 
			
		||||
	if len(sha) == 0 {
 | 
			
		||||
		ctx.Error(400, "ref/sha not given", nil)
 | 
			
		||||
		ctx.Error(400, "sha not given", nil)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	status := &models.CommitStatus{
 | 
			
		||||
@@ -121,7 +118,38 @@ func GetCommitStatusesByRef(ctx *context.APIContext) {
 | 
			
		||||
	// responses:
 | 
			
		||||
	//   "200":
 | 
			
		||||
	//     "$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) {
 | 
			
		||||
 
 | 
			
		||||
@@ -8,6 +8,7 @@ import (
 | 
			
		||||
	"code.gitea.io/gitea/modules/context"
 | 
			
		||||
 | 
			
		||||
	api "code.gitea.io/gitea/modules/structs"
 | 
			
		||||
	"code.gitea.io/gitea/routers/api/v1/convert"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ListSubscribers list a repo's subscribers (i.e. watchers)
 | 
			
		||||
@@ -38,7 +39,7 @@ func ListSubscribers(ctx *context.APIContext) {
 | 
			
		||||
	}
 | 
			
		||||
	users := make([]*api.User, len(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)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -9,12 +9,13 @@ import (
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/models"
 | 
			
		||||
	"code.gitea.io/gitea/modules/context"
 | 
			
		||||
	"code.gitea.io/gitea/routers/api/v1/convert"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func responseAPIUsers(ctx *context.APIContext, users []*models.User) {
 | 
			
		||||
	apiUsers := make([]*api.User, len(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)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -22,13 +22,13 @@ func appendPrivateInformation(apiKey *api.PublicKey, key *models.PublicKey, defa
 | 
			
		||||
		apiKey.KeyType = "user"
 | 
			
		||||
 | 
			
		||||
		if defaultUser.ID == key.OwnerID {
 | 
			
		||||
			apiKey.Owner = defaultUser.APIFormat()
 | 
			
		||||
			apiKey.Owner = convert.ToUser(defaultUser, true, true)
 | 
			
		||||
		} else {
 | 
			
		||||
			user, err := models.GetUserByID(key.OwnerID)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return apiKey, err
 | 
			
		||||
			}
 | 
			
		||||
			apiKey.Owner = user.APIFormat()
 | 
			
		||||
			apiKey.Owner = convert.ToUser(user, true, true)
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		apiKey.KeyType = "unknown"
 | 
			
		||||
 
 | 
			
		||||
@@ -104,11 +104,7 @@ func GetInfo(ctx *context.APIContext) {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Hide user e-mail when API caller isn't signed in.
 | 
			
		||||
	if !ctx.IsSigned {
 | 
			
		||||
		u.Email = ""
 | 
			
		||||
	}
 | 
			
		||||
	ctx.JSON(200, u.APIFormat())
 | 
			
		||||
	ctx.JSON(200, convert.ToUser(u, ctx.IsSigned, ctx.User.ID == u.ID || ctx.User.IsAdmin))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetAuthenticatedUser get current user's information
 | 
			
		||||
@@ -121,7 +117,7 @@ func GetAuthenticatedUser(ctx *context.APIContext) {
 | 
			
		||||
	// responses:
 | 
			
		||||
	//   "200":
 | 
			
		||||
	//     "$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
 | 
			
		||||
 
 | 
			
		||||
@@ -39,6 +39,7 @@ func Settings(ctx *context.Context) {
 | 
			
		||||
func SettingsPost(ctx *context.Context, form auth.UpdateOrgSettingForm) {
 | 
			
		||||
	ctx.Data["Title"] = ctx.Tr("org.settings")
 | 
			
		||||
	ctx.Data["PageIsSettingsOptions"] = true
 | 
			
		||||
	ctx.Data["CurrentVisibility"] = structs.VisibleType(ctx.Org.Organization.Visibility)
 | 
			
		||||
 | 
			
		||||
	if ctx.HasError() {
 | 
			
		||||
		ctx.HTML(200, tplSettingsOptions)
 | 
			
		||||
 
 | 
			
		||||
@@ -31,6 +31,7 @@ func HookPreReceive(ctx *macaron.Context) {
 | 
			
		||||
	userID := ctx.QueryInt64("userID")
 | 
			
		||||
	gitObjectDirectory := ctx.QueryTrim("gitObjectDirectory")
 | 
			
		||||
	gitAlternativeObjectDirectories := ctx.QueryTrim("gitAlternativeObjectDirectories")
 | 
			
		||||
	gitQuarantinePath := ctx.QueryTrim("gitQuarantinePath")
 | 
			
		||||
	prID := ctx.QueryInt64("prID")
 | 
			
		||||
 | 
			
		||||
	branchName := strings.TrimPrefix(refFullName, git.BranchPrefix)
 | 
			
		||||
@@ -63,11 +64,19 @@ func HookPreReceive(ctx *macaron.Context) {
 | 
			
		||||
 | 
			
		||||
		// detect force push
 | 
			
		||||
		if git.EmptySHA != oldCommitID {
 | 
			
		||||
			env := append(os.Environ(),
 | 
			
		||||
				private.GitAlternativeObjectDirectories+"="+gitAlternativeObjectDirectories,
 | 
			
		||||
				private.GitObjectDirectory+"="+gitObjectDirectory,
 | 
			
		||||
				private.GitQuarantinePath+"="+gitObjectDirectory,
 | 
			
		||||
			)
 | 
			
		||||
			env := os.Environ()
 | 
			
		||||
			if gitAlternativeObjectDirectories != "" {
 | 
			
		||||
				env = append(env,
 | 
			
		||||
					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)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
 
 | 
			
		||||
@@ -39,6 +39,7 @@ func Branches(ctx *context.Context) {
 | 
			
		||||
	ctx.Data["Title"] = "Branches"
 | 
			
		||||
	ctx.Data["IsRepoToolbarBranches"] = true
 | 
			
		||||
	ctx.Data["DefaultBranch"] = ctx.Repo.Repository.DefaultBranch
 | 
			
		||||
	ctx.Data["AllowsPulls"] = ctx.Repo.Repository.AllowsPulls()
 | 
			
		||||
	ctx.Data["IsWriter"] = ctx.Repo.CanWrite(models.UnitTypeCode)
 | 
			
		||||
	ctx.Data["IsMirror"] = ctx.Repo.Repository.IsMirror
 | 
			
		||||
	ctx.Data["PageIsViewCode"] = true
 | 
			
		||||
@@ -161,6 +162,12 @@ func loadBranches(ctx *context.Context) []*Branch {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	protectedBranches, err := ctx.Repo.Repository.GetProtectedBranches()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		ctx.ServerError("GetProtectedBranches", err)
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	branches := make([]*Branch, len(rawBranches))
 | 
			
		||||
	for i := range rawBranches {
 | 
			
		||||
		commit, err := rawBranches[i].GetCommit()
 | 
			
		||||
@@ -169,11 +176,13 @@ func loadBranches(ctx *context.Context) []*Branch {
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		var isProtected bool
 | 
			
		||||
		branchName := rawBranches[i].Name
 | 
			
		||||
		isProtected, err := ctx.Repo.Repository.IsProtectedBranch(branchName, ctx.User)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			ctx.ServerError("IsProtectedBranch", err)
 | 
			
		||||
			return nil
 | 
			
		||||
		for _, b := range protectedBranches {
 | 
			
		||||
			if b.BranchName == branchName {
 | 
			
		||||
				isProtected = true
 | 
			
		||||
				break
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		divergence, divergenceError := repofiles.CountDivergingCommits(ctx.Repo.Repository, branchName)
 | 
			
		||||
 
 | 
			
		||||
@@ -292,6 +292,13 @@ func CompareDiff(ctx *context.Context) {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	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)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			if !models.IsErrPullRequestNotExist(err) {
 | 
			
		||||
@@ -312,13 +319,6 @@ func CompareDiff(ctx *context.Context) {
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		headBranches, err := headGitRepo.GetBranches()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			ctx.ServerError("GetBranches", err)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		ctx.Data["HeadBranches"] = headBranches
 | 
			
		||||
	}
 | 
			
		||||
	beforeCommitID := ctx.Data["BeforeCommitID"].(string)
 | 
			
		||||
	afterCommitID := ctx.Data["AfterCommitID"].(string)
 | 
			
		||||
 
 | 
			
		||||
@@ -9,6 +9,7 @@ import (
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"path"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/models"
 | 
			
		||||
@@ -137,7 +138,7 @@ func editFile(ctx *context.Context, isNewFile bool) {
 | 
			
		||||
	} else {
 | 
			
		||||
		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["MarkdownFileExts"] = strings.Join(setting.Markdown.FileExtensions, ",")
 | 
			
		||||
	ctx.Data["LineWrapExtensions"] = strings.Join(setting.Repository.Editor.LineWrapExtensions, ",")
 | 
			
		||||
@@ -266,6 +267,10 @@ func editFilePost(ctx *context.Context, form auth.EditRepoFileForm, isNewFile bo
 | 
			
		||||
		} else {
 | 
			
		||||
			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 {
 | 
			
		||||
		ctx.Redirect(ctx.Repo.RepoLink + "/src/branch/" + util.PathEscapeSegments(branchName) + "/" + util.PathEscapeSegments(form.TreePath))
 | 
			
		||||
	}
 | 
			
		||||
@@ -335,7 +340,7 @@ func DeleteFile(ctx *context.Context) {
 | 
			
		||||
	} else {
 | 
			
		||||
		ctx.Data["commit_choice"] = frmCommitChoiceNewBranch
 | 
			
		||||
	}
 | 
			
		||||
	ctx.Data["new_branch_name"] = ""
 | 
			
		||||
	ctx.Data["new_branch_name"] = GetUniquePatchBranchName(ctx)
 | 
			
		||||
 | 
			
		||||
	ctx.HTML(200, tplDeleteFile)
 | 
			
		||||
}
 | 
			
		||||
@@ -362,7 +367,7 @@ func DeleteFilePost(ctx *context.Context, form auth.DeleteRepoFileForm) {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if branchName != ctx.Repo.BranchName && !canCommit {
 | 
			
		||||
	if branchName == ctx.Repo.BranchName && !canCommit {
 | 
			
		||||
		ctx.Data["Err_NewBranchName"] = true
 | 
			
		||||
		ctx.Data["commit_choice"] = frmCommitChoiceNewBranch
 | 
			
		||||
		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 {
 | 
			
		||||
		// This is where we handle all the errors thrown by repofiles.DeleteRepoFile
 | 
			
		||||
		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) {
 | 
			
		||||
			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) {
 | 
			
		||||
			ctx.Data["Err_TreePath"] = true
 | 
			
		||||
			if fileErr, ok := err.(models.ErrFilePathInvalid); ok {
 | 
			
		||||
				switch fileErr.Type {
 | 
			
		||||
				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:
 | 
			
		||||
					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:
 | 
			
		||||
					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:
 | 
			
		||||
					ctx.ServerError("DeleteRepoFile", err)
 | 
			
		||||
				}
 | 
			
		||||
@@ -410,25 +415,44 @@ func DeleteFilePost(ctx *context.Context, form auth.DeleteRepoFileForm) {
 | 
			
		||||
		} else if git.IsErrBranchNotExist(err) {
 | 
			
		||||
			// For when a user deletes a file to a branch that no longer exists
 | 
			
		||||
			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 {
 | 
			
		||||
				ctx.Error(500, err.Error())
 | 
			
		||||
			}
 | 
			
		||||
		} else if models.IsErrBranchAlreadyExists(err) {
 | 
			
		||||
			// For when a user specifies a new branch that already exists
 | 
			
		||||
			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 {
 | 
			
		||||
				ctx.Error(500, err.Error())
 | 
			
		||||
			}
 | 
			
		||||
		} 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 {
 | 
			
		||||
			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 {
 | 
			
		||||
		ctx.Flash.Success(ctx.Tr("repo.editor.file_delete_success", ctx.Repo.TreePath))
 | 
			
		||||
		ctx.Redirect(ctx.Repo.RepoLink + "/src/branch/" + util.PathEscapeSegments(branchName))
 | 
			
		||||
		treePath := filepath.Dir(ctx.Repo.TreePath)
 | 
			
		||||
		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 {
 | 
			
		||||
		ctx.Data["commit_choice"] = frmCommitChoiceNewBranch
 | 
			
		||||
	}
 | 
			
		||||
	ctx.Data["new_branch_name"] = ""
 | 
			
		||||
	ctx.Data["new_branch_name"] = GetUniquePatchBranchName(ctx)
 | 
			
		||||
 | 
			
		||||
	ctx.HTML(200, tplUploadFile)
 | 
			
		||||
}
 | 
			
		||||
@@ -565,7 +589,11 @@ func UploadFilePost(ctx *context.Context, form auth.UploadRepoFileForm) {
 | 
			
		||||
		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 {
 | 
			
		||||
@@ -645,3 +673,40 @@ func RemoveUploadFileFromServer(ctx *context.Context, form auth.RemoveUploadFile
 | 
			
		||||
	log.Trace("Upload file removed: %s", form.File)
 | 
			
		||||
	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
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,8 @@
 | 
			
		||||
package repo
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"code.gitea.io/gitea/modules/git"
 | 
			
		||||
	"code.gitea.io/gitea/modules/test"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/models"
 | 
			
		||||
@@ -37,3 +39,40 @@ func TestCleanUploadName(t *testing.T) {
 | 
			
		||||
		assert.EqualValues(t, cleanUploadFileName(k), v)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestGetUniquePatchBranchName(t *testing.T) {
 | 
			
		||||
	models.PrepareTestEnv(t)
 | 
			
		||||
	ctx := test.MockContext(t, "user2/repo1")
 | 
			
		||||
	ctx.SetParams(":id", "1")
 | 
			
		||||
	test.LoadRepo(t, ctx, 1)
 | 
			
		||||
	test.LoadRepoCommit(t, ctx)
 | 
			
		||||
	test.LoadUser(t, ctx, 2)
 | 
			
		||||
	test.LoadGitRepo(t, ctx)
 | 
			
		||||
	expectedBranchName := "user2-patch-1"
 | 
			
		||||
	branchName := GetUniquePatchBranchName(ctx)
 | 
			
		||||
	assert.Equal(t, expectedBranchName, branchName)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestGetClosestParentWithFiles(t *testing.T) {
 | 
			
		||||
	models.PrepareTestEnv(t)
 | 
			
		||||
	ctx := test.MockContext(t, "user2/repo1")
 | 
			
		||||
	ctx.SetParams(":id", "1")
 | 
			
		||||
	test.LoadRepo(t, ctx, 1)
 | 
			
		||||
	test.LoadRepoCommit(t, ctx)
 | 
			
		||||
	test.LoadUser(t, ctx, 2)
 | 
			
		||||
	test.LoadGitRepo(t, ctx)
 | 
			
		||||
	repo := ctx.Repo.Repository
 | 
			
		||||
	branch := repo.DefaultBranch
 | 
			
		||||
	gitRepo, _ := git.OpenRepository(repo.RepoPath())
 | 
			
		||||
	commit, _ := gitRepo.GetBranchCommit(branch)
 | 
			
		||||
	expectedTreePath := ""
 | 
			
		||||
 | 
			
		||||
	expectedTreePath = "" // Should return the root dir, empty string, since there are no subdirs in this repo
 | 
			
		||||
	for _, deletedFile := range []string{
 | 
			
		||||
		"dir1/dir2/dir3/file.txt",
 | 
			
		||||
		"file.txt",
 | 
			
		||||
	} {
 | 
			
		||||
		treePath := GetClosestParentWithFiles(deletedFile, commit)
 | 
			
		||||
		assert.Equal(t, expectedTreePath, treePath)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -215,7 +215,10 @@ func HTTP(ctx *context.Context) {
 | 
			
		||||
				// Check username and password
 | 
			
		||||
				authUser, err = models.UserSignIn(authUsername, authPasswd)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					if !models.IsErrUserNotExist(err) {
 | 
			
		||||
					if models.IsErrUserProhibitLogin(err) {
 | 
			
		||||
						ctx.HandleText(http.StatusForbidden, "User is not permitted to login")
 | 
			
		||||
						return
 | 
			
		||||
					} else if !models.IsErrUserNotExist(err) {
 | 
			
		||||
						ctx.ServerError("UserSignIn error: %v", err)
 | 
			
		||||
						return
 | 
			
		||||
					}
 | 
			
		||||
 
 | 
			
		||||
@@ -665,7 +665,7 @@ func RegisterRoutes(m *macaron.Macaron) {
 | 
			
		||||
		}, func(ctx *context.Context) {
 | 
			
		||||
			ctx.Data["PageIsSettings"] = true
 | 
			
		||||
		})
 | 
			
		||||
	}, reqSignIn, context.RepoAssignment(), reqRepoAdmin, context.UnitTypes(), context.RepoRef())
 | 
			
		||||
	}, reqSignIn, context.RepoAssignment(), context.UnitTypes(), reqRepoAdmin, context.RepoRef())
 | 
			
		||||
 | 
			
		||||
	m.Get("/:username/:reponame/action/:action", reqSignIn, context.RepoAssignment(), context.UnitTypes(), repo.Action)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,8 @@
 | 
			
		||||
 | 
			
		||||
	{{template "base/footer_content" .}}
 | 
			
		||||
 | 
			
		||||
	<script src="{{AppSubUrl}}/vendor/plugins/jquery/jquery.min.js"></script>
 | 
			
		||||
	<script src="{{AppSubUrl}}/vendor/plugins/jquery/jquery.min.js?v=3.4.1"></script>
 | 
			
		||||
	<script src="{{AppSubUrl}}/vendor/plugins/jquery-migrate/jquery-migrate.min.js?v=3.0.1"></script>
 | 
			
		||||
	<script src="{{AppSubUrl}}/vendor/plugins/jquery.areyousure/jquery.are-you-sure.js"></script>
 | 
			
		||||
{{if .RequireSimpleMDE}}
 | 
			
		||||
	<script src="{{AppSubUrl}}/vendor/plugins/simplemde/simplemde.min.js"></script>
 | 
			
		||||
 
 | 
			
		||||
@@ -17,23 +17,19 @@
 | 
			
		||||
 | 
			
		||||
					<div class="inline field {{if .Err_OrgVisibility}}error{{end}}">
 | 
			
		||||
						<span class="inline required field"><label for="visibility">{{.i18n.Tr "org.settings.visibility"}}</label></span>
 | 
			
		||||
						<div class="ui radio checkbox">
 | 
			
		||||
							<input class="hidden enable-system-radio" tabindex="0" name="visibility" type="radio" value="0" {{if .DefaultOrgVisibilityMode.IsPublic}}checked{{end}}/>
 | 
			
		||||
							<label>{{.i18n.Tr "org.settings.visibility.public"}}</label>
 | 
			
		||||
						</div>
 | 
			
		||||
					</div>
 | 
			
		||||
					<div class="inline field {{if .Err_OrgVisibility}}error{{end}}">
 | 
			
		||||
						<label> </label>
 | 
			
		||||
						<div class="ui radio checkbox">
 | 
			
		||||
							<input class="hidden enable-system-radio" tabindex="0" name="visibility" type="radio" value="1" {{if .DefaultOrgVisibilityMode.IsLimited}}checked{{end}}/>
 | 
			
		||||
							<label>{{.i18n.Tr "org.settings.visibility.limited"}}</label>
 | 
			
		||||
						</div>
 | 
			
		||||
					</div>
 | 
			
		||||
					<div class="inline field {{if .Err_OrgVisibility}}error{{end}}">
 | 
			
		||||
						<label> </label>
 | 
			
		||||
						<div class="ui radio checkbox">
 | 
			
		||||
							<input class="hidden enable-system-radio" tabindex="0" name="visibility" type="radio" value="2" {{if .DefaultOrgVisibilityMode.IsPrivate}}checked{{end}}/>
 | 
			
		||||
							<label>{{.i18n.Tr "org.settings.visibility.private"}}</label>
 | 
			
		||||
						<div class="inline-grouped-list">
 | 
			
		||||
							<div class="ui radio checkbox">
 | 
			
		||||
								<input class="hidden enable-system-radio" tabindex="0" name="visibility" type="radio" value="0" {{if .DefaultOrgVisibilityMode.IsPublic}}checked{{end}}/>
 | 
			
		||||
								<label>{{.i18n.Tr "org.settings.visibility.public"}}</label>
 | 
			
		||||
							</div>
 | 
			
		||||
							<div class="ui radio checkbox">
 | 
			
		||||
								<input class="hidden enable-system-radio" tabindex="0" name="visibility" type="radio" value="1" {{if .DefaultOrgVisibilityMode.IsLimited}}checked{{end}}/>
 | 
			
		||||
								<label>{{.i18n.Tr "org.settings.visibility.limited"}}</label>
 | 
			
		||||
							</div>
 | 
			
		||||
							<div class="ui radio checkbox">
 | 
			
		||||
								<input class="hidden enable-system-radio" tabindex="0" name="visibility" type="radio" value="2" {{if .DefaultOrgVisibilityMode.IsPrivate}}checked{{end}}/>
 | 
			
		||||
								<label>{{.i18n.Tr "org.settings.visibility.private"}}</label>
 | 
			
		||||
							</div>
 | 
			
		||||
						</div>
 | 
			
		||||
					</div>
 | 
			
		||||
					<div class="inline field">
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,8 @@ var STATIC_CACHE = 'static-cache-v1';
 | 
			
		||||
var urlsToCache = [
 | 
			
		||||
  // js
 | 
			
		||||
  '{{AppSubUrl}}/vendor/plugins/jquery.areyousure/jquery.are-you-sure.js',
 | 
			
		||||
  '{{AppSubUrl}}/vendor/plugins/jquery/jquery.min.js',
 | 
			
		||||
  '{{AppSubUrl}}/vendor/plugins/jquery/jquery.min.js?v=3.4.1',
 | 
			
		||||
  '{{AppSubUrl}}/vendor/plugins/jquery-migrate/jquery-migrate.min.js?v=3.0.1',
 | 
			
		||||
  '{{AppSubUrl}}/vendor/plugins/semantic/semantic.min.js',
 | 
			
		||||
  '{{AppSubUrl}}/js/index.js?v={{MD5 AppVer}}',
 | 
			
		||||
  '{{AppSubUrl}}/js/draw.js',
 | 
			
		||||
 
 | 
			
		||||
@@ -2,11 +2,11 @@
 | 
			
		||||
 | 
			
		||||
	<h4 class="ui top attached header" id="repo-read-file">
 | 
			
		||||
		<div class="ui stackable grid">
 | 
			
		||||
			<div class="ten wide column">
 | 
			
		||||
			<div class="eight wide column">
 | 
			
		||||
                <i class="file text outline icon ui left"></i>
 | 
			
		||||
                <strong>{{.FileName}}</strong> <span class="text grey normal">{{FileSize .FileSize}}{{if .IsLFSFile}} ({{.i18n.Tr "repo.stored_lfs"}}){{end}}</span>
 | 
			
		||||
			</div>
 | 
			
		||||
			<div class="six wide right aligned column">
 | 
			
		||||
			<div class="eight wide right aligned column">
 | 
			
		||||
                <div class="ui right file-actions">
 | 
			
		||||
                    <div class="ui buttons">
 | 
			
		||||
                        {{if not .IsViewCommit}}
 | 
			
		||||
@@ -48,4 +48,4 @@
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
</div>
 | 
			
		||||
</div>
 | 
			
		||||
 
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user