mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-11-03 08:02:36 +09:00 
			
		
		
		
	Compare commits
	
		
			85 Commits
		
	
	
		
			v1.15.0-de
			...
			v1.12.1
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					12f51ec7dd | ||
| 
						 | 
					82b843a5ab | ||
| 
						 | 
					dcbbf37082 | ||
| 
						 | 
					3e8618a543 | ||
| 
						 | 
					3a2679db2e | ||
| 
						 | 
					6839010bd6 | ||
| 
						 | 
					80da796025 | ||
| 
						 | 
					113c99512b | ||
| 
						 | 
					82343f4943 | ||
| 
						 | 
					d534007bc4 | ||
| 
						 | 
					6466053b4d | ||
| 
						 | 
					7dc8db9ea8 | ||
| 
						 | 
					ecad970a26 | ||
| 
						 | 
					47a5c8e1f7 | ||
| 
						 | 
					6abb8d751c | ||
| 
						 | 
					fdc6287973 | ||
| 
						 | 
					320031fce6 | ||
| 
						 | 
					ef2f18964e | ||
| 
						 | 
					f2bde40804 | ||
| 
						 | 
					6b1e5f7f88 | ||
| 
						 | 
					56660c3fd0 | ||
| 
						 | 
					87a82138c6 | ||
| 
						 | 
					d06f98d9a2 | ||
| 
						 | 
					c52f81eecc | ||
| 
						 | 
					9749c35656 | ||
| 
						 | 
					fc15e59475 | ||
| 
						 | 
					78f0b5b92b | ||
| 
						 | 
					20951c5c21 | ||
| 
						 | 
					99f7ec8f45 | ||
| 
						 | 
					a076cb2a4c | ||
| 
						 | 
					530ae650f3 | ||
| 
						 | 
					821570c0b0 | ||
| 
						 | 
					287e2c781b | ||
| 
						 | 
					921a5c0b62 | ||
| 
						 | 
					0ad4083cba | ||
| 
						 | 
					99058de553 | ||
| 
						 | 
					fb155b8fa3 | ||
| 
						 | 
					7dd9506d06 | ||
| 
						 | 
					f428d40822 | ||
| 
						 | 
					7339018c5e | ||
| 
						 | 
					a34826b19f | ||
| 
						 | 
					70739c32a9 | ||
| 
						 | 
					249e22bb98 | ||
| 
						 | 
					d78c31c216 | ||
| 
						 | 
					795b6865af | ||
| 
						 | 
					0e44fab5d6 | ||
| 
						 | 
					6ad0d0a1b9 | ||
| 
						 | 
					d9db28a25a | ||
| 
						 | 
					5911e129a8 | ||
| 
						 | 
					42f0769e30 | ||
| 
						 | 
					0c40b0badd | ||
| 
						 | 
					762c0463f4 | ||
| 
						 | 
					bf1dbd7c56 | ||
| 
						 | 
					600bb545f3 | ||
| 
						 | 
					5331af1854 | ||
| 
						 | 
					eb5ea5f67a | ||
| 
						 | 
					5e3dd3fafe | ||
| 
						 | 
					339f5bb397 | ||
| 
						 | 
					1ae5435e41 | ||
| 
						 | 
					ca61046f9f | ||
| 
						 | 
					29368309ce | ||
| 
						 | 
					a777f8ae75 | ||
| 
						 | 
					80853a2238 | ||
| 
						 | 
					ce958f45cd | ||
| 
						 | 
					3b1e114ede | ||
| 
						 | 
					573a9c6228 | ||
| 
						 | 
					d131d53cbb | ||
| 
						 | 
					2a6e6bf0f1 | ||
| 
						 | 
					655def5141 | ||
| 
						 | 
					2042cf2cce | ||
| 
						 | 
					7b438b3566 | ||
| 
						 | 
					8bde2e9813 | ||
| 
						 | 
					8525a48581 | ||
| 
						 | 
					034492384b | ||
| 
						 | 
					c83bc55b52 | ||
| 
						 | 
					09cc6392f6 | ||
| 
						 | 
					b67eafbc21 | ||
| 
						 | 
					c1ba480a7a | ||
| 
						 | 
					1197512b2b | ||
| 
						 | 
					1547ce5669 | ||
| 
						 | 
					1aa6176bd8 | ||
| 
						 | 
					2289e59bd7 | ||
| 
						 | 
					6e75bc013e | ||
| 
						 | 
					087719cb8d | ||
| 
						 | 
					bbd9bebcc3 | 
@@ -105,12 +105,6 @@ services:
 | 
			
		||||
        from_secret: gitlab_read_token
 | 
			
		||||
    depends_on:
 | 
			
		||||
      - build
 | 
			
		||||
    when:
 | 
			
		||||
      branch:
 | 
			
		||||
        - master
 | 
			
		||||
      event:
 | 
			
		||||
        - push
 | 
			
		||||
        - pull_request
 | 
			
		||||
 | 
			
		||||
  - name: mysql8
 | 
			
		||||
    pull: default
 | 
			
		||||
 
 | 
			
		||||
@@ -25,7 +25,7 @@ globals:
 | 
			
		||||
  Tribute: false
 | 
			
		||||
 | 
			
		||||
overrides:
 | 
			
		||||
  - files: ["web_src/**/*.worker.js"]
 | 
			
		||||
  - files: ["web_src/**/*.worker.js", "web_src/js/serviceworker.js"]
 | 
			
		||||
    env:
 | 
			
		||||
      worker: true
 | 
			
		||||
    rules:
 | 
			
		||||
@@ -48,6 +48,7 @@ rules:
 | 
			
		||||
  no-cond-assign: [2, except-parens]
 | 
			
		||||
  no-console: [1, {allow: [info, warn, error]}]
 | 
			
		||||
  no-continue: [0]
 | 
			
		||||
  no-empty: [2, {allowEmptyCatch: true}]
 | 
			
		||||
  no-eq-null: [2]
 | 
			
		||||
  no-mixed-operators: [0]
 | 
			
		||||
  no-multi-assign: [0]
 | 
			
		||||
@@ -57,6 +58,7 @@ rules:
 | 
			
		||||
  no-restricted-syntax: [0]
 | 
			
		||||
  no-return-await: [0]
 | 
			
		||||
  no-shadow: [0]
 | 
			
		||||
  no-underscore-dangle: [0]
 | 
			
		||||
  no-unused-vars: [2, {args: all, argsIgnorePattern: ^_, varsIgnorePattern: ^_, ignoreRestSiblings: true}]
 | 
			
		||||
  no-use-before-define: [0]
 | 
			
		||||
  no-var: [2]
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -76,6 +76,7 @@ coverage.all
 | 
			
		||||
/node_modules
 | 
			
		||||
/yarn.lock
 | 
			
		||||
/public/js
 | 
			
		||||
/public/serviceworker.js
 | 
			
		||||
/public/css
 | 
			
		||||
/public/fonts
 | 
			
		||||
/public/fomantic
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										389
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										389
									
								
								CHANGELOG.md
									
									
									
									
									
								
							@@ -4,6 +4,395 @@ 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.12.1](https://github.com/go-gitea/gitea/releases/tag/v1.12.1) - 2020-06-21
 | 
			
		||||
 | 
			
		||||
* BUGFIXES
 | 
			
		||||
  * Handle multiple merges in gitgraph.js (#11996) (#12000)
 | 
			
		||||
  * Add serviceworker.js to KnownPublicEntries (#11992) (#11994)
 | 
			
		||||
  * For language detection do not try to analyze big files by content (#11971) (#11975)
 | 
			
		||||
* ENHANCEMENTS
 | 
			
		||||
  * Fix scrollable header on dropdowns (#11893) (#11965)
 | 
			
		||||
 | 
			
		||||
## [1.11.8](https://github.com/go-gitea/gitea/releases/tag/v1.11.8) - 2020-06-21
 | 
			
		||||
 | 
			
		||||
* BUGFIXES
 | 
			
		||||
  * Really fix __webpack_public_path__ for 1.11 (#11961)
 | 
			
		||||
 | 
			
		||||
## [1.12.0](https://github.com/go-gitea/gitea/releases/tag/v1.12.0) - 2020-06-17
 | 
			
		||||
 | 
			
		||||
* BREAKING
 | 
			
		||||
  * When using API CreateRelease set created_unix to the tag commit time (#11218)
 | 
			
		||||
  * Enable ENABLE_HARD_LINE_BREAK by default for rendering markdown (#11162)
 | 
			
		||||
  * Fix sanitizer config - multiple rules (#11133)
 | 
			
		||||
  * Remove check on username when using AccessToken authentication for the API (#11015)
 | 
			
		||||
  * Return 404 from Contents API when items don't exist (#10323)
 | 
			
		||||
  * Notification API should always return a JSON object with the current count of notifications (#10059)
 | 
			
		||||
  * Remove migration support from versions earlier than 1.6.0 (#10026)
 | 
			
		||||
* SECURITY
 | 
			
		||||
  * Use -1 to disable key algorithm type in ssh.minimum_key_sizes (#11635) (#11662)
 | 
			
		||||
* FEATURES
 | 
			
		||||
  * Improve config logging when WrappedQueue times out (#11174)
 | 
			
		||||
  * Add branch delete to API (#11112)
 | 
			
		||||
  * Use markdown frontmatter to provide Table of contents, language and frontmatter rendering (#11047)
 | 
			
		||||
  * Add a way to mark Conversation (code comment) resolved (#11037)
 | 
			
		||||
  * Handle yaml frontmatter in markdown (#11016)
 | 
			
		||||
  * Cache PullRequest Divergence (#10914)
 | 
			
		||||
  * Make `gitea admin auth list` formatting configurable (#10844)
 | 
			
		||||
  * Add Matrix webhook (#10831)
 | 
			
		||||
  * Add Organization Wide Labels (#10814)
 | 
			
		||||
  * Allow to set protected file patterns for files that can not be changed under no conditions (#10806)
 | 
			
		||||
  * Option to set default branch at repository creation (#10803)
 | 
			
		||||
  * Add request review from specific reviewers feature in pull request (#10756)
 | 
			
		||||
  * Add NextCloud oauth (#10562)
 | 
			
		||||
  * System-wide webhooks (#10546)
 | 
			
		||||
  * Relax sanitization as per https://github.com/jch/html-pipeline (#10527)
 | 
			
		||||
  * Use media links for img in post-process (#10515)
 | 
			
		||||
  * Add API endpoints to manage OAuth2 Application (list/create/delete) (#10437)
 | 
			
		||||
  * Render READMEs in docs/ .gitea or .github from root (#10361)
 | 
			
		||||
  * Add feishu webhook support (#10229)
 | 
			
		||||
  * Cache last commit to accelerate the repository directory page visit (#10069)
 | 
			
		||||
  * Implement basic app.ini and path checks to doctor cmd (#10064)
 | 
			
		||||
  * Make WorkerPools and Queues flushable (#10001)
 | 
			
		||||
  * Implement "embedded" command to extract static resources (#9982)
 | 
			
		||||
  * Add API endpoint for repo transfer (#9947)
 | 
			
		||||
  * Make archive prefixing configurable with a global setting (#9943)
 | 
			
		||||
  * Add Unique Queue infrastructure and move TestPullRequests to this (#9856)
 | 
			
		||||
  * Issue/PR Context Popups (#9822)
 | 
			
		||||
  * Add "Update Branch" button to Pull Requests (#9784)
 | 
			
		||||
  * Add require signed commit for protected branch (#9708)
 | 
			
		||||
  * Mark PR reviews as stale at push and allow to dismiss stale approvals (#9532)
 | 
			
		||||
  * Add API notification endpoints (#9488)
 | 
			
		||||
  * Issue search support elasticsearch (#9428)
 | 
			
		||||
  * Add API branch protection endpoint (#9311)
 | 
			
		||||
  * Add a new command doctor to check if some wrong configurations on gitea instance (#9095)
 | 
			
		||||
  * Add support for migrating from Gitlab (#9084)
 | 
			
		||||
  * Add support for database schema in PostgreSQL (#8819)
 | 
			
		||||
  * Add setting to set default and global disabled repository units. (#8788)
 | 
			
		||||
  * Language statistics bar for repositories (#8037)
 | 
			
		||||
  * Restricted users (#6274)
 | 
			
		||||
* BUGFIXES
 | 
			
		||||
  * Fix commenting on non-utf8 encoded files (#11916) (#11950)
 | 
			
		||||
  * Use google/uuid to instead satori/go.uuid (#11943) (#11946)
 | 
			
		||||
  * Align show/hide outdated button on code review block (#11932) (#11944)
 | 
			
		||||
  * Update to go-git v5.1.0 (#11936) (#11941)
 | 
			
		||||
  * Use ID or Where to instead directly use Get when load object from database (#11925) (#11934)
 | 
			
		||||
  * Update CommitsAhead CommitsBehind on Pull BaseBranch Change too (#11912) (#11915)
 | 
			
		||||
  * Invalidate comments when file is shortened (#11882) (#11884)
 | 
			
		||||
  * Rework api/user/repos for pagination (#11827) (#11877)
 | 
			
		||||
  * Handle more pathological branch and tag names (#11843) (#11863)
 | 
			
		||||
  * Add doctor check to set IsArchived false if it is null (partial #11853) (#11859)
 | 
			
		||||
  * Prevent panic on empty HOST for mysql (#11850) (#11856)
 | 
			
		||||
  * Use DEFAULT_PAGING_NUM instead of MAX_RESPONSE_ITEMS in ListOptions (#11831) (#11836)
 | 
			
		||||
  * Fix reply octicon (#11821) (#11822)
 | 
			
		||||
  * Honor DEFAULT_PAGING_NUM for API (#11805) (#11813)
 | 
			
		||||
  * Ensure rejected push to refs/pull/index/head fails nicely (#11724) (#11809)
 | 
			
		||||
  * In File Create/Update API return 404 if Branch does not exist (#11791) (#11795)
 | 
			
		||||
  * Fix doer of rename repo (#11789) (#11794)
 | 
			
		||||
  * Initialize SimpleMDE when making a code comment (#11749) (#11785)
 | 
			
		||||
  * Fix timezone on issue deadline (#11697) (#11784)
 | 
			
		||||
  * Fix to allow comment poster to edit or delete his own comments (#11671) (#11774)
 | 
			
		||||
  * Show full 500 error in API when Gitea in dev mode (#11641) (#11753)
 | 
			
		||||
  * Add missing templates for Matrix system webhooks (#11729) (#11748)
 | 
			
		||||
  * Fix verification of subkeys of default gpg key (#11713) (#11747)
 | 
			
		||||
  * Fix styling for commiter on diff view (#11715) (#11744)
 | 
			
		||||
  * Properly truncate system notices (#11714) (#11742)
 | 
			
		||||
  * Handle expected errors in FileCreate & FileUpdate API (#11643) (#11718)
 | 
			
		||||
  * Fix missing authorization check on pull for public repos of private/limited org (#11656) (#11682)
 | 
			
		||||
  * Doctor check & fix db consistency (#11111) (#11676)
 | 
			
		||||
  * Exclude generated files from language statistics (#11653) (#11670)
 | 
			
		||||
  * Return json on 500 error from API (#11574) (#11659)
 | 
			
		||||
  * When must change password only show Signout (#11600) (#11637)
 | 
			
		||||
  * Backport various styling fixes (#11619)
 | 
			
		||||
  * Fix wrong milestone in webhook message (#11596) (#11611)
 | 
			
		||||
  * Fix serviceworker output file and misc improvements (#11562) (#11610)
 | 
			
		||||
  * When initialising repositories ensure that the user doing the creation is the initializer (#11601) (#11608)
 | 
			
		||||
  * Prevent empty query parameter being set on dashboard (#11561) (#11604)
 | 
			
		||||
  * Fix images in wiki edit preview (#11546) (#11602)
 | 
			
		||||
  * Prevent (caught) panic on login (#11590) (#11597)
 | 
			
		||||
  * Prevent transferring repos to invisible orgs (#11517) (#11549)
 | 
			
		||||
  * Move serviceworker to workbox and fix SSE interference (#11538) (#11547)
 | 
			
		||||
  * API PullReviewComment HTMLPullURL should return the HTMLURL (#11501) (#11533)
 | 
			
		||||
  * Fix repo-list private and total count bugs (#11500) (#11532)
 | 
			
		||||
  * Fix form action template substitutions on admin pages (backport #11519) (#11531)
 | 
			
		||||
  * Fix a bug where the reaction emoji doesn't disappear. (#11489) (#11530)
 | 
			
		||||
  * TrimSpace when reading InternalToken from a file (#11502) (#11524)
 | 
			
		||||
  * Fix selected line color in arc-green (#11492) (#11520)
 | 
			
		||||
  * Make localstorage read ssh or https correctly (#11483) (#11490)
 | 
			
		||||
  * Check branch protection on IsUserAllowedToUpdate (#11448)
 | 
			
		||||
  * Fix margin on attached segment headers when they are separated by other element (#11425)
 | 
			
		||||
  * Fix webhook template when validation errors occur (#11421)
 | 
			
		||||
  * Fix NPE in template due to missing signing key on commit page (#11392)
 | 
			
		||||
  * Restore active background to Register button on Register page (#11390)
 | 
			
		||||
  * Fix hook failure due to relative LFS_CONTENT_PATH (#11362)
 | 
			
		||||
  * Correctly set the organization num repos (#11339)
 | 
			
		||||
  * Prevent 500 with badly formed task list (#11328)
 | 
			
		||||
  * Allow compare page to look up base, head, own-fork, forkbase-of-head (#11327)
 | 
			
		||||
  * Handle panics that percolate up to the graceful module (#11291)
 | 
			
		||||
  * Don't allow registration via the web form, when AllowOnlyExternalRegistration is True (#11248)
 | 
			
		||||
  * Patch fomantic-ui to workaround build issue (#11244)
 | 
			
		||||
  * Prevent panic during wrappedConn close at hammertime (#11219)
 | 
			
		||||
  * On logout force redirect to start page (#11202)
 | 
			
		||||
  * Fix creation of Organization repos by Users with max created personal repos (#11183)
 | 
			
		||||
  * Add option to increase provided OAuth2 token maximum size (#11180)
 | 
			
		||||
  * Log the indexer path on failure (#11172)
 | 
			
		||||
  * Ensure that relative paths in edit preview work (#11143)
 | 
			
		||||
  * Make API EditIssue and EditPullRequest issue notifications (#11123)
 | 
			
		||||
  * Send 404 immediately for known public requests (#11117)
 | 
			
		||||
  * Remove nil inserts in models (#11096)
 | 
			
		||||
  * Add GetReviews() to RetryDownloader (#11093)
 | 
			
		||||
  * Remove nonexistent serviceworker entries (#11091)
 | 
			
		||||
  * Simplify and fix GetApprovalCounts (#11086)
 | 
			
		||||
  * Fix wiki revision template and simplify some tmpl conditions (#11080)
 | 
			
		||||
  * Make branch parameter optional for /api/v1/repos/{owner}/{repo}/contents/{filepath} (#11067)
 | 
			
		||||
  * Align review-item svg octicons (#11065)
 | 
			
		||||
  * Automatically remove Watches, Assignments, etc if user loses access due to being removed as collaborator or from a team (#10997)
 | 
			
		||||
  * Users should not be able to prohibit their own login (#10970)
 | 
			
		||||
  * Fix scrollbar issues in dropdowns (#10897)
 | 
			
		||||
  * Change the order of issues.closed_by to list opening user first (#10876)
 | 
			
		||||
  * Allow site admin to check /api/v1/orgs endpoints (#10867)
 | 
			
		||||
  * Avoid logging []byte in queue failures - convert to string first (#10865)
 | 
			
		||||
  * Use ErrKeyUnableToVerify if fail to calc fingerprint in ssh-keygen (#10863)
 | 
			
		||||
  * Fix assignees double load bug (#10856)
 | 
			
		||||
  * Handle push rejection in branch and upload (#10854)
 | 
			
		||||
  * In authorized_keys use double-quote for windows compatibility (#10841)
 | 
			
		||||
  * Fix milestone template (#10824)
 | 
			
		||||
  * log.Fatal on failure to listen to SSH port (#10795)
 | 
			
		||||
  * Fix forked repo has no icon and language stat. (#10791)
 | 
			
		||||
  * Fix tag/release deletion (#10663)
 | 
			
		||||
  * Fix webhook migration (#10641)
 | 
			
		||||
  * Migration for deleting orphaned dependencies (#10617)
 | 
			
		||||
  * Add migration to fix the old broken merge-bases (#10604)
 | 
			
		||||
  * Update templates for Go 1.14 (#10596)
 | 
			
		||||
  * Remove unnecessary parentheses in wiki/view template (#10583)
 | 
			
		||||
  * Change default value of DefaultCommandExecutionTimeout to match docs (#10581)
 | 
			
		||||
  * Handle panic in indexer initialisation better (#10534)
 | 
			
		||||
  * Set correct content_type value for Gogs/Gitea webhooks (#9504) (#10456)
 | 
			
		||||
  * Fixed wrong AppSubUrl in multiple templates (#10447)
 | 
			
		||||
  * Fix profile page CSS (#10406)
 | 
			
		||||
  * Inject SVG sprite via ajax (#10320)
 | 
			
		||||
  * Fix migration information update bug when linked github account (#10310)
 | 
			
		||||
  * Allow admin to check org membership by API for other users (#10201)
 | 
			
		||||
  * Fix topics dropdown (#10167)
 | 
			
		||||
  * Ensure DeleteUser is not allowed to Delete Orgs and visa versa (#10134)
 | 
			
		||||
  * Fix IsErrPullClosed (#10093)
 | 
			
		||||
  * Accept punctuation after simple+cross repository issue references (#10091)
 | 
			
		||||
  * On merge of already closed PR redirect back to the pulls page (#10010)
 | 
			
		||||
  * Fix crowdin update script (#9969)
 | 
			
		||||
  * Fix pull view when head repository or head branch missed and close related pull requests when delete head repository or head branch (#9927)
 | 
			
		||||
  * Add option to prevent LDAP from deactivating everything on empty search (#9879)
 | 
			
		||||
  * Fix admin handling at merge of PR (#9749)
 | 
			
		||||
  * err_admin_name_pattern_not_allowed String Clarification (#9731)
 | 
			
		||||
  * Fix wrong original git service type on a migrated repository (#9693)
 | 
			
		||||
  * Fix ref links in issue overviews for tags (#8742)
 | 
			
		||||
* ENHANCEMENTS
 | 
			
		||||
  * Fix search form button overlap (#11840) (#11864)
 | 
			
		||||
  * Make tabular menu styling consistent for arc-green (#11570) (#11798)
 | 
			
		||||
  * Add option to API to update PullRequest base branch (#11666) (#11796)
 | 
			
		||||
  * Increase maximum SQLite variables count to 32766 (#11696) (#11783)
 | 
			
		||||
  * Update emoji dataset with skin tone variants (#11678) (#11763)
 | 
			
		||||
  * Add logging to long migrations (#11647) (#11691)
 | 
			
		||||
  * Change language statistics to save size instead of percentage (#11681) (#11690)
 | 
			
		||||
  * Allow different HardBreaks settings for documents and comments (#11515) (#11599)
 | 
			
		||||
  * Fix alignment for commits on dashboard (#11595) (#11680)
 | 
			
		||||
  * Default MSSQL port 0 to allow automatic detection by default (#11642) (#11673)
 | 
			
		||||
  * Handle expected errors in AddGPGkey API  (#11644) (#11661)
 | 
			
		||||
  * Close EventSource before unloading the page (#11539) (#11557)
 | 
			
		||||
  * Ensure emoji render with regular font-weight (#11541) (#11545)
 | 
			
		||||
  * Fix webpack chunk loading with STATIC_URL_PREFIX (#11526) (#11542)
 | 
			
		||||
  * Tweak reaction buttons (#11516)
 | 
			
		||||
  * Use more toned colors for selected line (#11493) (#11511)
 | 
			
		||||
  * Increase width for authors on commit view (#11441)
 | 
			
		||||
  * Hide archived repos by default in repo-list (#11440)
 | 
			
		||||
  * Better styling for code review comment textarea (#11428)
 | 
			
		||||
  * Support view individual commit for wiki pages (#11415)
 | 
			
		||||
  * Fix yellow background on active elements in code review (#11414)
 | 
			
		||||
  * Better styling for code review comment form (#11413)
 | 
			
		||||
  * Change install description on homepage (#11395)
 | 
			
		||||
  * Ensure search action button is coalesced to adjacent input (#11385)
 | 
			
		||||
  * Switch code editor to Monaco (#11366)
 | 
			
		||||
  * Add paging and archive/private repository filtering to dashboard list (#11321)
 | 
			
		||||
  * Changed image of openid-connect logo for better look on arc-green theme (#11312)
 | 
			
		||||
  * Load Repo Topics on blame view too (#11307)
 | 
			
		||||
  * Change the style in admin notice content view from `<p>` to `<pre>` (#11301)
 | 
			
		||||
  * Allow log.xxx.default to set logging settings for the default logger only (#11292)
 | 
			
		||||
  * Automatically attempt auto recovery of broken disk queues (Update lunny/levelqueue to 0.3.0) (#11285)
 | 
			
		||||
  * Make sendmail a Process and have default timeout (#11256)
 | 
			
		||||
  * Check value of skip-repository flag in dump command (#11254)
 | 
			
		||||
  * Fix submit review form (#11252)
 | 
			
		||||
  * Allow unauthenticated users to compare (#11240)
 | 
			
		||||
  * Add EventSource support (#11235)
 | 
			
		||||
  * Refactor Milestone related (#11225)
 | 
			
		||||
  * Add pull review API endpoints (#11224)
 | 
			
		||||
  * Add a 'this' to issue close/reopened messages (#11204)
 | 
			
		||||
  * When migrating from Gitlab map Approvals to approving Reviews (#11147)
 | 
			
		||||
  * Improve representation of attachments in issues (#11141)
 | 
			
		||||
  * Protect default branch against deletion (#11115)
 | 
			
		||||
  * Add X-Total-Count on /repos/{owner]/{repo}/pulls API endpoint (#11113)
 | 
			
		||||
  * Fix status label on branches list vertical alignment (#11109)
 | 
			
		||||
  * Add single release page and latest redirect (#11102)
 | 
			
		||||
  * Add missing commit states to PR checks template (#11085)
 | 
			
		||||
  * Change icon on title for merged PR to git-merge (#11064)
 | 
			
		||||
  * Add MergePull comment type instead of close for merge PR (#11058)
 | 
			
		||||
  * Upgrade jQuery to 3.5.0, remove jQuery-Migrate, fix deprecations (#11055)
 | 
			
		||||
  * Consolidate author name across timeline (#11053)
 | 
			
		||||
  * Refactor UpdateOAuth2Application (#11034)
 | 
			
		||||
  * Support unicode emojis and remove emojify.js (#11032)
 | 
			
		||||
  * Add git hook "warning" to admin panel (#11030)
 | 
			
		||||
  * Add flash notify for email preference setting success (#11027)
 | 
			
		||||
  * Remove package code.gitea.io/gitea/modules/git import out of models (#11025)
 | 
			
		||||
  * Match arc-green code tag color to code blocks (#11023)
 | 
			
		||||
  * Move syntax highlighting to web worker (#11017)
 | 
			
		||||
  * Prevent merge of outdated PRs on protected branches (#11012)
 | 
			
		||||
  * Add Get/Update for api/v1/user/applications/oauth2 (#11008)
 | 
			
		||||
  * Upgrade to most recent bluemonday (#11007)
 | 
			
		||||
  * Tweak code tags in markdown (#11000)
 | 
			
		||||
  * Reject duplicate AccessToken names (#10994)
 | 
			
		||||
  * Fix Ctrl-Enter shortcut for issues (#10986)
 | 
			
		||||
  * Provide `OwnerName` field for README template (#10981)
 | 
			
		||||
  * Prettify Timeline (#10972)
 | 
			
		||||
  * Add issue subscription check to API (#10967)
 | 
			
		||||
  * Use AJAX for notifications table (#10961)
 | 
			
		||||
  * Adjust label padding (#10957)
 | 
			
		||||
  * Avoiding directory execution on hook (#10954) (#10955)
 | 
			
		||||
  * Migrate ActivityHeatmap to Vue SFC (#10953)
 | 
			
		||||
  * Change merge strategy: do not check write access if user in merge white list (#10951)
 | 
			
		||||
  * Enable GO111MODULE=on globally in Makefile (#10939)
 | 
			
		||||
  * API endpoint to get single commit via SHA and Ref (#10915)
 | 
			
		||||
  * Add accordion to release list and hide non-latest (#10910)
 | 
			
		||||
  * Split dashboard elements into separate template files (#10885)
 | 
			
		||||
  * Add more message on sidebar menus (#10872)
 | 
			
		||||
  * Set MySQL rowtype to dynamic for new tables (#10833)
 | 
			
		||||
  * Completely fix task-list checkbox styling (#10798)
 | 
			
		||||
  * Hide gear icon for user who can't use them on sidebar (#10750)
 | 
			
		||||
  * Refactor Cron and merge dashboard tasks (#10745)
 | 
			
		||||
  * Change review status icons on pr view style to github style (#10737)
 | 
			
		||||
  * Make pagination optional for API list notification endpoints (#10714)
 | 
			
		||||
  * Fix tab indentation in code view (#10671)
 | 
			
		||||
  * Fix task-list checkbox styling (#10668)
 | 
			
		||||
  * Multiple LFS improvements (#10667)
 | 
			
		||||
  * Make PR message on pushes configurable (#10664)
 | 
			
		||||
  * Move dropzone.js to npm/webpack (#10645)
 | 
			
		||||
  * Ensure Update button is enabled even when CI has failed (#10640)
 | 
			
		||||
  * Add restricted user filter to LDAP authentication (#10600)
 | 
			
		||||
  * Add Yandex OAuth2 provider (#8335) (#10564)
 | 
			
		||||
  * Make avatar lookup occur at image request (#10540)
 | 
			
		||||
  * Prevent accidential selection of language stats bar (#10537)
 | 
			
		||||
  * Add fluid-icon (#10491)
 | 
			
		||||
  * Inform participants on UI too (#10473)
 | 
			
		||||
  * Build with go 1.14 (and raise minimum go version to 1.12) (#10467)
 | 
			
		||||
  * Add max-file-size to LFS (#10463)
 | 
			
		||||
  * Enable paggination for ListRepoTags API (#10454)
 | 
			
		||||
  * Update JS dependencies (#10450)
 | 
			
		||||
  * Show the username as a fallback on feeds if full name is blank (#10438)
 | 
			
		||||
  * Various dark theme fixes (#10416)
 | 
			
		||||
  * Display pull request head branch even the branch deleted or repository deleted (#10413)
 | 
			
		||||
  * Prevent Firefox from using apple-touch-icon (#10402)
 | 
			
		||||
  * Fix input[type=file] on dark theme (#10382)
 | 
			
		||||
  * Improve mobile review-box sizing (#10297)
 | 
			
		||||
  * Notification: queue ui.go notification-service (#10281)
 | 
			
		||||
  * Add detected file language to code search (#10256)
 | 
			
		||||
  * Index code and stats only for non-empty repositories (#10251)
 | 
			
		||||
  * Add Approval Counts to pulls list (#10238)
 | 
			
		||||
  * Limit label list height on edit issue page (#10216)
 | 
			
		||||
  * Improve 404 error message (#10214)
 | 
			
		||||
  * Tweak locale to respect singular conflicting file message in PR list (#10177)
 | 
			
		||||
  * Fix commit view (#10169)
 | 
			
		||||
  * Reorganize frontend files and tooling (#10168)
 | 
			
		||||
  * Allow emoji on popup label (#10166)
 | 
			
		||||
  * ListIssues add filter for milestones API (#10148)
 | 
			
		||||
  * Show if a PR has conflicting files on the PR lists (#10130)
 | 
			
		||||
  * Fix inconsistent label color format in API (#10129)
 | 
			
		||||
  * Show download count info in release list (#10124)
 | 
			
		||||
  * Add Octicon SVG spritemap (#10107)
 | 
			
		||||
  * Update aria-fixed semantic-dropdown to fomantic master (#10096)
 | 
			
		||||
  * Fix apple-touch-icon, regenerate images (#10065)(#10006)
 | 
			
		||||
  * Style blockquote for default issue mail template (#10024)
 | 
			
		||||
  * More expansions in template repositories (#10021)
 | 
			
		||||
  * Allow list collaborators for users with Read access to repo (#9995)
 | 
			
		||||
  * Add explicit dimensions to navbar avatar (#9986)
 | 
			
		||||
  * Remove loadCSS and preload woff2 icon fonts (#9976)
 | 
			
		||||
  * Fix commit view JS features, reimplement folding (#9968)
 | 
			
		||||
  * Fix review avatar image (#9962)
 | 
			
		||||
  * Improve notification pager (#9821)
 | 
			
		||||
  * Move jquery and jquery-migrate to npm/webpack (#9813)
 | 
			
		||||
  * Change font to Roboto to support more charsets (#9803)
 | 
			
		||||
  * Move mailer to use a queue (#9789)
 | 
			
		||||
  * Issue search on my related repositories (#9758)
 | 
			
		||||
  * Add "before" query to ListIssueComments and ListRepoIssueComments API (#9685)
 | 
			
		||||
  * Move tracked time api convert to convert package (#9665)
 | 
			
		||||
  * Improve PR info in default merge message (#9635)
 | 
			
		||||
  * Granular webhook events (#9626)
 | 
			
		||||
  * Add Reviewed-on in commit message (#9623)
 | 
			
		||||
  * Add top author stats to activity page (#9615)
 | 
			
		||||
  * Allow repo admin to merge PR regardless of review status (#9611)
 | 
			
		||||
  * Migrate reactions when migrating repository from github (#9599)
 | 
			
		||||
  * API orgEditTeam make Fields optional (#9556)
 | 
			
		||||
  * Move create/fork repository from models to modules/repository (#9489)
 | 
			
		||||
  * Migrate reviews when migrating repository from github (#9463)
 | 
			
		||||
  * Times API add filters (#9373)
 | 
			
		||||
  * Move push commits from models to modules/repository (#9370)
 | 
			
		||||
  * Add API endpoint to check notifications [Extend #9488] (#9595)
 | 
			
		||||
  * Add GET /orgs API endpoint (#9560)
 | 
			
		||||
  * API add/generalize pagination (#9452)
 | 
			
		||||
  * Make create org repo API call same as github (#9186)
 | 
			
		||||
* BUILD
 | 
			
		||||
  * Turn off go modules for xgo and gxz (#10963)
 | 
			
		||||
  * Add gitea-vet (#10948)
 | 
			
		||||
  * Rename scripts to build and add revive command as a new build tool command (#10942)
 | 
			
		||||
  * Add 'make lint', restructure 'compliance' pipeline (#10861)
 | 
			
		||||
  * Move JS build dependencies to 'dependencies' (#10763)
 | 
			
		||||
  * Use whitelist to find go files, run find only once (#10594)
 | 
			
		||||
  * Move vue and vue-calendar-heatmap to npm/webpack (#10188)
 | 
			
		||||
  * Move jquery.are-you-sure to npm/webpack (#10063)
 | 
			
		||||
  * Move highlight.js to npm/webpack (#10011)
 | 
			
		||||
  * Generate Bindata if TAGS="bindata" and not up-to-date (#10004)
 | 
			
		||||
  * Move CSS build to webpack (#9983)
 | 
			
		||||
  * Move fomantic target, update 'make help' (#9945)
 | 
			
		||||
  * Add css extraction and minification to webpack (#9944)
 | 
			
		||||
  * Misc webpack tweaks (#9924)
 | 
			
		||||
  * Make node_modules a order-only prerequisite (#9923)
 | 
			
		||||
  * Update documentation for the go module era (#9751)
 | 
			
		||||
  * Move swagger-ui to webpack/npm and update it to 3.24.3 (#9714)
 | 
			
		||||
  * Use npm to manage fomantic and only build needed components (#9561)
 | 
			
		||||
* MISC
 | 
			
		||||
  * Add gnupg to Dockerfile (#11365)
 | 
			
		||||
  * Update snapcraft.yaml for core18 and latest features (#11300)
 | 
			
		||||
  * Update JS dependencies, min Node.js version 10.13 (#11246)
 | 
			
		||||
  * Change default charset for MySQL on install to utf8mb4 (#10989)
 | 
			
		||||
  * Return issue subscription status from API subscribe (#10966)
 | 
			
		||||
  * Fix queue log param (#10733)
 | 
			
		||||
  * Add warning when using relative path to app.ini (#10104)
 | 
			
		||||
 | 
			
		||||
## [1.11.7](https://github.com/go-gitea/gitea/releases/tag/v1.11.7) - 2020-06-18
 | 
			
		||||
 | 
			
		||||
* BUGFIXES
 | 
			
		||||
  * Use ID or Where to instead directly use Get when load object from database (#11925) (#11935)
 | 
			
		||||
  * Fix __webpack_public_path__ for 1.11 (#11907)
 | 
			
		||||
  * Fix verification of subkeys of default gpg key (#11713) (#11902)
 | 
			
		||||
  * Remove unnecessary parentheses in wiki/view template (#11781)
 | 
			
		||||
  * Doctor fix xorm.Count nil on sqlite error (#11741)
 | 
			
		||||
 | 
			
		||||
## [1.11.6](https://github.com/go-gitea/gitea/releases/tag/v1.11.6) - 2020-05-30
 | 
			
		||||
 | 
			
		||||
* SECURITY
 | 
			
		||||
  * Fix missing authorization check on pull for public repos of private/limited org (#11656) (#11683)
 | 
			
		||||
  * Use session for retrieving org teams (#11438) (#11439)
 | 
			
		||||
* BUGFIXES
 | 
			
		||||
  * Return json on 500 error from API (#11574) (#11660)
 | 
			
		||||
  * Fix wrong milestone in webhook message (#11596) (#11612)
 | 
			
		||||
  * Prevent (caught) panic on login (#11590) (#11598)
 | 
			
		||||
  * Fix commit page js error (#11527)
 | 
			
		||||
  * Use media links for img in post-process (#10515) (#11504)
 | 
			
		||||
  * Ensure public repositories in private organizations are visible and fix admin organizations list (#11465) (#11475)
 | 
			
		||||
  * Set correct Content-Type value for Gogs/Gitea webhooks (#9504) (#10456) (#11461)
 | 
			
		||||
  * Allow all members of private orgs to see public repos (#11442) (#11459)
 | 
			
		||||
  * Whenever the ctx.Session is updated, release it to save it before sending the redirect (#11456) (#11457)
 | 
			
		||||
  * Forcibly clean and destroy the session on logout (#11447) (#11451)
 | 
			
		||||
  * Fix /api/v1/orgs/* endpoints by changing parameter to :org from :orgname (#11381)
 | 
			
		||||
  * Add tracked time fix to doctor (part of #11111) (#11138)
 | 
			
		||||
  * Fix webpack chunk loading with STATIC_URL_PREFIX (#11526) (#11544)
 | 
			
		||||
  * Remove unnecessary parentheses in wiki/revision.tmpl to allow 1.11 to build on go1.14  (#11481)
 | 
			
		||||
 | 
			
		||||
## [1.11.5](https://github.com/go-gitea/gitea/releases/tag/v1.11.5) - 2020-05-09
 | 
			
		||||
 | 
			
		||||
* BUGFIXES
 | 
			
		||||
 
 | 
			
		||||
@@ -9,6 +9,7 @@ ENV GOPROXY ${GOPROXY:-direct}
 | 
			
		||||
ARG GITEA_VERSION
 | 
			
		||||
ARG TAGS="sqlite sqlite_unlock_notify"
 | 
			
		||||
ENV TAGS "bindata $TAGS"
 | 
			
		||||
ARG CGO_EXTRA_CFLAGS
 | 
			
		||||
 | 
			
		||||
#Build deps
 | 
			
		||||
RUN apk --no-cache add build-base git nodejs npm
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										20
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								Makefile
									
									
									
									
									
								
							@@ -33,6 +33,9 @@ MIN_NODE_VERSION := 010013000
 | 
			
		||||
ifeq ($(HAS_GO), GO)
 | 
			
		||||
	GOPATH ?= $(shell $(GO) env GOPATH)
 | 
			
		||||
	export PATH := $(GOPATH)/bin:$(PATH)
 | 
			
		||||
 | 
			
		||||
	CGO_EXTRA_CFLAGS := -DSQLITE_MAX_VARIABLE_NUMBER=32766
 | 
			
		||||
	CGO_CFLAGS ?= $(shell $(GO) env CGO_CFLAGS) $(CGO_EXTRA_CFLAGS)
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -88,7 +91,7 @@ GO_PACKAGES ?= $(filter-out code.gitea.io/gitea/integrations/migration-test,$(fi
 | 
			
		||||
WEBPACK_SOURCES := $(shell find web_src/js web_src/less -type f)
 | 
			
		||||
WEBPACK_CONFIGS := webpack.config.js
 | 
			
		||||
WEBPACK_DEST := public/js/index.js public/css/index.css
 | 
			
		||||
WEBPACK_DEST_DIRS := public/js public/css public/fonts
 | 
			
		||||
WEBPACK_DEST_ENTRIES := public/js public/css public/fonts public/serviceworker.js
 | 
			
		||||
 | 
			
		||||
BINDATA_DEST := modules/public/bindata.go modules/options/bindata.go modules/templates/bindata.go
 | 
			
		||||
BINDATA_HASH := $(addsuffix .hash,$(BINDATA_DEST))
 | 
			
		||||
@@ -194,7 +197,7 @@ node-check:
 | 
			
		||||
 | 
			
		||||
.PHONY: clean-all
 | 
			
		||||
clean-all: clean
 | 
			
		||||
	rm -rf $(WEBPACK_DEST_DIRS) $(FOMANTIC_DEST_DIR)
 | 
			
		||||
	rm -rf $(WEBPACK_DEST_ENTRIES) $(FOMANTIC_DEST_DIR)
 | 
			
		||||
 | 
			
		||||
.PHONY: clean
 | 
			
		||||
clean:
 | 
			
		||||
@@ -295,6 +298,7 @@ lint-frontend: node_modules
 | 
			
		||||
 | 
			
		||||
.PHONY: watch-frontend
 | 
			
		||||
watch-frontend: node_modules
 | 
			
		||||
	rm -rf $(WEBPACK_DEST_ENTRIES)
 | 
			
		||||
	NODE_ENV=development npx webpack --hide-modules --display-entrypoints=false --watch --progress
 | 
			
		||||
 | 
			
		||||
.PHONY: test
 | 
			
		||||
@@ -498,7 +502,7 @@ check: test
 | 
			
		||||
 | 
			
		||||
.PHONY: install $(TAGS_PREREQ)
 | 
			
		||||
install: $(wildcard *.go)
 | 
			
		||||
	$(GO) install -v -tags '$(TAGS)' -ldflags '-s -w $(LDFLAGS)'
 | 
			
		||||
	CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) install -v -tags '$(TAGS)' -ldflags '-s -w $(LDFLAGS)'
 | 
			
		||||
 | 
			
		||||
.PHONY: build
 | 
			
		||||
build: frontend backend
 | 
			
		||||
@@ -514,7 +518,7 @@ generate: $(TAGS_PREREQ)
 | 
			
		||||
	CC= GOOS= GOARCH= $(GO) generate -mod=vendor -tags '$(TAGS)' $(GO_PACKAGES)
 | 
			
		||||
 | 
			
		||||
$(EXECUTABLE): $(GO_SOURCES) $(TAGS_PREREQ)
 | 
			
		||||
	$(GO) build -mod=vendor $(GOFLAGS) $(EXTRA_GOFLAGS) -tags '$(TAGS)' -ldflags '-s -w $(LDFLAGS)' -o $@
 | 
			
		||||
	CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) build -mod=vendor $(GOFLAGS) $(EXTRA_GOFLAGS) -tags '$(TAGS)' -ldflags '-s -w $(LDFLAGS)' -o $@
 | 
			
		||||
 | 
			
		||||
.PHONY: release
 | 
			
		||||
release: frontend generate release-windows release-linux release-darwin release-copy release-compress release-sources release-check
 | 
			
		||||
@@ -527,7 +531,7 @@ release-windows: | $(DIST_DIRS)
 | 
			
		||||
	@hash xgo > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
 | 
			
		||||
		$(GO) get -u src.techknowlogick.com/xgo; \
 | 
			
		||||
	fi
 | 
			
		||||
	GO111MODULE=off xgo -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION) .
 | 
			
		||||
	CGO_CFLAGS="$(CGO_CFLAGS)" GO111MODULE=off xgo -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION) .
 | 
			
		||||
ifeq ($(CI),drone)
 | 
			
		||||
	cp /build/* $(DIST)/binaries
 | 
			
		||||
endif
 | 
			
		||||
@@ -537,7 +541,7 @@ release-linux: | $(DIST_DIRS)
 | 
			
		||||
	@hash xgo > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
 | 
			
		||||
		$(GO) get -u src.techknowlogick.com/xgo; \
 | 
			
		||||
	fi
 | 
			
		||||
	GO111MODULE=off xgo -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'linux/amd64,linux/386,linux/arm-5,linux/arm-6,linux/arm64,linux/mips64le,linux/mips,linux/mipsle' -out gitea-$(VERSION) .
 | 
			
		||||
	CGO_CFLAGS="$(CGO_CFLAGS)" GO111MODULE=off xgo -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'linux/amd64,linux/386,linux/arm-5,linux/arm-6,linux/arm64,linux/mips64le,linux/mips,linux/mipsle' -out gitea-$(VERSION) .
 | 
			
		||||
ifeq ($(CI),drone)
 | 
			
		||||
	cp /build/* $(DIST)/binaries
 | 
			
		||||
endif
 | 
			
		||||
@@ -547,7 +551,7 @@ release-darwin: | $(DIST_DIRS)
 | 
			
		||||
	@hash xgo > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
 | 
			
		||||
		$(GO) get -u src.techknowlogick.com/xgo; \
 | 
			
		||||
	fi
 | 
			
		||||
	GO111MODULE=off xgo -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '$(LDFLAGS)' -targets 'darwin/*' -out gitea-$(VERSION) .
 | 
			
		||||
	CGO_CFLAGS="$(CGO_CFLAGS)" GO111MODULE=off xgo -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '$(LDFLAGS)' -targets 'darwin/*' -out gitea-$(VERSION) .
 | 
			
		||||
ifeq ($(CI),drone)
 | 
			
		||||
	cp /build/* $(DIST)/binaries
 | 
			
		||||
endif
 | 
			
		||||
@@ -598,7 +602,7 @@ $(FOMANTIC_DEST): $(FOMANTIC_CONFIGS) package-lock.json | node_modules
 | 
			
		||||
webpack: $(WEBPACK_DEST)
 | 
			
		||||
 | 
			
		||||
$(WEBPACK_DEST): $(WEBPACK_SOURCES) $(WEBPACK_CONFIGS) package-lock.json | node_modules
 | 
			
		||||
	rm -rf $(WEBPACK_DEST_DIRS)
 | 
			
		||||
	rm -rf $(WEBPACK_DEST_ENTRIES)
 | 
			
		||||
	npx webpack --hide-modules --display-entrypoints=false
 | 
			
		||||
	@touch $(WEBPACK_DEST)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										63
									
								
								build/generate-emoji.go
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										63
									
								
								build/generate-emoji.go
									
									
									
									
										vendored
									
									
								
							@@ -19,6 +19,7 @@ import (
 | 
			
		||||
	"sort"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"unicode/utf8"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
@@ -39,6 +40,7 @@ type Emoji struct {
 | 
			
		||||
	Description    string   `json:"description,omitempty"`
 | 
			
		||||
	Aliases        []string `json:"aliases"`
 | 
			
		||||
	UnicodeVersion string   `json:"unicode_version,omitempty"`
 | 
			
		||||
	SkinTones      bool     `json:"skin_tones,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Don't include some fields in JSON
 | 
			
		||||
@@ -47,6 +49,7 @@ func (e Emoji) MarshalJSON() ([]byte, error) {
 | 
			
		||||
	x := emoji(e)
 | 
			
		||||
	x.UnicodeVersion = ""
 | 
			
		||||
	x.Description = ""
 | 
			
		||||
	x.SkinTones = false
 | 
			
		||||
	return json.Marshal(x)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -75,6 +78,7 @@ var replacer = strings.NewReplacer(
 | 
			
		||||
	", Description:", ", ",
 | 
			
		||||
	", Aliases:", ", ",
 | 
			
		||||
	", UnicodeVersion:", ", ",
 | 
			
		||||
	", SkinTones:", ", ",
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var emojiRE = regexp.MustCompile(`\{Emoji:"([^"]*)"`)
 | 
			
		||||
@@ -102,18 +106,20 @@ func generate() ([]byte, error) {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var re = regexp.MustCompile(`keycap|registered|copyright`)
 | 
			
		||||
	tmp := data[:0]
 | 
			
		||||
	var skinTones = make(map[string]string)
 | 
			
		||||
 | 
			
		||||
	skinTones["\U0001f3fb"] = "Light Skin Tone"
 | 
			
		||||
	skinTones["\U0001f3fc"] = "Medium-Light Skin Tone"
 | 
			
		||||
	skinTones["\U0001f3fd"] = "Medium Skin Tone"
 | 
			
		||||
	skinTones["\U0001f3fe"] = "Medium-Dark Skin Tone"
 | 
			
		||||
	skinTones["\U0001f3ff"] = "Dark Skin Tone"
 | 
			
		||||
 | 
			
		||||
	var tmp Gemoji
 | 
			
		||||
 | 
			
		||||
	//filter out emoji that require greater than max unicode version
 | 
			
		||||
	for i := range data {
 | 
			
		||||
		val, _ := strconv.ParseFloat(data[i].UnicodeVersion, 64)
 | 
			
		||||
		if int(val) <= maxUnicodeVersion {
 | 
			
		||||
			// remove these keycaps for now they really complicate matching since
 | 
			
		||||
			// they include normal letters in them
 | 
			
		||||
			if re.MatchString(data[i].Description) {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			tmp = append(tmp, data[i])
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
@@ -123,7 +129,6 @@ func generate() ([]byte, error) {
 | 
			
		||||
		return data[i].Aliases[0] < data[j].Aliases[0]
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	aliasPairs := make([]string, 0)
 | 
			
		||||
	aliasMap := make(map[string]int, len(data))
 | 
			
		||||
 | 
			
		||||
	for i, e := range data {
 | 
			
		||||
@@ -135,7 +140,6 @@ func generate() ([]byte, error) {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			aliasMap[a] = i
 | 
			
		||||
			aliasPairs = append(aliasPairs, ":"+a+":", e.Emoji)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -149,6 +153,43 @@ func generate() ([]byte, error) {
 | 
			
		||||
		data[i].Aliases = append(data[i].Aliases, "laugh")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// write a JSON file to use with tribute (write before adding skin tones since we can't support them there yet)
 | 
			
		||||
	file, _ := json.Marshal(data)
 | 
			
		||||
	_ = ioutil.WriteFile("assets/emoji.json", file, 0644)
 | 
			
		||||
 | 
			
		||||
	// Add skin tones to emoji that support it
 | 
			
		||||
	var (
 | 
			
		||||
		s              []string
 | 
			
		||||
		newEmoji       string
 | 
			
		||||
		newDescription string
 | 
			
		||||
		newData        Emoji
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	for i := range data {
 | 
			
		||||
		if data[i].SkinTones {
 | 
			
		||||
			for k, v := range skinTones {
 | 
			
		||||
				s = strings.Split(data[i].Emoji, "")
 | 
			
		||||
 | 
			
		||||
				if utf8.RuneCountInString(data[i].Emoji) == 1 {
 | 
			
		||||
					s = append(s, k)
 | 
			
		||||
				} else {
 | 
			
		||||
					// insert into slice after first element because all emoji that support skin tones
 | 
			
		||||
					// have that modifer placed at this spot
 | 
			
		||||
					s = append(s, "")
 | 
			
		||||
					copy(s[2:], s[1:])
 | 
			
		||||
					s[1] = k
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				newEmoji = strings.Join(s, "")
 | 
			
		||||
				newDescription = data[i].Description + ": " + v
 | 
			
		||||
				newAlias := data[i].Aliases[0] + "_" + strings.ReplaceAll(v, " ", "_")
 | 
			
		||||
 | 
			
		||||
				newData = Emoji{newEmoji, newDescription, []string{newAlias}, "12.0", false}
 | 
			
		||||
				data = append(data, newData)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// add header
 | 
			
		||||
	str := replacer.Replace(fmt.Sprintf(hdr, gemojiURL, data))
 | 
			
		||||
 | 
			
		||||
@@ -162,10 +203,6 @@ func generate() ([]byte, error) {
 | 
			
		||||
		return "{" + strconv.QuoteToASCII(s)
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	// write a JSON file to use with tribute
 | 
			
		||||
	file, _ := json.Marshal(data)
 | 
			
		||||
	_ = ioutil.WriteFile("assets/emoji.json", file, 0644)
 | 
			
		||||
 | 
			
		||||
	// format
 | 
			
		||||
	return format.Source([]byte(str))
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										103
									
								
								cmd/doctor.go
									
									
									
									
									
								
							
							
						
						
									
										103
									
								
								cmd/doctor.go
									
									
									
									
									
								
							@@ -85,10 +85,16 @@ var checklist = []check{
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		title:         "Check Database Version",
 | 
			
		||||
		name:          "check-db",
 | 
			
		||||
		name:          "check-db-version",
 | 
			
		||||
		isDefault:     true,
 | 
			
		||||
		f:             runDoctorCheckDBVersion,
 | 
			
		||||
		abortIfFailed: true,
 | 
			
		||||
		abortIfFailed: false,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		title:     "Check consistency of database",
 | 
			
		||||
		name:      "check-db-consistency",
 | 
			
		||||
		isDefault: false,
 | 
			
		||||
		f:         runDoctorCheckDBConsistency,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		title:     "Check if OpenSSH authorized_keys file is up-to-date",
 | 
			
		||||
@@ -495,3 +501,96 @@ func runDoctorScriptType(ctx *cli.Context) ([]string, error) {
 | 
			
		||||
	}
 | 
			
		||||
	return []string{fmt.Sprintf("ScriptType %s is on the current PATH at %s", setting.ScriptType, path)}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func runDoctorCheckDBConsistency(ctx *cli.Context) ([]string, error) {
 | 
			
		||||
	var results []string
 | 
			
		||||
 | 
			
		||||
	// make sure DB version is uptodate
 | 
			
		||||
	if err := models.NewEngine(context.Background(), migrations.EnsureUpToDate); err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("model version on the database does not match the current Gitea version. Model consistency will not be checked until the database is upgraded")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	//find labels without existing repo or org
 | 
			
		||||
	count, err := models.CountOrphanedLabels()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	if count > 0 {
 | 
			
		||||
		if ctx.Bool("fix") {
 | 
			
		||||
			if err = models.DeleteOrphanedLabels(); err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
			results = append(results, fmt.Sprintf("%d labels without existing repository/organisation deleted", count))
 | 
			
		||||
		} else {
 | 
			
		||||
			results = append(results, fmt.Sprintf("%d labels without existing repository/organisation", count))
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	//find issues without existing repository
 | 
			
		||||
	count, err = models.CountOrphanedIssues()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	if count > 0 {
 | 
			
		||||
		if ctx.Bool("fix") {
 | 
			
		||||
			if err = models.DeleteOrphanedIssues(); err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
			results = append(results, fmt.Sprintf("%d issues without existing repository deleted", count))
 | 
			
		||||
		} else {
 | 
			
		||||
			results = append(results, fmt.Sprintf("%d issues without existing repository", count))
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	//find pulls without existing issues
 | 
			
		||||
	count, err = models.CountOrphanedObjects("pull_request", "issue", "pull_request.issue_id=issue.id")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	if count > 0 {
 | 
			
		||||
		if ctx.Bool("fix") {
 | 
			
		||||
			if err = models.DeleteOrphanedObjects("pull_request", "issue", "pull_request.issue_id=issue.id"); err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
			results = append(results, fmt.Sprintf("%d pull requests without existing issue deleted", count))
 | 
			
		||||
		} else {
 | 
			
		||||
			results = append(results, fmt.Sprintf("%d pull requests without existing issue", count))
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	//find tracked times without existing issues/pulls
 | 
			
		||||
	count, err = models.CountOrphanedObjects("tracked_time", "issue", "tracked_time.issue_id=issue.id")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	if count > 0 {
 | 
			
		||||
		if ctx.Bool("fix") {
 | 
			
		||||
			if err = models.DeleteOrphanedObjects("tracked_time", "issue", "tracked_time.issue_id=issue.id"); err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
			results = append(results, fmt.Sprintf("%d tracked times without existing issue deleted", count))
 | 
			
		||||
		} else {
 | 
			
		||||
			results = append(results, fmt.Sprintf("%d tracked times without existing issue", count))
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	count, err = models.CountNullArchivedRepository()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	if count > 0 {
 | 
			
		||||
		if ctx.Bool("fix") {
 | 
			
		||||
			updatedCount, err := models.FixNullArchivedRepository()
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
			results = append(results, fmt.Sprintf("%d repositories with null is_archived updated", updatedCount))
 | 
			
		||||
		} else {
 | 
			
		||||
			results = append(results, fmt.Sprintf("%d repositories with null is_archived", count))
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	//ToDo: function to recalc all counters
 | 
			
		||||
 | 
			
		||||
	return results, nil
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -7,9 +7,11 @@ package cmd
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"os"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/modules/generate"
 | 
			
		||||
 | 
			
		||||
	"github.com/mattn/go-isatty"
 | 
			
		||||
	"github.com/urfave/cli"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@@ -59,7 +61,12 @@ func runGenerateInternalToken(c *cli.Context) error {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fmt.Printf("%s\n", internalToken)
 | 
			
		||||
	fmt.Printf("%s", internalToken)
 | 
			
		||||
 | 
			
		||||
	if isatty.IsTerminal(os.Stdout.Fd()) {
 | 
			
		||||
		fmt.Printf("\n")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -69,7 +76,12 @@ func runGenerateLfsJwtSecret(c *cli.Context) error {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fmt.Printf("%s\n", JWTSecretBase64)
 | 
			
		||||
	fmt.Printf("%s", JWTSecretBase64)
 | 
			
		||||
 | 
			
		||||
	if isatty.IsTerminal(os.Stdout.Fd()) {
 | 
			
		||||
		fmt.Printf("\n")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -79,6 +91,11 @@ func runGenerateSecretKey(c *cli.Context) error {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fmt.Printf("%s\n", secretKey)
 | 
			
		||||
	fmt.Printf("%s", secretKey)
 | 
			
		||||
 | 
			
		||||
	if isatty.IsTerminal(os.Stdout.Fd()) {
 | 
			
		||||
		fmt.Printf("\n")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -50,6 +50,8 @@ DISABLED_REPO_UNITS =
 | 
			
		||||
DEFAULT_REPO_UNITS = repo.code,repo.releases,repo.issues,repo.pulls,repo.wiki
 | 
			
		||||
; Prefix archive files by placing them in a directory named after the repository
 | 
			
		||||
PREFIX_ARCHIVE_FILES = true
 | 
			
		||||
; The default branch name of new repositories
 | 
			
		||||
DEFAULT_BRANCH=master
 | 
			
		||||
 | 
			
		||||
[repository.editor]
 | 
			
		||||
; List of file extensions for which lines should be wrapped in the Monaco editor
 | 
			
		||||
@@ -216,7 +218,10 @@ EVENT_SOURCE_UPDATE_TIME = 10s
 | 
			
		||||
; Render soft line breaks as hard line breaks, which means a single newline character between
 | 
			
		||||
; paragraphs will cause a line break and adding trailing whitespace to paragraphs is not
 | 
			
		||||
; necessary to force a line break.
 | 
			
		||||
ENABLE_HARD_LINE_BREAK = true
 | 
			
		||||
; Render soft line breaks as hard line breaks for comments
 | 
			
		||||
ENABLE_HARD_LINE_BREAK_IN_COMMENTS = true
 | 
			
		||||
; Render soft line breaks as hard line breaks for markdown documents
 | 
			
		||||
ENABLE_HARD_LINE_BREAK_IN_DOCUMENTS = false
 | 
			
		||||
; Comma separated list of custom URL-Schemes that are allowed as links when rendering Markdown
 | 
			
		||||
; for example git,magnet,ftp (more at https://en.wikipedia.org/wiki/List_of_URI_schemes)
 | 
			
		||||
; URLs starting with http and https are always displayed, whatever is put in this entry.
 | 
			
		||||
@@ -934,8 +939,8 @@ JWT_SECRET=Bk0yK7Y9g_p56v86KaHqjSbxvNvu3SbKoOdOt2ZcXvU
 | 
			
		||||
MAX_TOKEN_LENGTH=32767
 | 
			
		||||
 | 
			
		||||
[i18n]
 | 
			
		||||
LANGS = en-US,zh-CN,zh-HK,zh-TW,de-DE,fr-FR,nl-NL,lv-LV,ru-RU,uk-UA,ja-JP,es-ES,pt-BR,pl-PL,bg-BG,it-IT,fi-FI,tr-TR,cs-CZ,sr-SP,sv-SE,ko-KR
 | 
			
		||||
NAMES = English,简体中文,繁體中文(香港),繁體中文(台灣),Deutsch,français,Nederlands,latviešu,русский,Українська,日本語,español,português do Brasil,polski,български,italiano,suomi,Türkçe,čeština,српски,svenska,한국어
 | 
			
		||||
LANGS = en-US,zh-CN,zh-HK,zh-TW,de-DE,fr-FR,nl-NL,lv-LV,ru-RU,uk-UA,ja-JP,es-ES,pt-BR,pt-PT,pl-PL,bg-BG,it-IT,fi-FI,tr-TR,cs-CZ,sr-SP,sv-SE,ko-KR
 | 
			
		||||
NAMES = English,简体中文,繁體中文(香港),繁體中文(台灣),Deutsch,français,Nederlands,latviešu,русский,Українська,日本語,español,português do Brasil,Português de Portugal,polski,български,italiano,suomi,Türkçe,čeština,српски,svenska,한국어
 | 
			
		||||
 | 
			
		||||
; Used for datetimepicker
 | 
			
		||||
[i18n.datelang]
 | 
			
		||||
@@ -952,6 +957,7 @@ uk-UA = uk
 | 
			
		||||
ja-JP = ja
 | 
			
		||||
es-ES = es
 | 
			
		||||
pt-BR = pt-BR
 | 
			
		||||
pt-PT = pt
 | 
			
		||||
pl-PL = pl
 | 
			
		||||
bg-BG = bg
 | 
			
		||||
it-IT = it
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								docker/Makefile
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								docker/Makefile
									
									
									
									
										vendored
									
									
								
							@@ -11,4 +11,4 @@ docker:
 | 
			
		||||
 | 
			
		||||
.PHONY: docker-build
 | 
			
		||||
docker-build:
 | 
			
		||||
	docker run -ti --rm -v $(CURDIR):/srv/app/src/code.gitea.io/gitea -w /srv/app/src/code.gitea.io/gitea -e TAGS="bindata $(TAGS)" LDFLAGS="$(LDFLAGS)" webhippie/golang:edge make clean build
 | 
			
		||||
	docker run -ti --rm -v $(CURDIR):/srv/app/src/code.gitea.io/gitea -w /srv/app/src/code.gitea.io/gitea -e TAGS="bindata $(TAGS)" LDFLAGS="$(LDFLAGS)" CGO_EXTRA_CFLAGS="$(CGO_EXTRA_CFLAGS)" webhippie/golang:edge make clean build
 | 
			
		||||
 
 | 
			
		||||
@@ -312,3 +312,50 @@ languages:
 | 
			
		||||
          url: https://discourse.gitea.io/
 | 
			
		||||
          weight: 80
 | 
			
		||||
          pre: group
 | 
			
		||||
 | 
			
		||||
  pt-pt:
 | 
			
		||||
    weight: 6
 | 
			
		||||
    languageName: Português de Portugal
 | 
			
		||||
    menu:
 | 
			
		||||
      page:
 | 
			
		||||
        - name: Página inicial
 | 
			
		||||
          url: https://gitea.io/pt-pt/
 | 
			
		||||
          weight: 10
 | 
			
		||||
          pre: home
 | 
			
		||||
        - name: Documentação
 | 
			
		||||
          url: /pt-pt/
 | 
			
		||||
          weight: 20
 | 
			
		||||
          pre: question
 | 
			
		||||
          post: active
 | 
			
		||||
        - name: API
 | 
			
		||||
          url: https://try.gitea.io/api/swagger
 | 
			
		||||
          weight: 45
 | 
			
		||||
          pre: plug
 | 
			
		||||
        - name: Blog
 | 
			
		||||
          url: https://blog.gitea.io/
 | 
			
		||||
          weight: 30
 | 
			
		||||
          pre: rss
 | 
			
		||||
        - name: Código-fonte
 | 
			
		||||
          url: https://code.gitea.io/
 | 
			
		||||
          weight: 40
 | 
			
		||||
          pre: code
 | 
			
		||||
        - name: Tradução
 | 
			
		||||
          url: https://crowdin.com/project/gitea
 | 
			
		||||
          weight: 41
 | 
			
		||||
          pre: language
 | 
			
		||||
        - name: Descarregamentos
 | 
			
		||||
          url: https://dl.gitea.io/
 | 
			
		||||
          weight: 50
 | 
			
		||||
          pre: download
 | 
			
		||||
        - name: GitHub
 | 
			
		||||
          url: https://github.com/go-gitea/
 | 
			
		||||
          weight: 60
 | 
			
		||||
          pre: github
 | 
			
		||||
        - name: Discussão no Discord
 | 
			
		||||
          url: https://discord.gg/Gitea
 | 
			
		||||
          weight: 70
 | 
			
		||||
          pre: comment
 | 
			
		||||
        - name: Fórum
 | 
			
		||||
          url: https://discourse.gitea.io/
 | 
			
		||||
          weight: 80
 | 
			
		||||
          pre: group
 | 
			
		||||
 
 | 
			
		||||
@@ -69,6 +69,7 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`.
 | 
			
		||||
- `ENABLE_PUSH_CREATE_USER`:  **false**: Allow users to push local repositories to Gitea and have them automatically created for a user.
 | 
			
		||||
- `ENABLE_PUSH_CREATE_ORG`:  **false**: Allow users to push local repositories to Gitea and have them automatically created for an org.
 | 
			
		||||
- `PREFIX_ARCHIVE_FILES`: **true**: Prefix archive files by placing them in a directory named after the repository.
 | 
			
		||||
- `DEFAULT_BRANCH`: **master**: Default branch name of all repositories.
 | 
			
		||||
 | 
			
		||||
### Repository - Pull Request (`repository.pull-request`)
 | 
			
		||||
 | 
			
		||||
@@ -152,7 +153,10 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`.
 | 
			
		||||
 | 
			
		||||
## Markdown (`markdown`)
 | 
			
		||||
 | 
			
		||||
- `ENABLE_HARD_LINE_BREAK`: **true**: Render soft line breaks as hard line breaks, which
 | 
			
		||||
- `ENABLE_HARD_LINE_BREAK_IN_COMMENTS`: **true**: Render soft line breaks as hard line breaks in comments, which
 | 
			
		||||
  means a single newline character between paragraphs will cause a line break and adding
 | 
			
		||||
  trailing whitespace to paragraphs is not necessary to force a line break.
 | 
			
		||||
- `ENABLE_HARD_LINE_BREAK_IN_DOCUMENTS`: **false**: Render soft line breaks as hard line breaks in documents, which
 | 
			
		||||
  means a single newline character between paragraphs will cause a line break and adding
 | 
			
		||||
  trailing whitespace to paragraphs is not necessary to force a line break.
 | 
			
		||||
- `CUSTOM_URL_SCHEMES`: Use a comma separated list (ftp,git,svn) to indicate additional
 | 
			
		||||
@@ -602,8 +606,8 @@ NB: You must `REDIRECT_MACARON_LOG` and have `DISABLE_ROUTER_LOG` set to `false`
 | 
			
		||||
 | 
			
		||||
## i18n (`i18n`)
 | 
			
		||||
 | 
			
		||||
- `LANGS`: **en-US,zh-CN,zh-HK,zh-TW,de-DE,fr-FR,nl-NL,lv-LV,ru-RU,ja-JP,es-ES,pt-BR,pl-PL,bg-BG,it-IT,fi-FI,tr-TR,cs-CZ,sr-SP,sv-SE,ko-KR**: List of locales shown in language selector
 | 
			
		||||
- `NAMES`: **English,简体中文,繁體中文(香港),繁體中文(台灣),Deutsch,français,Nederlands,latviešu,русский,日本語,español,português do Brasil,polski,български,italiano,suomi,Türkçe,čeština,српски,svenska,한국어**: Visible names corresponding to the locales
 | 
			
		||||
- `LANGS`: **en-US,zh-CN,zh-HK,zh-TW,de-DE,fr-FR,nl-NL,lv-LV,ru-RU,ja-JP,es-ES,pt-BR,pt-PT,pl-PL,bg-BG,it-IT,fi-FI,tr-TR,cs-CZ,sr-SP,sv-SE,ko-KR**: List of locales shown in language selector
 | 
			
		||||
- `NAMES`: **English,简体中文,繁體中文(香港),繁體中文(台灣),Deutsch,français,Nederlands,latviešu,русский,日本語,español,português do Brasil,Português de Portugal,polski,български,italiano,suomi,Türkçe,čeština,српски,svenska,한국어**: Visible names corresponding to the locales
 | 
			
		||||
 | 
			
		||||
### i18n - Datepicker Language (`i18n.datelang`)
 | 
			
		||||
Maps locales to the languages used by the datepicker plugin
 | 
			
		||||
@@ -620,6 +624,7 @@ Maps locales to the languages used by the datepicker plugin
 | 
			
		||||
- `ja-JP`: **ja**
 | 
			
		||||
- `es-ES`: **es**
 | 
			
		||||
- `pt-BR`: **pt-BR**
 | 
			
		||||
- `pt-PT`: **pt**
 | 
			
		||||
- `pl-PL`: **pl**
 | 
			
		||||
- `bg-BG`: **bg**
 | 
			
		||||
- `it-IT`: **it**
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										12
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								go.mod
									
									
									
									
									
								
							@@ -37,9 +37,9 @@ require (
 | 
			
		||||
	github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870 // indirect
 | 
			
		||||
	github.com/gliderlabs/ssh v0.2.2
 | 
			
		||||
	github.com/glycerine/go-unsnap-stream v0.0.0-20190901134440-81cf024a9e0a // indirect
 | 
			
		||||
	github.com/go-enry/go-enry/v2 v2.3.0
 | 
			
		||||
	github.com/go-enry/go-enry/v2 v2.5.2
 | 
			
		||||
	github.com/go-git/go-billy/v5 v5.0.0
 | 
			
		||||
	github.com/go-git/go-git/v5 v5.0.0
 | 
			
		||||
	github.com/go-git/go-git/v5 v5.1.0
 | 
			
		||||
	github.com/go-openapi/jsonreference v0.19.3 // indirect
 | 
			
		||||
	github.com/go-redis/redis v6.15.2+incompatible
 | 
			
		||||
	github.com/go-sql-driver/mysql v1.4.1
 | 
			
		||||
@@ -49,6 +49,7 @@ require (
 | 
			
		||||
	github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14
 | 
			
		||||
	github.com/golang/protobuf v1.4.1 // indirect
 | 
			
		||||
	github.com/google/go-github/v24 v24.0.1
 | 
			
		||||
	github.com/google/uuid v1.1.1
 | 
			
		||||
	github.com/gorilla/context v1.1.1
 | 
			
		||||
	github.com/hashicorp/go-retryablehttp v0.6.6 // indirect
 | 
			
		||||
	github.com/huandu/xstrings v1.3.0
 | 
			
		||||
@@ -85,7 +86,6 @@ require (
 | 
			
		||||
	github.com/prometheus/procfs v0.0.4 // indirect
 | 
			
		||||
	github.com/quasoft/websspi v1.0.0
 | 
			
		||||
	github.com/remyoudompheng/bigfft v0.0.0-20190321074620-2f0d2b0e0001 // indirect
 | 
			
		||||
	github.com/satori/go.uuid v1.2.0
 | 
			
		||||
	github.com/sergi/go-diff v1.1.0
 | 
			
		||||
	github.com/shurcooL/httpfs v0.0.0-20190527155220-6a4d4a70508b // indirect
 | 
			
		||||
	github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd
 | 
			
		||||
@@ -102,10 +102,10 @@ require (
 | 
			
		||||
	github.com/yohcop/openid-go v1.0.0
 | 
			
		||||
	github.com/yuin/goldmark v1.1.25
 | 
			
		||||
	github.com/yuin/goldmark-meta v0.0.0-20191126180153-f0638e958b60
 | 
			
		||||
	golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79
 | 
			
		||||
	golang.org/x/net v0.0.0-20200506145744-7e3656a0809f
 | 
			
		||||
	golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9
 | 
			
		||||
	golang.org/x/net v0.0.0-20200602114024-627f9648deb9
 | 
			
		||||
	golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
 | 
			
		||||
	golang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f
 | 
			
		||||
	golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1
 | 
			
		||||
	golang.org/x/text v0.3.2
 | 
			
		||||
	golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1 // indirect
 | 
			
		||||
	golang.org/x/tools v0.0.0-20200325010219-a49f79bcc224
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										32
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										32
									
								
								go.sum
									
									
									
									
									
								
							@@ -193,18 +193,18 @@ github.com/glycerine/go-unsnap-stream v0.0.0-20190901134440-81cf024a9e0a h1:FQqo
 | 
			
		||||
github.com/glycerine/go-unsnap-stream v0.0.0-20190901134440-81cf024a9e0a/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE=
 | 
			
		||||
github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31 h1:gclg6gY70GLy3PbkQ1AERPfmLMMagS60DKF78eWwLn8=
 | 
			
		||||
github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24=
 | 
			
		||||
github.com/go-enry/go-enry/v2 v2.3.0 h1:o8KwgY6uSplysrIpj+Y42J/xGPp90ogVpxE2Z3s8Unk=
 | 
			
		||||
github.com/go-enry/go-enry/v2 v2.3.0/go.mod h1:+xFJwbqWi15bvqFHb2ELUWVRKFQtwB61+sDrkvvxxGI=
 | 
			
		||||
github.com/go-enry/go-oniguruma v1.2.0 h1:oBO9XC1IDT9+AoWW5oFsa/7gFeOPacEqDbyXZKWXuDs=
 | 
			
		||||
github.com/go-enry/go-oniguruma v1.2.0/go.mod h1:bWDhYP+S6xZQgiRL7wlTScFYBe023B6ilRZbCAD5Hf4=
 | 
			
		||||
github.com/go-enry/go-enry/v2 v2.5.2 h1:3f3PFAO6JitWkPi1GQ5/m6Xu4gNL1U5soJ8QaYqJ0YQ=
 | 
			
		||||
github.com/go-enry/go-enry/v2 v2.5.2/go.mod h1:GVzIiAytiS5uT/QiuakK7TF1u4xDab87Y8V5EJRpsIQ=
 | 
			
		||||
github.com/go-enry/go-oniguruma v1.2.1 h1:k8aAMuJfMrqm/56SG2lV9Cfti6tC4x8673aHCcBk+eo=
 | 
			
		||||
github.com/go-enry/go-oniguruma v1.2.1/go.mod h1:bWDhYP+S6xZQgiRL7wlTScFYBe023B6ilRZbCAD5Hf4=
 | 
			
		||||
github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4=
 | 
			
		||||
github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E=
 | 
			
		||||
github.com/go-git/go-billy/v5 v5.0.0 h1:7NQHvd9FVid8VL4qVUMm8XifBK+2xCoZ2lSk0agRrHM=
 | 
			
		||||
github.com/go-git/go-billy/v5 v5.0.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
 | 
			
		||||
github.com/go-git/go-git-fixtures/v4 v4.0.1 h1:q+IFMfLx200Q3scvt2hN79JsEzy4AmBTp/pqnefH+Bc=
 | 
			
		||||
github.com/go-git/go-git-fixtures/v4 v4.0.1/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw=
 | 
			
		||||
github.com/go-git/go-git/v5 v5.0.0 h1:k5RWPm4iJwYtfWoxIJy4wJX9ON7ihPeZZYC1fLYDnpg=
 | 
			
		||||
github.com/go-git/go-git/v5 v5.0.0/go.mod h1:oYD8y9kWsGINPFJoLdaScGCN6dlKg23blmClfZwtUVA=
 | 
			
		||||
github.com/go-git/go-git/v5 v5.1.0 h1:HxJn9g/E7eYvKW3Fm7Jt4ee8LXfPOm/H1cdDu8vEssk=
 | 
			
		||||
github.com/go-git/go-git/v5 v5.1.0/go.mod h1:ZKfuPUoY1ZqIG4QG9BDBh3G4gLM5zvPuSJAozQrZuyM=
 | 
			
		||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
 | 
			
		||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
 | 
			
		||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
 | 
			
		||||
@@ -371,6 +371,8 @@ github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
 | 
			
		||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
 | 
			
		||||
github.com/huandu/xstrings v1.3.0 h1:gvV6jG9dTgFEncxo+AF7PH6MZXi/vZl25owA/8Dg8Wo=
 | 
			
		||||
github.com/huandu/xstrings v1.3.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
 | 
			
		||||
github.com/imdario/mergo v0.3.9 h1:UauaLniWCFHWd+Jp9oCEkTBj8VO/9DKg3PV3VCNMDIg=
 | 
			
		||||
github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
 | 
			
		||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
 | 
			
		||||
github.com/issue9/assert v1.3.1/go.mod h1:9Ger+iz8X7r1zMYYwEhh++2wMGWcNN2oVI+zIQXxcio=
 | 
			
		||||
github.com/issue9/assert v1.3.2 h1:IaTa37u4m1fUuTH9K9ldO5IONKVDXjLiUO1T9vj0OF0=
 | 
			
		||||
@@ -556,8 +558,6 @@ github.com/remyoudompheng/bigfft v0.0.0-20190321074620-2f0d2b0e0001/go.mod h1:qq
 | 
			
		||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
 | 
			
		||||
github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
 | 
			
		||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
 | 
			
		||||
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
 | 
			
		||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
 | 
			
		||||
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
 | 
			
		||||
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
 | 
			
		||||
github.com/shurcooL/httpfs v0.0.0-20190527155220-6a4d4a70508b h1:4kg1wyftSKxLtnPAvcRWakIPpokB9w780/KwrNLnfPA=
 | 
			
		||||
@@ -616,8 +616,6 @@ github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDW
 | 
			
		||||
github.com/tinylib/msgp v1.1.2 h1:gWmO7n0Ys2RBEb7GPYB9Ujq8Mk5p2U08lRnmMcGy6BQ=
 | 
			
		||||
github.com/tinylib/msgp v1.1.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
 | 
			
		||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
 | 
			
		||||
github.com/toqueteos/trie v1.0.0 h1:8i6pXxNUXNRAqP246iibb7w/pSFquNTQ+uNfriG7vlk=
 | 
			
		||||
github.com/toqueteos/trie v1.0.0/go.mod h1:Ywk48QhEqhU1+DwhMkJ2x7eeGxDHiGkAdc9+0DYcbsM=
 | 
			
		||||
github.com/toqueteos/webbrowser v1.2.0 h1:tVP/gpK69Fx+qMJKsLE7TD8LuGWPnEV71wBN9rrstGQ=
 | 
			
		||||
github.com/toqueteos/webbrowser v1.2.0/go.mod h1:XWoZq4cyp9WeUeak7w7LXRUQf1F1ATJMir8RTqb4ayM=
 | 
			
		||||
github.com/tstranex/u2f v1.0.0 h1:HhJkSzDDlVSVIVt7pDJwCHQj67k7A5EeBgPmeD+pVsQ=
 | 
			
		||||
@@ -683,8 +681,8 @@ golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad/go.mod h1:yigFU9vqHzYiE8U
 | 
			
		||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 | 
			
		||||
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073 h1:xMPOj6Pz6UipU1wXLkrtqpHbR0AVFnyPEQq/wRWz9lM=
 | 
			
		||||
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 | 
			
		||||
golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79 h1:IaQbIIB2X/Mp/DKctl6ROxz1KyMlKp4uyvL6+kQ7C88=
 | 
			
		||||
golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 | 
			
		||||
golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9 h1:vEg9joUBmeBcK9iSJftGNf3coIG4HqZElCPehJsfAYM=
 | 
			
		||||
golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 | 
			
		||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 | 
			
		||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
 | 
			
		||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
 | 
			
		||||
@@ -723,8 +721,8 @@ golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLL
 | 
			
		||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 | 
			
		||||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0=
 | 
			
		||||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 | 
			
		||||
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f h1:QBjCr1Fz5kw158VqdE9JfI9cJnl/ymnJWAdMuinqL7Y=
 | 
			
		||||
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
 | 
			
		||||
golang.org/x/net v0.0.0-20200602114024-627f9648deb9 h1:pNX+40auqi2JqRfOP1akLGtYcn15TUbkhwuCO3foqqM=
 | 
			
		||||
golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
 | 
			
		||||
golang.org/x/oauth2 v0.0.0-20180620175406-ef147856a6dd/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 | 
			
		||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 | 
			
		||||
golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 | 
			
		||||
@@ -771,8 +769,8 @@ golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 h1:uYVVQ9WP/Ds2ROhcaGPeIdVq0
 | 
			
		||||
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
			
		||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
 | 
			
		||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
			
		||||
golang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f h1:mOhmO9WsBaJCNmaZHPtHs9wOcdqdKCjF6OPJlmDM3KI=
 | 
			
		||||
golang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
			
		||||
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1 h1:ogLJMz+qpzav7lGMh10LMvAkM/fAoGlaiiHYiFYdm80=
 | 
			
		||||
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
			
		||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 | 
			
		||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 | 
			
		||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
 | 
			
		||||
@@ -876,8 +874,6 @@ gopkg.in/testfixtures.v2 v2.5.0 h1:N08B7l2GzFQenyYbzqthDnKAA+cmb17iAZhhFxr7JHw=
 | 
			
		||||
gopkg.in/testfixtures.v2 v2.5.0/go.mod h1:vyAq+MYCgNpR29qitQdLZhdbLFf4mR/2MFJRFoQZZ2M=
 | 
			
		||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
 | 
			
		||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
 | 
			
		||||
gopkg.in/toqueteos/substring.v1 v1.0.2 h1:urLqCeMm6x/eTuQa1oZerNw8N1KNOIp5hD5kGL7lFsE=
 | 
			
		||||
gopkg.in/toqueteos/substring.v1 v1.0.2/go.mod h1:Eb2Z1UYehlVK8LYW2WBVR2rwbujsz3aX8XDrM1vbNew=
 | 
			
		||||
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
 | 
			
		||||
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
 | 
			
		||||
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
 | 
			
		||||
 
 | 
			
		||||
@@ -32,7 +32,7 @@ func TestGPGKeys(t *testing.T) {
 | 
			
		||||
			results: []int{http.StatusUnauthorized, http.StatusUnauthorized, http.StatusUnauthorized, http.StatusUnauthorized, http.StatusUnauthorized, http.StatusUnauthorized, http.StatusUnauthorized, http.StatusUnauthorized},
 | 
			
		||||
		},
 | 
			
		||||
		{name: "LoggedAsUser2", makeRequest: session.MakeRequest, token: token,
 | 
			
		||||
			results: []int{http.StatusOK, http.StatusOK, http.StatusNotFound, http.StatusNoContent, http.StatusInternalServerError, http.StatusInternalServerError, http.StatusCreated, http.StatusCreated}},
 | 
			
		||||
			results: []int{http.StatusOK, http.StatusOK, http.StatusNotFound, http.StatusNoContent, http.StatusUnprocessableEntity, http.StatusNotFound, http.StatusCreated, http.StatusCreated}},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, tc := range tt {
 | 
			
		||||
 
 | 
			
		||||
@@ -86,6 +86,11 @@ func TestAPIPullReview(t *testing.T) {
 | 
			
		||||
			Body:       "first old line",
 | 
			
		||||
			OldLineNum: 1,
 | 
			
		||||
			NewLineNum: 0,
 | 
			
		||||
		}, {
 | 
			
		||||
			Path:       "iso-8859-1.txt",
 | 
			
		||||
			Body:       "this line contains a non-utf-8 character",
 | 
			
		||||
			OldLineNum: 0,
 | 
			
		||||
			NewLineNum: 1,
 | 
			
		||||
		},
 | 
			
		||||
		},
 | 
			
		||||
	})
 | 
			
		||||
@@ -93,7 +98,7 @@ func TestAPIPullReview(t *testing.T) {
 | 
			
		||||
	DecodeJSON(t, resp, &review)
 | 
			
		||||
	assert.EqualValues(t, 6, review.ID)
 | 
			
		||||
	assert.EqualValues(t, "PENDING", review.State)
 | 
			
		||||
	assert.EqualValues(t, 2, review.CodeCommentsCount)
 | 
			
		||||
	assert.EqualValues(t, 3, review.CodeCommentsCount)
 | 
			
		||||
 | 
			
		||||
	// test SubmitPullReview
 | 
			
		||||
	req = NewRequestWithJSON(t, http.MethodPost, fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d/reviews/%d?token=%s", repo.OwnerName, repo.Name, pullIssue.Index, review.ID, token), &api.SubmitPullReviewOptions{
 | 
			
		||||
@@ -104,7 +109,7 @@ func TestAPIPullReview(t *testing.T) {
 | 
			
		||||
	DecodeJSON(t, resp, &review)
 | 
			
		||||
	assert.EqualValues(t, 6, review.ID)
 | 
			
		||||
	assert.EqualValues(t, "APPROVED", review.State)
 | 
			
		||||
	assert.EqualValues(t, 2, review.CodeCommentsCount)
 | 
			
		||||
	assert.EqualValues(t, 3, review.CodeCommentsCount)
 | 
			
		||||
 | 
			
		||||
	// test DeletePullReview
 | 
			
		||||
	req = NewRequestWithJSON(t, http.MethodPost, fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d/reviews?token=%s", repo.OwnerName, repo.Name, pullIssue.Index, token), &api.CreatePullReviewOptions{
 | 
			
		||||
 
 | 
			
		||||
@@ -58,7 +58,7 @@ func TestAPIMergePullWIP(t *testing.T) {
 | 
			
		||||
	session.MakeRequest(t, req, http.StatusMethodNotAllowed)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestAPICreatePullSuccess1(t *testing.T) {
 | 
			
		||||
func TestAPICreatePullSuccess(t *testing.T) {
 | 
			
		||||
	defer prepareTestEnv(t)()
 | 
			
		||||
	repo10 := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 10}).(*models.Repository)
 | 
			
		||||
	// repo10 have code, pulls units.
 | 
			
		||||
@@ -78,7 +78,7 @@ func TestAPICreatePullSuccess1(t *testing.T) {
 | 
			
		||||
	session.MakeRequest(t, req, 201)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestAPICreatePullSuccess2(t *testing.T) {
 | 
			
		||||
func TestAPIEditPull(t *testing.T) {
 | 
			
		||||
	defer prepareTestEnv(t)()
 | 
			
		||||
	repo10 := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 10}).(*models.Repository)
 | 
			
		||||
	owner10 := models.AssertExistsAndLoadBean(t, &models.User{ID: repo10.OwnerID}).(*models.User)
 | 
			
		||||
@@ -90,6 +90,21 @@ func TestAPICreatePullSuccess2(t *testing.T) {
 | 
			
		||||
		Base:  "master",
 | 
			
		||||
		Title: "create a success pr",
 | 
			
		||||
	})
 | 
			
		||||
	pull := new(api.PullRequest)
 | 
			
		||||
	resp := session.MakeRequest(t, req, 201)
 | 
			
		||||
	DecodeJSON(t, resp, pull)
 | 
			
		||||
	assert.EqualValues(t, "master", pull.Base.Name)
 | 
			
		||||
 | 
			
		||||
	session.MakeRequest(t, req, 201)
 | 
			
		||||
	req = NewRequestWithJSON(t, http.MethodPatch, fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d?token=%s", owner10.Name, repo10.Name, pull.Index, token), &api.EditPullRequestOption{
 | 
			
		||||
		Base:  "feature/1",
 | 
			
		||||
		Title: "edit a this pr",
 | 
			
		||||
	})
 | 
			
		||||
	resp = session.MakeRequest(t, req, 201)
 | 
			
		||||
	DecodeJSON(t, resp, pull)
 | 
			
		||||
	assert.EqualValues(t, "feature/1", pull.Base.Name)
 | 
			
		||||
 | 
			
		||||
	req = NewRequestWithJSON(t, http.MethodPatch, fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d?token=%s", owner10.Name, repo10.Name, pull.Index, token), &api.EditPullRequestOption{
 | 
			
		||||
		Base: "not-exist",
 | 
			
		||||
	})
 | 
			
		||||
	session.MakeRequest(t, req, 404)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -189,7 +189,7 @@ func TestAPICreateFile(t *testing.T) {
 | 
			
		||||
		treePath = "README.md"
 | 
			
		||||
		url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo1.Name, treePath, token2)
 | 
			
		||||
		req = NewRequestWithJSON(t, "POST", url, &createFileOptions)
 | 
			
		||||
		resp = session.MakeRequest(t, req, http.StatusInternalServerError)
 | 
			
		||||
		resp = session.MakeRequest(t, req, http.StatusUnprocessableEntity)
 | 
			
		||||
		expectedAPIError := context.APIError{
 | 
			
		||||
			Message: "repository file already exists [path: " + treePath + "]",
 | 
			
		||||
			URL:     setting.API.SwaggerURL,
 | 
			
		||||
 
 | 
			
		||||
@@ -208,7 +208,7 @@ func TestAPIUpdateFile(t *testing.T) {
 | 
			
		||||
		updateFileOptions.SHA = "badsha"
 | 
			
		||||
		url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo1.Name, treePath, token2)
 | 
			
		||||
		req = NewRequestWithJSON(t, "PUT", url, &updateFileOptions)
 | 
			
		||||
		resp = session.MakeRequest(t, req, http.StatusInternalServerError)
 | 
			
		||||
		resp = session.MakeRequest(t, req, http.StatusUnprocessableEntity)
 | 
			
		||||
		expectedAPIError := context.APIError{
 | 
			
		||||
			Message: "sha does not match [given: " + updateFileOptions.SHA + ", expected: " + correctSHA + "]",
 | 
			
		||||
			URL:     setting.API.SwaggerURL,
 | 
			
		||||
 
 | 
			
		||||
@@ -13,6 +13,7 @@ import (
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/models"
 | 
			
		||||
	"code.gitea.io/gitea/modules/setting"
 | 
			
		||||
	api "code.gitea.io/gitea/modules/structs"
 | 
			
		||||
 | 
			
		||||
	"github.com/stretchr/testify/assert"
 | 
			
		||||
@@ -57,6 +58,12 @@ func TestAPISearchRepo(t *testing.T) {
 | 
			
		||||
	user4 := models.AssertExistsAndLoadBean(t, &models.User{ID: 20}).(*models.User)
 | 
			
		||||
	orgUser := models.AssertExistsAndLoadBean(t, &models.User{ID: 17}).(*models.User)
 | 
			
		||||
 | 
			
		||||
	oldAPIDefaultNum := setting.API.DefaultPagingNum
 | 
			
		||||
	defer func() {
 | 
			
		||||
		setting.API.DefaultPagingNum = oldAPIDefaultNum
 | 
			
		||||
	}()
 | 
			
		||||
	setting.API.DefaultPagingNum = 10
 | 
			
		||||
 | 
			
		||||
	// Map of expected results, where key is user for login
 | 
			
		||||
	type expectedResults map[*models.User]struct {
 | 
			
		||||
		count           int
 | 
			
		||||
@@ -79,7 +86,7 @@ func TestAPISearchRepo(t *testing.T) {
 | 
			
		||||
			user:  {count: 10},
 | 
			
		||||
			user2: {count: 10}},
 | 
			
		||||
		},
 | 
			
		||||
		{name: "RepositoriesDefaultMax10", requestURL: "/api/v1/repos/search?default&private=false", expectedResults: expectedResults{
 | 
			
		||||
		{name: "RepositoriesDefault", requestURL: "/api/v1/repos/search?default&private=false", expectedResults: expectedResults{
 | 
			
		||||
			nil:   {count: 10},
 | 
			
		||||
			user:  {count: 10},
 | 
			
		||||
			user2: {count: 10}},
 | 
			
		||||
 
 | 
			
		||||
@@ -32,14 +32,14 @@ func TestDeleteBranch(t *testing.T) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestUndoDeleteBranch(t *testing.T) {
 | 
			
		||||
	defer prepareTestEnv(t)()
 | 
			
		||||
 | 
			
		||||
	onGiteaRun(t, func(t *testing.T, u *url.URL) {
 | 
			
		||||
		deleteBranch(t)
 | 
			
		||||
		htmlDoc, name := branchAction(t, ".undo-button")
 | 
			
		||||
		assert.Contains(t,
 | 
			
		||||
			htmlDoc.doc.Find(".ui.positive.message").Text(),
 | 
			
		||||
			i18n.Tr("en", "repo.branch.restore_success", name),
 | 
			
		||||
		)
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func deleteBranch(t *testing.T) {
 | 
			
		||||
 
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							@@ -0,0 +1,2 @@
 | 
			
		||||
xe<><65>N<EFBFBD>0D<>#<23><1F><03>4 
 | 
			
		||||
J<EFBFBD>A<05>5<EFBFBD><35><EFBFBD><EFBFBD>,<2C>x<EFBFBD>zsV<73><56><EFBFBD>5<08>D<EFBFBD><44>ػ<EFBFBD>7<EFBFBD>,=<3D><>o.<13>E卢<45>q5J=<3D><><EFBFBD><EFBFBD><EFBFBD>	r<>=>4<1B><1D>
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							@@ -1 +1 @@
 | 
			
		||||
4a357436d925b5c974181ff12a994538ddc5a269
 | 
			
		||||
5f22f7d0d95d614d25a5b68592adb345a4b5c7fd
 | 
			
		||||
 
 | 
			
		||||
@@ -76,6 +76,53 @@ nARUPZ9SqaUmRm+KGsSyoYnvN9apiDk5KVQoyfrmweNN7DCIIcoh/B9Ax8nmouKz
 | 
			
		||||
yBB2fjCM/bJNtN/AsgYbZIScuYK/xqTkwNtbe5WdCyD/QJOHTsPJzx59hgSVo6gf
 | 
			
		||||
Fe8VBnxHtrY8gPSUU3gkhYLvLzyVX+YLNzRcffobd8gJbfumwFJUkz91oGvYz7xg
 | 
			
		||||
XN2qmsgBNCbTIzWZMpRDMAbY+n2QFImGf+EJZlMdj6gOrIYq8N4+nMW1FwJivsOb
 | 
			
		||||
muqySyjZnD2AYjEA6OYPXfCVhaB5fTfhQXbIrZbgsEh4ob/eIdM=
 | 
			
		||||
=oSDR
 | 
			
		||||
muqySyjZnD2AYjEA6OYPXfCVhaB5fTfhQXbIrZbgsEh4ob/eIdOdBVgEXta5egEM
 | 
			
		||||
AMYlmZ47NqBMBeaN0o/ahYMe8eIMaroWkufMfC9VRBSMAkpbDl34oNp0cflmnMYo
 | 
			
		||||
AFAl8ucRMFTiUnjiWpo27q14tjSyDVsn/CqwbnrgJgCFNV/MGsYsToEkb4JwDIRC
 | 
			
		||||
bky+1BvqvI8RMlO3MlwzrlIaMrlQfx5NtUb9TyO7S4xZTz864+Ty5p3HhRwbdZMe
 | 
			
		||||
Ko8sfXFhCcCHFXosI0mX83EyzsrXlbkGRawId7jvrdOAUg/cYP8f/XmV6z1NHHH9
 | 
			
		||||
cvz+3oLOGuVxUdG0KuS/jigHrLWdRuKM3xfEeesp870yZU3AbyFdoHnGXROJePTl
 | 
			
		||||
FV8j2P5Ahf/yuVhjdyJSKdZC2h6+HtLG9RiGgLviLLYhtlZG2H6pYyKY5Ud3php+
 | 
			
		||||
qw1aYL1xtdxrHYkQlAa0vLY/mwpuPfMke9I+rtnrwlLRMCstdiN34ybZ4sRD+gL1
 | 
			
		||||
w5VIZ/aM6/Gsczd3s/T8psIi09TKPfEU2gWLMGvlDsgz+aSDdVP7XYQpNglaEPet
 | 
			
		||||
PwARAQABAAv8CHg6+hnV2pblTwGTlTU7V8DO3gwMfn/QhQ/8ju66G5a7J6p/ZreQ
 | 
			
		||||
nfCJnqYq4AgoW0SuqVSBbbTENF6YjixNmiSlb9iHMZ+ilms24xG0Y3lOMBYYCY3Y
 | 
			
		||||
nTSNf6nXyconz31TW7jLmTdG9hpykKEKO9WFgt5UpgWe+2CAgtUoBDZyaLrVBZ2h
 | 
			
		||||
te99WmziDbPQZeZPm7UQ0aX0iRBclxy4+dxjcnrcmi1mdQAM/glgs2sHbEjN7JnV
 | 
			
		||||
dTOvUSN7/8ixj6I719Wx6MN6jE+BNd0ytZOun6tcDl0vamfT5fBpqbQoJMib2ggo
 | 
			
		||||
+FGg9VFnzEMLqyI47LfOKUjCIhwVsxS4q9HXa2FtpO8UfRMPjDKgDZQzRTRJScrP
 | 
			
		||||
s1NJ9HiM/eCHS1YjRmgroo60HygxkoLVCHp+Rz/hi0tG/ptv4q6mdnm8Mwb5JJtV
 | 
			
		||||
48EvmZoNTWl9xOez1wmQn6caVHipc0qDqn/veoe8N5wdc+3hoMEXbSXqU+kx2KUa
 | 
			
		||||
cVxCCVoUeURhBgDUGWtx34j1y17zE92BYhtVJTCU89dDe4wOEqGPyCGvRtgTmZ+1
 | 
			
		||||
KwWr66pij91MV9mlY+7Ue2QHUSmgav2EFGIjVes956p4/F/CJ6qaYoekirMSnmX5
 | 
			
		||||
jhRt4p6RW7m4omha3LAQ+gN4Fqa4acZUywENBvv1x3v+IWbjGJGn3eBnRrP3o9P+
 | 
			
		||||
QUAtyMifiRm0ZN8J767o+bzUVmscXrkh7Qml47lQfDToyRI1UZZQmP2izpwHcwbZ
 | 
			
		||||
NtfkgRUdeEq4GJUGAO8o4Oebbt0ALZ54E2LHhk8xi4ofKkFBDCkUFjcqS3bJJNck
 | 
			
		||||
rkhfqEkMLETNhPbiC4TRNiunI5PXOinwNPkKI8P/hfp4S49WdIvnARazCoxjZNtl
 | 
			
		||||
0Cbo+F1wtOH9FZaaWzNlU2lCQ2JJ3MCpLHz+nEmdYWOIWGQu2/s7smLODVEFbYKR
 | 
			
		||||
50VWVRL7mB83v1XdfMFvExdQ7i5MOX4hFvmwi/WJIKClJfhNwTrHp6Jrm9jA66RL
 | 
			
		||||
+dNyPKfwcFcYrqt1gwYAruZzP7QgTYVL+cmvGtCaHY4KoR8hanbpqR4YbzzyEXwS
 | 
			
		||||
ll2FUCaVSokuRAdH3+/CHF9bqog3Zvn6HYcCS/A/rHVGIU9a+7s5IbRe0Ysc2FAN
 | 
			
		||||
Nm9AsC5YnuyoAjW3cJGaZLYxp2WOZcMEXZeLPFYrNz22R1nRoxnUIPRpsKICXcK0
 | 
			
		||||
aC4rSMk479jc/8WprWx4d45EVG+6Gsh1AT8LVhDL9yHFrh50ss2jCe1Fnftet6DI
 | 
			
		||||
V5zHcxBx4sCs91aPxxe12UiJA2wEGAEKACAWIQQ4G/p4KVUOUEVu5g5R68KXFICq
 | 
			
		||||
DwUCXta5egIbAgHACRBR68KXFICqD8D0IAQZAQoAHRYhBKAm5ShdO9gmF/o8jan0
 | 
			
		||||
RkmWoKbKBQJe1rl6AAoJEKn0RkmWoKbKacUL/3YYKmiVvcr5LYFzMdwdahkla+6m
 | 
			
		||||
hEEkL0l3dJNuU97Ou71tA1ieF0fjbVRSWjXKsntKwhyPoXjaZEZwMmv7iZ8BXV+b
 | 
			
		||||
oO/EG5sg2/6iukJFXZqGnQwMdLVo1jPoXDteZU1qYiCoxLHhGhHL7ivtD1ygEi6w
 | 
			
		||||
/cMbbOEB5Le1vOWIwqazs8dDcAYyy1PKthRl0ygvh8CpqPwy+AK3uLm0TVwetQAp
 | 
			
		||||
taux0bDYWCb5Aft1r1nlV44gU4RiC131TDo+TKd754+UuI+UHk1D+LjTmZxRX2S6
 | 
			
		||||
fXgoMXzrWmthGPdqvVOgKWm7Ef18hmaBECvPnp/tUJeDVVe02KrYQi8Bf2kxveSd
 | 
			
		||||
8T0N/ExcydU9HgzTL8MuyPI+yp086elQzKJu6vb9tpgxCcglQZrUNT9Uy82pzTRY
 | 
			
		||||
z9MmhnCDI2SD5L/CW5PsNpPTPy7s3f9DOV0G5Vka4LTSBOCK64NvAGBmRf8rFjJU
 | 
			
		||||
lPtRPhC7h6uHdUIx3Q550Xogvq5sQm8UBCsbG8OJDADT3FJSIulR9Sh96OsES3sc
 | 
			
		||||
H09juN4KcbpS03MAeUFwXqw3jBMhDoGKlsjX17Jf31qh/nI/XjigS3XWyj1BLSMG
 | 
			
		||||
rJfH0NyYoGDCnff37tf+8lD9km9TlnV4Qjd9ujYbDRsefhaSjLVcy/gqdxZEuNBC
 | 
			
		||||
BWmGwsmLI3nyZ4KDtNsa5JUHUNNZLBN20hvmE41Eszmz4Yg9Ho9DxKiFKvzUULMc
 | 
			
		||||
bnMHaVHseHHq6+NVUnN1SAcOA0ygjnEid8D57RtdBCD90LXjLB7vlR+HaSMZYOnr
 | 
			
		||||
DtseivHvqqy4+rxhwV2S3avnls9vRwE4bV6GCiqhoBnWIZRrARLZc2OTBIya82vS
 | 
			
		||||
BIS1eyhjif1mE7Lqhs6aPD+eqQK2mBtQ/sidN8P/IfKfVF5siXfFbuGZLz5nRIho
 | 
			
		||||
Yp1z7oO3OZ09lpUk0G1h+ouIFF6goDP48M/AKtbvs9OWk3QKxnOUZD8sRncq95x6
 | 
			
		||||
m4q1MVb+aJyxwBqDRGaFY+3TVArB1b+kG1JsAvV5dag=
 | 
			
		||||
=511T
 | 
			
		||||
-----END PGP PRIVATE KEY BLOCK-----
 | 
			
		||||
 
 | 
			
		||||
@@ -194,7 +194,7 @@ func TestCantMergeWorkInProgress(t *testing.T) {
 | 
			
		||||
		req := NewRequest(t, "GET", resp.Header().Get("Location"))
 | 
			
		||||
		resp = session.MakeRequest(t, req, http.StatusOK)
 | 
			
		||||
		htmlDoc := NewHTMLParser(t, resp.Body)
 | 
			
		||||
		text := strings.TrimSpace(htmlDoc.doc.Find(".attached.header > .text.grey").Last().Text())
 | 
			
		||||
		text := strings.TrimSpace(htmlDoc.doc.Find(".attached.merge-section.no-header > .text.grey").Last().Text())
 | 
			
		||||
		assert.NotEmpty(t, text, "Can't find WIP text")
 | 
			
		||||
 | 
			
		||||
		// remove <strong /> from lang
 | 
			
		||||
 
 | 
			
		||||
@@ -10,6 +10,7 @@ import (
 | 
			
		||||
	"testing"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/modules/setting"
 | 
			
		||||
	"code.gitea.io/gitea/modules/test"
 | 
			
		||||
 | 
			
		||||
	"github.com/stretchr/testify/assert"
 | 
			
		||||
@@ -106,6 +107,12 @@ func TestCreateReleaseDraft(t *testing.T) {
 | 
			
		||||
func TestCreateReleasePaging(t *testing.T) {
 | 
			
		||||
	defer prepareTestEnv(t)()
 | 
			
		||||
 | 
			
		||||
	oldAPIDefaultNum := setting.API.DefaultPagingNum
 | 
			
		||||
	defer func() {
 | 
			
		||||
		setting.API.DefaultPagingNum = oldAPIDefaultNum
 | 
			
		||||
	}()
 | 
			
		||||
	setting.API.DefaultPagingNum = 10
 | 
			
		||||
 | 
			
		||||
	session := loginUser(t, "user2")
 | 
			
		||||
	// Create enaugh releases to have paging
 | 
			
		||||
	for i := 0; i < 12; i++ {
 | 
			
		||||
 
 | 
			
		||||
@@ -14,7 +14,7 @@ import (
 | 
			
		||||
	api "code.gitea.io/gitea/modules/structs"
 | 
			
		||||
	"code.gitea.io/gitea/modules/timeutil"
 | 
			
		||||
 | 
			
		||||
	gouuid "github.com/satori/go.uuid"
 | 
			
		||||
	gouuid "github.com/google/uuid"
 | 
			
		||||
	"xorm.io/xorm"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@@ -97,7 +97,7 @@ func (a *Attachment) LinkedRepository() (*Repository, UnitType, error) {
 | 
			
		||||
 | 
			
		||||
// NewAttachment creates a new attachment object.
 | 
			
		||||
func NewAttachment(attach *Attachment, buf []byte, file io.Reader) (_ *Attachment, err error) {
 | 
			
		||||
	attach.UUID = gouuid.NewV4().String()
 | 
			
		||||
	attach.UUID = gouuid.New().String()
 | 
			
		||||
 | 
			
		||||
	localPath := attach.LocalPath()
 | 
			
		||||
	if err = os.MkdirAll(path.Dir(localPath), os.ModePerm); err != nil {
 | 
			
		||||
@@ -136,9 +136,8 @@ func GetAttachmentByID(id int64) (*Attachment, error) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getAttachmentByID(e Engine, id int64) (*Attachment, error) {
 | 
			
		||||
	attach := &Attachment{ID: id}
 | 
			
		||||
 | 
			
		||||
	if has, err := e.Get(attach); err != nil {
 | 
			
		||||
	attach := &Attachment{}
 | 
			
		||||
	if has, err := e.ID(id).Get(attach); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	} else if !has {
 | 
			
		||||
		return nil, ErrAttachmentNotExist{ID: id, UUID: ""}
 | 
			
		||||
@@ -147,8 +146,8 @@ func getAttachmentByID(e Engine, id int64) (*Attachment, error) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getAttachmentByUUID(e Engine, uuid string) (*Attachment, error) {
 | 
			
		||||
	attach := &Attachment{UUID: uuid}
 | 
			
		||||
	has, err := e.Get(attach)
 | 
			
		||||
	attach := &Attachment{}
 | 
			
		||||
	has, err := e.Where("uuid=?", uuid).Get(attach)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	} else if !has {
 | 
			
		||||
 
 | 
			
		||||
@@ -240,8 +240,8 @@ func getProtectedBranchBy(e Engine, repoID int64, branchName string) (*Protected
 | 
			
		||||
 | 
			
		||||
// GetProtectedBranchByID getting protected branch by ID
 | 
			
		||||
func GetProtectedBranchByID(id int64) (*ProtectedBranch, error) {
 | 
			
		||||
	rel := &ProtectedBranch{ID: id}
 | 
			
		||||
	has, err := x.Get(rel)
 | 
			
		||||
	rel := &ProtectedBranch{}
 | 
			
		||||
	has, err := x.ID(id).Get(rel)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
@@ -509,9 +509,9 @@ func (repo *Repository) GetDeletedBranches() ([]*DeletedBranch, error) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetDeletedBranchByID get a deleted branch by its ID
 | 
			
		||||
func (repo *Repository) GetDeletedBranchByID(ID int64) (*DeletedBranch, error) {
 | 
			
		||||
	deletedBranch := &DeletedBranch{ID: ID}
 | 
			
		||||
	has, err := x.Get(deletedBranch)
 | 
			
		||||
func (repo *Repository) GetDeletedBranchByID(id int64) (*DeletedBranch, error) {
 | 
			
		||||
	deletedBranch := &DeletedBranch{}
 | 
			
		||||
	has, err := x.ID(id).Get(deletedBranch)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -10,6 +10,7 @@ import (
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"github.com/stretchr/testify/assert"
 | 
			
		||||
	"xorm.io/builder"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// consistencyCheckable a type that can be tested for database consistency
 | 
			
		||||
@@ -167,3 +168,130 @@ func (action *Action) checkForConsistency(t *testing.T) {
 | 
			
		||||
	repo := AssertExistsAndLoadBean(t, &Repository{ID: action.RepoID}).(*Repository)
 | 
			
		||||
	assert.Equal(t, repo.IsPrivate, action.IsPrivate, "action: %+v", action)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CountOrphanedLabels return count of labels witch are broken and not accessible via ui anymore
 | 
			
		||||
func CountOrphanedLabels() (int64, error) {
 | 
			
		||||
	noref, err := x.Table("label").Where("repo_id=? AND org_id=?", 0, 0).Count("label.id")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	norepo, err := x.Table("label").
 | 
			
		||||
		Join("LEFT", "repository", "label.repo_id=repository.id").
 | 
			
		||||
		Where(builder.IsNull{"repository.id"}).And(builder.Gt{"label.repo_id": 0}).
 | 
			
		||||
		Count("id")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	noorg, err := x.Table("label").
 | 
			
		||||
		Join("LEFT", "`user`", "label.org_id=`user`.id").
 | 
			
		||||
		Where(builder.IsNull{"`user`.id"}).And(builder.Gt{"label.org_id": 0}).
 | 
			
		||||
		Count("id")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return noref + norepo + noorg, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeleteOrphanedLabels delete labels witch are broken and not accessible via ui anymore
 | 
			
		||||
func DeleteOrphanedLabels() error {
 | 
			
		||||
	// delete labels with no reference
 | 
			
		||||
	if _, err := x.Table("label").Where("repo_id=? AND org_id=?", 0, 0).Delete(new(Label)); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// delete labels with none existing repos
 | 
			
		||||
	if _, err := x.In("id", builder.Select("label.id").From("label").
 | 
			
		||||
		Join("LEFT", "repository", "label.repo_id=repository.id").
 | 
			
		||||
		Where(builder.IsNull{"repository.id"}).And(builder.Gt{"label.repo_id": 0})).
 | 
			
		||||
		Delete(Label{}); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// delete labels with none existing orgs
 | 
			
		||||
	if _, err := x.In("id", builder.Select("label.id").From("label").
 | 
			
		||||
		Join("LEFT", "`user`", "label.org_id=`user`.id").
 | 
			
		||||
		Where(builder.IsNull{"`user`.id"}).And(builder.Gt{"label.org_id": 0})).
 | 
			
		||||
		Delete(Label{}); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CountOrphanedIssues count issues without a repo
 | 
			
		||||
func CountOrphanedIssues() (int64, error) {
 | 
			
		||||
	return x.Table("issue").
 | 
			
		||||
		Join("LEFT", "repository", "issue.repo_id=repository.id").
 | 
			
		||||
		Where(builder.IsNull{"repository.id"}).
 | 
			
		||||
		Count("id")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeleteOrphanedIssues delete issues without a repo
 | 
			
		||||
func DeleteOrphanedIssues() error {
 | 
			
		||||
	sess := x.NewSession()
 | 
			
		||||
	defer sess.Close()
 | 
			
		||||
	if err := sess.Begin(); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var ids []int64
 | 
			
		||||
 | 
			
		||||
	if err := sess.Table("issue").Distinct("issue.repo_id").
 | 
			
		||||
		Join("LEFT", "repository", "issue.repo_id=repository.id").
 | 
			
		||||
		Where(builder.IsNull{"repository.id"}).GroupBy("issue.repo_id").
 | 
			
		||||
		Find(&ids); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var attachmentPaths []string
 | 
			
		||||
	for i := range ids {
 | 
			
		||||
		paths, err := deleteIssuesByRepoID(sess, ids[i])
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		attachmentPaths = append(attachmentPaths, paths...)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := sess.Commit(); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Remove issue attachment files.
 | 
			
		||||
	for i := range attachmentPaths {
 | 
			
		||||
		removeAllWithNotice(x, "Delete issue attachment", attachmentPaths[i])
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CountOrphanedObjects count subjects with have no existing refobject anymore
 | 
			
		||||
func CountOrphanedObjects(subject, refobject, joinCond string) (int64, error) {
 | 
			
		||||
	return x.Table("`"+subject+"`").
 | 
			
		||||
		Join("LEFT", refobject, joinCond).
 | 
			
		||||
		Where(builder.IsNull{"`" + refobject + "`.id"}).
 | 
			
		||||
		Count("id")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeleteOrphanedObjects delete subjects with have no existing refobject anymore
 | 
			
		||||
func DeleteOrphanedObjects(subject, refobject, joinCond string) error {
 | 
			
		||||
	_, err := x.In("id", builder.Select("`"+subject+"`.id").
 | 
			
		||||
		From("`"+subject+"`").
 | 
			
		||||
		Join("LEFT", "`"+refobject+"`", joinCond).
 | 
			
		||||
		Where(builder.IsNull{"`" + refobject + "`.id"})).
 | 
			
		||||
		Delete("`" + subject + "`")
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CountNullArchivedRepository counts the number of repositories with is_archived is null
 | 
			
		||||
func CountNullArchivedRepository() (int64, error) {
 | 
			
		||||
	return x.Where(builder.IsNull{"is_archived"}).Count(new(Repository))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FixNullArchivedRepository sets is_archived to false where it is null
 | 
			
		||||
func FixNullArchivedRepository() (int64, error) {
 | 
			
		||||
	return x.Where(builder.IsNull{"is_archived"}).Cols("is_archived").Update(&Repository{
 | 
			
		||||
		IsArchived: false,
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -273,7 +273,7 @@ func parseGPGKey(ownerID int64, e *openpgp.Entity) (*GPGKey, error) {
 | 
			
		||||
	for i, k := range e.Subkeys {
 | 
			
		||||
		subs, err := parseSubGPGKey(ownerID, pubkey.KeyIdString(), k.PublicKey, expiry)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
			return nil, ErrGPGKeyParsing{ParseError: err}
 | 
			
		||||
		}
 | 
			
		||||
		subkeys[i] = subs
 | 
			
		||||
	}
 | 
			
		||||
@@ -741,6 +741,21 @@ func verifyWithGPGSettings(gpgSettings *git.GPGSettings, sig *packet.Signature,
 | 
			
		||||
		CanSign: pubkey.CanSign(),
 | 
			
		||||
		KeyID:   pubkey.KeyIdString(),
 | 
			
		||||
	}
 | 
			
		||||
	for _, subKey := range ekey.Subkeys {
 | 
			
		||||
		content, err := base64EncPubKey(subKey.PublicKey)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return &CommitVerification{
 | 
			
		||||
				CommittingUser: committer,
 | 
			
		||||
				Verified:       false,
 | 
			
		||||
				Reason:         "gpg.error.generate_hash",
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		k.SubsKey = append(k.SubsKey, &GPGKey{
 | 
			
		||||
			Content: content,
 | 
			
		||||
			CanSign: subKey.PublicKey.CanSign(),
 | 
			
		||||
			KeyID:   subKey.PublicKey.KeyIdString(),
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
	if commitVerification := hashAndVerifyWithSubKeys(sig, payload, k, committer, &User{
 | 
			
		||||
		Name:  gpgSettings.Name,
 | 
			
		||||
		Email: gpgSettings.Email,
 | 
			
		||||
 
 | 
			
		||||
@@ -76,7 +76,6 @@ var (
 | 
			
		||||
const issueTasksRegexpStr = `(^\s*[-*]\s\[[\sxX]\]\s.)|(\n\s*[-*]\s\[[\sxX]\]\s.)`
 | 
			
		||||
const issueTasksDoneRegexpStr = `(^\s*[-*]\s\[[xX]\]\s.)|(\n\s*[-*]\s\[[xX]\]\s.)`
 | 
			
		||||
const issueMaxDupIndexAttempts = 3
 | 
			
		||||
const maxIssueIDs = 950
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	issueTasksPat = regexp.MustCompile(issueTasksRegexpStr)
 | 
			
		||||
@@ -249,7 +248,7 @@ func (issue *Issue) loadReactions(e Engine) (err error) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (issue *Issue) loadMilestone(e Engine) (err error) {
 | 
			
		||||
	if issue.Milestone == nil && issue.MilestoneID > 0 {
 | 
			
		||||
	if (issue.Milestone == nil || issue.Milestone.ID != issue.MilestoneID) && issue.MilestoneID > 0 {
 | 
			
		||||
		issue.Milestone, err = getMilestoneByRepoID(e, issue.RepoID, issue.MilestoneID)
 | 
			
		||||
		if err != nil && !IsErrMilestoneNotExist(err) {
 | 
			
		||||
			return fmt.Errorf("getMilestoneByRepoID [repo_id: %d, milestone_id: %d]: %v", issue.RepoID, issue.MilestoneID, err)
 | 
			
		||||
@@ -1114,9 +1113,6 @@ func (opts *IssuesOptions) setupSession(sess *xorm.Session) {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(opts.IssueIDs) > 0 {
 | 
			
		||||
		if len(opts.IssueIDs) > maxIssueIDs {
 | 
			
		||||
			opts.IssueIDs = opts.IssueIDs[:maxIssueIDs]
 | 
			
		||||
		}
 | 
			
		||||
		sess.In("issue.id", opts.IssueIDs)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -1360,9 +1356,6 @@ func getIssueStatsChunk(opts *IssueStatsOptions, issueIDs []int64) (*IssueStats,
 | 
			
		||||
			Where("issue.repo_id = ?", opts.RepoID)
 | 
			
		||||
 | 
			
		||||
		if len(opts.IssueIDs) > 0 {
 | 
			
		||||
			if len(opts.IssueIDs) > maxIssueIDs {
 | 
			
		||||
				opts.IssueIDs = opts.IssueIDs[:maxIssueIDs]
 | 
			
		||||
			}
 | 
			
		||||
			sess.In("issue.id", opts.IssueIDs)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@@ -1446,9 +1439,6 @@ func GetUserIssueStats(opts UserIssueStatsOptions) (*IssueStats, error) {
 | 
			
		||||
		cond = cond.And(builder.In("issue.repo_id", opts.RepoIDs))
 | 
			
		||||
	}
 | 
			
		||||
	if len(opts.IssueIDs) > 0 {
 | 
			
		||||
		if len(opts.IssueIDs) > maxIssueIDs {
 | 
			
		||||
			opts.IssueIDs = opts.IssueIDs[:maxIssueIDs]
 | 
			
		||||
		}
 | 
			
		||||
		cond = cond.And(builder.In("issue.id", opts.IssueIDs))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -1916,3 +1906,70 @@ func UpdateReactionsMigrationsByType(gitServiceType structs.GitServiceType, orig
 | 
			
		||||
		})
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func deleteIssuesByRepoID(sess Engine, repoID int64) (attachmentPaths []string, err error) {
 | 
			
		||||
	deleteCond := builder.Select("id").From("issue").Where(builder.Eq{"issue.repo_id": repoID})
 | 
			
		||||
 | 
			
		||||
	// Delete comments and attachments
 | 
			
		||||
	if _, err = sess.In("issue_id", deleteCond).
 | 
			
		||||
		Delete(&Comment{}); err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Dependencies for issues in this repository
 | 
			
		||||
	if _, err = sess.In("issue_id", deleteCond).
 | 
			
		||||
		Delete(&IssueDependency{}); err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Delete dependencies for issues in other repositories
 | 
			
		||||
	if _, err = sess.In("dependency_id", deleteCond).
 | 
			
		||||
		Delete(&IssueDependency{}); err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if _, err = sess.In("issue_id", deleteCond).
 | 
			
		||||
		Delete(&IssueUser{}); err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if _, err = sess.In("issue_id", deleteCond).
 | 
			
		||||
		Delete(&Reaction{}); err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if _, err = sess.In("issue_id", deleteCond).
 | 
			
		||||
		Delete(&IssueWatch{}); err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if _, err = sess.In("issue_id", deleteCond).
 | 
			
		||||
		Delete(&Stopwatch{}); err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if _, err = sess.In("issue_id", deleteCond).
 | 
			
		||||
		Delete(&TrackedTime{}); err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var attachments []*Attachment
 | 
			
		||||
	if err = sess.In("issue_id", deleteCond).
 | 
			
		||||
		Find(&attachments); err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	for j := range attachments {
 | 
			
		||||
		attachmentPaths = append(attachmentPaths, attachments[j].LocalPath())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if _, err = sess.In("issue_id", deleteCond).
 | 
			
		||||
		Delete(&Attachment{}); err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if _, err = sess.Delete(&Issue{RepoID: repoID}); err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -8,7 +8,10 @@ package models
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"regexp"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"unicode/utf8"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/modules/git"
 | 
			
		||||
	"code.gitea.io/gitea/modules/log"
 | 
			
		||||
@@ -138,7 +141,8 @@ type Comment struct {
 | 
			
		||||
	RenderedContent string `xorm:"-"`
 | 
			
		||||
 | 
			
		||||
	// Path represents the 4 lines of code cemented by this comment
 | 
			
		||||
	Patch string `xorm:"TEXT"`
 | 
			
		||||
	Patch       string `xorm:"-"`
 | 
			
		||||
	PatchQuoted string `xorm:"TEXT patch"`
 | 
			
		||||
 | 
			
		||||
	CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
 | 
			
		||||
	UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
 | 
			
		||||
@@ -182,6 +186,33 @@ func (c *Comment) loadIssue(e Engine) (err error) {
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// BeforeInsert will be invoked by XORM before inserting a record
 | 
			
		||||
func (c *Comment) BeforeInsert() {
 | 
			
		||||
	c.PatchQuoted = c.Patch
 | 
			
		||||
	if !utf8.ValidString(c.Patch) {
 | 
			
		||||
		c.PatchQuoted = strconv.Quote(c.Patch)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// BeforeUpdate will be invoked by XORM before updating a record
 | 
			
		||||
func (c *Comment) BeforeUpdate() {
 | 
			
		||||
	c.PatchQuoted = c.Patch
 | 
			
		||||
	if !utf8.ValidString(c.Patch) {
 | 
			
		||||
		c.PatchQuoted = strconv.Quote(c.Patch)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AfterLoad is invoked from XORM after setting the values of all fields of this object.
 | 
			
		||||
func (c *Comment) AfterLoad(session *xorm.Session) {
 | 
			
		||||
	c.Patch = c.PatchQuoted
 | 
			
		||||
	if len(c.PatchQuoted) > 0 && c.PatchQuoted[0] == '"' {
 | 
			
		||||
		unquoted, err := strconv.Unquote(c.PatchQuoted)
 | 
			
		||||
		if err == nil {
 | 
			
		||||
			c.Patch = unquoted
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Comment) loadPoster(e Engine) (err error) {
 | 
			
		||||
	if c.PosterID <= 0 || c.Poster != nil {
 | 
			
		||||
		return nil
 | 
			
		||||
@@ -489,10 +520,12 @@ func (c *Comment) LoadReview() error {
 | 
			
		||||
	return c.loadReview(x)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var notEnoughLines = regexp.MustCompile(`fatal: file .* has only \d+ lines?`)
 | 
			
		||||
 | 
			
		||||
func (c *Comment) checkInvalidation(doer *User, repo *git.Repository, branch string) error {
 | 
			
		||||
	// FIXME differentiate between previous and proposed line
 | 
			
		||||
	commit, err := repo.LineBlame(branch, repo.Path, c.TreePath, uint(c.UnsignedLine()))
 | 
			
		||||
	if err != nil && strings.Contains(err.Error(), "fatal: no such path") {
 | 
			
		||||
	if err != nil && (strings.Contains(err.Error(), "fatal: no such path") || notEnoughLines.MatchString(err.Error())) {
 | 
			
		||||
		c.Invalidated = true
 | 
			
		||||
		return UpdateComment(c, doer)
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -295,10 +295,8 @@ func getLabelByID(e Engine, labelID int64) (*Label, error) {
 | 
			
		||||
		return nil, ErrLabelNotExist{labelID}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	l := &Label{
 | 
			
		||||
		ID: labelID,
 | 
			
		||||
	}
 | 
			
		||||
	has, err := e.Get(l)
 | 
			
		||||
	l := &Label{}
 | 
			
		||||
	has, err := e.ID(labelID).Get(l)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	} else if !has {
 | 
			
		||||
 
 | 
			
		||||
@@ -38,7 +38,10 @@ func (opts ListOptions) setEnginePagination(e Engine) Engine {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (opts ListOptions) setDefaultValues() {
 | 
			
		||||
	if opts.PageSize <= 0 || opts.PageSize > setting.API.MaxResponseItems {
 | 
			
		||||
	if opts.PageSize <= 0 {
 | 
			
		||||
		opts.PageSize = setting.API.DefaultPagingNum
 | 
			
		||||
	}
 | 
			
		||||
	if opts.PageSize > setting.API.MaxResponseItems {
 | 
			
		||||
		opts.PageSize = setting.API.MaxResponseItems
 | 
			
		||||
	}
 | 
			
		||||
	if opts.Page <= 0 {
 | 
			
		||||
 
 | 
			
		||||
@@ -300,7 +300,7 @@ func (source *LoginSource) SSPI() *SSPIConfig {
 | 
			
		||||
// CreateLoginSource inserts a LoginSource in the DB if not already
 | 
			
		||||
// existing with the given name.
 | 
			
		||||
func CreateLoginSource(source *LoginSource) error {
 | 
			
		||||
	has, err := x.Get(&LoginSource{Name: source.Name})
 | 
			
		||||
	has, err := x.Where("name=?", source.Name).Exist(new(LoginSource))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	} else if has {
 | 
			
		||||
 
 | 
			
		||||
@@ -212,6 +212,8 @@ var migrations = []Migration{
 | 
			
		||||
	NewMigration("Add ResolveDoerID to Comment table", addResolveDoerIDCommentColumn),
 | 
			
		||||
	// v139 -> v140
 | 
			
		||||
	NewMigration("prepend refs/heads/ to issue refs", prependRefsHeadsToIssueRefs),
 | 
			
		||||
	// v140 -> v141
 | 
			
		||||
	NewMigration("Save detected language file size to database instead of percent", fixLanguageStatsToSaveSize),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetCurrentDBVersion returns the current db version
 | 
			
		||||
 
 | 
			
		||||
@@ -8,8 +8,10 @@ import (
 | 
			
		||||
	"crypto/md5"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"math"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/modules/log"
 | 
			
		||||
	"code.gitea.io/gitea/modules/setting"
 | 
			
		||||
@@ -26,8 +28,19 @@ func renameExistingUserAvatarName(x *xorm.Engine) error {
 | 
			
		||||
		LowerName string `xorm:"UNIQUE NOT NULL"`
 | 
			
		||||
		Avatar    string
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ticker := time.NewTicker(5 * time.Second)
 | 
			
		||||
	defer ticker.Stop()
 | 
			
		||||
 | 
			
		||||
	count, err := x.Count(new(User))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	log.Info("%d User Avatar(s) to migrate ...", count)
 | 
			
		||||
 | 
			
		||||
	deleteList := make(map[string]struct{})
 | 
			
		||||
	start := 0
 | 
			
		||||
	migrated := 0
 | 
			
		||||
	for {
 | 
			
		||||
		if err := sess.Begin(); err != nil {
 | 
			
		||||
			return fmt.Errorf("session.Begin: %v", err)
 | 
			
		||||
@@ -73,6 +86,19 @@ func renameExistingUserAvatarName(x *xorm.Engine) error {
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			deleteList[filepath.Join(setting.AvatarUploadPath, oldAvatar)] = struct{}{}
 | 
			
		||||
			migrated++
 | 
			
		||||
			select {
 | 
			
		||||
			case <-ticker.C:
 | 
			
		||||
				log.Info(
 | 
			
		||||
					"%d/%d (%2.0f%%) User Avatar(s) migrated (%d old avatars to be deleted) in %d batches. %d Remaining ...",
 | 
			
		||||
					migrated,
 | 
			
		||||
					count,
 | 
			
		||||
					float64(migrated)/float64(count)*100,
 | 
			
		||||
					len(deleteList),
 | 
			
		||||
					int(math.Ceil(float64(migrated)/float64(50))),
 | 
			
		||||
					count-int64(migrated))
 | 
			
		||||
			default:
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if err := sess.Commit(); err != nil {
 | 
			
		||||
			_ = sess.Rollback()
 | 
			
		||||
@@ -80,11 +106,28 @@ func renameExistingUserAvatarName(x *xorm.Engine) error {
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	deleteCount := len(deleteList)
 | 
			
		||||
	log.Info("Deleting %d old avatars ...", deleteCount)
 | 
			
		||||
	i := 0
 | 
			
		||||
	for file := range deleteList {
 | 
			
		||||
		if err := os.Remove(file); err != nil {
 | 
			
		||||
			log.Warn("os.Remove: %v", err)
 | 
			
		||||
		}
 | 
			
		||||
		i++
 | 
			
		||||
		select {
 | 
			
		||||
		case <-ticker.C:
 | 
			
		||||
			log.Info(
 | 
			
		||||
				"%d/%d (%2.0f%%) Old User Avatar(s) deleted. %d Remaining ...",
 | 
			
		||||
				i,
 | 
			
		||||
				deleteCount,
 | 
			
		||||
				float64(i)/float64(deleteCount)*100,
 | 
			
		||||
				deleteCount-i)
 | 
			
		||||
		default:
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	log.Info("Completed migrating %d User Avatar(s) and deleting %d Old Avatars", count, deleteCount)
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -6,8 +6,10 @@ package migrations
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"math"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/modules/git"
 | 
			
		||||
	"code.gitea.io/gitea/modules/log"
 | 
			
		||||
@@ -43,17 +45,27 @@ func fixMergeBase(x *xorm.Engine) error {
 | 
			
		||||
		limit = 50
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ticker := time.NewTicker(5 * time.Second)
 | 
			
		||||
	defer ticker.Stop()
 | 
			
		||||
 | 
			
		||||
	count, err := x.Count(new(PullRequest))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	log.Info("%d Pull Request(s) to migrate ...", count)
 | 
			
		||||
 | 
			
		||||
	i := 0
 | 
			
		||||
	start := 0
 | 
			
		||||
	for {
 | 
			
		||||
		prs := make([]PullRequest, 0, 50)
 | 
			
		||||
		if err := x.Limit(limit, i).Asc("id").Find(&prs); err != nil {
 | 
			
		||||
		if err := x.Limit(limit, start).Asc("id").Find(&prs); err != nil {
 | 
			
		||||
			return fmt.Errorf("Find: %v", err)
 | 
			
		||||
		}
 | 
			
		||||
		if len(prs) == 0 {
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		i += len(prs)
 | 
			
		||||
		start += 50
 | 
			
		||||
		for _, pr := range prs {
 | 
			
		||||
			baseRepo := &Repository{ID: pr.BaseRepoID}
 | 
			
		||||
			has, err := x.Table("repository").Get(baseRepo)
 | 
			
		||||
@@ -102,8 +114,14 @@ func fixMergeBase(x *xorm.Engine) error {
 | 
			
		||||
			}
 | 
			
		||||
			pr.MergeBase = strings.TrimSpace(pr.MergeBase)
 | 
			
		||||
			x.ID(pr.ID).Cols("merge_base").Update(pr)
 | 
			
		||||
			i++
 | 
			
		||||
			select {
 | 
			
		||||
			case <-ticker.C:
 | 
			
		||||
				log.Info("%d/%d (%2.0f%%) Pull Request(s) migrated in %d batches. %d PRs Remaining ...", i, count, float64(i)/float64(count)*100, int(math.Ceil(float64(i)/float64(limit))), count-int64(i))
 | 
			
		||||
			default:
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
	log.Info("Completed migrating %d Pull Request(s) in: %d batches", count, int(math.Ceil(float64(i)/float64(limit))))
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -6,8 +6,10 @@ package migrations
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"math"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/modules/git"
 | 
			
		||||
	"code.gitea.io/gitea/modules/log"
 | 
			
		||||
@@ -43,17 +45,26 @@ func refixMergeBase(x *xorm.Engine) error {
 | 
			
		||||
		limit = 50
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ticker := time.NewTicker(5 * time.Second)
 | 
			
		||||
	defer ticker.Stop()
 | 
			
		||||
	count, err := x.Where("has_merged = ?", true).Count(new(PullRequest))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	log.Info("%d Merged Pull Request(s) to migrate ...", count)
 | 
			
		||||
 | 
			
		||||
	i := 0
 | 
			
		||||
	start := 0
 | 
			
		||||
	for {
 | 
			
		||||
		prs := make([]PullRequest, 0, 50)
 | 
			
		||||
		if err := x.Limit(limit, i).Asc("id").Where("has_merged = ?", true).Find(&prs); err != nil {
 | 
			
		||||
		if err := x.Limit(limit, start).Asc("id").Where("has_merged = ?", true).Find(&prs); err != nil {
 | 
			
		||||
			return fmt.Errorf("Find: %v", err)
 | 
			
		||||
		}
 | 
			
		||||
		if len(prs) == 0 {
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		i += len(prs)
 | 
			
		||||
		start += 50
 | 
			
		||||
		for _, pr := range prs {
 | 
			
		||||
			baseRepo := &Repository{ID: pr.BaseRepoID}
 | 
			
		||||
			has, err := x.Table("repository").Get(baseRepo)
 | 
			
		||||
@@ -90,7 +101,15 @@ func refixMergeBase(x *xorm.Engine) error {
 | 
			
		||||
			}
 | 
			
		||||
			pr.MergeBase = strings.TrimSpace(pr.MergeBase)
 | 
			
		||||
			x.ID(pr.ID).Cols("merge_base").Update(pr)
 | 
			
		||||
			i++
 | 
			
		||||
			select {
 | 
			
		||||
			case <-ticker.C:
 | 
			
		||||
				log.Info("%d/%d (%2.0f%%) Pull Request(s) migrated in %d batches. %d PRs Remaining ...", i, count, float64(i)/float64(count)*100, int(math.Ceil(float64(i)/float64(limit))), count-int64(i))
 | 
			
		||||
			default:
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	log.Info("Completed migrating %d Pull Request(s) in: %d batches", count, int(math.Ceil(float64(i)/float64(limit))))
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -6,25 +6,60 @@ package migrations
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"math"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/models"
 | 
			
		||||
	"code.gitea.io/gitea/modules/git"
 | 
			
		||||
	"code.gitea.io/gitea/modules/log"
 | 
			
		||||
	"code.gitea.io/gitea/modules/setting"
 | 
			
		||||
	pull_service "code.gitea.io/gitea/services/pull"
 | 
			
		||||
 | 
			
		||||
	"xorm.io/xorm"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func addCommitDivergenceToPulls(x *xorm.Engine) error {
 | 
			
		||||
	type Repository struct {
 | 
			
		||||
		ID        int64 `xorm:"pk autoincr"`
 | 
			
		||||
		OwnerID   int64 `xorm:"UNIQUE(s) index"`
 | 
			
		||||
		OwnerName string
 | 
			
		||||
		LowerName string `xorm:"UNIQUE(s) INDEX NOT NULL"`
 | 
			
		||||
		Name      string `xorm:"INDEX NOT NULL"`
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	type PullRequest struct {
 | 
			
		||||
		ID int64 `xorm:"pk autoincr"`
 | 
			
		||||
 | 
			
		||||
		CommitsAhead  int
 | 
			
		||||
		CommitsBehind int
 | 
			
		||||
 | 
			
		||||
		BaseRepoID int64 `xorm:"INDEX"`
 | 
			
		||||
		BaseBranch string
 | 
			
		||||
 | 
			
		||||
		HasMerged      bool   `xorm:"INDEX"`
 | 
			
		||||
		MergedCommitID string `xorm:"VARCHAR(40)"`
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := x.Sync2(new(models.PullRequest)); err != nil {
 | 
			
		||||
		return fmt.Errorf("Sync2: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var last int
 | 
			
		||||
	last := 0
 | 
			
		||||
	migrated := 0
 | 
			
		||||
 | 
			
		||||
	batchSize := setting.Database.IterateBufferSize
 | 
			
		||||
	sess := x.NewSession()
 | 
			
		||||
	defer sess.Close()
 | 
			
		||||
 | 
			
		||||
	ticker := time.NewTicker(5 * time.Second)
 | 
			
		||||
	defer ticker.Stop()
 | 
			
		||||
	count, err := sess.Where("has_merged = ?", false).Count(new(PullRequest))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	log.Info("%d Unmerged Pull Request(s) to migrate ...", count)
 | 
			
		||||
 | 
			
		||||
	for {
 | 
			
		||||
		if err := sess.Begin(); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
@@ -37,27 +72,53 @@ func addCommitDivergenceToPulls(x *xorm.Engine) error {
 | 
			
		||||
		if len(results) == 0 {
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
		last += len(results)
 | 
			
		||||
		last += batchSize
 | 
			
		||||
 | 
			
		||||
		for _, pr := range results {
 | 
			
		||||
			divergence, err := pull_service.GetDiverging(pr)
 | 
			
		||||
			baseRepo := &Repository{ID: pr.BaseRepoID}
 | 
			
		||||
			has, err := x.Table("repository").Get(baseRepo)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return fmt.Errorf("Unable to get base repo %d %v", pr.BaseRepoID, err)
 | 
			
		||||
			}
 | 
			
		||||
			if !has {
 | 
			
		||||
				log.Error("Missing base repo with id %d for PR ID %d", pr.BaseRepoID, pr.ID)
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			userPath := filepath.Join(setting.RepoRootPath, strings.ToLower(baseRepo.OwnerName))
 | 
			
		||||
			repoPath := filepath.Join(userPath, strings.ToLower(baseRepo.Name)+".git")
 | 
			
		||||
 | 
			
		||||
			gitRefName := fmt.Sprintf("refs/pull/%d/head", pr.Index)
 | 
			
		||||
 | 
			
		||||
			divergence, err := git.GetDivergingCommits(repoPath, pr.BaseBranch, gitRefName)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				log.Warn("Could not recalculate Divergence for pull: %d", pr.ID)
 | 
			
		||||
				pr.CommitsAhead = 0
 | 
			
		||||
				pr.CommitsBehind = 0
 | 
			
		||||
			}
 | 
			
		||||
			if divergence != nil {
 | 
			
		||||
			pr.CommitsAhead = divergence.Ahead
 | 
			
		||||
			pr.CommitsBehind = divergence.Behind
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if _, err = sess.ID(pr.ID).Cols("commits_ahead", "commits_behind").Update(pr); err != nil {
 | 
			
		||||
				return fmt.Errorf("Update Cols: %v", err)
 | 
			
		||||
			}
 | 
			
		||||
			migrated++
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if err := sess.Commit(); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		select {
 | 
			
		||||
		case <-ticker.C:
 | 
			
		||||
			log.Info(
 | 
			
		||||
				"%d/%d (%2.0f%%) Pull Request(s) migrated in %d batches. %d PRs Remaining ...",
 | 
			
		||||
				migrated,
 | 
			
		||||
				count,
 | 
			
		||||
				float64(migrated)/float64(count)*100,
 | 
			
		||||
				int(math.Ceil(float64(migrated)/float64(batchSize))),
 | 
			
		||||
				count-int64(migrated))
 | 
			
		||||
		default:
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	log.Info("Completed migrating %d Pull Request(s) in: %d batches", count, int(math.Ceil(float64(migrated)/float64(batchSize))))
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										56
									
								
								models/migrations/v140.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								models/migrations/v140.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,56 @@
 | 
			
		||||
// Copyright 2020 The Gitea Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a MIT-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package migrations
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/modules/setting"
 | 
			
		||||
 | 
			
		||||
	"xorm.io/xorm"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func fixLanguageStatsToSaveSize(x *xorm.Engine) error {
 | 
			
		||||
	// LanguageStat see models/repo_language_stats.go
 | 
			
		||||
	type LanguageStat struct {
 | 
			
		||||
		Size int64 `xorm:"NOT NULL DEFAULT 0"`
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// RepoIndexerType specifies the repository indexer type
 | 
			
		||||
	type RepoIndexerType int
 | 
			
		||||
 | 
			
		||||
	const (
 | 
			
		||||
		// RepoIndexerTypeCode code indexer
 | 
			
		||||
		RepoIndexerTypeCode RepoIndexerType = iota // 0
 | 
			
		||||
		// RepoIndexerTypeStats repository stats indexer
 | 
			
		||||
		RepoIndexerTypeStats // 1
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	// RepoIndexerStatus see models/repo_indexer.go
 | 
			
		||||
	type RepoIndexerStatus struct {
 | 
			
		||||
		IndexerType RepoIndexerType `xorm:"INDEX(s) NOT NULL DEFAULT 0"`
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := x.Sync2(new(LanguageStat)); err != nil {
 | 
			
		||||
		return fmt.Errorf("Sync2: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	x.Delete(&RepoIndexerStatus{IndexerType: RepoIndexerTypeStats})
 | 
			
		||||
 | 
			
		||||
	// Delete language stat statuses
 | 
			
		||||
	truncExpr := "TRUNCATE TABLE"
 | 
			
		||||
	if setting.Database.UseSQLite3 {
 | 
			
		||||
		truncExpr = "DELETE FROM"
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Delete language stats
 | 
			
		||||
	if _, err := x.Exec(fmt.Sprintf("%s language_stat", truncExpr)); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sess := x.NewSession()
 | 
			
		||||
	defer sess.Close()
 | 
			
		||||
	return dropTableColumns(sess, "language_stat", "percentage")
 | 
			
		||||
}
 | 
			
		||||
@@ -182,6 +182,10 @@ func SetEngine() (err error) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewEngine initializes a new xorm.Engine
 | 
			
		||||
// This function must never call .Sync2() if the provided migration function fails.
 | 
			
		||||
// When called from the "doctor" command, the migration function is a version check
 | 
			
		||||
// that prevents the doctor from fixing anything in the database if the migration level
 | 
			
		||||
// is different from the expected value.
 | 
			
		||||
func NewEngine(ctx context.Context, migrateFunc func(*xorm.Engine) error) (err error) {
 | 
			
		||||
	if err = SetEngine(); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,7 @@ import (
 | 
			
		||||
	"code.gitea.io/gitea/modules/timeutil"
 | 
			
		||||
 | 
			
		||||
	"github.com/dgrijalva/jwt-go"
 | 
			
		||||
	uuid "github.com/satori/go.uuid"
 | 
			
		||||
	uuid "github.com/google/uuid"
 | 
			
		||||
	"github.com/unknwon/com"
 | 
			
		||||
	"golang.org/x/crypto/bcrypt"
 | 
			
		||||
	"xorm.io/xorm"
 | 
			
		||||
@@ -174,7 +174,7 @@ func CreateOAuth2Application(opts CreateOAuth2ApplicationOptions) (*OAuth2Applic
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func createOAuth2Application(e Engine, opts CreateOAuth2ApplicationOptions) (*OAuth2Application, error) {
 | 
			
		||||
	clientID := uuid.NewV4().String()
 | 
			
		||||
	clientID := uuid.New().String()
 | 
			
		||||
	app := &OAuth2Application{
 | 
			
		||||
		UID:          opts.UserID,
 | 
			
		||||
		Name:         opts.Name,
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										101
									
								
								models/repo.go
									
									
									
									
									
								
							
							
						
						
									
										101
									
								
								models/repo.go
									
									
									
									
									
								
							@@ -175,6 +175,7 @@ type Repository struct {
 | 
			
		||||
	Status     RepositoryStatus `xorm:"NOT NULL DEFAULT 0"`
 | 
			
		||||
 | 
			
		||||
	RenderingMetas         map[string]string `xorm:"-"`
 | 
			
		||||
	DocumentRenderingMetas map[string]string `xorm:"-"`
 | 
			
		||||
	Units                  []*RepoUnit       `xorm:"-"`
 | 
			
		||||
	PrimaryLanguage        *LanguageStat     `xorm:"-"`
 | 
			
		||||
 | 
			
		||||
@@ -534,11 +535,12 @@ func (repo *Repository) mustOwner(e Engine) *User {
 | 
			
		||||
 | 
			
		||||
// ComposeMetas composes a map of metas for properly rendering issue links and external issue trackers.
 | 
			
		||||
func (repo *Repository) ComposeMetas() map[string]string {
 | 
			
		||||
	if repo.RenderingMetas == nil {
 | 
			
		||||
	if len(repo.RenderingMetas) == 0 {
 | 
			
		||||
		metas := map[string]string{
 | 
			
		||||
			"user":     repo.OwnerName,
 | 
			
		||||
			"repo":     repo.Name,
 | 
			
		||||
			"repoPath": repo.RepoPath(),
 | 
			
		||||
			"mode":     "comment",
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		unit, err := repo.GetUnit(UnitTypeExternalTracker)
 | 
			
		||||
@@ -570,6 +572,19 @@ func (repo *Repository) ComposeMetas() map[string]string {
 | 
			
		||||
	return repo.RenderingMetas
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ComposeDocumentMetas composes a map of metas for properly rendering documents
 | 
			
		||||
func (repo *Repository) ComposeDocumentMetas() map[string]string {
 | 
			
		||||
	if len(repo.DocumentRenderingMetas) == 0 {
 | 
			
		||||
		metas := map[string]string{}
 | 
			
		||||
		for k, v := range repo.ComposeMetas() {
 | 
			
		||||
			metas[k] = v
 | 
			
		||||
		}
 | 
			
		||||
		metas["mode"] = "document"
 | 
			
		||||
		repo.DocumentRenderingMetas = metas
 | 
			
		||||
	}
 | 
			
		||||
	return repo.DocumentRenderingMetas
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeleteWiki removes the actual and local copy of repository wiki.
 | 
			
		||||
func (repo *Repository) DeleteWiki() error {
 | 
			
		||||
	return repo.deleteWiki(x)
 | 
			
		||||
@@ -1575,67 +1590,9 @@ func DeleteRepository(doer *User, uid, repoID int64) error {
 | 
			
		||||
		return fmt.Errorf("deleteBeans: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	deleteCond := builder.Select("id").From("issue").Where(builder.Eq{"repo_id": repoID})
 | 
			
		||||
	// Delete comments and attachments
 | 
			
		||||
	if _, err = sess.In("issue_id", deleteCond).
 | 
			
		||||
		Delete(&Comment{}); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Dependencies for issues in this repository
 | 
			
		||||
	if _, err = sess.In("issue_id", deleteCond).
 | 
			
		||||
		Delete(&IssueDependency{}); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Delete dependencies for issues in other repositories
 | 
			
		||||
	if _, err = sess.In("dependency_id", deleteCond).
 | 
			
		||||
		Delete(&IssueDependency{}); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if _, err = sess.In("issue_id", deleteCond).
 | 
			
		||||
		Delete(&IssueUser{}); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if _, err = sess.In("issue_id", deleteCond).
 | 
			
		||||
		Delete(&Reaction{}); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if _, err = sess.In("issue_id", deleteCond).
 | 
			
		||||
		Delete(&IssueWatch{}); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if _, err = sess.In("issue_id", deleteCond).
 | 
			
		||||
		Delete(&Stopwatch{}); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if _, err = sess.In("issue_id", deleteCond).
 | 
			
		||||
		Delete(&TrackedTime{}); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	attachments = attachments[:0]
 | 
			
		||||
	if err = sess.Join("INNER", "issue", "issue.id = attachment.issue_id").
 | 
			
		||||
		Where("issue.repo_id = ?", repoID).
 | 
			
		||||
		Find(&attachments); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	attachmentPaths := make([]string, 0, len(attachments))
 | 
			
		||||
	for j := range attachments {
 | 
			
		||||
		attachmentPaths = append(attachmentPaths, attachments[j].LocalPath())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if _, err = sess.In("issue_id", deleteCond).
 | 
			
		||||
		Delete(&Attachment{}); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if _, err = sess.Delete(&Issue{RepoID: repoID}); err != nil {
 | 
			
		||||
	// Delete Issues and related objects
 | 
			
		||||
	var attachmentPaths []string
 | 
			
		||||
	if attachmentPaths, err = deleteIssuesByRepoID(sess, repoID); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -1798,22 +1755,28 @@ func GetRepositoriesMapByIDs(ids []int64) (map[int64]*Repository, error) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetUserRepositories returns a list of repositories of given user.
 | 
			
		||||
func GetUserRepositories(opts *SearchRepoOptions) ([]*Repository, error) {
 | 
			
		||||
func GetUserRepositories(opts *SearchRepoOptions) ([]*Repository, int64, error) {
 | 
			
		||||
	if len(opts.OrderBy) == 0 {
 | 
			
		||||
		opts.OrderBy = "updated_unix DESC"
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sess := x.
 | 
			
		||||
		Where("owner_id = ?", opts.Actor.ID).
 | 
			
		||||
		OrderBy(opts.OrderBy.String())
 | 
			
		||||
	var cond = builder.NewCond()
 | 
			
		||||
	cond = cond.And(builder.Eq{"owner_id": opts.Actor.ID})
 | 
			
		||||
	if !opts.Private {
 | 
			
		||||
		sess.And("is_private=?", false)
 | 
			
		||||
		cond = cond.And(builder.Eq{"is_private": false})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sess = opts.setSessionPagination(sess)
 | 
			
		||||
	sess := x.NewSession()
 | 
			
		||||
	defer sess.Close()
 | 
			
		||||
 | 
			
		||||
	count, err := sess.Where(cond).Count(new(Repository))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, 0, fmt.Errorf("Count: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sess.Where(cond).OrderBy(opts.OrderBy.String())
 | 
			
		||||
	repos := make([]*Repository, 0, opts.PageSize)
 | 
			
		||||
	return repos, opts.setSessionPagination(sess).Find(&repos)
 | 
			
		||||
	return repos, count, opts.setSessionPagination(sess).Find(&repos)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetUserMirrorRepositories returns a list of mirror repositories of given user.
 | 
			
		||||
 
 | 
			
		||||
@@ -20,7 +20,8 @@ type LanguageStat struct {
 | 
			
		||||
	CommitID    string
 | 
			
		||||
	IsPrimary   bool
 | 
			
		||||
	Language    string             `xorm:"VARCHAR(30) UNIQUE(s) INDEX NOT NULL"`
 | 
			
		||||
	Percentage  float32            `xorm:"NUMERIC(5,2) NOT NULL DEFAULT 0"`
 | 
			
		||||
	Percentage  float32            `xorm:"-"`
 | 
			
		||||
	Size        int64              `xorm:"NOT NULL DEFAULT 0"`
 | 
			
		||||
	Color       string             `xorm:"-"`
 | 
			
		||||
	CreatedUnix timeutil.TimeStamp `xorm:"INDEX CREATED"`
 | 
			
		||||
}
 | 
			
		||||
@@ -34,12 +35,36 @@ func (stats LanguageStatList) loadAttributes() {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (stats LanguageStatList) getLanguagePercentages() map[string]float32 {
 | 
			
		||||
	langPerc := make(map[string]float32)
 | 
			
		||||
	var otherPerc float32 = 100
 | 
			
		||||
	var total int64
 | 
			
		||||
 | 
			
		||||
	for _, stat := range stats {
 | 
			
		||||
		total += stat.Size
 | 
			
		||||
	}
 | 
			
		||||
	if total > 0 {
 | 
			
		||||
		for _, stat := range stats {
 | 
			
		||||
			perc := float32(math.Round(float64(stat.Size)/float64(total)*1000) / 10)
 | 
			
		||||
			if perc <= 0.1 {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			otherPerc -= perc
 | 
			
		||||
			langPerc[stat.Language] = perc
 | 
			
		||||
		}
 | 
			
		||||
		otherPerc = float32(math.Round(float64(otherPerc)*10) / 10)
 | 
			
		||||
	}
 | 
			
		||||
	if otherPerc > 0 {
 | 
			
		||||
		langPerc["other"] = otherPerc
 | 
			
		||||
	}
 | 
			
		||||
	return langPerc
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (repo *Repository) getLanguageStats(e Engine) (LanguageStatList, error) {
 | 
			
		||||
	stats := make(LanguageStatList, 0, 6)
 | 
			
		||||
	if err := e.Where("`repo_id` = ?", repo.ID).Desc("`percentage`").Find(&stats); err != nil {
 | 
			
		||||
	if err := e.Where("`repo_id` = ?", repo.ID).Desc("`size`").Find(&stats); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	stats.loadAttributes()
 | 
			
		||||
	return stats, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -54,13 +79,18 @@ func (repo *Repository) GetTopLanguageStats(limit int) (LanguageStatList, error)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	perc := stats.getLanguagePercentages()
 | 
			
		||||
	topstats := make(LanguageStatList, 0, limit)
 | 
			
		||||
	var other float32
 | 
			
		||||
	for i := range stats {
 | 
			
		||||
		if stats[i].Language == "other" || len(topstats) >= limit {
 | 
			
		||||
			other += stats[i].Percentage
 | 
			
		||||
		if _, ok := perc[stats[i].Language]; !ok {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		if stats[i].Language == "other" || len(topstats) >= limit {
 | 
			
		||||
			other += perc[stats[i].Language]
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		stats[i].Percentage = perc[stats[i].Language]
 | 
			
		||||
		topstats = append(topstats, stats[i])
 | 
			
		||||
	}
 | 
			
		||||
	if other > 0 {
 | 
			
		||||
@@ -71,11 +101,12 @@ func (repo *Repository) GetTopLanguageStats(limit int) (LanguageStatList, error)
 | 
			
		||||
			Percentage: float32(math.Round(float64(other)*10) / 10),
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
	topstats.loadAttributes()
 | 
			
		||||
	return topstats, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UpdateLanguageStats updates the language statistics for repository
 | 
			
		||||
func (repo *Repository) UpdateLanguageStats(commitID string, stats map[string]float32) error {
 | 
			
		||||
func (repo *Repository) UpdateLanguageStats(commitID string, stats map[string]int64) error {
 | 
			
		||||
	sess := x.NewSession()
 | 
			
		||||
	if err := sess.Begin(); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
@@ -87,15 +118,15 @@ func (repo *Repository) UpdateLanguageStats(commitID string, stats map[string]fl
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	var topLang string
 | 
			
		||||
	var p float32
 | 
			
		||||
	for lang, perc := range stats {
 | 
			
		||||
		if perc > p {
 | 
			
		||||
			p = perc
 | 
			
		||||
	var s int64
 | 
			
		||||
	for lang, size := range stats {
 | 
			
		||||
		if size > s {
 | 
			
		||||
			s = size
 | 
			
		||||
			topLang = strings.ToLower(lang)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for lang, perc := range stats {
 | 
			
		||||
	for lang, size := range stats {
 | 
			
		||||
		upd := false
 | 
			
		||||
		llang := strings.ToLower(lang)
 | 
			
		||||
		for _, s := range oldstats {
 | 
			
		||||
@@ -103,8 +134,8 @@ func (repo *Repository) UpdateLanguageStats(commitID string, stats map[string]fl
 | 
			
		||||
			if strings.ToLower(s.Language) == llang {
 | 
			
		||||
				s.CommitID = commitID
 | 
			
		||||
				s.IsPrimary = llang == topLang
 | 
			
		||||
				s.Percentage = perc
 | 
			
		||||
				if _, err := sess.ID(s.ID).Cols("`commit_id`", "`percentage`", "`is_primary`").Update(s); err != nil {
 | 
			
		||||
				s.Size = size
 | 
			
		||||
				if _, err := sess.ID(s.ID).Cols("`commit_id`", "`size`", "`is_primary`").Update(s); err != nil {
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
				upd = true
 | 
			
		||||
@@ -118,7 +149,7 @@ func (repo *Repository) UpdateLanguageStats(commitID string, stats map[string]fl
 | 
			
		||||
				CommitID:  commitID,
 | 
			
		||||
				IsPrimary: llang == topLang,
 | 
			
		||||
				Language:  lang,
 | 
			
		||||
				Percentage: perc,
 | 
			
		||||
				Size:      size,
 | 
			
		||||
			}); err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
@@ -153,7 +184,7 @@ func CopyLanguageStat(originalRepo, destRepo *Repository) error {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	RepoLang := make(LanguageStatList, 0, 6)
 | 
			
		||||
	if err := sess.Where("`repo_id` = ?", originalRepo.ID).Desc("`percentage`").Find(&RepoLang); err != nil {
 | 
			
		||||
	if err := sess.Where("`repo_id` = ?", originalRepo.ID).Desc("`size`").Find(&RepoLang); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if len(RepoLang) > 0 {
 | 
			
		||||
 
 | 
			
		||||
@@ -140,10 +140,13 @@ type SearchRepoOptions struct {
 | 
			
		||||
	PriorityOwnerID int64
 | 
			
		||||
	OrderBy         SearchOrderBy
 | 
			
		||||
	Private         bool // Include private repositories in results
 | 
			
		||||
	OnlyPrivate     bool // Include only private repositories in results
 | 
			
		||||
	StarredByID     int64
 | 
			
		||||
	AllPublic       bool // Include also all public repositories of users and public organisations
 | 
			
		||||
	AllLimited      bool // Include also all public repositories of limited organisations
 | 
			
		||||
	// None -> include public and private
 | 
			
		||||
	// True -> include just private
 | 
			
		||||
	// False -> incude just public
 | 
			
		||||
	IsPrivate util.OptionalBool
 | 
			
		||||
	// None -> include collaborative AND non-collaborative
 | 
			
		||||
	// True -> include just collaborative
 | 
			
		||||
	// False -> incude just non-collaborative
 | 
			
		||||
@@ -221,15 +224,8 @@ func SearchRepositoryCondition(opts *SearchRepoOptions) builder.Cond {
 | 
			
		||||
				))))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if opts.OnlyPrivate {
 | 
			
		||||
		cond = cond.And(
 | 
			
		||||
			builder.Or(
 | 
			
		||||
				builder.Eq{"is_private": true},
 | 
			
		||||
				builder.In("owner_id", builder.Select("id").From("`user`").Where(
 | 
			
		||||
					builder.And(
 | 
			
		||||
						builder.Eq{"type": UserTypeOrganization},
 | 
			
		||||
						builder.Or(builder.Eq{"visibility": structs.VisibleTypeLimited}, builder.Eq{"visibility": structs.VisibleTypePrivate}),
 | 
			
		||||
					)))))
 | 
			
		||||
	if opts.IsPrivate != util.OptionalBoolNone {
 | 
			
		||||
		cond = cond.And(builder.Eq{"is_private": opts.IsPrivate.IsTrue()})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if opts.Template != util.OptionalBoolNone {
 | 
			
		||||
@@ -249,14 +245,35 @@ func SearchRepositoryCondition(opts *SearchRepoOptions) builder.Cond {
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if opts.Collaborate != util.OptionalBoolFalse {
 | 
			
		||||
			// A Collaboration is:
 | 
			
		||||
			collaborateCond := builder.And(
 | 
			
		||||
				// 1. Repository we don't own
 | 
			
		||||
				builder.Neq{"owner_id": opts.OwnerID},
 | 
			
		||||
				// 2. But we can see because of:
 | 
			
		||||
				builder.Or(
 | 
			
		||||
					builder.Expr("repository.id IN (SELECT repo_id FROM `access` WHERE access.user_id = ?)", opts.OwnerID),
 | 
			
		||||
					builder.In("id", builder.Select("`team_repo`.repo_id").
 | 
			
		||||
					// A. We have access
 | 
			
		||||
					builder.In("`repository`.id",
 | 
			
		||||
						builder.Select("`access`.repo_id").
 | 
			
		||||
							From("access").
 | 
			
		||||
							Where(builder.Eq{"`access`.user_id": opts.OwnerID})),
 | 
			
		||||
					// B. We are in a team for
 | 
			
		||||
					builder.In("`repository`.id", builder.Select("`team_repo`.repo_id").
 | 
			
		||||
						From("team_repo").
 | 
			
		||||
						Where(builder.Eq{"`team_user`.uid": opts.OwnerID}).
 | 
			
		||||
						Join("INNER", "team_user", "`team_user`.team_id = `team_repo`.team_id"))),
 | 
			
		||||
				builder.Neq{"owner_id": opts.OwnerID})
 | 
			
		||||
						Join("INNER", "team_user", "`team_user`.team_id = `team_repo`.team_id")),
 | 
			
		||||
					// C. Public repositories in private organizations that we are member of
 | 
			
		||||
					builder.And(
 | 
			
		||||
						builder.Eq{"`repository`.is_private": false},
 | 
			
		||||
						builder.In("`repository`.owner_id",
 | 
			
		||||
							builder.Select("`org_user`.org_id").
 | 
			
		||||
								From("org_user").
 | 
			
		||||
								Join("INNER", "`user`", "`user`.id = `org_user`.org_id").
 | 
			
		||||
								Where(builder.Eq{
 | 
			
		||||
									"`org_user`.uid":    opts.OwnerID,
 | 
			
		||||
									"`user`.type":       UserTypeOrganization,
 | 
			
		||||
									"`user`.visibility": structs.VisibleTypePrivate,
 | 
			
		||||
								})))),
 | 
			
		||||
			)
 | 
			
		||||
			if !opts.Private {
 | 
			
		||||
				collaborateCond = collaborateCond.And(builder.Expr("owner_id NOT IN (SELECT org_id FROM org_user WHERE org_user.uid = ? AND org_user.is_public = ?)", opts.OwnerID, false))
 | 
			
		||||
			}
 | 
			
		||||
 
 | 
			
		||||
@@ -13,7 +13,7 @@ import (
 | 
			
		||||
	"code.gitea.io/gitea/modules/generate"
 | 
			
		||||
	"code.gitea.io/gitea/modules/timeutil"
 | 
			
		||||
 | 
			
		||||
	gouuid "github.com/satori/go.uuid"
 | 
			
		||||
	gouuid "github.com/google/uuid"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// AccessToken represents a personal access token.
 | 
			
		||||
@@ -45,7 +45,7 @@ func NewAccessToken(t *AccessToken) error {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	t.TokenSalt = salt
 | 
			
		||||
	t.Token = base.EncodeSha1(gouuid.NewV4().String())
 | 
			
		||||
	t.Token = base.EncodeSha1(gouuid.New().String())
 | 
			
		||||
	t.TokenHash = hashToken(t.Token, t.TokenSalt)
 | 
			
		||||
	t.TokenLastEight = t.Token[len(t.Token)-8:]
 | 
			
		||||
	_, err = x.Insert(t)
 | 
			
		||||
 
 | 
			
		||||
@@ -142,8 +142,8 @@ func UpdateTwoFactor(t *TwoFactor) error {
 | 
			
		||||
// GetTwoFactorByUID returns the two-factor authentication token associated with
 | 
			
		||||
// the user, if any.
 | 
			
		||||
func GetTwoFactorByUID(uid int64) (*TwoFactor, error) {
 | 
			
		||||
	twofa := &TwoFactor{UID: uid}
 | 
			
		||||
	has, err := x.Get(twofa)
 | 
			
		||||
	twofa := &TwoFactor{}
 | 
			
		||||
	has, err := x.Where("uid=?", uid).Get(twofa)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	} else if !has {
 | 
			
		||||
 
 | 
			
		||||
@@ -14,7 +14,7 @@ import (
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/modules/setting"
 | 
			
		||||
 | 
			
		||||
	gouuid "github.com/satori/go.uuid"
 | 
			
		||||
	gouuid "github.com/google/uuid"
 | 
			
		||||
	"github.com/unknwon/com"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@@ -46,7 +46,7 @@ func (upload *Upload) LocalPath() string {
 | 
			
		||||
// NewUpload creates a new upload object.
 | 
			
		||||
func NewUpload(name string, buf []byte, file multipart.File) (_ *Upload, err error) {
 | 
			
		||||
	upload := &Upload{
 | 
			
		||||
		UUID: gouuid.NewV4().String(),
 | 
			
		||||
		UUID: gouuid.New().String(),
 | 
			
		||||
		Name: name,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -76,8 +76,8 @@ func NewUpload(name string, buf []byte, file multipart.File) (_ *Upload, err err
 | 
			
		||||
 | 
			
		||||
// GetUploadByUUID returns the Upload by UUID
 | 
			
		||||
func GetUploadByUUID(uuid string) (*Upload, error) {
 | 
			
		||||
	upload := &Upload{UUID: uuid}
 | 
			
		||||
	has, err := x.Get(upload)
 | 
			
		||||
	upload := &Upload{}
 | 
			
		||||
	has, err := x.Where("uuid=?", uuid).Get(upload)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	} else if !has {
 | 
			
		||||
 
 | 
			
		||||
@@ -29,6 +29,7 @@ import (
 | 
			
		||||
	"code.gitea.io/gitea/modules/generate"
 | 
			
		||||
	"code.gitea.io/gitea/modules/git"
 | 
			
		||||
	"code.gitea.io/gitea/modules/log"
 | 
			
		||||
	"code.gitea.io/gitea/modules/public"
 | 
			
		||||
	"code.gitea.io/gitea/modules/setting"
 | 
			
		||||
	"code.gitea.io/gitea/modules/structs"
 | 
			
		||||
	api "code.gitea.io/gitea/modules/structs"
 | 
			
		||||
@@ -645,7 +646,7 @@ func (u *User) GetOrganizationCount() (int64, error) {
 | 
			
		||||
 | 
			
		||||
// GetRepositories returns repositories that user owns, including private repositories.
 | 
			
		||||
func (u *User) GetRepositories(listOpts ListOptions) (err error) {
 | 
			
		||||
	u.Repos, err = GetUserRepositories(&SearchRepoOptions{Actor: u, Private: true, ListOptions: listOpts})
 | 
			
		||||
	u.Repos, _, err = GetUserRepositories(&SearchRepoOptions{Actor: u, Private: true, ListOptions: listOpts})
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -878,7 +879,7 @@ func (u *User) IsGhost() bool {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	reservedUsernames = []string{
 | 
			
		||||
	reservedUsernames = append([]string{
 | 
			
		||||
		".",
 | 
			
		||||
		"..",
 | 
			
		||||
		".well-known",
 | 
			
		||||
@@ -888,17 +889,13 @@ var (
 | 
			
		||||
		"attachments",
 | 
			
		||||
		"avatars",
 | 
			
		||||
		"commits",
 | 
			
		||||
		"css",
 | 
			
		||||
		"debug",
 | 
			
		||||
		"error",
 | 
			
		||||
		"explore",
 | 
			
		||||
		"fomantic",
 | 
			
		||||
		"ghost",
 | 
			
		||||
		"help",
 | 
			
		||||
		"img",
 | 
			
		||||
		"install",
 | 
			
		||||
		"issues",
 | 
			
		||||
		"js",
 | 
			
		||||
		"less",
 | 
			
		||||
		"login",
 | 
			
		||||
		"manifest.json",
 | 
			
		||||
@@ -916,8 +913,8 @@ var (
 | 
			
		||||
		"stars",
 | 
			
		||||
		"template",
 | 
			
		||||
		"user",
 | 
			
		||||
		"vendor",
 | 
			
		||||
	}
 | 
			
		||||
	}, public.KnownPublicEntries...)
 | 
			
		||||
 | 
			
		||||
	reservedUserPatterns = []string{"*.keys", "*.gpg"}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@@ -1558,8 +1555,8 @@ func GetUserByEmailContext(ctx DBContext, email string) (*User, error) {
 | 
			
		||||
	// Finally, if email address is the protected email address:
 | 
			
		||||
	if strings.HasSuffix(email, fmt.Sprintf("@%s", setting.Service.NoReplyAddress)) {
 | 
			
		||||
		username := strings.TrimSuffix(email, fmt.Sprintf("@%s", setting.Service.NoReplyAddress))
 | 
			
		||||
		user := &User{LowerName: username}
 | 
			
		||||
		has, err := ctx.e.Get(user)
 | 
			
		||||
		user := &User{}
 | 
			
		||||
		has, err := ctx.e.Where("lower_name=?", username).Get(user)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
@@ -71,8 +71,8 @@ func GetEmailAddresses(uid int64) ([]*EmailAddress, error) {
 | 
			
		||||
// GetEmailAddressByID gets a user's email address by ID
 | 
			
		||||
func GetEmailAddressByID(uid, id int64) (*EmailAddress, error) {
 | 
			
		||||
	// User ID is required for security reasons
 | 
			
		||||
	email := &EmailAddress{ID: id, UID: uid}
 | 
			
		||||
	if has, err := x.Get(email); err != nil {
 | 
			
		||||
	email := &EmailAddress{UID: uid}
 | 
			
		||||
	if has, err := x.ID(id).Get(email); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	} else if !has {
 | 
			
		||||
		return nil, nil
 | 
			
		||||
@@ -126,7 +126,7 @@ func isEmailUsed(e Engine, email string) (bool, error) {
 | 
			
		||||
		return true, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return e.Get(&EmailAddress{Email: email})
 | 
			
		||||
	return e.Where("email=?", email).Get(&EmailAddress{})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsEmailUsed returns true if the email has been used.
 | 
			
		||||
@@ -251,8 +251,8 @@ func MakeEmailPrimary(email *EmailAddress) error {
 | 
			
		||||
		return ErrEmailNotActivated
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	user := &User{ID: email.UID}
 | 
			
		||||
	has, err = x.Get(user)
 | 
			
		||||
	user := &User{}
 | 
			
		||||
	has, err = x.ID(email.UID).Get(user)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	} else if !has {
 | 
			
		||||
 
 | 
			
		||||
@@ -111,8 +111,8 @@ func GetUserByOpenID(uri string) (*User, error) {
 | 
			
		||||
	log.Trace("Normalized OpenID URI: " + uri)
 | 
			
		||||
 | 
			
		||||
	// Otherwise, check in openid table
 | 
			
		||||
	oid := &UserOpenID{URI: uri}
 | 
			
		||||
	has, err := x.Get(oid)
 | 
			
		||||
	oid := &UserOpenID{}
 | 
			
		||||
	has, err := x.Where("uri=?", uri).Get(oid)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -15,7 +15,7 @@ import (
 | 
			
		||||
	api "code.gitea.io/gitea/modules/structs"
 | 
			
		||||
	"code.gitea.io/gitea/modules/timeutil"
 | 
			
		||||
 | 
			
		||||
	gouuid "github.com/satori/go.uuid"
 | 
			
		||||
	gouuid "github.com/google/uuid"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// HookContentType is the content type of a web hook
 | 
			
		||||
@@ -769,7 +769,7 @@ func createHookTask(e Engine, t *HookTask) error {
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	t.UUID = gouuid.NewV4().String()
 | 
			
		||||
	t.UUID = gouuid.New().String()
 | 
			
		||||
	t.PayloadContent = string(data)
 | 
			
		||||
	_, err = e.Insert(t)
 | 
			
		||||
	return err
 | 
			
		||||
 
 | 
			
		||||
@@ -10,8 +10,8 @@ import (
 | 
			
		||||
	"github.com/go-enry/go-enry/v2"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// GetCodeLanguageWithCallback detects code language based on file name and content using callback
 | 
			
		||||
func GetCodeLanguageWithCallback(filename string, contentFunc func() ([]byte, error)) string {
 | 
			
		||||
// GetCodeLanguage detects code language based on file name and content
 | 
			
		||||
func GetCodeLanguage(filename string, content []byte) string {
 | 
			
		||||
	if language, ok := enry.GetLanguageByExtension(filename); ok {
 | 
			
		||||
		return language
 | 
			
		||||
	}
 | 
			
		||||
@@ -20,17 +20,9 @@ func GetCodeLanguageWithCallback(filename string, contentFunc func() ([]byte, er
 | 
			
		||||
		return language
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	content, err := contentFunc()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
	if len(content) == 0 {
 | 
			
		||||
		return enry.OtherLanguage
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return enry.GetLanguage(filepath.Base(filename), content)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetCodeLanguage detects code language based on file name and content
 | 
			
		||||
func GetCodeLanguage(filename string, content []byte) string {
 | 
			
		||||
	return GetCodeLanguageWithCallback(filename, func() ([]byte, error) {
 | 
			
		||||
		return content, nil
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -10,6 +10,7 @@ import (
 | 
			
		||||
	"code.gitea.io/gitea/modules/log"
 | 
			
		||||
	"code.gitea.io/gitea/modules/setting"
 | 
			
		||||
 | 
			
		||||
	uuid "github.com/google/uuid"
 | 
			
		||||
	"github.com/lafriks/xormstore"
 | 
			
		||||
	"github.com/markbates/goth"
 | 
			
		||||
	"github.com/markbates/goth/gothic"
 | 
			
		||||
@@ -25,7 +26,6 @@ import (
 | 
			
		||||
	"github.com/markbates/goth/providers/openidConnect"
 | 
			
		||||
	"github.com/markbates/goth/providers/twitter"
 | 
			
		||||
	"github.com/markbates/goth/providers/yandex"
 | 
			
		||||
	uuid "github.com/satori/go.uuid"
 | 
			
		||||
	"xorm.io/xorm"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@@ -61,7 +61,7 @@ func Init(x *xorm.Engine) error {
 | 
			
		||||
	gothic.Store = store
 | 
			
		||||
 | 
			
		||||
	gothic.SetState = func(req *http.Request) string {
 | 
			
		||||
		return uuid.NewV4().String()
 | 
			
		||||
		return uuid.New().String()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	gothic.GetProviderName = func(req *http.Request) (string, error) {
 | 
			
		||||
 
 | 
			
		||||
@@ -14,7 +14,7 @@ import (
 | 
			
		||||
 | 
			
		||||
	"gitea.com/macaron/macaron"
 | 
			
		||||
	"gitea.com/macaron/session"
 | 
			
		||||
	gouuid "github.com/satori/go.uuid"
 | 
			
		||||
	gouuid "github.com/google/uuid"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Ensure the struct implements the interface.
 | 
			
		||||
@@ -92,7 +92,7 @@ func (r *ReverseProxy) newUser(ctx *macaron.Context) *models.User {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	email := gouuid.NewV4().String() + "@localhost"
 | 
			
		||||
	email := gouuid.New().String() + "@localhost"
 | 
			
		||||
	if setting.Service.EnableReverseProxyEmail {
 | 
			
		||||
		webAuthEmail := ctx.Req.Header.Get(setting.ReverseProxyAuthEmail)
 | 
			
		||||
		if len(webAuthEmail) > 0 {
 | 
			
		||||
 
 | 
			
		||||
@@ -17,8 +17,8 @@ import (
 | 
			
		||||
	"gitea.com/macaron/macaron"
 | 
			
		||||
	"gitea.com/macaron/session"
 | 
			
		||||
 | 
			
		||||
	gouuid "github.com/google/uuid"
 | 
			
		||||
	"github.com/quasoft/websspi"
 | 
			
		||||
	gouuid "github.com/satori/go.uuid"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
@@ -157,12 +157,12 @@ func (s *SSPI) shouldAuthenticate(ctx *macaron.Context) (shouldAuth bool) {
 | 
			
		||||
// newUser creates a new user object for the purpose of automatic registration
 | 
			
		||||
// and populates its name and email with the information present in request headers.
 | 
			
		||||
func (s *SSPI) newUser(ctx *macaron.Context, username string, cfg *models.SSPIConfig) (*models.User, error) {
 | 
			
		||||
	email := gouuid.NewV4().String() + "@localhost.localdomain"
 | 
			
		||||
	email := gouuid.New().String() + "@localhost.localdomain"
 | 
			
		||||
	user := &models.User{
 | 
			
		||||
		Name:                         username,
 | 
			
		||||
		Email:                        email,
 | 
			
		||||
		KeepEmailPrivate:             true,
 | 
			
		||||
		Passwd:                       gouuid.NewV4().String(),
 | 
			
		||||
		Passwd:                       gouuid.New().String(),
 | 
			
		||||
		IsActive:                     cfg.AutoActivateUsers,
 | 
			
		||||
		Language:                     cfg.DefaultLanguage,
 | 
			
		||||
		UseCustomAvatar:              true,
 | 
			
		||||
 
 | 
			
		||||
@@ -7,6 +7,7 @@ package context
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
@@ -64,18 +65,22 @@ type APINotFound struct{}
 | 
			
		||||
// swagger:response redirect
 | 
			
		||||
type APIRedirect struct{}
 | 
			
		||||
 | 
			
		||||
// Error responses error message to client with given message.
 | 
			
		||||
// Error responds with an error message to client with given obj as the message.
 | 
			
		||||
// If status is 500, also it prints error to log.
 | 
			
		||||
func (ctx *APIContext) Error(status int, title string, obj interface{}) {
 | 
			
		||||
	var message string
 | 
			
		||||
	if err, ok := obj.(error); ok {
 | 
			
		||||
		message = err.Error()
 | 
			
		||||
	} else {
 | 
			
		||||
		message = obj.(string)
 | 
			
		||||
		message = fmt.Sprintf("%s", obj)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if status == 500 {
 | 
			
		||||
		log.Error("%s: %s", title, message)
 | 
			
		||||
	if status == http.StatusInternalServerError {
 | 
			
		||||
		log.ErrorWithSkip(1, "%s: %s", title, message)
 | 
			
		||||
 | 
			
		||||
		if macaron.Env == macaron.PROD {
 | 
			
		||||
			message = ""
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ctx.JSON(status, APIError{
 | 
			
		||||
@@ -84,6 +89,22 @@ func (ctx *APIContext) Error(status int, title string, obj interface{}) {
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// InternalServerError responds with an error message to the client with the error as a message
 | 
			
		||||
// and the file and line of the caller.
 | 
			
		||||
func (ctx *APIContext) InternalServerError(err error) {
 | 
			
		||||
	log.ErrorWithSkip(1, "InternalServerError: %v", err)
 | 
			
		||||
 | 
			
		||||
	var message string
 | 
			
		||||
	if macaron.Env != macaron.PROD {
 | 
			
		||||
		message = err.Error()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ctx.JSON(http.StatusInternalServerError, APIError{
 | 
			
		||||
		Message: message,
 | 
			
		||||
		URL:     setting.API.SwaggerURL,
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func genAPILinks(curURL *url.URL, total, pageSize, curPage int) []string {
 | 
			
		||||
	page := NewPagination(total, pageSize, curPage, 0)
 | 
			
		||||
	paginater := page.Paginater
 | 
			
		||||
 
 | 
			
		||||
@@ -49,7 +49,9 @@ func Toggle(options *ToggleOptions) macaron.Handler {
 | 
			
		||||
				if ctx.Req.URL.Path != "/user/settings/change_password" {
 | 
			
		||||
					ctx.Data["Title"] = ctx.Tr("auth.must_change_password")
 | 
			
		||||
					ctx.Data["ChangePasscodeLink"] = setting.AppSubURL + "/user/change_password"
 | 
			
		||||
					if ctx.Req.URL.Path != "/user/events" {
 | 
			
		||||
						ctx.SetCookie("redirect_to", setting.AppSubURL+ctx.Req.URL.RequestURI(), 0, setting.AppSubURL)
 | 
			
		||||
					}
 | 
			
		||||
					ctx.Redirect(setting.AppSubURL + "/user/settings/change_password")
 | 
			
		||||
					return
 | 
			
		||||
				}
 | 
			
		||||
 
 | 
			
		||||
@@ -103,7 +103,7 @@ func ToPullReviewCommentList(review *models.Review, doer *models.User) ([]*api.P
 | 
			
		||||
					OrigCommitID: comment.OldRef,
 | 
			
		||||
					DiffHunk:     patch2diff(comment.Patch),
 | 
			
		||||
					HTMLURL:      comment.HTMLURL(),
 | 
			
		||||
					HTMLPullURL:  review.Issue.APIURL(),
 | 
			
		||||
					HTMLPullURL:  review.Issue.HTMLURL(),
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if comment.Line < 0 {
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,7 @@ import (
 | 
			
		||||
// ToCorrectPageSize makes sure page size is in allowed range.
 | 
			
		||||
func ToCorrectPageSize(size int) int {
 | 
			
		||||
	if size <= 0 {
 | 
			
		||||
		size = 10
 | 
			
		||||
		size = setting.API.DefaultPagingNum
 | 
			
		||||
	} else if size > setting.API.MaxResponseItems {
 | 
			
		||||
		size = setting.API.MaxResponseItems
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,7 @@
 | 
			
		||||
package emoji
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"sort"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"sync"
 | 
			
		||||
)
 | 
			
		||||
@@ -19,6 +20,7 @@ type Emoji struct {
 | 
			
		||||
	Description    string
 | 
			
		||||
	Aliases        []string
 | 
			
		||||
	UnicodeVersion string
 | 
			
		||||
	SkinTones      bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
@@ -48,6 +50,12 @@ func loadMap() {
 | 
			
		||||
		// process emoji codes and aliases
 | 
			
		||||
		codePairs := make([]string, 0)
 | 
			
		||||
		aliasPairs := make([]string, 0)
 | 
			
		||||
 | 
			
		||||
		// sort from largest to small so we match combined emoji first
 | 
			
		||||
		sort.Slice(GemojiData, func(i, j int) bool {
 | 
			
		||||
			return len(GemojiData[i].Emoji) > len(GemojiData[j].Emoji)
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
		for i, e := range GemojiData {
 | 
			
		||||
			if e.Emoji == "" || len(e.Aliases) == 0 {
 | 
			
		||||
				continue
 | 
			
		||||
@@ -72,6 +80,7 @@ func loadMap() {
 | 
			
		||||
		codeReplacer = strings.NewReplacer(codePairs...)
 | 
			
		||||
		aliasReplacer = strings.NewReplacer(aliasPairs...)
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FromCode retrieves the emoji data based on the provided unicode code (ie,
 | 
			
		||||
@@ -117,3 +126,22 @@ func ReplaceAliases(s string) string {
 | 
			
		||||
	loadMap()
 | 
			
		||||
	return aliasReplacer.Replace(s)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FindEmojiSubmatchIndex returns index pair of longest emoji in a string
 | 
			
		||||
func FindEmojiSubmatchIndex(s string) []int {
 | 
			
		||||
	loadMap()
 | 
			
		||||
 | 
			
		||||
	//see if there are any emoji in string before looking for position of specific ones
 | 
			
		||||
	//no performance difference when there is a match but 10x faster when there are not
 | 
			
		||||
	if s == ReplaceCodes(s) {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for j := range GemojiData {
 | 
			
		||||
		i := strings.Index(s, GemojiData[j].Emoji)
 | 
			
		||||
		if i != -1 {
 | 
			
		||||
			return []int{i, i + len(GemojiData[j].Emoji)}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -46,7 +46,7 @@ func (repo *Repository) GetBranchCommitID(name string) (string, error) {
 | 
			
		||||
 | 
			
		||||
// GetTagCommitID returns last commit ID string of given tag.
 | 
			
		||||
func (repo *Repository) GetTagCommitID(name string) (string, error) {
 | 
			
		||||
	stdout, err := NewCommand("rev-list", "-n", "1", name).RunInDir(repo.Path)
 | 
			
		||||
	stdout, err := NewCommand("rev-list", "-n", "1", TagPrefix+name).RunInDir(repo.Path)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if strings.Contains(err.Error(), "unknown revision or path") {
 | 
			
		||||
			return "", ErrNotExist{name, ""}
 | 
			
		||||
 
 | 
			
		||||
@@ -8,7 +8,6 @@ import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"io"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"math"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/modules/analyze"
 | 
			
		||||
 | 
			
		||||
@@ -18,10 +17,25 @@ import (
 | 
			
		||||
	"github.com/go-git/go-git/v5/plumbing/object"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const fileSizeLimit int64 = 16 * 1024 * 1024
 | 
			
		||||
const fileSizeLimit int64 = 16 * 1024 // 16 KiB
 | 
			
		||||
const bigFileSize int64 = 1024 * 1024 // 1 MiB
 | 
			
		||||
 | 
			
		||||
// specialLanguages defines list of languages that are excluded from the calculation
 | 
			
		||||
// unless they are the only language present in repository. Only languages which under
 | 
			
		||||
// normal circumstances are not considered to be code should be listed here.
 | 
			
		||||
var specialLanguages = []string{
 | 
			
		||||
	"XML",
 | 
			
		||||
	"JSON",
 | 
			
		||||
	"TOML",
 | 
			
		||||
	"YAML",
 | 
			
		||||
	"INI",
 | 
			
		||||
	"SVG",
 | 
			
		||||
	"Text",
 | 
			
		||||
	"Markdown",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetLanguageStats calculates language stats for git repository at specified commit
 | 
			
		||||
func (repo *Repository) GetLanguageStats(commitID string) (map[string]float32, error) {
 | 
			
		||||
func (repo *Repository) GetLanguageStats(commitID string) (map[string]int64, error) {
 | 
			
		||||
	r, err := git.PlainOpen(repo.Path)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
@@ -43,24 +57,35 @@ func (repo *Repository) GetLanguageStats(commitID string) (map[string]float32, e
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sizes := make(map[string]int64)
 | 
			
		||||
	var total int64
 | 
			
		||||
	err = tree.Files().ForEach(func(f *object.File) error {
 | 
			
		||||
		if enry.IsVendor(f.Name) || enry.IsDotFile(f.Name) ||
 | 
			
		||||
		if f.Size == 0 || enry.IsVendor(f.Name) || enry.IsDotFile(f.Name) ||
 | 
			
		||||
			enry.IsDocumentation(f.Name) || enry.IsConfiguration(f.Name) {
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// If content can not be read or file is too big just do detection by filename
 | 
			
		||||
		var content []byte
 | 
			
		||||
		if f.Size <= bigFileSize {
 | 
			
		||||
			content, _ = readFile(f, fileSizeLimit)
 | 
			
		||||
		}
 | 
			
		||||
		if enry.IsGenerated(f.Name, content) {
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// TODO: Use .gitattributes file for linguist overrides
 | 
			
		||||
 | 
			
		||||
		language := analyze.GetCodeLanguageWithCallback(f.Name, func() ([]byte, error) {
 | 
			
		||||
			return readFile(f, fileSizeLimit)
 | 
			
		||||
		})
 | 
			
		||||
		language := analyze.GetCodeLanguage(f.Name, content)
 | 
			
		||||
		if language == enry.OtherLanguage || language == "" {
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// group languages, such as Pug -> HTML; SCSS -> CSS
 | 
			
		||||
		group := enry.GetLanguageGroup(language)
 | 
			
		||||
		if group != "" {
 | 
			
		||||
			language = group
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		sizes[language] += f.Size
 | 
			
		||||
		total += f.Size
 | 
			
		||||
 | 
			
		||||
		return nil
 | 
			
		||||
	})
 | 
			
		||||
@@ -68,21 +93,14 @@ func (repo *Repository) GetLanguageStats(commitID string) (map[string]float32, e
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	stats := make(map[string]float32)
 | 
			
		||||
	var otherPerc float32 = 100
 | 
			
		||||
	for language, size := range sizes {
 | 
			
		||||
		perc := float32(math.Round(float64(size)/float64(total)*1000) / 10)
 | 
			
		||||
		if perc <= 0.1 {
 | 
			
		||||
			continue
 | 
			
		||||
	// filter special languages unless they are the only language
 | 
			
		||||
	if len(sizes) > 1 {
 | 
			
		||||
		for _, language := range specialLanguages {
 | 
			
		||||
			delete(sizes, language)
 | 
			
		||||
		}
 | 
			
		||||
		otherPerc -= perc
 | 
			
		||||
		stats[language] = perc
 | 
			
		||||
	}
 | 
			
		||||
	otherPerc = float32(math.Round(float64(otherPerc)*10) / 10)
 | 
			
		||||
	if otherPerc > 0 {
 | 
			
		||||
		stats["other"] = otherPerc
 | 
			
		||||
	}
 | 
			
		||||
	return stats, nil
 | 
			
		||||
 | 
			
		||||
	return sizes, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func readFile(f *object.File, limit int64) ([]byte, error) {
 | 
			
		||||
 
 | 
			
		||||
@@ -34,9 +34,10 @@ func TestRepoStatsIndex(t *testing.T) {
 | 
			
		||||
 | 
			
		||||
	repo, err := models.GetRepositoryByID(1)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	status, err := repo.GetIndexerStatus(models.RepoIndexerTypeStats)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.Equal(t, "65f1bf27bc3bf70f64657658635e66094edbcb4d", status.CommitSha)
 | 
			
		||||
	langs, err := repo.GetTopLanguageStats(5)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.Len(t, langs, 1)
 | 
			
		||||
	assert.Equal(t, "other", langs[0].Language)
 | 
			
		||||
	assert.Equal(t, float32(100), langs[0].Percentage)
 | 
			
		||||
	assert.Empty(t, langs)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -65,10 +65,6 @@ var (
 | 
			
		||||
 | 
			
		||||
	// EmojiShortCodeRegex find emoji by alias like :smile:
 | 
			
		||||
	EmojiShortCodeRegex = regexp.MustCompile(`\:[\w\+\-]+\:{1}`)
 | 
			
		||||
 | 
			
		||||
	// find emoji literal: search all emoji hex range as many times as they appear as
 | 
			
		||||
	// some emojis (skin color etc..) are just two or more chained together
 | 
			
		||||
	emojiRegex = regexp.MustCompile(`[\x{1F000}-\x{1FFFF}|\x{2000}-\x{32ff}|\x{fe4e5}-\x{fe4ee}|\x{200D}|\x{FE0F}|\x{e0000}-\x{e007f}]+`)
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// CSS class for action keywords (e.g. "closes: #1")
 | 
			
		||||
@@ -922,8 +918,7 @@ func emojiShortCodeProcessor(ctx *postProcessCtx, node *html.Node) {
 | 
			
		||||
 | 
			
		||||
// emoji processor to match emoji and add emoji class
 | 
			
		||||
func emojiProcessor(ctx *postProcessCtx, node *html.Node) {
 | 
			
		||||
	m := emojiRegex.FindStringSubmatchIndex(node.Data)
 | 
			
		||||
 | 
			
		||||
	m := emoji.FindEmojiSubmatchIndex(node.Data)
 | 
			
		||||
	if m == nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -263,7 +263,9 @@ func TestRender_emoji(t *testing.T) {
 | 
			
		||||
	test(
 | 
			
		||||
		"Some text with :smile: in the middle",
 | 
			
		||||
		`<p>Some text with <span class="emoji" aria-label="grinning face with smiling eyes">😄</span> in the middle</p>`)
 | 
			
		||||
 | 
			
		||||
	test(
 | 
			
		||||
		"Some text with 😄😄 2 emoji next to each other",
 | 
			
		||||
		`<p>Some text with <span class="emoji" aria-label="grinning face with smiling eyes">😄</span><span class="emoji" aria-label="grinning face with smiling eyes">😄</span> 2 emoji next to each other</p>`)
 | 
			
		||||
	// should match nothing
 | 
			
		||||
	test(
 | 
			
		||||
		"2001:0db8:85a3:0000:0000:8a2e:0370:7334",
 | 
			
		||||
 
 | 
			
		||||
@@ -151,6 +151,16 @@ func (g *ASTTransformer) Transform(node *ast.Document, reader text.Reader, pc pa
 | 
			
		||||
					v.AppendChild(v, newChild)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		case *ast.Text:
 | 
			
		||||
			if v.SoftLineBreak() && !v.HardLineBreak() {
 | 
			
		||||
				renderMetas := pc.Get(renderMetasKey).(map[string]string)
 | 
			
		||||
				mode := renderMetas["mode"]
 | 
			
		||||
				if mode != "document" {
 | 
			
		||||
					v.SetHardLineBreak(setting.Markdown.EnableHardLineBreakInComments)
 | 
			
		||||
				} else {
 | 
			
		||||
					v.SetHardLineBreak(setting.Markdown.EnableHardLineBreakInDocuments)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return ast.WalkContinue, nil
 | 
			
		||||
	})
 | 
			
		||||
 
 | 
			
		||||
@@ -29,17 +29,19 @@ var once = sync.Once{}
 | 
			
		||||
 | 
			
		||||
var urlPrefixKey = parser.NewContextKey()
 | 
			
		||||
var isWikiKey = parser.NewContextKey()
 | 
			
		||||
var renderMetasKey = parser.NewContextKey()
 | 
			
		||||
 | 
			
		||||
// NewGiteaParseContext creates a parser.Context with the gitea context set
 | 
			
		||||
func NewGiteaParseContext(urlPrefix string, isWiki bool) parser.Context {
 | 
			
		||||
func NewGiteaParseContext(urlPrefix string, metas map[string]string, isWiki bool) parser.Context {
 | 
			
		||||
	pc := parser.NewContext(parser.WithIDs(newPrefixedIDs()))
 | 
			
		||||
	pc.Set(urlPrefixKey, urlPrefix)
 | 
			
		||||
	pc.Set(isWikiKey, isWiki)
 | 
			
		||||
	pc.Set(renderMetasKey, metas)
 | 
			
		||||
	return pc
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RenderRaw renders Markdown to HTML without handling special links.
 | 
			
		||||
func RenderRaw(body []byte, urlPrefix string, wikiMarkdown bool) []byte {
 | 
			
		||||
// render renders Markdown to HTML without handling special links.
 | 
			
		||||
func render(body []byte, urlPrefix string, metas map[string]string, wikiMarkdown bool) []byte {
 | 
			
		||||
	once.Do(func() {
 | 
			
		||||
		converter = goldmark.New(
 | 
			
		||||
			goldmark.WithExtensions(extension.Table,
 | 
			
		||||
@@ -75,12 +77,9 @@ func RenderRaw(body []byte, urlPrefix string, wikiMarkdown bool) []byte {
 | 
			
		||||
			),
 | 
			
		||||
		)
 | 
			
		||||
 | 
			
		||||
		if setting.Markdown.EnableHardLineBreak {
 | 
			
		||||
			converter.Renderer().AddOptions(html.WithHardWraps())
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	pc := NewGiteaParseContext(urlPrefix, wikiMarkdown)
 | 
			
		||||
	pc := NewGiteaParseContext(urlPrefix, metas, wikiMarkdown)
 | 
			
		||||
	var buf bytes.Buffer
 | 
			
		||||
	if err := converter.Convert(giteautil.NormalizeEOL(body), &buf, parser.WithContext(pc)); err != nil {
 | 
			
		||||
		log.Error("Unable to render: %v", err)
 | 
			
		||||
@@ -112,7 +111,7 @@ func (Parser) Extensions() []string {
 | 
			
		||||
 | 
			
		||||
// Render implements markup.Parser
 | 
			
		||||
func (Parser) Render(rawBytes []byte, urlPrefix string, metas map[string]string, isWiki bool) []byte {
 | 
			
		||||
	return RenderRaw(rawBytes, urlPrefix, isWiki)
 | 
			
		||||
	return render(rawBytes, urlPrefix, metas, isWiki)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Render renders Markdown to HTML with all specific handling stuff.
 | 
			
		||||
@@ -120,6 +119,11 @@ func Render(rawBytes []byte, urlPrefix string, metas map[string]string) []byte {
 | 
			
		||||
	return markup.Render("a.md", rawBytes, urlPrefix, metas)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RenderRaw renders Markdown to HTML without handling special links.
 | 
			
		||||
func RenderRaw(body []byte, urlPrefix string, wikiMarkdown bool) []byte {
 | 
			
		||||
	return render(body, urlPrefix, map[string]string{}, wikiMarkdown)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RenderString renders Markdown to HTML with special links and returns string type.
 | 
			
		||||
func RenderString(raw, urlPrefix string, metas map[string]string) string {
 | 
			
		||||
	return markup.RenderString("a.md", raw, urlPrefix, metas)
 | 
			
		||||
 
 | 
			
		||||
@@ -29,7 +29,7 @@ import (
 | 
			
		||||
	"code.gitea.io/gitea/modules/structs"
 | 
			
		||||
	"code.gitea.io/gitea/modules/timeutil"
 | 
			
		||||
 | 
			
		||||
	gouuid "github.com/satori/go.uuid"
 | 
			
		||||
	gouuid "github.com/google/uuid"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
@@ -260,7 +260,7 @@ func (g *GiteaLocalUploader) CreateReleases(releases ...*base.Release) error {
 | 
			
		||||
 | 
			
		||||
		for _, asset := range release.Assets {
 | 
			
		||||
			var attach = models.Attachment{
 | 
			
		||||
				UUID:          gouuid.NewV4().String(),
 | 
			
		||||
				UUID:          gouuid.New().String(),
 | 
			
		||||
				Name:          asset.Name,
 | 
			
		||||
				DownloadCount: int64(*asset.DownloadCount),
 | 
			
		||||
				Size:          int64(*asset.Size),
 | 
			
		||||
 
 | 
			
		||||
@@ -30,12 +30,13 @@ type Options struct {
 | 
			
		||||
	Prefix       string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// List of known entries inside the `public` directory
 | 
			
		||||
var knownEntries = []string{
 | 
			
		||||
// KnownPublicEntries list all direct children in the `public` directory
 | 
			
		||||
var KnownPublicEntries = []string{
 | 
			
		||||
	"css",
 | 
			
		||||
	"fomantic",
 | 
			
		||||
	"img",
 | 
			
		||||
	"js",
 | 
			
		||||
	"serviceworker.js",
 | 
			
		||||
	"vendor",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -114,7 +115,7 @@ func (opts *Options) handle(ctx *macaron.Context, log *log.Logger, opt *Options)
 | 
			
		||||
			if len(parts) < 2 {
 | 
			
		||||
				return false
 | 
			
		||||
			}
 | 
			
		||||
			for _, entry := range knownEntries {
 | 
			
		||||
			for _, entry := range KnownPublicEntries {
 | 
			
		||||
				if entry == parts[1] {
 | 
			
		||||
					ctx.Resp.WriteHeader(404)
 | 
			
		||||
					return true
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,6 @@ import (
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/models"
 | 
			
		||||
	"code.gitea.io/gitea/modules/git"
 | 
			
		||||
	"code.gitea.io/gitea/modules/log"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// GetBranch returns a branch by its name
 | 
			
		||||
@@ -74,39 +73,9 @@ func CreateNewBranch(doer *models.User, repo *models.Repository, oldBranchName,
 | 
			
		||||
		return fmt.Errorf("OldBranch: %s does not exist. Cannot create new branch from this", oldBranchName)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	basePath, err := models.CreateTemporaryPath("branch-maker")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	defer func() {
 | 
			
		||||
		if err := models.RemoveTemporaryPath(basePath); err != nil {
 | 
			
		||||
			log.Error("CreateNewBranch: RemoveTemporaryPath: %s", err)
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	if err := git.Clone(repo.RepoPath(), basePath, git.CloneRepoOptions{
 | 
			
		||||
		Bare:   true,
 | 
			
		||||
		Shared: true,
 | 
			
		||||
	}); err != nil {
 | 
			
		||||
		log.Error("Failed to clone repository: %s (%v)", repo.FullName(), err)
 | 
			
		||||
		return fmt.Errorf("Failed to clone repository: %s (%v)", repo.FullName(), err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	gitRepo, err := git.OpenRepository(basePath)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Error("Unable to open temporary repository: %s (%v)", basePath, err)
 | 
			
		||||
		return fmt.Errorf("Failed to open new temporary repository in: %s %v", basePath, err)
 | 
			
		||||
	}
 | 
			
		||||
	defer gitRepo.Close()
 | 
			
		||||
 | 
			
		||||
	if err = gitRepo.CreateBranch(branchName, oldBranchName); err != nil {
 | 
			
		||||
		log.Error("Unable to create branch: %s from %s. (%v)", branchName, oldBranchName, err)
 | 
			
		||||
		return fmt.Errorf("Unable to create branch: %s from %s. (%v)", branchName, oldBranchName, err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err = git.Push(basePath, git.PushOptions{
 | 
			
		||||
		Remote: "origin",
 | 
			
		||||
		Branch: branchName,
 | 
			
		||||
	if err := git.Push(repo.RepoPath(), git.PushOptions{
 | 
			
		||||
		Remote: repo.RepoPath(),
 | 
			
		||||
		Branch: fmt.Sprintf("%s:%s%s", oldBranchName, git.BranchPrefix, branchName),
 | 
			
		||||
		Env:    models.PushingEnvironment(doer, repo),
 | 
			
		||||
	}); err != nil {
 | 
			
		||||
		if git.IsErrPushOutOfDate(err) || git.IsErrPushRejected(err) {
 | 
			
		||||
@@ -124,39 +93,10 @@ func CreateNewBranchFromCommit(doer *models.User, repo *models.Repository, commi
 | 
			
		||||
	if err := checkBranchName(repo, branchName); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	basePath, err := models.CreateTemporaryPath("branch-maker")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	defer func() {
 | 
			
		||||
		if err := models.RemoveTemporaryPath(basePath); err != nil {
 | 
			
		||||
			log.Error("CreateNewBranchFromCommit: RemoveTemporaryPath: %s", err)
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	if err := git.Clone(repo.RepoPath(), basePath, git.CloneRepoOptions{
 | 
			
		||||
		Bare:   true,
 | 
			
		||||
		Shared: true,
 | 
			
		||||
	}); err != nil {
 | 
			
		||||
		log.Error("Failed to clone repository: %s (%v)", repo.FullName(), err)
 | 
			
		||||
		return fmt.Errorf("Failed to clone repository: %s (%v)", repo.FullName(), err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	gitRepo, err := git.OpenRepository(basePath)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Error("Unable to open temporary repository: %s (%v)", basePath, err)
 | 
			
		||||
		return fmt.Errorf("Failed to open new temporary repository in: %s %v", basePath, err)
 | 
			
		||||
	}
 | 
			
		||||
	defer gitRepo.Close()
 | 
			
		||||
 | 
			
		||||
	if err = gitRepo.CreateBranch(branchName, commit); err != nil {
 | 
			
		||||
		log.Error("Unable to create branch: %s from %s. (%v)", branchName, commit, err)
 | 
			
		||||
		return fmt.Errorf("Unable to create branch: %s from %s. (%v)", branchName, commit, err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err = git.Push(basePath, git.PushOptions{
 | 
			
		||||
		Remote: "origin",
 | 
			
		||||
		Branch: branchName,
 | 
			
		||||
	if err := git.Push(repo.RepoPath(), git.PushOptions{
 | 
			
		||||
		Remote: repo.RepoPath(),
 | 
			
		||||
		Branch: fmt.Sprintf("%s:%s%s", commit, git.BranchPrefix, branchName),
 | 
			
		||||
		Env:    models.PushingEnvironment(doer, repo),
 | 
			
		||||
	}); err != nil {
 | 
			
		||||
		if git.IsErrPushOutOfDate(err) || git.IsErrPushRejected(err) {
 | 
			
		||||
 
 | 
			
		||||
@@ -47,7 +47,7 @@ func CreateRepository(doer, u *models.User, opts models.CreateRepoOptions) (_ *m
 | 
			
		||||
		// No need for init mirror.
 | 
			
		||||
		if !opts.IsMirror {
 | 
			
		||||
			repoPath := models.RepoPath(u.Name, repo.Name)
 | 
			
		||||
			if err = initRepository(ctx, repoPath, u, repo, opts); err != nil {
 | 
			
		||||
			if err = initRepository(ctx, repoPath, doer, repo, opts); err != nil {
 | 
			
		||||
				if err2 := os.RemoveAll(repoPath); err2 != nil {
 | 
			
		||||
					log.Error("initRepository: %v", err)
 | 
			
		||||
					return fmt.Errorf(
 | 
			
		||||
 
 | 
			
		||||
@@ -16,6 +16,7 @@ import (
 | 
			
		||||
	"code.gitea.io/gitea/models"
 | 
			
		||||
	"code.gitea.io/gitea/modules/git"
 | 
			
		||||
	"code.gitea.io/gitea/modules/log"
 | 
			
		||||
	"code.gitea.io/gitea/modules/setting"
 | 
			
		||||
 | 
			
		||||
	"github.com/mcuadros/go-version"
 | 
			
		||||
	"github.com/unknwon/com"
 | 
			
		||||
@@ -147,7 +148,7 @@ func initRepoCommit(tmpPath string, repo *models.Repository, u *models.User, def
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(defaultBranch) == 0 {
 | 
			
		||||
		defaultBranch = "master"
 | 
			
		||||
		defaultBranch = setting.Repository.DefaultBranch
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if stdout, err := git.NewCommand("push", "origin", "master:"+defaultBranch).
 | 
			
		||||
 
 | 
			
		||||
@@ -111,6 +111,7 @@ type VirtualStore struct {
 | 
			
		||||
	sid      string
 | 
			
		||||
	lock     sync.RWMutex
 | 
			
		||||
	data     map[interface{}]interface{}
 | 
			
		||||
	released bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewVirtualStore creates and returns a virtual session store.
 | 
			
		||||
@@ -164,7 +165,7 @@ func (s *VirtualStore) Release() error {
 | 
			
		||||
		// Now ensure that we don't exist!
 | 
			
		||||
		realProvider := s.p.provider
 | 
			
		||||
 | 
			
		||||
		if realProvider.Exist(s.sid) {
 | 
			
		||||
		if !s.released && realProvider.Exist(s.sid) {
 | 
			
		||||
			// This is an error!
 | 
			
		||||
			return fmt.Errorf("new sid '%s' already exists", s.sid)
 | 
			
		||||
		}
 | 
			
		||||
@@ -172,12 +173,19 @@ func (s *VirtualStore) Release() error {
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		if err := realStore.Flush(); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		for key, value := range s.data {
 | 
			
		||||
			if err := realStore.Set(key, value); err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return realStore.Release()
 | 
			
		||||
		err = realStore.Release()
 | 
			
		||||
		if err == nil {
 | 
			
		||||
			s.released = true
 | 
			
		||||
		}
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -105,7 +105,7 @@ func DBConnStr() (string, error) {
 | 
			
		||||
	switch Database.Type {
 | 
			
		||||
	case "mysql":
 | 
			
		||||
		connType := "tcp"
 | 
			
		||||
		if Database.Host[0] == '/' { // looks like a unix socket
 | 
			
		||||
		if len(Database.Host) > 0 && Database.Host[0] == '/' { // looks like a unix socket
 | 
			
		||||
			connType = "unix"
 | 
			
		||||
		}
 | 
			
		||||
		tls := Database.SSLMode
 | 
			
		||||
@@ -163,7 +163,7 @@ func getPostgreSQLConnectionString(dbHost, dbUser, dbPasswd, dbName, dbParam, db
 | 
			
		||||
 | 
			
		||||
// ParseMSSQLHostPort splits the host into host and port
 | 
			
		||||
func ParseMSSQLHostPort(info string) (string, string) {
 | 
			
		||||
	host, port := "127.0.0.1", "1433"
 | 
			
		||||
	host, port := "127.0.0.1", "0"
 | 
			
		||||
	if strings.Contains(info, ":") {
 | 
			
		||||
		host = strings.Split(info, ":")[0]
 | 
			
		||||
		port = strings.Split(info, ":")[1]
 | 
			
		||||
 
 | 
			
		||||
@@ -40,6 +40,7 @@ var (
 | 
			
		||||
		DisabledRepoUnits                       []string
 | 
			
		||||
		DefaultRepoUnits                        []string
 | 
			
		||||
		PrefixArchiveFiles                      bool
 | 
			
		||||
		DefaultBranch                           string
 | 
			
		||||
 | 
			
		||||
		// Repository editor settings
 | 
			
		||||
		Editor struct {
 | 
			
		||||
@@ -201,6 +202,7 @@ func newRepository() {
 | 
			
		||||
	Repository.DisableHTTPGit = sec.Key("DISABLE_HTTP_GIT").MustBool()
 | 
			
		||||
	Repository.UseCompatSSHURI = sec.Key("USE_COMPAT_SSH_URI").MustBool()
 | 
			
		||||
	Repository.MaxCreationLimit = sec.Key("MAX_CREATION_LIMIT").MustInt(-1)
 | 
			
		||||
	Repository.DefaultBranch = sec.Key("DEFAULT_BRANCH").MustString("master")
 | 
			
		||||
	RepoRootPath = sec.Key("ROOT").MustString(path.Join(homeDir, "gitea-repositories"))
 | 
			
		||||
	forcePathSeparator(RepoRootPath)
 | 
			
		||||
	if !filepath.IsAbs(RepoRootPath) {
 | 
			
		||||
 
 | 
			
		||||
@@ -256,11 +256,13 @@ var (
 | 
			
		||||
 | 
			
		||||
	// Markdown settings
 | 
			
		||||
	Markdown = struct {
 | 
			
		||||
		EnableHardLineBreak bool
 | 
			
		||||
		EnableHardLineBreakInComments  bool
 | 
			
		||||
		EnableHardLineBreakInDocuments bool
 | 
			
		||||
		CustomURLSchemes               []string `ini:"CUSTOM_URL_SCHEMES"`
 | 
			
		||||
		FileExtensions                 []string
 | 
			
		||||
	}{
 | 
			
		||||
		EnableHardLineBreak: true,
 | 
			
		||||
		EnableHardLineBreakInComments:  true,
 | 
			
		||||
		EnableHardLineBreakInDocuments: false,
 | 
			
		||||
		FileExtensions:                 strings.Split(".md,.markdown,.mdown,.mkd", ","),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -728,6 +730,8 @@ func NewContext() {
 | 
			
		||||
	for _, key := range minimumKeySizes {
 | 
			
		||||
		if key.MustInt() != -1 {
 | 
			
		||||
			SSH.MinimumKeySizes[strings.ToLower(key.Name())] = key.MustInt()
 | 
			
		||||
		} else {
 | 
			
		||||
			delete(SSH.MinimumKeySizes, strings.ToLower(key.Name()))
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	SSH.AuthorizedKeysBackup = sec.Key("SSH_AUTHORIZED_KEYS_BACKUP").MustBool(true)
 | 
			
		||||
@@ -999,15 +1003,15 @@ func NewContext() {
 | 
			
		||||
	if len(Langs) == 0 {
 | 
			
		||||
		Langs = []string{
 | 
			
		||||
			"en-US", "zh-CN", "zh-HK", "zh-TW", "de-DE", "fr-FR", "nl-NL", "lv-LV",
 | 
			
		||||
			"ru-RU", "uk-UA", "ja-JP", "es-ES", "pt-BR", "pl-PL", "bg-BG", "it-IT",
 | 
			
		||||
			"fi-FI", "tr-TR", "cs-CZ", "sr-SP", "sv-SE", "ko-KR"}
 | 
			
		||||
			"ru-RU", "uk-UA", "ja-JP", "es-ES", "pt-BR", "pt-PT", "pl-PL", "bg-BG",
 | 
			
		||||
			"it-IT", "fi-FI", "tr-TR", "cs-CZ", "sr-SP", "sv-SE", "ko-KR"}
 | 
			
		||||
	}
 | 
			
		||||
	Names = Cfg.Section("i18n").Key("NAMES").Strings(",")
 | 
			
		||||
	if len(Names) == 0 {
 | 
			
		||||
		Names = []string{"English", "简体中文", "繁體中文(香港)", "繁體中文(台灣)", "Deutsch",
 | 
			
		||||
			"français", "Nederlands", "latviešu", "русский", "Українська", "日本語",
 | 
			
		||||
			"español", "português do Brasil", "polski", "български", "italiano",
 | 
			
		||||
			"suomi", "Türkçe", "čeština", "српски", "svenska", "한국어"}
 | 
			
		||||
			"español", "português do Brasil", "Português de Portugal", "polski", "български",
 | 
			
		||||
			"italiano", "suomi", "Türkçe", "čeština", "српски", "svenska", "한국어"}
 | 
			
		||||
	}
 | 
			
		||||
	dateLangs = Cfg.Section("i18n.datelang").KeysHash()
 | 
			
		||||
 | 
			
		||||
@@ -1069,7 +1073,7 @@ func loadInternalToken(sec *ini.Section) string {
 | 
			
		||||
			return token
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return string(buf)
 | 
			
		||||
		return strings.TrimSpace(string(buf))
 | 
			
		||||
	default:
 | 
			
		||||
		log.Fatal("Unsupported URI-Scheme %q (INTERNAL_TOKEN_URI = %q)", tempURI.Scheme, uri)
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -82,6 +82,7 @@ type CreatePullRequestOption struct {
 | 
			
		||||
type EditPullRequestOption struct {
 | 
			
		||||
	Title     string   `json:"title"`
 | 
			
		||||
	Body      string   `json:"body"`
 | 
			
		||||
	Base      string   `json:"base"`
 | 
			
		||||
	Assignee  string   `json:"assignee"`
 | 
			
		||||
	Assignees []string `json:"assignees"`
 | 
			
		||||
	Milestone int64    `json:"milestone"`
 | 
			
		||||
 
 | 
			
		||||
@@ -48,18 +48,6 @@ func JSONRenderer() macaron.Handler {
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// JSRenderer implements the macaron handler for serving JS templates.
 | 
			
		||||
func JSRenderer() macaron.Handler {
 | 
			
		||||
	return macaron.Renderer(macaron.RenderOptions{
 | 
			
		||||
		Funcs:     NewFuncMap(),
 | 
			
		||||
		Directory: path.Join(setting.StaticRootPath, "templates"),
 | 
			
		||||
		AppendDirectories: []string{
 | 
			
		||||
			path.Join(setting.CustomPath, "templates"),
 | 
			
		||||
		},
 | 
			
		||||
		HTMLContentType: "application/javascript",
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Mailer provides the templates required for sending notification mails.
 | 
			
		||||
func Mailer() (*texttmpl.Template, *template.Template) {
 | 
			
		||||
	for _, funcs := range NewTextFuncMap() {
 | 
			
		||||
 
 | 
			
		||||
@@ -132,15 +132,6 @@ func JSONRenderer() macaron.Handler {
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// JSRenderer implements the macaron handler for serving JS templates.
 | 
			
		||||
func JSRenderer() macaron.Handler {
 | 
			
		||||
	return macaron.Renderer(macaron.RenderOptions{
 | 
			
		||||
		Funcs:              NewFuncMap(),
 | 
			
		||||
		TemplateFileSystem: NewTemplateFileSystem(),
 | 
			
		||||
		HTMLContentType:    "application/javascript",
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Mailer provides the templates required for sending notification mails.
 | 
			
		||||
func Mailer() (*texttmpl.Template, *template.Template) {
 | 
			
		||||
	for _, funcs := range NewTextFuncMap() {
 | 
			
		||||
 
 | 
			
		||||
@@ -75,6 +75,11 @@ func (ts TimeStamp) FormatShort() string {
 | 
			
		||||
	return ts.Format("Jan 02, 2006")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FormatDate formats a date in YYYY-MM-DD server time zone
 | 
			
		||||
func (ts TimeStamp) FormatDate() string {
 | 
			
		||||
	return time.Unix(int64(ts), 0).String()[:10]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsZero is zero time
 | 
			
		||||
func (ts TimeStamp) IsZero() bool {
 | 
			
		||||
	return ts.AsTimeInLocation(time.Local).IsZero()
 | 
			
		||||
 
 | 
			
		||||
@@ -25,6 +25,7 @@ Damaris Padieu <damizx AT hotmail DOT fr>
 | 
			
		||||
Daniel Speichert <daniel AT speichert DOT pl>
 | 
			
		||||
David Yzaguirre <dvdyzag AT gmail DOT com>
 | 
			
		||||
Dmitriy Nogay <me AT catwhocode DOT ga>
 | 
			
		||||
Emanuel Angelo <emanuel DOT angelo AT gmail DOT com>
 | 
			
		||||
Enrico Testori hypertesto AT gmail DOT com
 | 
			
		||||
Ezequiel Gonzalez Rial <gonrial AT gmail DOT com>
 | 
			
		||||
Gabriel Dugny <gabriel DOT dugny AT gmail DOT com>
 | 
			
		||||
 
 | 
			
		||||
@@ -1647,6 +1647,7 @@ diff.review.placeholder = Review comment
 | 
			
		||||
diff.review.comment = Comment
 | 
			
		||||
diff.review.approve = Approve
 | 
			
		||||
diff.review.reject = Request changes
 | 
			
		||||
diff.committed_by = committed by
 | 
			
		||||
 | 
			
		||||
releases.desc = Track project versions and downloads.
 | 
			
		||||
release.releases = Releases
 | 
			
		||||
@@ -1872,7 +1873,6 @@ dashboard.resync_all_sshkeys.desc = (Not needed for the built-in SSH server.)
 | 
			
		||||
dashboard.resync_all_hooks = Resynchronize pre-receive, update and post-receive hooks of all repositories.
 | 
			
		||||
dashboard.reinit_missing_repos = Reinitialize all missing Git repositories for which records exist
 | 
			
		||||
dashboard.sync_external_users = Synchronize external user data
 | 
			
		||||
dashboard.git_fsck = Execute health checks on all repositories
 | 
			
		||||
dashboard.server_uptime = Server Uptime
 | 
			
		||||
dashboard.current_goroutine = Current Goroutines
 | 
			
		||||
dashboard.current_memory_usage = Current Memory Usage
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										22
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										22
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							@@ -14852,6 +14852,28 @@
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz",
 | 
			
		||||
      "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8="
 | 
			
		||||
    },
 | 
			
		||||
    "workbox-core": {
 | 
			
		||||
      "version": "5.1.3",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/workbox-core/-/workbox-core-5.1.3.tgz",
 | 
			
		||||
      "integrity": "sha512-TFSIPxxciX9sFaj0FDiohBeIKpwMcCyNduydi9i3LChItcndDS6TJpErxybv8aBWeCMraXt33TWtF6kKuIObNw=="
 | 
			
		||||
    },
 | 
			
		||||
    "workbox-routing": {
 | 
			
		||||
      "version": "5.1.3",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/workbox-routing/-/workbox-routing-5.1.3.tgz",
 | 
			
		||||
      "integrity": "sha512-F+sAp9Iy3lVl3BEG+pzXWVq4AftzjiFpHDaZ4Kf4vLoBoKQE0hIHet4zE5DpHqYdyw+Udhp4wrfHamX6PN6z1Q==",
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "workbox-core": "^5.1.3"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "workbox-strategies": {
 | 
			
		||||
      "version": "5.1.3",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/workbox-strategies/-/workbox-strategies-5.1.3.tgz",
 | 
			
		||||
      "integrity": "sha512-wiXHfmOKnWABeIVW+/ye0e00+2CcS5y7SIj2f9zcdy2ZLEbcOf7B+yOl5OrWpBGlTUwRjIYhV++ZqiKm3Dc+8w==",
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "workbox-core": "^5.1.3",
 | 
			
		||||
        "workbox-routing": "^5.1.3"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "worker-farm": {
 | 
			
		||||
      "version": "1.7.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz",
 | 
			
		||||
 
 | 
			
		||||
@@ -47,6 +47,8 @@
 | 
			
		||||
    "webpack": "4.43.0",
 | 
			
		||||
    "webpack-cli": "3.3.11",
 | 
			
		||||
    "webpack-fix-style-only-entries": "0.4.0",
 | 
			
		||||
    "workbox-routing": "5.1.3",
 | 
			
		||||
    "workbox-strategies": "5.1.3",
 | 
			
		||||
    "worker-loader": "2.0.0"
 | 
			
		||||
  },
 | 
			
		||||
  "devDependencies": {
 | 
			
		||||
 
 | 
			
		||||
@@ -48,10 +48,12 @@ func Markdown(ctx *context.APIContext, form api.MarkdownOption) {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch form.Mode {
 | 
			
		||||
	case "comment":
 | 
			
		||||
		fallthrough
 | 
			
		||||
	case "gfm":
 | 
			
		||||
		md := []byte(form.Text)
 | 
			
		||||
		urlPrefix := form.Context
 | 
			
		||||
		var meta map[string]string
 | 
			
		||||
		meta := map[string]string{}
 | 
			
		||||
		if !strings.HasPrefix(setting.AppSubURL+"/", urlPrefix) {
 | 
			
		||||
			// check if urlPrefix is already set to a URL
 | 
			
		||||
			linkRegex, _ := xurls.StrictMatchingScheme("https?://")
 | 
			
		||||
@@ -61,8 +63,16 @@ func Markdown(ctx *context.APIContext, form api.MarkdownOption) {
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if ctx.Repo != nil && ctx.Repo.Repository != nil {
 | 
			
		||||
			// "gfm" = Github Flavored Markdown - set this to render as a document
 | 
			
		||||
			if form.Mode == "gfm" {
 | 
			
		||||
				meta = ctx.Repo.Repository.ComposeDocumentMetas()
 | 
			
		||||
			} else {
 | 
			
		||||
				meta = ctx.Repo.Repository.ComposeMetas()
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if form.Mode == "gfm" {
 | 
			
		||||
			meta["mode"] = "document"
 | 
			
		||||
		}
 | 
			
		||||
		if form.Wiki {
 | 
			
		||||
			_, err := ctx.Write([]byte(markdown.RenderWiki(md, urlPrefix, meta)))
 | 
			
		||||
			if err != nil {
 | 
			
		||||
 
 | 
			
		||||
@@ -94,7 +94,7 @@ Here are some links to the most important topics. You can find the full list of
 | 
			
		||||
<p><strong>Wine Staging</strong> on website <a href="http://wine-staging.com" rel="nofollow">wine-staging.com</a>.</p>
 | 
			
		||||
<h2 id="user-content-quick-links">Quick Links</h2>
 | 
			
		||||
<p>Here are some links to the most important topics. You can find the full list of pages at the sidebar.</p>
 | 
			
		||||
<p><a href="` + AppSubURL + `wiki/Configuration" rel="nofollow">Configuration</a><br/>
 | 
			
		||||
<p><a href="` + AppSubURL + `wiki/Configuration" rel="nofollow">Configuration</a>
 | 
			
		||||
<a href="` + AppSubURL + `wiki/raw/images/icon-bug.png" rel="nofollow"><img src="` + AppSubURL + `wiki/raw/images/icon-bug.png" title="icon-bug.png" alt="images/icon-bug.png"/></a></p>
 | 
			
		||||
`,
 | 
			
		||||
		// Guard wiki sidebar: special syntax
 | 
			
		||||
 
 | 
			
		||||
@@ -7,6 +7,7 @@ package repo
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/base64"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
@@ -198,6 +199,16 @@ func CreateFile(ctx *context.APIContext, apiOpts api.CreateFileOptions) {
 | 
			
		||||
	// responses:
 | 
			
		||||
	//   "201":
 | 
			
		||||
	//     "$ref": "#/responses/FileResponse"
 | 
			
		||||
	//   "403":
 | 
			
		||||
	//     "$ref": "#/responses/error"
 | 
			
		||||
	//   "404":
 | 
			
		||||
	//     "$ref": "#/responses/notFound"
 | 
			
		||||
	//   "422":
 | 
			
		||||
	//     "$ref": "#/responses/error"
 | 
			
		||||
 | 
			
		||||
	if ctx.Repo.Repository.IsEmpty {
 | 
			
		||||
		ctx.Error(http.StatusUnprocessableEntity, "RepoIsEmpty", fmt.Errorf("repo is empty"))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if apiOpts.BranchName == "" {
 | 
			
		||||
		apiOpts.BranchName = ctx.Repo.Repository.DefaultBranch
 | 
			
		||||
@@ -235,7 +246,7 @@ func CreateFile(ctx *context.APIContext, apiOpts api.CreateFileOptions) {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if fileResponse, err := createOrUpdateFile(ctx, opts); err != nil {
 | 
			
		||||
		ctx.Error(http.StatusInternalServerError, "CreateFile", err)
 | 
			
		||||
		handleCreateOrUpdateFileError(ctx, err)
 | 
			
		||||
	} else {
 | 
			
		||||
		ctx.JSON(http.StatusCreated, fileResponse)
 | 
			
		||||
	}
 | 
			
		||||
@@ -274,6 +285,16 @@ func UpdateFile(ctx *context.APIContext, apiOpts api.UpdateFileOptions) {
 | 
			
		||||
	// responses:
 | 
			
		||||
	//   "200":
 | 
			
		||||
	//     "$ref": "#/responses/FileResponse"
 | 
			
		||||
	//   "403":
 | 
			
		||||
	//     "$ref": "#/responses/error"
 | 
			
		||||
	//   "404":
 | 
			
		||||
	//     "$ref": "#/responses/notFound"
 | 
			
		||||
	//   "422":
 | 
			
		||||
	//     "$ref": "#/responses/error"
 | 
			
		||||
 | 
			
		||||
	if ctx.Repo.Repository.IsEmpty {
 | 
			
		||||
		ctx.Error(http.StatusUnprocessableEntity, "RepoIsEmpty", fmt.Errorf("repo is empty"))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if apiOpts.BranchName == "" {
 | 
			
		||||
		apiOpts.BranchName = ctx.Repo.Repository.DefaultBranch
 | 
			
		||||
@@ -313,12 +334,30 @@ func UpdateFile(ctx *context.APIContext, apiOpts api.UpdateFileOptions) {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if fileResponse, err := createOrUpdateFile(ctx, opts); err != nil {
 | 
			
		||||
		ctx.Error(http.StatusInternalServerError, "UpdateFile", err)
 | 
			
		||||
		handleCreateOrUpdateFileError(ctx, err)
 | 
			
		||||
	} else {
 | 
			
		||||
		ctx.JSON(http.StatusOK, fileResponse)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func handleCreateOrUpdateFileError(ctx *context.APIContext, err error) {
 | 
			
		||||
	if models.IsErrUserCannotCommit(err) || models.IsErrFilePathProtected(err) {
 | 
			
		||||
		ctx.Error(http.StatusForbidden, "Access", err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if models.IsErrBranchAlreadyExists(err) || models.IsErrFilenameInvalid(err) || models.IsErrSHADoesNotMatch(err) ||
 | 
			
		||||
		models.IsErrFilePathInvalid(err) || models.IsErrRepoFileAlreadyExists(err) {
 | 
			
		||||
		ctx.Error(http.StatusUnprocessableEntity, "Invalid", err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if git.IsErrBranchNotExist(err) {
 | 
			
		||||
		ctx.Error(http.StatusNotFound, "BranchDoesNotExist", err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ctx.Error(http.StatusInternalServerError, "UpdateFile", err)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Called from both CreateFile or UpdateFile to handle both
 | 
			
		||||
func createOrUpdateFile(ctx *context.APIContext, opts *repofiles.UpdateRepoFileOptions) (*api.FileResponse, error) {
 | 
			
		||||
	if !canWriteFiles(ctx.Repo) {
 | 
			
		||||
 
 | 
			
		||||
@@ -691,7 +691,7 @@ func UpdateIssueDeadline(ctx *context.APIContext, form api.EditDeadlineOption) {
 | 
			
		||||
	var deadline time.Time
 | 
			
		||||
	if form.Deadline != nil && !form.Deadline.IsZero() {
 | 
			
		||||
		deadline = time.Date(form.Deadline.Year(), form.Deadline.Month(), form.Deadline.Day(),
 | 
			
		||||
			23, 59, 59, 0, form.Deadline.Location())
 | 
			
		||||
			23, 59, 59, 0, time.Local)
 | 
			
		||||
		deadlineUnix = timeutil.TimeStamp(deadline.Unix())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -382,6 +382,8 @@ func EditPullRequest(ctx *context.APIContext, form api.EditPullRequestOption) {
 | 
			
		||||
	//     "$ref": "#/responses/PullRequest"
 | 
			
		||||
	//   "403":
 | 
			
		||||
	//     "$ref": "#/responses/forbidden"
 | 
			
		||||
	//   "409":
 | 
			
		||||
	//     "$ref": "#/responses/error"
 | 
			
		||||
	//   "412":
 | 
			
		||||
	//     "$ref": "#/responses/error"
 | 
			
		||||
	//   "422":
 | 
			
		||||
@@ -508,6 +510,30 @@ func EditPullRequest(ctx *context.APIContext, form api.EditPullRequestOption) {
 | 
			
		||||
		notification.NotifyIssueChangeStatus(ctx.User, issue, statusChangeComment, issue.IsClosed)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// change pull target branch
 | 
			
		||||
	if len(form.Base) != 0 && form.Base != pr.BaseBranch {
 | 
			
		||||
		if !ctx.Repo.GitRepo.IsBranchExist(form.Base) {
 | 
			
		||||
			ctx.Error(http.StatusNotFound, "NewBaseBranchNotExist", fmt.Errorf("new base '%s' not exist", form.Base))
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		if err := pull_service.ChangeTargetBranch(pr, ctx.User, form.Base); err != nil {
 | 
			
		||||
			if models.IsErrPullRequestAlreadyExists(err) {
 | 
			
		||||
				ctx.Error(http.StatusConflict, "IsErrPullRequestAlreadyExists", err)
 | 
			
		||||
				return
 | 
			
		||||
			} else if models.IsErrIssueIsClosed(err) {
 | 
			
		||||
				ctx.Error(http.StatusUnprocessableEntity, "IsErrIssueIsClosed", err)
 | 
			
		||||
				return
 | 
			
		||||
			} else if models.IsErrPullRequestHasMerged(err) {
 | 
			
		||||
				ctx.Error(http.StatusConflict, "IsErrPullRequestHasMerged", err)
 | 
			
		||||
				return
 | 
			
		||||
			} else {
 | 
			
		||||
				ctx.InternalServerError(err)
 | 
			
		||||
			}
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		notification.NotifyPullRequestChangeTargetBranch(ctx.User, pr, form.Base)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Refetch from database
 | 
			
		||||
	pr, err = models.GetPullRequestByIndex(ctx.Repo.Repository.ID, pr.Index)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
 
 | 
			
		||||
@@ -78,9 +78,9 @@ func Search(ctx *context.APIContext) {
 | 
			
		||||
	//   in: query
 | 
			
		||||
	//   description: include private repositories this user has access to (defaults to true)
 | 
			
		||||
	//   type: boolean
 | 
			
		||||
	// - name: onlyPrivate
 | 
			
		||||
	// - name: is_private
 | 
			
		||||
	//   in: query
 | 
			
		||||
	//   description: only include private repositories this user has access to (defaults to false)
 | 
			
		||||
	//   description: show only pubic, private or all repositories (defaults to all)
 | 
			
		||||
	//   type: boolean
 | 
			
		||||
	// - name: template
 | 
			
		||||
	//   in: query
 | 
			
		||||
@@ -133,7 +133,6 @@ func Search(ctx *context.APIContext) {
 | 
			
		||||
		TopicOnly:          ctx.QueryBool("topic"),
 | 
			
		||||
		Collaborate:        util.OptionalBoolNone,
 | 
			
		||||
		Private:            ctx.IsSigned && (ctx.Query("private") == "" || ctx.QueryBool("private")),
 | 
			
		||||
		OnlyPrivate:        ctx.IsSigned && ctx.QueryBool("onlyPrivate"),
 | 
			
		||||
		Template:           util.OptionalBoolNone,
 | 
			
		||||
		StarredByID:        ctx.QueryInt64("starredBy"),
 | 
			
		||||
		IncludeDescription: ctx.QueryBool("includeDesc"),
 | 
			
		||||
@@ -169,6 +168,10 @@ func Search(ctx *context.APIContext) {
 | 
			
		||||
		opts.Archived = util.OptionalBoolOf(ctx.QueryBool("archived"))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ctx.Query("is_private") != "" {
 | 
			
		||||
		opts.IsPrivate = util.OptionalBoolOf(ctx.QueryBool("is_private"))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var sortMode = ctx.Query("sort")
 | 
			
		||||
	if len(sortMode) > 0 {
 | 
			
		||||
		var sortOrder = ctx.Query("order")
 | 
			
		||||
 
 | 
			
		||||
@@ -275,12 +275,6 @@ func TopicSearch(ctx *context.APIContext) {
 | 
			
		||||
	kw := ctx.Query("q")
 | 
			
		||||
 | 
			
		||||
	listOptions := utils.GetListOptions(ctx)
 | 
			
		||||
	if listOptions.Page < 1 {
 | 
			
		||||
		listOptions.Page = 1
 | 
			
		||||
	}
 | 
			
		||||
	if listOptions.PageSize < 1 {
 | 
			
		||||
		listOptions.PageSize = 10
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	topics, err := models.FindTopics(&models.FindTopicOptions{
 | 
			
		||||
		Keyword:     kw,
 | 
			
		||||
 
 | 
			
		||||
@@ -144,6 +144,8 @@ func CreateGPGKey(ctx *context.APIContext, form api.CreateGPGKeyOption) {
 | 
			
		||||
	// responses:
 | 
			
		||||
	//   "201":
 | 
			
		||||
	//     "$ref": "#/responses/GPGKey"
 | 
			
		||||
	//   "404":
 | 
			
		||||
	//     "$ref": "#/responses/notFound"
 | 
			
		||||
	//   "422":
 | 
			
		||||
	//     "$ref": "#/responses/validationError"
 | 
			
		||||
 | 
			
		||||
@@ -169,6 +171,8 @@ func DeleteGPGKey(ctx *context.APIContext) {
 | 
			
		||||
	//     "$ref": "#/responses/empty"
 | 
			
		||||
	//   "403":
 | 
			
		||||
	//     "$ref": "#/responses/forbidden"
 | 
			
		||||
	//   "404":
 | 
			
		||||
	//     "$ref": "#/responses/notFound"
 | 
			
		||||
 | 
			
		||||
	if err := models.DeleteGPGKey(ctx.User, ctx.ParamsInt64(":id")); err != nil {
 | 
			
		||||
		if models.IsErrGPGKeyAccessDenied(err) {
 | 
			
		||||
@@ -186,9 +190,13 @@ func DeleteGPGKey(ctx *context.APIContext) {
 | 
			
		||||
func HandleAddGPGKeyError(ctx *context.APIContext, err error) {
 | 
			
		||||
	switch {
 | 
			
		||||
	case models.IsErrGPGKeyAccessDenied(err):
 | 
			
		||||
		ctx.Error(http.StatusUnprocessableEntity, "", "You do not have access to this GPG key")
 | 
			
		||||
		ctx.Error(http.StatusUnprocessableEntity, "GPGKeyAccessDenied", "You do not have access to this GPG key")
 | 
			
		||||
	case models.IsErrGPGKeyIDAlreadyUsed(err):
 | 
			
		||||
		ctx.Error(http.StatusUnprocessableEntity, "", "A key with the same id already exists")
 | 
			
		||||
		ctx.Error(http.StatusUnprocessableEntity, "GPGKeyIDAlreadyUsed", "A key with the same id already exists")
 | 
			
		||||
	case models.IsErrGPGKeyParsing(err):
 | 
			
		||||
		ctx.Error(http.StatusUnprocessableEntity, "GPGKeyParsing", err)
 | 
			
		||||
	case models.IsErrGPGNoEmailFound(err):
 | 
			
		||||
		ctx.Error(http.StatusNotFound, "GPGNoEmailFound", err)
 | 
			
		||||
	default:
 | 
			
		||||
		ctx.Error(http.StatusInternalServerError, "AddGPGKey", err)
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,7 @@ package user
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"strconv"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/models"
 | 
			
		||||
	"code.gitea.io/gitea/modules/context"
 | 
			
		||||
@@ -15,10 +16,12 @@ import (
 | 
			
		||||
 | 
			
		||||
// listUserRepos - List the repositories owned by the given user.
 | 
			
		||||
func listUserRepos(ctx *context.APIContext, u *models.User, private bool) {
 | 
			
		||||
	repos, err := models.GetUserRepositories(&models.SearchRepoOptions{
 | 
			
		||||
	opts := utils.GetListOptions(ctx)
 | 
			
		||||
 | 
			
		||||
	repos, count, err := models.GetUserRepositories(&models.SearchRepoOptions{
 | 
			
		||||
		Actor:       u,
 | 
			
		||||
		Private:     private,
 | 
			
		||||
		ListOptions: utils.GetListOptions(ctx),
 | 
			
		||||
		ListOptions: opts,
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		ctx.Error(http.StatusInternalServerError, "GetUserRepositories", err)
 | 
			
		||||
@@ -36,6 +39,9 @@ func listUserRepos(ctx *context.APIContext, u *models.User, private bool) {
 | 
			
		||||
			apiRepos = append(apiRepos, repos[i].APIFormat(access))
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ctx.SetLinkHeader(int(count), opts.PageSize)
 | 
			
		||||
	ctx.Header().Set("X-Total-Count", strconv.FormatInt(count, 10))
 | 
			
		||||
	ctx.JSON(http.StatusOK, &apiRepos)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -92,31 +98,37 @@ func ListMyRepos(ctx *context.APIContext) {
 | 
			
		||||
	//   "200":
 | 
			
		||||
	//     "$ref": "#/responses/RepositoryList"
 | 
			
		||||
 | 
			
		||||
	ownRepos, err := models.GetUserRepositories(&models.SearchRepoOptions{
 | 
			
		||||
		Actor:       ctx.User,
 | 
			
		||||
		Private:     true,
 | 
			
		||||
	opts := &models.SearchRepoOptions{
 | 
			
		||||
		ListOptions:        utils.GetListOptions(ctx),
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		ctx.Error(http.StatusInternalServerError, "GetUserRepositories", err)
 | 
			
		||||
		return
 | 
			
		||||
		Actor:              ctx.User,
 | 
			
		||||
		OwnerID:            ctx.User.ID,
 | 
			
		||||
		Private:            ctx.IsSigned,
 | 
			
		||||
		IncludeDescription: true,
 | 
			
		||||
	}
 | 
			
		||||
	accessibleReposMap, err := ctx.User.GetRepositoryAccesses()
 | 
			
		||||
 | 
			
		||||
	var err error
 | 
			
		||||
	repos, count, err := models.SearchRepository(opts)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		ctx.Error(http.StatusInternalServerError, "GetRepositoryAccesses", err)
 | 
			
		||||
		ctx.Error(http.StatusInternalServerError, "SearchRepository", err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	apiRepos := make([]*api.Repository, len(ownRepos)+len(accessibleReposMap))
 | 
			
		||||
	for i := range ownRepos {
 | 
			
		||||
		apiRepos[i] = ownRepos[i].APIFormat(models.AccessModeOwner)
 | 
			
		||||
	results := make([]*api.Repository, len(repos))
 | 
			
		||||
	for i, repo := range repos {
 | 
			
		||||
		if err = repo.GetOwner(); err != nil {
 | 
			
		||||
			ctx.Error(http.StatusInternalServerError, "GetOwner", err)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	i := len(ownRepos)
 | 
			
		||||
	for repo, access := range accessibleReposMap {
 | 
			
		||||
		apiRepos[i] = repo.APIFormat(access)
 | 
			
		||||
		i++
 | 
			
		||||
		accessMode, err := models.AccessLevel(ctx.User, repo)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			ctx.Error(http.StatusInternalServerError, "AccessLevel", err)
 | 
			
		||||
		}
 | 
			
		||||
	ctx.JSON(http.StatusOK, &apiRepos)
 | 
			
		||||
		results[i] = repo.APIFormat(accessMode)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ctx.SetLinkHeader(int(count), opts.ListOptions.PageSize)
 | 
			
		||||
	ctx.Header().Set("X-Total-Count", strconv.FormatInt(count, 10))
 | 
			
		||||
	ctx.JSON(http.StatusOK, &results)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ListOrgRepos - list the repositories of an organization.
 | 
			
		||||
 
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user