Compare commits

..

93 Commits

Author SHA1 Message Date
Lunny Xiao
09b76295f1 Add changelog for v1.16.8 (#19724)
* Add changelog for v1.16.8

Co-authored-by: 6543 <6543@obermui.de>
Co-authored-by: Gusted <williamzijl7@hotmail.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2022-05-16 19:27:23 +02:00
Gusted
38acce2f3f Fix issue overview for teams (#19652) (#19653)
- Backport #19652
  - Don't use hacky solution to limit to the correct RepoID's, instead use current code to handle these limits. The existing code is more correct than the hacky solution.
  - Resolves #19636
2022-05-16 17:48:16 +08:00
6543
8f44d00f22 Delete user related oauth stuff on user deletion too (#19677) (#19680)
Backport (#19677)

* delete user related oauth stuff on user deletion too

* extend doctor check-db-consistency

* make it build for v1.16.x
2022-05-12 13:32:48 +02:00
Lunny Xiao
4386eb751f Fix oauth setting list bug (#19681) 2022-05-11 21:05:58 +08:00
Lunny Xiao
d6aab069ed Fix new release from tags list UI (#19670) (#19673) 2022-05-10 22:55:28 +02:00
singuliere
f4fb8dbc87 [doctor] Add check/fix for bogus action rows (#19656) (#19669)
Co-authored-by: Loïc Dachary <loic@dachary.org>

Conflicts:
	models/consistency_test.go
	 trivial context conflict.
2022-05-10 16:05:34 +03:00
Lunny Xiao
c7c18e0eb2 Revert "Add finalizers to ensure that repos are closed and blobreaders are closed (#19495) (#19496)" (#19659)
This reverts commit 88da50674f.

because it caused a memleak
2022-05-09 13:03:44 +02:00
singuliere
0a2d618d85 GetFeeds must always discard actions with dangling repo_id (#19598) (#19629)
Co-authored-by: Loïc Dachary <loic@dachary.org>
(cherry picked from commit b536b65189)

Conflicts:
        models/action_test.go
	  The GetFeeds function does not have a Context argument in 1.16.
	models/action.go
	  The SQL statement is essentially the same in 1.16 but
	  structured differently. The Join() was copied and the
   	  created_unix field prefixed with `action`.
	models/action_list.go
	  in 1.16 the loadRepoOwner method did not exist and
	  it was done in the RetrieveFeeds method of web/feed/profile.go.
          The safeguard to skip when act.Repo == nil was moved there.
2022-05-08 15:05:40 +02:00
Jimmy Praet
c8a83ace59 Only show accessible teams in dashboard dropdown list (#19642) (#19645)
Fixes #19637
2022-05-07 17:50:34 +02:00
techknowlogick
59d132f0b3 Set safe dir for git operations in .drone.yml CI (#19641) (#19643)
Our drone by necessity runs on git repositories not owned by the drone process. Unfortunately this means that git operations and thence CI builds will fail without the `safe.directory` option being set. 

See: https://drone.gitea.io/go-gitea/gitea/54632/2/8
2022-05-06 14:09:54 -04:00
zeripath
18dd49a4ab Prevent NPE when checking repo units if the user is nil (#19625) (#19630)
Backport #19625

CheckRepoUnitUser should tolerate nil users.

Fix #19613

Signed-off-by: Andrew Thornton <art27@cantab.net>

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2022-05-06 18:01:08 +08:00
wxiaoguang
46637b1164 Call MultipartForm.RemoveAll when request finishes (#19606) (#19607) 2022-05-05 16:13:59 +02:00
Eekle
7b18c67ac9 Make .cs highlighting legible on dark themes (#19604) (#19605) 2022-05-04 18:45:00 +08:00
99rgosse
6eb3c05cb7 Avoid MoreThanOne Error (#19557) (#19591)
Backport #19557
2022-05-03 20:36:58 +08:00
Gusted
82f24bedc2 Fix sending empty notifications (#19589) (#19590)
- Backport #19589
  - Don't send empty notifications on read notifications API.
2022-05-02 21:28:12 -05:00
zeripath
88da50674f Add finalizers to ensure that repos are closed and blobreaders are closed (#19495) (#19496)
It may be prudent to add runtime finalizers to the git.Repository and
git.blobReader objects to absolutely ensure that these are both properly
cancelled, cleaned and closed out.

This commit is a backport of an extract from #19448

Signed-off-by: Andrew Thornton <art27@cantab.net>
2022-05-02 20:44:45 +08:00
wxiaoguang
35a7db49b4 ignore DNS error when doing migration allow/block check (#19567)
Co-authored-by: Lauris BH <lauris@nix.lv>
2022-05-02 08:11:45 +03:00
6543
f4729e2418 Add Changelog v1.16.7 (#19575)
Co-authored-by: techknowlogick <matti@mdranta.net>
Co-authored-by: Gusted <williamzijl7@hotmail.com>
2022-05-02 05:41:09 +02:00
6543
f7330fd027 Dont overwrite err with nil (part #19572) (#19574)
* Dont overwrite err with nil (part #19572)


Co-authored-by: Gusted <williamzijl7@hotmail.com>
2022-05-02 01:54:20 +02:00
6543
755d8e21ad Migration: only write commit-graph if wiki clone was successfull (#19563) (#19568) 2022-05-01 00:22:42 +02:00
Jimmy Praet
7c0bf06d96 Respect DefaultUserIsRestricted system default when creating new user (#19310 ) (#19560) 2022-04-30 15:00:14 +02:00
Gusted
0d196e29e8 Don't error when branch's commit doesn't exist (#19547) (#19548)
- Backport #19547
  - If one of the branches no longer exists, don't throw an error, it's possible that the branch was destroyed during the process. Simply skip it and disregard it.
  - Resolves #19541
2022-04-29 12:25:19 +02:00
wxiaoguang
b86606fa38 Support hostname:port to pass host matcher's check (#19543) (#19544)
Backport #19543 
hostmatcher: split the hostname from the hostname:port string, use the correct hostname to do the match.
2022-04-29 01:41:58 +08:00
zeripath
74602bb487 Prevent intermittent race in attribute reader close (#19537) (#19539)
Backport #19537

There is a potential rare race possible whereby the c.running channel could
be closed twice. Looking at the code I do not see a need for this c.running
channel and therefore I think we can remove this. (I think the c.running
might have been some attempt to prevent a hang but the use of os.Pipes should
prevent that.)

Signed-off-by: Andrew Thornton <art27@cantab.net>
2022-04-28 17:00:01 +02:00
Gusted
1465e0cbb2 Fix 64-bit atomic operations on 32-bit machines (#19531) (#19532)
- Backport #19531
  - Doing 64-bit atomic operations on 32-bit machines is a bit tricky by golang, as they can only be done under certain set of conditions(https://pkg.go.dev/sync/atomic#pkg-note-BUG).
  - This PR fixes such case whereby the conditions weren't met, it moves the int64 to the first field of the struct, which will 64-bit operations happening on this property on 32-bit machines.
  - Resolves #19518
2022-04-27 10:32:28 -05:00
Lunny Xiao
928b603d19 Fix migrate release from github (#19510) (#19523)
* Fix migrate release from github

* Fix bug
2022-04-27 14:46:00 +02:00
Lunny Xiao
8ff542c1a2 When view _Siderbar or _Footer, just display once (#19501) (#19522)
Co-authored-by: zeripath <art27@cantab.net>
2022-04-27 14:04:53 +02:00
zeripath
39a0db6ecf Prevent dangling archiver goroutine (#19516) (#19526)
Backport #19516

Within doArchive there is a service goroutine that performs the
archiving function.  This goroutine reports its error using a `chan
error` called `done`. Prior to this PR this channel had 0 capacity
meaning that the goroutine would block until the `done` channel was
cleared - however there are a couple of ways in which this channel might
not be read.

The simplest solution is to add a single space of capacity to the
goroutine which will mean that the goroutine will always complete and
even if the `done` channel is not read it will be simply garbage
collected away.

(The PR also contains two other places when setting up the indexers
which do not leak but where the blocking of the sending goroutine is
also unnecessary and so we should just add a small amount of capacity
and let the sending goroutine complete as soon as it can.)

Signed-off-by: Andrew Thornton <art27@cantab.net>

Co-authored-by: 6543 <6543@obermui.de>

Co-authored-by: 6543 <6543@obermui.de>
2022-04-27 16:05:52 +08:00
techknowlogick
9cc93c05cd Unset git author/committer variables when running integration tests (#19512) (#19519)
TestAPIGitTag (and likely others) will fail if the running environment contains
GIT_AUTHOR_NAME and other env variables like it.

This PR simply unsets these when running the integration tests.

Fix #14247

Signed-off-by: Andrew Thornton <art27@cantab.net>

Co-authored-by: zeripath <art27@cantab.net>
2022-04-26 19:23:54 -04:00
Lunny Xiao
b31418edd9 Fix blame page select range error and some typos (#19503)
Partially back port from #19500 and fix two typos.
2022-04-26 20:19:52 +01:00
6543
242f7f1a52 Add notags to fetch (#19487) (#19490)
* Add notags to fetch (#19487)

* gofumpt
2022-04-25 20:26:17 +02:00
6543
8d7f1e430a User specific repoID or xorm builder conditions for issue search (#19475) (#19476) 2022-04-25 15:28:47 +02:00
Pilou
a6b32adc45 [doctor] authorized-keys: fix displayed check name (backport #19464) (#19484)
The registered check name is authorized-keys, not authorized_keys.
2022-04-25 13:45:18 +02:00
Gusted
1f0dca4614 Mark TemplateLoading error as "UnprocessableEntity" (#19445) (#19446)
* Mark TemplateLoading error as "UnprocessableEntity" (#19445)

- Backport #19445
  - Don't return Internal Server error if the user provide incorrect label template, instead return UnprocessableEntity.
  - Resolves #19399

- dep: upgrade: github.com/gogs/chardet
2022-04-22 21:07:57 +02:00
6543
1d665da32f Prevent dangling cat-file calls (goroutine alternative) (#19454) (#19466)
If an `os/exec.Command` is passed non `*os.File` as an input/output, go
will create `os.Pipe`s and wait for their closure in `cmd.Wait()`.  If
the code following this is responsible for closing `io.Pipe`s or other
handlers then on process death from context cancellation the `Wait` can
hang.

There are two possible solutions:

1. use `os.Pipe` as the input/output as `cmd.Wait` does not wait for these.
2. create a goroutine waiting on the context cancellation that will close the inputs.

This PR provides the second option - which is a simpler change that can
be more easily backported.

Closes #19448

Signed-off-by: Andrew Thornton <art27@cantab.net>

Co-authored-by: zeripath <art27@cantab.net>
2022-04-22 16:58:50 +01:00
Gusted
09adc26eb6 Set correct PR status on 3way on conflict checking (#19457) (#19458)
- Backport #19457
  - When 3-way merge is enabled for conflict checking, it has a new interesting behavior that it doesn't return any error when it found a conflict, so we change the condition to not check for the error, but instead check if conflictedfiles is populated, this fixes a issue whereby PR status wasn't correctly on conflicted PR's.
  - Refactor the mergeable property(which was incorrectly set and lead me this bug) to be more maintainable.
  - Add a dedicated test for conflicting checking, so it should prevent future issues with this.
  - Ref: Fix the latest error for https://gitea.com/gitea/go-sdk/pulls/579

Co-authored-by: zeripath <art27@cantab.net>
2022-04-22 09:11:42 +08:00
6543
297346a762 RepoAssignment ensure to close before overwrite (#19449) (#19460)
* check if GitRepo already open and close if

* Only run RepoAssignment once
2022-04-21 18:55:44 +02:00
6543
acd648061d Add Changelog v1.16.6 (#19339)
Co-authored-by: delvh <dev.lh@web.de>
Co-authored-by: techknowlogick <matti@mdranta.net>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: zeripath <art27@cantab.net>
2022-04-21 01:33:50 +02:00
6543
c5fe0a096d When dumping trim the standard suffices instead of a random suffix (#19440) (#19447)
* When dumping trim the standard suffices instead of a random suffix

Instead of using the `path.Ext()` to trim the last "extension" suffix, just iterate
through the supported suffices and trim those.

Fix #19424

Signed-off-by: Andrew Thornton <art27@cantab.net>

* fix enum with to have correct supported types only

Co-authored-by: 6543 <6543@obermui.de>

Co-authored-by: zeripath <art27@cantab.net>
2022-04-20 23:26:03 +01:00
Gusted
0c7bf6801f Fix DELETE request for non-existent public key (#19443) (#19444)
- Backport #19443
  - Add a return for the first "block" of errors, which fixes the double error messages.
  - Add a return for `externallyManaged`.
  - Resolves #19398

Co-authored-by: 6543 <6543@obermui.de>
2022-04-20 23:24:56 +01:00
Gusted
5863f7e048 Don't panic on ErrEmailInvalid (#19441) (#19442)
- Backport #19441
  - Don't panic on `ErrEmailInvalid`, this was caused due that we were trying to force `ErrEmailCharIsNotSupported` interface, which panics.
  - Resolves #19397

Co-authored-by: 6543 <6543@obermui.de>
2022-04-20 23:24:07 +01:00
6543
a785c46ca8 Add uploadpack.allowAnySHA1InWant to allow --filter=blob:none with older git clients (#19430) (#19438)
Older git clients need uploadpack.allowAnySHA1InWant if partial cloning is allowed.

Fix #19118

Signed-off-by: Andrew Thornton <art27@cantab.net>

Co-authored-by: zeripath <art27@cantab.net>
2022-04-20 20:54:36 +02:00
6543
6bddfd3086 Warn on SSH connection for incorrect configuration (#19317) (#19437)
Backport #19317

- Warn on SSH connection for incorrect configuration
- When `setting.RepoRootPath` cannot be found(most likely due to
incorrect configuration) show "Gitea: Incorrect configuration" on the
client-side to help easier with debugging the problem.

Co-authored-by: delvh <dev.lh@web.de>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: techknowlogick <techknowlogick@gitea.io>
2022-04-20 19:18:23 +02:00
6543
dd8a726b25 API: Search Issues, dont show 500 if filter result in empty list (#19244) (#19436)
Backport #19244

* remove error who is none

* use setupSessionNoLimit instead of setupSessionWithLimit when no pagination

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2022-04-20 18:30:42 +02:00
zeripath
08eecba32b When updating mirror repo intervals by API reschedule next update too (#19429) (#19433)
Backport #19429

When a mirror repo interval is updated by the UI it is rescheduled with that interval
however the API does not do this. The API also lacks the enable_prune option.

This PR adds this functionality in to the API Edit Repo endpoint.

Signed-off-by: Andrew Thornton <art27@cantab.net>
2022-04-20 16:04:26 +02:00
wxiaoguang
9c2212df15 Fix nil error when some pages are rendered outside request context (#19428) 2022-04-19 19:30:16 -04:00
Lunny Xiao
9b4746967c Only request write when necessary (#18657) (#19422)
* Only request write when necessary

- Only request write for `INTERNAL_TOKEN_URI` when no token was found.
- Resolves #18655

* Fix perm

* Update setting.go

* Update setting.go

* Update setting.go

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: zeripath <art27@cantab.net>

Co-authored-by: Gusted <williamzijl7@hotmail.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: zeripath <art27@cantab.net>
2022-04-19 12:10:24 -04:00
Gusted
00da1facc4 Fix double blob-hunk on diff page (#19404) (#19405)
- Don't show the blob-hunk twice on diff page
- Backport #19404
2022-04-15 11:27:04 +08:00
techknowlogick
b461993775 go get -u crypto (#19388) 2022-04-12 22:45:58 -04:00
Vasiliy Bukharev
b885e57762 Update locale_ru-RU.ini (#19383) (#19387)
Signed-off-by: bvp <bvp-yar@ya.ru>
2022-04-13 08:15:03 +08:00
Gusted
081449d7a5 Don't allow merging PR's which are being conflict checked (#19357) (#19358)
* Don't allow merging PR's which are being conflict checked (#19357)

- Backport of #19357
  - When a PR is still being conflict checked, don't allow the PR to be merged(the merge button could already be visible before e.g. a new commit was pushed to the PR).
  - Resolves #19352

* Update error message
2022-04-13 00:38:41 +08:00
Gusted
ee3a21a537 Fix middleware function's placements for /user/... (#19377) (#19378)
- Backport #19377
  - Add reqSignIn to `/user/task/{task}` as it specific to a logged in user currently not-logged in user could cause a NPE.
  - Remove `/user/active` reqSignIn middleware, because when you want to active a account you're not "signed in" so it doesn't make sense to add that middleware.
2022-04-12 11:06:07 +08:00
silverwind
61c7732e12 Disable service worker by default (#18914) (#19342)
The service worker causes a lot of issues with JS errors after instance
upgrades while not bringing any real performance gain over regular HTTP
caching.

Disable it by default for this reason. Maybe later we can remove it
completely, as I simply see no benefit in having it.
2022-04-07 20:08:24 +02:00
wxiaoguang
57c2ca7f26 Fix invalid CSRF token bug, make sure CSRF tokens can be up-to-date (#19338)
There was a bug that the CSRF token wouldn't in 24h. This fix just does what the CSRF function comment says: If this request is a GET request, it will generate a new token. Then the CSRF token can be kept up-to-date.
2022-04-06 23:47:58 +08:00
Lunny Xiao
0704009dd7 Revert the minimal golang version requirement from 1.17 to 1.16 and add a warning in Makefile (#19319)
* Revert the minimal golang version requirement from 1.17 to 1.16 and add a warning in Makefile

* Apply suggestions from code review

Co-authored-by: John Olheiser <john.olheiser@gmail.com>

* 1.16

* Update modules/util/net.go

Co-authored-by: Gusted <williamzijl7@hotmail.com>

* correct bool conditional

yay tests for catching this :)

* Update hostmatcher.go

Co-authored-by: John Olheiser <john.olheiser@gmail.com>
Co-authored-by: techknowlogick <techknowlogick@gitea.io>
Co-authored-by: Gusted <williamzijl7@hotmail.com>
2022-04-05 13:32:24 -04:00
zeripath
14a6aafb50 Restore user autoregistration with email addresses (#19261) (#19312)
Backport #19261

Unfortunately #18789 disabled autoregistration using email addresses as they would
be shortcut to email address does not exist.

This PR attempts to restore autoregistration by allowing an unknown email address
to percolate through to the autoregistration path of UserSignin.

Fix #19256

Signed-off-by: Andrew Thornton <art27@cantab.net>
2022-04-02 20:36:47 -04:00
Lunny Xiao
471a1e8111 Performance improvement for add team user when org has more than 1000 repositories (#19227) (#19289) 2022-04-01 11:36:12 +03:00
6543
123c254b84 Move checks for pulls before merge into own function (#19271) (#19277)
Backport #19271

Fix:
* The API does ignore issue dependencies where Web does not
* The API checks if "IsSignedIfRequired" where Web does not - UI probably do but nothing will some to craft custom requests
* Default merge message is crafted a bit different between API and Web if not set on specific cases ...
2022-03-31 16:57:13 +02:00
zeripath
db43f63c53 Use full output of git show-ref --tags to get tags for PushUpdateAddTag (#19235) (#19236)
* Use full output of git show-ref --tags to get tags for PushUpdateAddTag (#19235)

Strangely #19038 appears to relate to an issue whereby a tag appears to
be listed in `git show-ref --tags` but then does not appear when `git
show-ref --tags -- short_name` is called.

As a solution though I propose to stop the second call as it is
unnecessary and only likely to cause problems.

I've also noticed that the tags calls are wildly inefficient and aren't using the common cat-files - so these have been added.

I've also noticed that the git commit-graph is not being written on mirroring - so I've also added writing this to the migration which should improve mirror rendering somewhat.

Fix #19038

Signed-off-by: Andrew Thornton <art27@cantab.net>
Co-authored-by: 6543 <6543@obermui.de>

* fix rebase relict

Co-authored-by: 6543 <6543@obermui.de>
2022-03-29 23:19:57 +03:00
John Olheiser
3ecd520f8e Granular webhook events in editHook (#19251) (#19257)
Signed-off-by: jolheiser <john.olheiser@gmail.com>
2022-03-29 18:26:51 +02:00
zeripath
e9935d358c Only send webhook events to active system webhooks and only deliver to active hooks (#19234) (#19248)
Backport #19234

There is a bug in the system webhooks whereby the active state is not checked when
webhooks are prepared and there is a bug that deactivating webhooks do not prevent
queued deliveries.

* Only add SystemWebhooks to the prepareWebhooks list if they are active
* At the time of delivery if the underlying webhook is not active mark it
as "delivered" but with a failed delivery so it does not get delivered.

Fix #19220

Signed-off-by: Andrew Thornton <art27@cantab.net>
2022-03-29 14:12:56 +02:00
wxiaoguang
8d653b148b Check go and nodejs version by go.mod and package.json (#19197) (#19254)
* Check go and nodejs version by go.mod and package.json 
* Update Go official site URL 

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: gesangtome <gesangtome@foxmail.com>
2022-03-29 15:32:38 +08:00
wxiaoguang
b702f2dac3 Fix clone url JS error for the empty repo page (#19209)
Co-authored-by: 6543 <6543@obermui.de>
Co-authored-by: zeripath <art27@cantab.net>
2022-03-29 11:04:29 +08:00
6543
d59b8541f2 Use goproxy.io instead of goproxy.cn (#19242) (#19246)
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2022-03-29 02:22:55 +01:00
zeripath
efd34d0d7d Prevent intermittent failures in RepoIndexerTest (#19225 #19229) (#19228)
Backport #19225
Backport #19229

The RepoIndexerTest is failing with considerable frequency due to a race inherrent in
its design. This PR adjust this test to avoid the reliance on waiting for the populate
repo indexer to run and forcibly adds the repo to the queue. It then flushes the queue.

It may be worth separating out the tests somewhat by testing the Index function
directly away from the queue however, this forceful method should solve the current
problem.

Fix #19162

Signed-off-by: Andrew Thornton <art27@cantab.net>
2022-03-28 01:01:53 +02:00
zeripath
2ec2935f78 Touch mirrors on even on fail to update (#19217) (#19233)
Backport #19217

If a mirror fails to be synchronised it should be pushed to the bottom of the queue
of the awaiting mirrors to be synchronised. At present if there LIMIT number of
broken mirrors they can effectively prevent all other mirrors from being synchronized
as their last_updated time will remain earlier than other mirrors.

Signed-off-by: Andrew Thornton <art27@cantab.net>
2022-03-27 23:08:28 +02:00
Lunny Xiao
540541caa2 Hide sensitive content on admin panel progress monitor (#19218 & #19226) (#19231)
* Hide sensitive content on admin panel progress monitor (#19218)

Sanitize urls within git process descriptions.

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Andrew Thornton <art27@cantab.net>

* Do not include global arguments in process manager (#19226)

Backport #19226

The git command by default adds a number of global arguments. These are not
helpful to be displayed in the process manager and so should be skipped for
default process descriptions.

Signed-off-by: Andrew Thornton <art27@cantab.net>

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Andrew Thornton <art27@cantab.net>
2022-03-27 18:21:59 +01:00
Robert Kaussow
a13d64bf98 Bump goldmark to v1.4.11 (#19201) (#19203)
* Bump goldmark to v1.4.11

* fix go.sum

Signed-off-by: Andrew Thornton <art27@cantab.net>

* add testcase

Signed-off-by: Andrew Thornton <art27@cantab.net>

Co-authored-by: Andrew Thornton <art27@cantab.net>
2022-03-24 11:47:40 -04:00
zeripath
bab7d885aa Changelog for 1.16.5 (#19189)
* Changelog for 1.16.5

 ## [1.16.5](https://github.com/go-gitea/gitea/releases/tag/1.16.5) - 2022-03-23

Signed-off-by: Andrew Thornton <art27@cantab.net>
Co-authored-by: 6543 <6543@obermui.de>
2022-03-24 01:13:52 +01:00
6543
42229dc0b8 Fix showing issues in your repositories (#18916) (#19191)
- Make a restriction on which issues can be shown based on if you the user or team has write permission to the repository.
- Fixes a issue whereby you wouldn't see any associated issues with a specific team on a organization if you wasn't a member(fixed by zeroing the User{ID} in the options).
- Resolves #18913

Co-authored-by: Gusted <williamzijl7@hotmail.com>
2022-03-24 00:36:38 +01:00
zeripath
e3d8e92bdc Prevent redirect to Host (2) (#19175) (#19186)
Backport #19175

Unhelpfully Locations starting with `/\` will be converted by the
browser to `//` because ... well I do not fully understand. Certainly
the RFCs and MDN do not indicate that this would be expected. Providing
"compatibility" with the (mis)behaviour of a certain proprietary OS is
my suspicion. However, we clearly have to protect against this.

Therefore we should reject redirection locations that match the regular
expression: `^/[\\\\/]+`

Reference #9678

Signed-off-by: Andrew Thornton <art27@cantab.net>
2022-03-23 20:01:23 +00:00
zeripath
6fc73a8433 Fix compare link in active feeds for new branch (#19149) (#19185)
Backport #19149

When a new branch is pushed the old SHA is always listed as the empty sha and thus the compare link that is created does not work correctly.

Therefore when creating the compare link for new branches:

1. Attempt to get the parent of the first commit and use that as the basis
for the compare link.
2. If this is not possible make a comparison to the default branch
3. Finally if that is not possible simply do not show a compare link.

However, there are multiple broken compare links remaining therefore, in order for these to not break we will simply make the compare link redirect to the default branch.

Fix #19144

Signed-off-by: a1012112796 <1012112796@qq.com>
Signed-off-by: Andrew Thornton <art27@cantab.net>

Co-authored-by: Andrew Thornton <art27@cantab.net>
Co-authored-by: a1012112796 <1012112796@qq.com>
2022-03-23 19:04:50 +00:00
zeripath
b1a0a78a51 Redirect .wiki/* ui link to /wiki (#18831) (#19184)
Backport #18831

Redirect .wiki/* ui link to /wiki

fix #18590

Signed-off-by: a1012112796 <1012112796@qq.com>
Signed-off-by: Andrew Thornton <art27@cantab.net>

Co-authored-by: Andrew Thornton <art27@cantab.net>
Co-authored-by: a1012112796 <1012112796@qq.com>
2022-03-23 16:46:08 +00:00
Andrew Thornton
9c7d8b3096 Prevent start panic due to missing DotEscape function
Unfortunately #19169 causing a panic at startup in prod mode. This was hidden by dev
mode because the templates are compiled dynamically there. The issue is that DotEscape
is not in the original FuncMap at the time of compilation which causes a panic.

Ref #19169

Signed-off-by: Andrew Thornton <art27@cantab.net>
2022-03-23 16:09:57 +00:00
zeripath
93feb1a666 Fix the bug: deploy key with write access can not push (#19010) (#19182)
Backport #19010

Use DeployKeyID to replace the IsDeployKey, then CanWriteCode uses the DeployKeyID to check the write permission.

Fix #19009

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2022-03-23 13:44:41 +00:00
zeripath
bb0e2121a3 Try to prevent autolinking of displaynames by email readers (#19169) (#19183)
Backport #19169

Unfortunately many email readers will (helpfully) detect url or url-like names and
automatically create links to them, even in HTML emails. This is not ideal when
usernames can have dots in them.

This PR tries to prevent this behaviour by sticking ZWJ characters between dots and
also set the meta tag to prevent format detection.

Not every email template has been changed in this way - just the activation emails but
it may be that we should be setting the above meta tag in all of our emails too.

Signed-off-by: Andrew Thornton <art27@cantab.net>
2022-03-23 15:18:11 +02:00
zeripath
d21b7fd3af Clean paths when looking in Storage (#19124) (#19179)
Backport #19124

* Clean paths when looking in Storage

Ensure paths are clean for minio aswell as local storage.

Use url.Path not RequestURI/EscapedPath in storageHandler.

Signed-off-by: Andrew Thornton <art27@cantab.net>

* Apply suggestions from code review

Co-authored-by: Lauris BH <lauris@nix.lv>
2022-03-23 09:23:00 +00:00
Norwin
743553f3e9 Cleanup protected branches when deleting users & teams (#19158) (#19174)
* Clean up protected_branches when deleting user

fixes #19094

* Clean up protected_branches when deleting teams

* fix issue

Co-authored-by: Lauris BH <lauris@nix.lv>

Co-authored-by: Lauris BH <lauris@nix.lv>
Co-authored-by: zeripath <art27@cantab.net>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2022-03-23 13:56:53 +08:00
zeripath
a3ccbb5b7f Ensure that setting.LocalURL always has a trailing slash (#19171) (#19177)
Backport #19171

Fix #19166

Signed-off-by: Andrew Thornton <art27@cantab.net>

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2022-03-23 12:56:52 +08:00
zeripath
4b7cb813e6 Use the new/choose link for New Issue on project page (#19172) (#19176)
Backport #19172

Extend issues/new/choose to pass the project id and change New Issue
link on project page to use new/choose

Fix #19170

Signed-off-by: Andrew Thornton <art27@cantab.net>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2022-03-23 09:41:12 +08:00
zeripath
23b8214549 Use IterateBufferSize whilst querying repositories during adoption check (#19140) (#19160)
Backport #19140

The adoption page checks directories to see if they are repositories by querying the
db on a per user basis. This can lead to problems if a user has a large number of
repositories or putative repositories.

This PR changes the buffering to check the db in IterataeBufferSize batches instead.

Fix #19137

Signed-off-by: Andrew Thornton <art27@cantab.net>
2022-03-22 09:11:22 +08:00
zeripath
08feb6b664 Ensure isSSH is set whenever DISABLE_HTTP_GIT is set (#19028) (#19146)
Backport #19028

When DISABLE_HTTP_GIT is set we should always show the SSH button

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: techknowlogick <techknowlogick@gitea.io>
2022-03-21 08:59:55 +08:00
Abheek Dhawan
1aa5dc75df Use custom favicon when viewing static files if it exists (#19130) (#19152)
Redirect `/favicon.ico` to `/assets/img/favicon.png`.

Fix #19109

Co-authored-by: zeripath <art27@cantab.net>
2022-03-20 20:28:35 -04:00
Gusted
ee234aff61 Fix NPE /repos/issues/search when not signed in (#19154) (#19155)
- Backport #19154

  - Don't panic when on `/repos/issues/search?{created,assigned,mentioned,review_requested}=true` when client didn't pass any authentication.
  - Resolves #19115
2022-03-20 22:42:31 +01:00
zeripath
a3f3e310fb Fix wrong scopes caused by empty scope input (#19029) (#19145)
Backport #19029
Fix #18972 Gitea prepends requested openid scope with + after updating authentication source
2022-03-21 03:13:18 +08:00
zeripath
ea56bdca5f Fix the editor height in review box (#19003) (#19147)
Backport #19003

Fix the height problem in  https://github.com/go-gitea/gitea/pull/18862#issuecomment-1059329539

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2022-03-20 10:29:49 +08:00
zeripath
45c836badc Do not send notification emails to inactive users (#19131) (#19139)
Backport #19131
Backport #19142

Emails should not be sent to inactive users except for Activate and ResetPassword
messages.

Fix #18950

Signed-off-by: Andrew Thornton <art27@cantab.net>
2022-03-19 18:33:32 +00:00
techknowlogick
f9ea4ab69a Bump to build with go1.18 (#19120 et al) (#19127)
Backport #19120 
Backport #19099 
Backport #18874 
Backport #18420
Backport #19128
Backport #18270 

Bump to build with go1.18

Co-authored-by: techknowlogick <techknowlogick@gitea.io>
Signed-off-by: Andrew Thornton <art27@cantab.net>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: 6543 <6543@obermui.de>
Co-authored-by: zeripath <art27@cantab.net>
Co-authored-by: Jelle Hulter <jellehulter@gmail.com>
2022-03-19 18:46:47 +01:00
zeripath
e6d46eeb55 Make migrations SKIP_TLS_VERIFY apply to git too (#19132) (#19141)
Backport #19132

Make SKIP_TLS_VERIFY apply to git data migrations too through adding the `-c http.sslVerify=false` option to the git clone command.

Fix #18998

Signed-off-by: Andrew Thornton <art27@cantab.net>
2022-03-19 16:20:26 +00:00
zeripath
5bb0c92b6c Do not send activation email if manual confirm is set (#19119) (#19122)
Backport #19119

If the mailer is configured then even if Manual confirm is set an activation email
is still being sent because `handleUserCreated` is not checking for this case.

Fix #17263

Signed-off-by: Andrew Thornton <art27@cantab.net>
2022-03-19 14:20:42 +00:00
Gusted
c1e6be47d7 Update golang.org/x/crypto (#19097) (#19098)
Backport #19097

* Update golang.org/x/crypto (#19097)

- Backport #19097

* Fix deprecation notice

* Backport workaround removal
2022-03-19 12:16:15 +00:00
Lunny Xiao
79a5e68816 Handle email address not exist (#19089) (#19121)
Backport #19089

* Handle email address not exist. (#19089)

* Fix lint about strings.Title

Co-authored-by: KN4CK3R <admin@oldschoolhack.me>
2022-03-19 11:35:23 +00:00
Gusted
9bcbbd419f Update json-iterator (#18644) (#19100)
- Backport #18644
2022-03-15 17:29:06 -04:00
172 changed files with 3161 additions and 1397 deletions

View File

@@ -25,7 +25,7 @@ steps:
- make deps-frontend
- name: deps-backend
image: golang:1.17
image: golang:1.18
pull: always
commands:
- make deps-backend
@@ -45,32 +45,41 @@ steps:
commands:
- make lint-backend
environment:
GOPROXY: https://goproxy.cn # proxy.golang.org is blocked in China, this proxy is not
GOPROXY: https://goproxy.io # proxy.golang.org is blocked in China, this proxy is not
GOSUMDB: sum.golang.org
TAGS: bindata sqlite sqlite_unlock_notify
depends_on: [deps-backend]
volumes:
- name: deps
path: /go
- name: lint-backend-windows
image: gitea/test_env:linux-amd64 # https://gitea.com/gitea/test-env
commands:
- make golangci-lint vet
- make golangci-lint-windows vet
environment:
GOPROXY: https://goproxy.cn # proxy.golang.org is blocked in China, this proxy is not
GOPROXY: https://goproxy.io # proxy.golang.org is blocked in China, this proxy is not
GOSUMDB: sum.golang.org
TAGS: bindata sqlite sqlite_unlock_notify
GOOS: windows
GOARCH: amd64
depends_on: [deps-backend]
volumes:
- name: deps
path: /go
- name: lint-backend-gogit
image: gitea/test_env:linux-amd64 # https://gitea.com/gitea/test-env
commands:
- make lint-backend
environment:
GOPROXY: https://goproxy.cn # proxy.golang.org is blocked in China, this proxy is not
GOPROXY: https://goproxy.io # proxy.golang.org is blocked in China, this proxy is not
GOSUMDB: sum.golang.org
TAGS: bindata gogit sqlite sqlite_unlock_notify
depends_on: [deps-backend]
volumes:
- name: deps
path: /go
- name: checks-frontend
image: node:16
@@ -79,7 +88,7 @@ steps:
depends_on: [deps-frontend]
- name: checks-backend
image: golang:1.17
image: golang:1.18
commands:
- make checks-backend
depends_on: [deps-backend]
@@ -104,7 +113,7 @@ steps:
pull: always
environment:
GO111MODULE: on
GOPROXY: https://goproxy.cn
GOPROXY: https://goproxy.io
commands:
- go build -o gitea_no_gcc # test if build succeeds without the sqlite tag
depends_on: [deps-backend, checks-backend]
@@ -113,10 +122,10 @@ steps:
path: /go
- name: build-backend-arm64
image: golang:1.17
image: golang:1.18
environment:
GO111MODULE: on
GOPROXY: https://goproxy.cn
GOPROXY: https://goproxy.io
GOOS: linux
GOARCH: arm64
TAGS: bindata gogit
@@ -129,10 +138,10 @@ steps:
path: /go
- name: build-backend-windows
image: golang:1.17
image: golang:1.18
environment:
GO111MODULE: on
GOPROXY: https://goproxy.cn
GOPROXY: https://goproxy.io
GOOS: windows
GOARCH: amd64
TAGS: bindata gogit
@@ -144,10 +153,10 @@ steps:
path: /go
- name: build-backend-386
image: golang:1.17
image: golang:1.18
environment:
GO111MODULE: on
GOPROXY: https://goproxy.cn
GOPROXY: https://goproxy.io
GOOS: linux
GOARCH: 386
commands:
@@ -226,6 +235,7 @@ steps:
image: docker:git
pull: always
commands:
- git config --global --add safe.directory /drone/src
- git fetch --tags --force
when:
event:
@@ -233,7 +243,7 @@ steps:
- pull_request
- name: deps-backend
image: golang:1.17
image: golang:1.18
pull: always
commands:
- make deps-backend
@@ -260,7 +270,7 @@ steps:
- ./build/test-env-check.sh
- make backend
environment:
GOPROXY: https://goproxy.cn # proxy.golang.org is blocked in China, this proxy is not
GOPROXY: https://goproxy.io # proxy.golang.org is blocked in China, this proxy is not
GOSUMDB: sum.golang.org
TAGS: bindata sqlite sqlite_unlock_notify
depends_on: [deps-backend, prepare-test-env]
@@ -274,7 +284,7 @@ steps:
commands:
- make unit-test-coverage test-check
environment:
GOPROXY: https://goproxy.cn
GOPROXY: https://goproxy.io
TAGS: bindata sqlite sqlite_unlock_notify
RACE_ENABLED: true
GITHUB_READ_TOKEN:
@@ -290,7 +300,7 @@ steps:
commands:
- make unit-test-coverage test-check
environment:
GOPROXY: https://goproxy.cn
GOPROXY: https://goproxy.io
TAGS: bindata gogit sqlite sqlite_unlock_notify
RACE_ENABLED: true
GITHUB_READ_TOKEN:
@@ -306,7 +316,7 @@ steps:
commands:
- make test-mysql-migration integration-test-coverage
environment:
GOPROXY: https://goproxy.cn
GOPROXY: https://goproxy.io
TAGS: bindata
RACE_ENABLED: true
TEST_LDAP: 1
@@ -323,7 +333,7 @@ steps:
commands:
- timeout -s ABRT 40m make test-mysql8-migration test-mysql8
environment:
GOPROXY: https://goproxy.cn
GOPROXY: https://goproxy.io
TAGS: bindata
RACE_ENABLED: true
TEST_LDAP: 1
@@ -339,7 +349,7 @@ steps:
commands:
- make test-mssql-migration test-mssql
environment:
GOPROXY: https://goproxy.cn
GOPROXY: https://goproxy.io
TAGS: bindata
RACE_ENABLED: true
TEST_LDAP: 1
@@ -350,11 +360,11 @@ steps:
path: /go
- name: generate-coverage
image: golang:1.17
image: golang:1.18
commands:
- make coverage
environment:
GOPROXY: https://goproxy.cn
GOPROXY: https://goproxy.io
TAGS: bindata
depends_on: [unit-test, test-mysql]
when:
@@ -418,6 +428,7 @@ steps:
image: docker:git
pull: always
commands:
- git config --global --add safe.directory /drone/src
- git fetch --tags --force
when:
event:
@@ -425,7 +436,7 @@ steps:
- pull_request
- name: deps-backend
image: golang:1.17
image: golang:1.18
pull: always
commands:
- make deps-backend
@@ -446,7 +457,7 @@ steps:
- ./build/test-env-check.sh
- make backend
environment:
GOPROXY: https://goproxy.cn # proxy.golang.org is blocked in China, this proxy is not
GOPROXY: https://goproxy.io # proxy.golang.org is blocked in China, this proxy is not
GOSUMDB: sum.golang.org
TAGS: bindata gogit sqlite sqlite_unlock_notify
depends_on: [deps-backend, prepare-test-env]
@@ -460,7 +471,7 @@ steps:
commands:
- timeout -s ABRT 40m make test-sqlite-migration test-sqlite
environment:
GOPROXY: https://goproxy.cn
GOPROXY: https://goproxy.io
TAGS: bindata gogit sqlite sqlite_unlock_notify
RACE_ENABLED: true
TEST_TAGS: gogit sqlite sqlite_unlock_notify
@@ -476,7 +487,7 @@ steps:
commands:
- timeout -s ABRT 40m make test-pgsql-migration test-pgsql
environment:
GOPROXY: https://goproxy.cn
GOPROXY: https://goproxy.io
TAGS: bindata gogit
RACE_ENABLED: true
TEST_TAGS: gogit
@@ -567,7 +578,7 @@ trigger:
steps:
- name: download
image: golang:1.17
image: golang:1.18
pull: always
commands:
- timeout -s ABRT 40m make generate-license generate-gitignore
@@ -619,6 +630,7 @@ steps:
image: docker:git
pull: always
commands:
- git config --global --add safe.directory /drone/src
- git fetch --tags --force
- name: deps-frontend
@@ -628,7 +640,7 @@ steps:
- make deps-frontend
- name: deps-backend
image: golang:1.17
image: golang:1.18
pull: always
commands:
- make deps-backend
@@ -637,14 +649,14 @@ steps:
path: /go
- name: static
image: techknowlogick/xgo:go-1.17.x
image: techknowlogick/xgo:go-1.18.x
pull: always
commands:
- curl -sL https://deb.nodesource.com/setup_16.x | bash - && apt-get install -y nodejs
- export PATH=$PATH:$GOPATH/bin
- make release
environment:
GOPROXY: https://goproxy.cn # proxy.golang.org is blocked in China, this proxy is not
GOPROXY: https://goproxy.io # proxy.golang.org is blocked in China, this proxy is not
TAGS: bindata sqlite sqlite_unlock_notify
volumes:
- name: deps
@@ -737,6 +749,7 @@ steps:
image: docker:git
pull: always
commands:
- git config --global --add safe.directory /drone/src
- git fetch --tags --force
- name: deps-frontend
@@ -746,7 +759,7 @@ steps:
- make deps-frontend
- name: deps-backend
image: golang:1.17
image: golang:1.18
pull: always
commands:
- make deps-backend
@@ -755,14 +768,14 @@ steps:
path: /go
- name: static
image: techknowlogick/xgo:go-1.17.x
image: techknowlogick/xgo:go-1.18.x
pull: always
commands:
- curl -sL https://deb.nodesource.com/setup_16.x | bash - && apt-get install -y nodejs
- export PATH=$PATH:$GOPATH/bin
- make release
environment:
GOPROXY: https://goproxy.cn # proxy.golang.org is blocked in China, this proxy is not
GOPROXY: https://goproxy.io # proxy.golang.org is blocked in China, this proxy is not
TAGS: bindata sqlite sqlite_unlock_notify
depends_on: [fetch-tags]
volumes:
@@ -882,6 +895,7 @@ steps:
image: docker:git
pull: always
commands:
- git config --global --add safe.directory /drone/src
- git fetch --tags --force
- name: publish
@@ -892,7 +906,7 @@ steps:
auto_tag_suffix: linux-amd64
repo: gitea/gitea
build_args:
- GOPROXY=https://goproxy.cn
- GOPROXY=https://goproxy.io
password:
from_secret: docker_password
username:
@@ -910,7 +924,7 @@ steps:
auto_tag_suffix: linux-amd64-rootless
repo: gitea/gitea
build_args:
- GOPROXY=https://goproxy.cn
- GOPROXY=https://goproxy.io
password:
from_secret: docker_password
username:
@@ -945,6 +959,7 @@ steps:
image: docker:git
pull: always
commands:
- git config --global --add safe.directory /drone/src
- git fetch --tags --force
- name: publish
@@ -955,7 +970,7 @@ steps:
tags: dev-linux-amd64
repo: gitea/gitea
build_args:
- GOPROXY=https://goproxy.cn
- GOPROXY=https://goproxy.io
password:
from_secret: docker_password
username:
@@ -973,7 +988,7 @@ steps:
tags: dev-linux-amd64-rootless
repo: gitea/gitea
build_args:
- GOPROXY=https://goproxy.cn
- GOPROXY=https://goproxy.io
password:
from_secret: docker_password
username:
@@ -1007,6 +1022,7 @@ steps:
image: docker:git
pull: always
commands:
- git config --global --add safe.directory /drone/src
- git fetch --tags --force
- name: publish
@@ -1017,7 +1033,7 @@ steps:
tags: ${DRONE_BRANCH##release/v}-dev-linux-amd64
repo: gitea/gitea
build_args:
- GOPROXY=https://goproxy.cn
- GOPROXY=https://goproxy.io
password:
from_secret: docker_password
username:
@@ -1035,7 +1051,7 @@ steps:
tags: ${DRONE_BRANCH##release/v}-dev-linux-amd64-rootless
repo: gitea/gitea
build_args:
- GOPROXY=https://goproxy.cn
- GOPROXY=https://goproxy.io
password:
from_secret: docker_password
username:
@@ -1070,7 +1086,7 @@ steps:
repo: gitea/gitea
tags: linux-arm64
build_args:
- GOPROXY=https://goproxy.cn
- GOPROXY=https://goproxy.io
environment:
PLUGIN_MIRROR:
from_secret: plugin_mirror
@@ -1103,6 +1119,7 @@ steps:
image: docker:git
pull: always
commands:
- git config --global --add safe.directory /drone/src
- git fetch --tags --force
- name: publish
@@ -1113,7 +1130,7 @@ steps:
auto_tag_suffix: linux-arm64
repo: gitea/gitea
build_args:
- GOPROXY=https://goproxy.cn
- GOPROXY=https://goproxy.io
password:
from_secret: docker_password
username:
@@ -1131,7 +1148,7 @@ steps:
auto_tag_suffix: linux-arm64-rootless
repo: gitea/gitea
build_args:
- GOPROXY=https://goproxy.cn
- GOPROXY=https://goproxy.io
password:
from_secret: docker_password
username:
@@ -1166,6 +1183,7 @@ steps:
image: docker:git
pull: always
commands:
- git config --global --add safe.directory /drone/src
- git fetch --tags --force
- name: publish
@@ -1176,7 +1194,7 @@ steps:
tags: dev-linux-arm64
repo: gitea/gitea
build_args:
- GOPROXY=https://goproxy.cn
- GOPROXY=https://goproxy.io
password:
from_secret: docker_password
username:
@@ -1194,7 +1212,7 @@ steps:
tags: dev-linux-arm64-rootless
repo: gitea/gitea
build_args:
- GOPROXY=https://goproxy.cn
- GOPROXY=https://goproxy.io
password:
from_secret: docker_password
username:
@@ -1228,6 +1246,7 @@ steps:
image: docker:git
pull: always
commands:
- git config --global --add safe.directory /drone/src
- git fetch --tags --force
- name: publish
@@ -1238,7 +1257,7 @@ steps:
tags: ${DRONE_BRANCH##release/v}-dev-linux-arm64
repo: gitea/gitea
build_args:
- GOPROXY=https://goproxy.cn
- GOPROXY=https://goproxy.io
password:
from_secret: docker_password
username:
@@ -1256,7 +1275,7 @@ steps:
tags: ${DRONE_BRANCH##release/v}-dev-linux-arm64-rootless
repo: gitea/gitea
build_args:
- GOPROXY=https://goproxy.cn
- GOPROXY=https://goproxy.io
password:
from_secret: docker_password
username:

View File

@@ -13,7 +13,7 @@ linters:
#- gocyclo # The cyclomatic complexety of a lot of functions is too high, we should refactor those another time.
- gofmt
- misspell
- gocritic
#- gocritic # TODO: disabled until fixed with go 1.18
- bidichk
- ineffassign
- revive
@@ -22,7 +22,7 @@ linters:
fast: false
run:
timeout: 3m
timeout: 10m
skip-dirs:
- node_modules
- public
@@ -61,6 +61,9 @@ linters-settings:
- name: errorf
- name: duplicated-imports
- name: modifies-value-receiver
gofumpt:
extra-rules: true
lang-version: 1.18
issues:
exclude-rules:
@@ -148,3 +151,11 @@ issues:
- path: models/user/openid.go
linters:
- golint
- linters: staticcheck
text: "strings.Title is deprecated: The rule Title uses for word boundaries does not handle Unicode punctuation properly. Use golang.org/x/text/cases instead."
- linters: staticcheck
text: "util.FindClosure is deprecated: This function can not handle newlines. Many elements can be existed over multiple lines(e.g. link labels). Use text.Reader.FindClosure."
- linters: staticcheck
text: "gossh.SigAlgoRSASHA2256 is deprecated: use KeyAlgoRSASHA256."
- linters: staticcheck
text: "gossh.SigAlgoRSASHA2512 is deprecated: use KeyAlgoRSASHA512."

View File

@@ -4,6 +4,112 @@ 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.16.8](https://github.com/go-gitea/gitea/releases/tag/v1.16.8) - 2022-05-16
* ENHANCEMENTS
* Add doctor check/fix for bogus action rows (#19656) (#19669)
* Make .cs highlighting legible on dark themes. (#19604) (#19605)
* BUGFIXES
* Fix oauth setting list bug (#19681)
* Delete user related oauth stuff on user deletion too (#19677) (#19680)
* Fix new release from tags list UI (#19670) (#19673)
* Prevent NPE when checking repo units if the user is nil (#19625) (#19630)
* GetFeeds must always discard actions with dangling repo_id (#19598) (#19629)
* Call MultipartForm.RemoveAll when request finishes (#19606) (#19607)
* Avoid MoreThanOne error when creating a branch whose name conflicts with other ref names (#19557) (#19591)
* Fix sending empty notifications (#19589) (#19590)
* Ignore DNS error when doing migration allow/block check (#19566) (#19567)
* Fix issue overview for teams (#19652) (#19653)
## [1.16.7](https://github.com/go-gitea/gitea/releases/tag/v1.16.7) - 2022-05-02
* SECURITY
* Escape git fetch remote (#19487) (#19490)
* BUGFIXES
* Don't overwrite err with nil (#19572) (#19574)
* On Migrations, only write commit-graph if wiki clone was successful (#19563) (#19568)
* Respect DefaultUserIsRestricted system default when creating new user (#19310) (#19560)
* Don't error when branch's commit doesn't exist (#19547) (#19548)
* Support `hostname:port` to pass host matcher's check (#19543) (#19544)
* Prevent intermittent race in attribute reader close (#19537) (#19539)
* Fix 64-bit atomic operations on 32-bit machines (#19531) (#19532)
* Prevent dangling archiver goroutine (#19516) (#19526)
* Fix migrate release from github (#19510) (#19523)
* When view _Siderbar or _Footer, just display once (#19501) (#19522)
* Fix blame page select range error and some typos (#19503)
* Fix name of doctor fix "authorized-keys" in hints (#19464) (#19484)
* User specific repoID or xorm builder conditions for issue search (#19475) (#19476)
* Prevent dangling cat-file calls (goroutine alternative) (#19454) (#19466)
* RepoAssignment ensure to close before overwrite (#19449) (#19460)
* Set correct PR status on 3way on conflict checking (#19457) (#19458)
* Mark TemplateLoading error as "UnprocessableEntity" (#19445) (#19446)
## [1.16.6](https://github.com/go-gitea/gitea/releases/tag/v1.16.6) - 2022-04-20
* ENHANCEMENTS
* Only request write when necessary (#18657) (#19422)
* Disable service worker by default (#18914) (#19342)
* BUGFIXES
* When dumping trim the standard suffices instead of a random suffix (#19440) (#19447)
* Fix DELETE request for non-existent public key (#19443) (#19444)
* Don't panic on ErrEmailInvalid (#19441) (#19442)
* Add uploadpack.allowAnySHA1InWant to allow --filter=blob:none with older git clients (#19430) (#19438)
* Warn on SSH connection for incorrect configuration (#19317) (#19437)
* Search Issues via API, dont show 500 if filter result in empty list (#19244) (#19436)
* When updating mirror repo intervals by API reschedule next update too (#19429) (#19433)
* Fix nil error when some pages are rendered outside request context (#19427) (#19428)
* Fix double blob-hunk on diff page (#19404) (#19405)
* Don't allow merging PR's which are being conflict checked (#19357) (#19358)
* Fix middleware function's placements (#19377) (#19378)
* Fix invalid CSRF token bug, make sure CSRF tokens can be up-to-date (#19338)
* Restore user autoregistration with email addresses (#19261) (#19312)
* Move checks for pulls before merge into own function (#19271) (#19277)
* Granular webhook events in editHook (#19251) (#19257)
* Only send webhook events to active system webhooks and only deliver to active hooks (#19234) (#19248)
* Use full output of git show-ref --tags to get tags for PushUpdateAddTag (#19235) (#19236)
* Touch mirrors on even on fail to update (#19217) (#19233)
* Hide sensitive content on admin panel progress monitor (#19218 & #19226) (#19231)
* Fix clone url JS error for the empty repo page (#19209)
* Bump goldmark to v1.4.11 (#19201) (#19203)
* TESTING
* Prevent intermittent failures in RepoIndexerTest (#19225 #19229) (#19228)
* BUILD
* Revert the minimal golang version requirement from 1.17 to 1.16 and add a warning in Makefile (#19319)
* MISC
* Performance improvement for add team user when org has more than 1000 repositories (#19227) (#19289)
* Check go and nodejs version by go.mod and package.json (#19197) (#19254)
## [1.16.5](https://github.com/go-gitea/gitea/releases/tag/v1.16.5) - 2022-03-23
* BREAKING
* Bump to build with go1.18 (#19120 et al) (#19127)
* SECURITY
* Prevent redirect to Host (2) (#19175) (#19186)
* Try to prevent autolinking of displaynames by email readers (#19169) (#19183)
* Clean paths when looking in Storage (#19124) (#19179)
* Do not send notification emails to inactive users (#19131) (#19139)
* Do not send activation email if manual confirm is set (#19119) (#19122)
* ENHANCEMENTS
* Use the new/choose link for New Issue on project page (#19172) (#19176)
* BUGFIXES
* Fix showing issues in your repositories (#18916) (#19191)
* Fix compare link in active feeds for new branch (#19149) (#19185)
* Redirect .wiki/* ui link to /wiki (#18831) (#19184)
* Ensure deploy keys with write access can push (#19010) (#19182)
* Ensure that setting.LocalURL always has a trailing slash (#19171) (#19177)
* Cleanup protected branches when deleting users & teams (#19158) (#19174)
* Use IterateBufferSize whilst querying repositories during adoption check (#19140) (#19160)
* Fix NPE /repos/issues/search when not signed in (#19154) (#19155)
* Use custom favicon when viewing static files if it exists (#19130) (#19152)
* Fix the editor height in review box (#19003) (#19147)
* Ensure isSSH is set whenever DISABLE_HTTP_GIT is set (#19028) (#19146)
* Fix wrong scopes caused by empty scope input (#19029) (#19145)
* Make migrations SKIP_TLS_VERIFY apply to git too (#19132) (#19141)
* Handle email address not exist (#19089) (#19121)
* MISC
* Update json-iterator to allow compilation with go1.18 (#18644) (#19100)
* Update golang.org/x/crypto (#19097) (#19098)
## [1.16.4](https://github.com/go-gitea/gitea/releases/tag/v1.16.4) - 2022-03-14
* SECURITY

View File

@@ -1,7 +1,5 @@
###################################
#Build stage - temporarily using techknowlogick image until we upgrade to latest official alpine/go image
FROM techknowlogick/go:1.17-alpine3.13 AS build-env
#Build stage
FROM golang:1.18-alpine3.15 AS build-env
ARG GOPROXY
ENV GOPROXY ${GOPROXY:-direct}

View File

@@ -1,7 +1,5 @@
###################################
#Build stage - temporarily using techknowlogick image until we upgrade to latest official alpine/go image
FROM techknowlogick/go:1.17-alpine3.13 AS build-env
#Build stage
FROM golang:1.18-alpine3.15 AS build-env
ARG GOPROXY
ENV GOPROXY ${GOPROXY:-direct}

109
Makefile
View File

@@ -24,10 +24,17 @@ SHASUM ?= shasum -a 256
HAS_GO = $(shell hash $(GO) > /dev/null 2>&1 && echo "GO" || echo "NOGO" )
COMMA := ,
XGO_VERSION := go-1.17.x
MIN_GO_VERSION := 001016000
MIN_NODE_VERSION := 012017000
MIN_GOLANGCI_LINT_VERSION := 001043000
XGO_VERSION := go-1.18.x
AIR_PACKAGE ?= github.com/cosmtrek/air@v1.29.0
EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/cmd/editorconfig-checker@2.4.0
ERRCHECK_PACKAGE ?= github.com/kisielk/errcheck@v1.6.0
GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.3.0
GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.44.2
GXZ_PAGAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.10
MISSPELL_PACKAGE ?= github.com/client9/misspell/cmd/misspell@v0.3.4
SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@v0.29.0
XGO_PACKAGE ?= src.techknowlogick.com/xgo@latest
DOCKER_IMAGE ?= gitea/gitea
DOCKER_TAG ?= latest
@@ -125,8 +132,6 @@ ifeq ($(filter $(TAGS_SPLIT),bindata),bindata)
GO_SOURCES += $(BINDATA_DEST)
endif
#To update swagger use: GO111MODULE=on go get -u github.com/go-swagger/go-swagger/cmd/swagger
SWAGGER := $(GO) run github.com/go-swagger/go-swagger/cmd/swagger
SWAGGER_SPEC := templates/swagger/v1_json.tmpl
SWAGGER_SPEC_S_TMPL := s|"basePath": *"/api/v1"|"basePath": "{{AppSubUrl \| JSEscape \| Safe}}/api/v1"|g
SWAGGER_SPEC_S_JSON := s|"basePath": *"{{AppSubUrl \| JSEscape \| Safe}}/api/v1"|"basePath": "/api/v1"|g
@@ -196,10 +201,15 @@ help:
.PHONY: go-check
go-check:
$(eval GO_VERSION := $(shell printf "%03d%03d%03d" $(shell $(GO) version | grep -Eo '[0-9]+\.[0-9.]+' | tr '.' ' ');))
$(eval MIN_GO_VERSION_STR := $(shell grep -Eo '^go\s+[0-9]+\.[0-9.]+' go.mod | cut -d' ' -f2))
$(eval MIN_GO_VERSION := $(shell printf "%03d%03d%03d" $(shell echo '$(MIN_GO_VERSION_STR)' | tr '.' ' ')))
$(eval GO_VERSION_STR := $(shell $(GO) version | grep -Eo '[0-9]+\.[0-9.]+'))
$(eval GO_VERSION := $(shell printf "%03d%03d%03d" $(shell echo '$(GO_VERSION_STR)' | tr '.' ' ')))
@if [ "$(GO_VERSION)" -lt "$(MIN_GO_VERSION)" ]; then \
echo "Gitea requires Go 1.16 or greater to build. You can get it at https://golang.org/dl/"; \
echo "Gitea requires Go $(MIN_GO_VERSION_STR) or greater to build, but $(GO_VERSION) was found. You can get an updated version at https://go.dev/dl/"; \
exit 1; \
else \
echo "WARNING: Please ensure Go $(GO_VERSION_STR) is still maintained to avoid possible security problems. You can check it at https://go.dev/dl/"; \
fi
.PHONY: git-check
@@ -211,11 +221,12 @@ git-check:
.PHONY: node-check
node-check:
$(eval MIN_NODE_VERSION_STR := $(shell grep -Eo '"node":.*[0-9.]+"' package.json | sed -n 's/.*[^0-9.]\([0-9.]*\)"/\1/p'))
$(eval MIN_NODE_VERSION := $(shell printf "%03d%03d%03d" $(shell echo '$(MIN_NODE_VERSION_STR)' | tr '.' ' ')))
$(eval NODE_VERSION := $(shell printf "%03d%03d%03d" $(shell node -v | cut -c2- | tr '.' ' ');))
$(eval MIN_NODE_VER_FMT := $(shell printf "%g.%g.%g" $(shell echo $(MIN_NODE_VERSION) | grep -o ...)))
$(eval NPM_MISSING := $(shell hash npm > /dev/null 2>&1 || echo 1))
@if [ "$(NODE_VERSION)" -lt "$(MIN_NODE_VERSION)" -o "$(NPM_MISSING)" = "1" ]; then \
echo "Gitea requires Node.js $(MIN_NODE_VER_FMT) or greater and npm to build. You can get it at https://nodejs.org/en/download/"; \
echo "Gitea requires Node.js $(MIN_NODE_VERSION_STR) or greater and npm to build. You can get it at https://nodejs.org/en/download/"; \
exit 1; \
fi
@@ -234,8 +245,8 @@ clean:
.PHONY: fmt
fmt:
@echo "Running gitea-fmt(with gofmt)..."
@$(GO) run build/code-batch-process.go gitea-fmt -s -w '{file-list}'
@echo "Running gitea-fmt (with gofumpt)..."
@MISSPELL_PACKAGE=$(MISSPELL_PACKAGE) GOFUMPT_PACKAGE=$(GOFUMPT_PACKAGE) $(GO) run build/code-batch-process.go gitea-fmt -w '{file-list}'
.PHONY: vet
vet:
@@ -254,7 +265,7 @@ endif
.PHONY: generate-swagger
generate-swagger:
$(SWAGGER) generate spec -x "$(SWAGGER_EXCLUDE)" -o './$(SWAGGER_SPEC)'
$(GO) run $(SWAGGER_PACKAGE) generate spec -x "$(SWAGGER_EXCLUDE)" -o './$(SWAGGER_SPEC)'
$(SED_INPLACE) '$(SWAGGER_SPEC_S_TMPL)' './$(SWAGGER_SPEC)'
$(SED_INPLACE) $(SWAGGER_NEWLINE_COMMAND) './$(SWAGGER_SPEC)'
@@ -270,21 +281,18 @@ swagger-check: generate-swagger
.PHONY: swagger-validate
swagger-validate:
$(SED_INPLACE) '$(SWAGGER_SPEC_S_JSON)' './$(SWAGGER_SPEC)'
$(SWAGGER) validate './$(SWAGGER_SPEC)'
$(GO) run $(SWAGGER_PACKAGE) validate './$(SWAGGER_SPEC)'
$(SED_INPLACE) '$(SWAGGER_SPEC_S_TMPL)' './$(SWAGGER_SPEC)'
.PHONY: errcheck
errcheck:
@hash errcheck > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
$(GO) install github.com/kisielk/errcheck@8ddee489636a8311a376fc92e27a6a13c6658344; \
fi
@echo "Running errcheck..."
@errcheck $(GO_PACKAGES)
$(GO) run $(ERRCHECK_PACKAGE) $(GO_PACKAGES)
.PHONY: fmt-check
fmt-check:
# get all go files and run gitea-fmt (with gofmt) on them
@diff=$$($(GO) run build/code-batch-process.go gitea-fmt -s -d '{file-list}'); \
@diff=$$(MISSPELL_PACKAGE=$(MISSPELL_PACKAGE) GOFUMPT_PACKAGE=$(GOFUMPT_PACKAGE) $(GO) run build/code-batch-process.go gitea-fmt -l '{file-list}'); \
if [ -n "$$diff" ]; then \
echo "Please run 'make fmt' and commit the result:"; \
echo "$${diff}"; \
@@ -323,10 +331,7 @@ watch-frontend: node-check node_modules
.PHONY: watch-backend
watch-backend: go-check
@hash air > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
$(GO) install github.com/cosmtrek/air@bedc18201271882c2be66d216d0e1a275b526ec4; \
fi
air -c .air.toml
$(GO) run $(AIR_PACKAGE) -c .air.toml
.PHONY: test
test: test-frontend test-backend
@@ -599,12 +604,9 @@ $(DIST_DIRS):
.PHONY: release-windows
release-windows: | $(DIST_DIRS)
@hash xgo > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
$(GO) install src.techknowlogick.com/xgo@latest; \
fi
CGO_CFLAGS="$(CGO_CFLAGS)" xgo -go $(XGO_VERSION) -buildmode exe -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION) .
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -buildmode exe -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION) .
ifeq (,$(findstring gogit,$(TAGS)))
CGO_CFLAGS="$(CGO_CFLAGS)" xgo -go $(XGO_VERSION) -buildmode exe -dest $(DIST)/binaries -tags 'netgo osusergo gogit $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION)-gogit .
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -buildmode exe -dest $(DIST)/binaries -tags 'netgo osusergo gogit $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION)-gogit .
endif
ifeq ($(CI),drone)
cp /build/* $(DIST)/binaries
@@ -612,20 +614,14 @@ endif
.PHONY: release-linux
release-linux: | $(DIST_DIRS)
@hash xgo > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
$(GO) install src.techknowlogick.com/xgo@latest; \
fi
CGO_CFLAGS="$(CGO_CFLAGS)" xgo -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets '$(LINUX_ARCHS)' -out gitea-$(VERSION) .
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets '$(LINUX_ARCHS)' -out gitea-$(VERSION) .
ifeq ($(CI),drone)
cp /build/* $(DIST)/binaries
endif
.PHONY: release-darwin
release-darwin: | $(DIST_DIRS)
@hash xgo > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
$(GO) install src.techknowlogick.com/xgo@latest; \
fi
CGO_CFLAGS="$(CGO_CFLAGS)" xgo -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '$(LDFLAGS)' -targets 'darwin-10.12/amd64,darwin-10.12/arm64' -out gitea-$(VERSION) .
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '$(LDFLAGS)' -targets 'darwin-10.12/amd64,darwin-10.12/arm64' -out gitea-$(VERSION) .
ifeq ($(CI),drone)
cp /build/* $(DIST)/binaries
endif
@@ -640,10 +636,7 @@ release-check: | $(DIST_DIRS)
.PHONY: release-compress
release-compress: | $(DIST_DIRS)
@hash gxz > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
$(GO) install github.com/ulikunitz/xz/cmd/gxz@v0.5.10; \
fi
cd $(DIST)/release/; for file in `find . -type f -name "*"`; do echo "compressing $${file}" && gxz -k -9 $${file}; done;
cd $(DIST)/release/; for file in `find . -type f -name "*"`; do echo "compressing $${file}" && $(GO) run $(GXZ_PAGAGE) -k -9 $${file}; done;
.PHONY: release-sources
release-sources: | $(DIST_DIRS)
@@ -673,6 +666,15 @@ deps-frontend: node_modules
.PHONY: deps-backend
deps-backend:
$(GO) mod download
$(GO) install $(AIR_PACKAGE)
$(GO) install $(EDITORCONFIG_CHECKER_PACKAGE)
$(GO) install $(ERRCHECK_PACKAGE)
$(GO) install $(GOFUMPT_PACKAGE)
$(GO) install $(GOLANGCI_LINT_PACKAGE)
$(GO) install $(GXZ_PAGAGE)
$(GO) install $(MISSPELL_PACKAGE)
$(GO) install $(SWAGGER_PACKAGE)
$(GO) install $(XGO_PACKAGE)
node_modules: package-lock.json
npm install --no-save
@@ -766,22 +768,19 @@ pr\#%: clean-all
$(GO) run contrib/pr/checkout.go $*
.PHONY: golangci-lint
golangci-lint: golangci-lint-check
golangci-lint run --timeout 10m
golangci-lint:
$(GO) run $(GOLANGCI_LINT_PACKAGE) run
.PHONY: golangci-lint-check
golangci-lint-check:
$(eval GOLANGCI_LINT_VERSION := $(shell printf "%03d%03d%03d" $(shell golangci-lint --version | grep -Eo '[0-9]+\.[0-9.]+' | tr '.' ' ');))
$(eval MIN_GOLANGCI_LINT_VER_FMT := $(shell printf "%g.%g.%g" $(shell echo $(MIN_GOLANGCI_LINT_VERSION) | grep -o ...)))
@hash golangci-lint > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
echo "Downloading golangci-lint v${MIN_GOLANGCI_LINT_VER_FMT}"; \
export BINARY="golangci-lint"; \
curl -sfL "https://raw.githubusercontent.com/golangci/golangci-lint/v${MIN_GOLANGCI_LINT_VER_FMT}/install.sh" | sh -s -- -b $(GOPATH)/bin v$(MIN_GOLANGCI_LINT_VER_FMT); \
elif [ "$(GOLANGCI_LINT_VERSION)" -lt "$(MIN_GOLANGCI_LINT_VERSION)" ]; then \
echo "Downloading newer version of golangci-lint v${MIN_GOLANGCI_LINT_VER_FMT}"; \
export BINARY="golangci-lint"; \
curl -sfL "https://raw.githubusercontent.com/golangci/golangci-lint/v${MIN_GOLANGCI_LINT_VER_FMT}/install.sh" | sh -s -- -b $(GOPATH)/bin v$(MIN_GOLANGCI_LINT_VER_FMT); \
fi
# workaround step for the lint-backend-windows CI task because 'go run' can not
# have distinct GOOS/GOARCH for its build and run steps
.PHONY: golangci-lint-windows
golangci-lint-windows:
@GOOS= GOARCH= $(GO) install $(GOLANGCI_LINT_PACKAGE)
golangci-lint run
.PHONY: editorconfig-checker
editorconfig-checker:
$(GO) run $(EDITORCONFIG_CHECKER_PACKAGE) templates
.PHONY: docker
docker:

View File

@@ -73,7 +73,7 @@ or if SQLite support is required:
The `build` target is split into two sub-targets:
- `make backend` which requires [Go 1.16](https://golang.org/dl/) or greater.
- `make backend` which requires [Go 1.17](https://go.dev/dl/) or greater.
- `make frontend` which requires [Node.js LTS](https://nodejs.org/en/download/) or greater and Internet connectivity to download npm dependencies.
When building from the official source tarballs which include pre-built frontend files, the `frontend` target will not be triggered, making it possible to build without Node.js and Internet connectivity.

View File

@@ -40,7 +40,7 @@ func passThroughCmd(cmd string, args []string) error {
}
c := exec.Cmd{
Path: foundCmd,
Args: args,
Args: append([]string{cmd}, args...),
Stdin: os.Stdin,
Stdout: os.Stdout,
Stderr: os.Stderr,
@@ -270,9 +270,10 @@ func main() {
if containsString(subArgs, "-w") {
cmdErrors = append(cmdErrors, giteaFormatGoImports(files))
}
cmdErrors = append(cmdErrors, passThroughCmd("gofmt", substArgs))
cmdErrors = append(cmdErrors, giteaFormatGoImports(files, containsString(subArgs, "-l"), containsString(subArgs, "-w")))
cmdErrors = append(cmdErrors, passThroughCmd("go", append([]string{"run", os.Getenv("GOFUMPT_PACKAGE"), "-extra", "-lang", "1.17"}, substArgs...)))
case "misspell":
cmdErrors = append(cmdErrors, passThroughCmd("misspell", substArgs))
cmdErrors = append(cmdErrors, passThroughCmd("go", append([]string{"run", os.Getenv("MISSPELL_PACKAGE")}, substArgs...)))
default:
log.Fatalf("unknown cmd: %s %v", subCmd, subArgs)
}

View File

@@ -25,6 +25,7 @@ import (
repo_module "code.gitea.io/gitea/modules/repository"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/storage"
"code.gitea.io/gitea/modules/util"
auth_service "code.gitea.io/gitea/services/auth"
"code.gitea.io/gitea/services/auth/source/oauth2"
"code.gitea.io/gitea/services/auth/source/smtp"
@@ -113,6 +114,10 @@ var (
Name: "access-token",
Usage: "Generate access token for the user",
},
cli.BoolFlag{
Name: "restricted",
Usage: "Make a restricted user account",
},
},
}
@@ -537,17 +542,26 @@ func runCreateUser(c *cli.Context) error {
changePassword = c.Bool("must-change-password")
}
restricted := util.OptionalBoolNone
if c.IsSet("restricted") {
restricted = util.OptionalBoolOf(c.Bool("restricted"))
}
u := &user_model.User{
Name: username,
Email: c.String("email"),
Passwd: password,
IsActive: true,
IsAdmin: c.Bool("admin"),
MustChangePassword: changePassword,
Theme: setting.UI.DefaultTheme,
}
if err := user_model.CreateUser(u); err != nil {
overwriteDefault := &user_model.CreateUserOverwriteOptions{
IsActive: util.OptionalBoolTrue,
IsRestricted: restricted,
}
if err := user_model.CreateUser(u, overwriteDefault); err != nil {
return fmt.Errorf("CreateUser: %v", err)
}

View File

@@ -86,7 +86,7 @@ func (o outputType) String() string {
}
var outputTypeEnum = &outputType{
Enum: []string{"zip", "rar", "tar", "sz", "tar.gz", "tar.xz", "tar.bz2", "tar.br", "tar.lz4"},
Enum: []string{"zip", "tar", "tar.sz", "tar.gz", "tar.xz", "tar.bz2", "tar.br", "tar.lz4"},
Default: "zip",
}
@@ -160,7 +160,12 @@ func runDump(ctx *cli.Context) error {
fatal("Deleting default logger failed. Can not write to stdout: %v", err)
}
} else {
fileName = strings.TrimSuffix(fileName, path.Ext(fileName))
for _, suffix := range outputTypeEnum.Enum {
if strings.HasSuffix(fileName, "."+suffix) {
fileName = strings.TrimSuffix(fileName, "."+suffix)
break
}
}
fileName += "." + outType
}
setting.LoadFromExisting()

View File

@@ -185,7 +185,7 @@ Gitea or set your environment appropriately.`, "")
reponame := os.Getenv(models.EnvRepoName)
userID, _ := strconv.ParseInt(os.Getenv(models.EnvPusherID), 10, 64)
prID, _ := strconv.ParseInt(os.Getenv(models.EnvPRID), 10, 64)
isDeployKey, _ := strconv.ParseBool(os.Getenv(models.EnvIsDeployKey))
deployKeyID, _ := strconv.ParseInt(os.Getenv(models.EnvDeployKeyID), 10, 64)
hookOptions := private.HookOptions{
UserID: userID,
@@ -194,7 +194,7 @@ Gitea or set your environment appropriately.`, "")
GitQuarantinePath: os.Getenv(private.GitQuarantinePath),
GitPushOptions: pushOptions(),
PullRequestID: prID,
IsDeployKey: isDeployKey,
DeployKeyID: deployKeyID,
}
scanner := bufio.NewScanner(os.Stdin)

View File

@@ -243,7 +243,7 @@ func runServ(c *cli.Context) error {
os.Setenv(models.EnvPusherID, strconv.FormatInt(results.UserID, 10))
os.Setenv(models.EnvRepoID, strconv.FormatInt(results.RepoID, 10))
os.Setenv(models.EnvPRID, fmt.Sprintf("%d", 0))
os.Setenv(models.EnvIsDeployKey, fmt.Sprintf("%t", results.IsDeployKey))
os.Setenv(models.EnvDeployKeyID, fmt.Sprintf("%d", results.DeployKeyID))
os.Setenv(models.EnvKeyID, fmt.Sprintf("%d", results.KeyID))
os.Setenv(models.EnvAppURL, setting.AppURL)
@@ -297,6 +297,15 @@ func runServ(c *cli.Context) error {
gitcmd = exec.CommandContext(ctx, verb, repoPath)
}
// Check if setting.RepoRootPath exists. It could be the case that it doesn't exist, this can happen when
// `[repository]` `ROOT` is a relative path and $GITEA_WORK_DIR isn't passed to the SSH connection.
if _, err := os.Stat(setting.RepoRootPath); err != nil {
if os.IsNotExist(err) {
return fail("Incorrect configuration.",
"Directory `[repository]` `ROOT` was not found, please check if $GITEA_WORK_DIR is passed to the SSH connection or make `[repository]` `ROOT` an absolute value.")
}
}
gitcmd.Dir = setting.RepoRootPath
gitcmd.Stdout = os.Stdout
gitcmd.Stdin = os.Stdin

View File

@@ -1075,7 +1075,7 @@ PATH =
;SEARCH_REPO_DESCRIPTION = true
;;
;; Whether to enable a Service Worker to cache frontend assets
;USE_SERVICE_WORKER = true
;USE_SERVICE_WORKER = false
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

View File

@@ -18,9 +18,9 @@ params:
description: Git with a cup of tea
author: The Gitea Authors
website: https://docs.gitea.io
version: 1.16.0
version: 1.16.4
minGoVersion: 1.16
goVersion: 1.17
goVersion: 1.18
minNodeVersion: 12.17
outputs:

View File

@@ -189,7 +189,7 @@ The following configuration set `Content-Type: application/vnd.android.package-a
add it to this config.
- `DEFAULT_SHOW_FULL_NAME`: **false**: Whether the full name of the users should be shown where possible. If the full name isn't set, the username will be used.
- `SEARCH_REPO_DESCRIPTION`: **true**: Whether to search within description at repository search on explore page.
- `USE_SERVICE_WORKER`: **true**: Whether to enable a Service Worker to cache frontend assets.
- `USE_SERVICE_WORKER`: **false**: Whether to enable a Service Worker to cache frontend assets.
### UI - Admin (`ui.admin`)

View File

@@ -185,8 +185,6 @@ Before committing, make sure the linters pass:
make lint-frontend
```
Note: When working on frontend code, set `USE_SERVICE_WORKER` to `false` in `app.ini` to prevent undesirable caching of frontend assets.
### Building and adding SVGs
SVG icons are built using the `make svg` target which compiles the icon sources defined in `build/generate-svg.js` into the output directory `public/img/svg`. Custom icons can be added in the `web_src/svg` directory.

View File

@@ -43,7 +43,7 @@ Vous devriez avoir une instance fonctionnelle de Gitea. Pour accèder à l'inter
## Named Volumes
Ce guide aboutira à une installation avec les données Gita et PostgreSQL stockées dans des volumes nommés. Cela permet une sauvegarde, une restauration et des mises à niveau en toute simplicité.
Ce guide aboutira à une installation avec les données Gitea et PostgreSQL stockées dans des volumes nommés. Cela permet une sauvegarde, une restauration et des mises à niveau en toute simplicité.
### The Database

152
go.mod
View File

@@ -3,7 +3,6 @@ module code.gitea.io/gitea
go 1.16
require (
cloud.google.com/go v0.78.0 // indirect
code.gitea.io/gitea-vet v0.2.1
code.gitea.io/sdk/gitea v0.15.1
gitea.com/go-chi/binding v0.0.0-20220309004920-114340dabecb
@@ -12,22 +11,13 @@ require (
gitea.com/go-chi/session v0.0.0-20211218221615-e3605d8b28b8
gitea.com/lunny/levelqueue v0.4.1
github.com/42wim/sshsig v0.0.0-20211121163825-841cf5bbc121
github.com/Microsoft/go-winio v0.5.0 // indirect
github.com/NYTimes/gziphandler v1.1.1
github.com/ProtonMail/go-crypto v0.0.0-20210705153151-cc34b1f6908b // indirect
github.com/PuerkitoBio/goquery v1.7.0
github.com/alecthomas/chroma v0.9.4
github.com/andybalholm/brotli v1.0.3 // indirect
github.com/andybalholm/cascadia v1.2.0 // indirect
github.com/blevesearch/bleve/v2 v2.3.0
github.com/boombuler/barcode v1.0.1 // indirect
github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b // indirect
github.com/caddyserver/certmagic v0.15.2
github.com/PuerkitoBio/goquery v1.8.0
github.com/alecthomas/chroma v0.10.0
github.com/blevesearch/bleve/v2 v2.3.1
github.com/caddyserver/certmagic v0.15.4
github.com/chi-middleware/proxy v1.1.1
github.com/couchbase/go-couchbase v0.0.0-20210224140812-5740cd35f448 // indirect
github.com/couchbase/gomemcached v0.1.2 // indirect
github.com/couchbase/goutils v0.0.0-20210118111533-e33d3ffb5401 // indirect
github.com/denisenkom/go-mssqldb v0.10.0
github.com/denisenkom/go-mssqldb v0.12.0
github.com/djherbis/buffer v1.2.0
github.com/djherbis/nio/v3 v3.0.1
github.com/duo-labs/webauthn v0.0.0-20220122034320-81aea484c951
@@ -36,8 +26,7 @@ require (
github.com/emirpasic/gods v1.12.0
github.com/ethantkoenig/rupture v1.0.0
github.com/gliderlabs/ssh v0.3.3
github.com/go-asn1-ber/asn1-ber v1.5.3 // indirect
github.com/go-chi/chi/v5 v5.0.4
github.com/go-chi/chi/v5 v5.0.7
github.com/go-chi/cors v1.2.0
github.com/go-enry/go-enry/v2 v2.7.1
github.com/go-git/go-billy/v5 v5.3.1
@@ -48,97 +37,124 @@ require (
github.com/go-swagger/go-swagger v0.27.0
github.com/go-testfixtures/testfixtures/v3 v3.6.1
github.com/gobwas/glob v0.2.3
github.com/gogs/chardet v0.0.0-20191104214054-4b6791f73a28
github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f
github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14
github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85
github.com/golang-jwt/jwt/v4 v4.2.0
github.com/golang/snappy v0.0.4 // indirect
github.com/golang-jwt/jwt/v4 v4.3.0
github.com/google/go-github/v39 v39.2.0
github.com/google/uuid v1.3.0
github.com/gorilla/feeds v1.1.1
github.com/gorilla/mux v1.8.0 // indirect
github.com/gorilla/sessions v1.2.1
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-retryablehttp v0.7.0 // indirect
github.com/hashicorp/go-version v1.3.1
github.com/hashicorp/go-version v1.4.0
github.com/hashicorp/golang-lru v0.5.4
github.com/huandu/xstrings v1.3.2
github.com/jaytaylor/html2text v0.0.0-20200412013138-3577fbdbcff7
github.com/json-iterator/go v1.1.11
github.com/json-iterator/go v1.1.12
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
github.com/kevinburke/ssh_config v1.1.0 // indirect
github.com/keybase/go-crypto v0.0.0-20200123153347-de78d2cb44f4
github.com/klauspost/compress v1.13.1
github.com/klauspost/compress v1.13.6
github.com/klauspost/cpuid/v2 v2.0.9
github.com/klauspost/pgzip v1.2.5 // indirect
github.com/lib/pq v1.10.2
github.com/lunny/dingtalk_webhook v0.0.0-20171025031554-e3534c89ef96
github.com/markbates/goth v1.68.0
github.com/mattn/go-isatty v0.0.13
github.com/mattn/go-runewidth v0.0.13 // indirect
github.com/mattn/go-sqlite3 v1.14.8
github.com/mholt/archiver/v3 v3.5.0
github.com/microcosm-cc/bluemonday v1.0.16
github.com/minio/md5-simd v1.1.2 // indirect
github.com/minio/minio-go/v7 v7.0.12
github.com/minio/sha256-simd v1.0.0 // indirect
github.com/mrjones/oauth v0.0.0-20190623134757-126b35219450 // indirect
github.com/msteinert/pam v0.0.0-20201130170657-e61372126161
github.com/markbates/goth v1.69.0
github.com/mattn/go-isatty v0.0.14
github.com/mattn/go-sqlite3 v1.14.12
github.com/mholt/archiver/v3 v3.5.1
github.com/microcosm-cc/bluemonday v1.0.18
github.com/minio/minio-go/v7 v7.0.23
github.com/msteinert/pam v1.0.0
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
github.com/niklasfasching/go-org v1.6.1
github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/niklasfasching/go-org v1.6.2
github.com/oliamb/cutter v0.2.2
github.com/olivere/elastic/v7 v7.0.25
github.com/pelletier/go-toml v1.9.0 // indirect
github.com/pierrec/lz4/v4 v4.1.8 // indirect
github.com/olivere/elastic/v7 v7.0.31
github.com/pkg/errors v0.9.1
github.com/pquerna/otp v1.3.0
github.com/prometheus/client_golang v1.11.0
github.com/quasoft/websspi v1.0.0
github.com/rs/xid v1.3.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/prometheus/client_golang v1.12.1
github.com/quasoft/websspi v1.1.2
github.com/sergi/go-diff v1.2.0
github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 // indirect
github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect
github.com/stretchr/testify v1.7.0
github.com/syndtr/goleveldb v1.0.0
github.com/tstranex/u2f v1.0.0
github.com/ulikunitz/xz v0.5.10 // indirect
github.com/unknwon/com v1.0.1
github.com/unknwon/i18n v0.0.0-20210321134014-0ebbf2df1c44
github.com/unknwon/paginater v0.0.0-20200328080006-042474bd0eae
github.com/unrolled/render v1.4.0
github.com/urfave/cli v1.22.5
github.com/xanzy/go-gitlab v0.50.1
github.com/xanzy/go-gitlab v0.58.0
github.com/yohcop/openid-go v1.0.0
github.com/yuin/goldmark v1.4.0
github.com/yuin/goldmark-highlighting v0.0.0-20210516132338-9216f9c5aa01
github.com/yuin/goldmark-meta v1.0.0
go.etcd.io/bbolt v1.3.6 // indirect
github.com/yuin/goldmark v1.4.11
github.com/yuin/goldmark-highlighting v0.0.0-20220208100518-594be1970594
github.com/yuin/goldmark-meta v1.1.0
go.jolheiser.com/hcaptcha v0.0.4
go.jolheiser.com/pwn v0.0.3
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.7.0 // indirect
go.uber.org/zap v1.19.0 // indirect
golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd
golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e
go.uber.org/multierr v1.8.0 // indirect
go.uber.org/zap v1.21.0 // indirect
golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4
golang.org/x/net v0.0.0-20220225172249-27dd8689420f
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9
golang.org/x/text v0.3.7
golang.org/x/time v0.0.0-20210611083556-38a9dc6acbc6 // indirect
golang.org/x/tools v0.1.0
google.golang.org/protobuf v1.27.1 // indirect
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
golang.org/x/tools v0.1.9
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
gopkg.in/ini.v1 v1.62.0
gopkg.in/ini.v1 v1.66.2
gopkg.in/yaml.v2 v2.4.0
mvdan.cc/xurls/v2 v2.2.0
strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251
xorm.io/builder v0.3.9
xorm.io/builder v0.3.10
xorm.io/xorm v1.2.5
)
require (
github.com/Azure/go-ntlmssp v0.0.0-20211209120228-48547f28849e // indirect
github.com/Microsoft/go-winio v0.5.2 // indirect
github.com/ProtonMail/go-crypto v0.0.0-20220113124808-70ae35bab23f // indirect
github.com/andybalholm/brotli v1.0.4 // indirect
github.com/bits-and-blooms/bitset v1.2.1 // indirect
github.com/boombuler/barcode v1.0.1 // indirect
github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b // indirect
github.com/cloudflare/cfssl v1.6.1 // indirect
github.com/couchbase/go-couchbase v0.0.0-20210224140812-5740cd35f448 // indirect
github.com/couchbase/gomemcached v0.1.2 // indirect
github.com/couchbase/goutils v0.0.0-20210118111533-e33d3ffb5401 // indirect
github.com/felixge/httpsnoop v1.0.2 // indirect
github.com/fxamacker/cbor/v2 v2.4.0 // indirect
github.com/go-asn1-ber/asn1-ber v1.5.3 // indirect
github.com/go-openapi/analysis v0.21.2 // indirect
github.com/go-openapi/errors v0.20.2 // indirect
github.com/go-openapi/runtime v0.21.1 // indirect
github.com/go-openapi/strfmt v0.21.1 // indirect
github.com/go-stack/stack v1.8.1 // indirect
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/gorilla/mux v1.8.0 // indirect
github.com/hashicorp/go-retryablehttp v0.7.0 // indirect
github.com/kevinburke/ssh_config v1.1.0 // indirect
github.com/kr/pretty v0.3.0 // indirect
github.com/mattn/go-runewidth v0.0.13 // indirect
github.com/mholt/acmez v1.0.2 // indirect
github.com/miekg/dns v1.1.46 // indirect
github.com/minio/md5-simd v1.1.2 // indirect
github.com/minio/sha256-simd v1.0.0 // indirect
github.com/mrjones/oauth v0.0.0-20190623134757-126b35219450 // indirect
github.com/nwaples/rardecode v1.1.3 // indirect
github.com/pierrec/lz4/v4 v4.1.14 // indirect
github.com/rogpeppe/go-internal v1.8.1 // indirect
github.com/rs/xid v1.3.0 // indirect
github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 // indirect
github.com/spf13/afero v1.8.0 // indirect
github.com/spf13/cobra v1.3.0 // indirect
github.com/spf13/viper v1.10.1 // indirect
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect
github.com/ulikunitz/xz v0.5.10 // indirect
github.com/xanzy/ssh-agent v0.3.1 // indirect
go.etcd.io/bbolt v1.3.6 // indirect
go.mongodb.org/mongo-driver v1.8.2 // indirect
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 // indirect
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
)
replace github.com/hashicorp/go-version => github.com/6543/go-version v1.3.1
replace github.com/markbates/goth v1.68.0 => github.com/zeripath/goth v1.68.1-0.20220109111530-754359885dce

864
go.sum

File diff suppressed because it is too large Load Diff

View File

@@ -47,7 +47,7 @@ func TestAPIPrivateServ(t *testing.T) {
results, err := private.ServCommand(ctx, 1, "user2", "repo1", perm.AccessModeWrite, "git-upload-pack", "")
assert.NoError(t, err)
assert.False(t, results.IsWiki)
assert.False(t, results.IsDeployKey)
assert.Zero(t, results.DeployKeyID)
assert.Equal(t, int64(1), results.KeyID)
assert.Equal(t, "user2@localhost", results.KeyName)
assert.Equal(t, "user2", results.UserName)
@@ -70,7 +70,7 @@ func TestAPIPrivateServ(t *testing.T) {
results, err = private.ServCommand(ctx, 1, "user15", "big_test_public_1", perm.AccessModeRead, "git-upload-pack", "")
assert.NoError(t, err)
assert.False(t, results.IsWiki)
assert.False(t, results.IsDeployKey)
assert.Zero(t, results.DeployKeyID)
assert.Equal(t, int64(1), results.KeyID)
assert.Equal(t, "user2@localhost", results.KeyName)
assert.Equal(t, "user2", results.UserName)
@@ -92,7 +92,7 @@ func TestAPIPrivateServ(t *testing.T) {
results, err = private.ServCommand(ctx, deployKey.KeyID, "user15", "big_test_private_1", perm.AccessModeRead, "git-upload-pack", "")
assert.NoError(t, err)
assert.False(t, results.IsWiki)
assert.True(t, results.IsDeployKey)
assert.NotZero(t, results.DeployKeyID)
assert.Equal(t, deployKey.KeyID, results.KeyID)
assert.Equal(t, "test-deploy", results.KeyName)
assert.Equal(t, "user15", results.UserName)
@@ -129,7 +129,7 @@ func TestAPIPrivateServ(t *testing.T) {
results, err = private.ServCommand(ctx, deployKey.KeyID, "user15", "big_test_private_2", perm.AccessModeRead, "git-upload-pack", "")
assert.NoError(t, err)
assert.False(t, results.IsWiki)
assert.True(t, results.IsDeployKey)
assert.NotZero(t, results.DeployKeyID)
assert.Equal(t, deployKey.KeyID, results.KeyID)
assert.Equal(t, "test-deploy", results.KeyName)
assert.Equal(t, "user15", results.UserName)
@@ -142,7 +142,7 @@ func TestAPIPrivateServ(t *testing.T) {
results, err = private.ServCommand(ctx, deployKey.KeyID, "user15", "big_test_private_2", perm.AccessModeWrite, "git-upload-pack", "")
assert.NoError(t, err)
assert.False(t, results.IsWiki)
assert.True(t, results.IsDeployKey)
assert.NotZero(t, results.DeployKeyID)
assert.Equal(t, deployKey.KeyID, results.KeyID)
assert.Equal(t, "test-deploy", results.KeyName)
assert.Equal(t, "user15", results.UserName)

View File

@@ -69,6 +69,12 @@ func TestAPIAddEmail(t *testing.T) {
Primary: false,
},
}, emails)
opts = api.CreateEmailOption{
Emails: []string{"notAEmail"},
}
req = NewRequestWithJSON(t, "POST", "/api/v1/user/emails?token="+token, &opts)
session.MakeRequest(t, req, http.StatusUnprocessableEntity)
}
func TestAPIDeleteEmail(t *testing.T) {

View File

@@ -112,6 +112,13 @@ func TestMain(m *testing.M) {
}
}
os.Unsetenv("GIT_AUTHOR_NAME")
os.Unsetenv("GIT_AUTHOR_EMAIL")
os.Unsetenv("GIT_AUTHOR_DATE")
os.Unsetenv("GIT_COMMITTER_NAME")
os.Unsetenv("GIT_COMMITTER_EMAIL")
os.Unsetenv("GIT_COMMITTER_DATE")
err := unittest.InitFixtures(
unittest.FixturesOptions{
Dir: filepath.Join(filepath.Dir(setting.AppPath), "models/fixtures/"),

View File

@@ -25,6 +25,8 @@ import (
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/test"
"code.gitea.io/gitea/services/pull"
repo_service "code.gitea.io/gitea/services/repository"
files_service "code.gitea.io/gitea/services/repository/files"
"github.com/stretchr/testify/assert"
"github.com/unknwon/i18n"
@@ -65,7 +67,7 @@ func testPullCleanUp(t *testing.T, session *TestSession, user, repo, pullnum str
func TestPullMerge(t *testing.T) {
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
hookTasks, err := webhook.HookTasks(1, 1) //Retrieve previous hook number
hookTasks, err := webhook.HookTasks(1, 1) // Retrieve previous hook number
assert.NoError(t, err)
hookTasksLenBefore := len(hookTasks)
@@ -87,7 +89,7 @@ func TestPullMerge(t *testing.T) {
func TestPullRebase(t *testing.T) {
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
hookTasks, err := webhook.HookTasks(1, 1) //Retrieve previous hook number
hookTasks, err := webhook.HookTasks(1, 1) // Retrieve previous hook number
assert.NoError(t, err)
hookTasksLenBefore := len(hookTasks)
@@ -109,7 +111,7 @@ func TestPullRebase(t *testing.T) {
func TestPullRebaseMerge(t *testing.T) {
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
hookTasks, err := webhook.HookTasks(1, 1) //Retrieve previous hook number
hookTasks, err := webhook.HookTasks(1, 1) // Retrieve previous hook number
assert.NoError(t, err)
hookTasksLenBefore := len(hookTasks)
@@ -131,7 +133,7 @@ func TestPullRebaseMerge(t *testing.T) {
func TestPullSquash(t *testing.T) {
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
hookTasks, err := webhook.HookTasks(1, 1) //Retrieve previous hook number
hookTasks, err := webhook.HookTasks(1, 1) // Retrieve previous hook number
assert.NoError(t, err)
hookTasksLenBefore := len(hookTasks)
@@ -335,3 +337,74 @@ func TestCantMergeUnrelated(t *testing.T) {
gitRepo.Close()
})
}
func TestConflictChecking(t *testing.T) {
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
// Create new clean repo to test conflict checking.
baseRepo, err := repo_service.CreateRepository(user, user, models.CreateRepoOptions{
Name: "conflict-checking",
Description: "Tempo repo",
AutoInit: true,
Readme: "Default",
DefaultBranch: "main",
})
assert.NoError(t, err)
assert.NotEmpty(t, baseRepo)
// create a commit on new branch.
_, err = files_service.CreateOrUpdateRepoFile(baseRepo, user, &files_service.UpdateRepoFileOptions{
TreePath: "important_file",
Message: "Add a important file",
Content: "Just a non-important file",
IsNewFile: true,
OldBranch: "main",
NewBranch: "important-secrets",
})
assert.NoError(t, err)
// create a commit on main branch.
_, err = files_service.CreateOrUpdateRepoFile(baseRepo, user, &files_service.UpdateRepoFileOptions{
TreePath: "important_file",
Message: "Add a important file",
Content: "Not the same content :P",
IsNewFile: true,
OldBranch: "main",
NewBranch: "main",
})
assert.NoError(t, err)
// create Pull to merge the important-secrets branch into main branch.
pullIssue := &models.Issue{
RepoID: baseRepo.ID,
Title: "PR with conflict!",
PosterID: user.ID,
Poster: user,
IsPull: true,
}
pullRequest := &models.PullRequest{
HeadRepoID: baseRepo.ID,
BaseRepoID: baseRepo.ID,
HeadBranch: "important-secrets",
BaseBranch: "main",
HeadRepo: baseRepo,
BaseRepo: baseRepo,
Type: models.PullRequestGitea,
}
err = pull.NewPullRequest(baseRepo, pullIssue, nil, nil, pullRequest, nil)
assert.NoError(t, err)
issue := unittest.AssertExistsAndLoadBean(t, &models.Issue{Title: "PR with conflict!"}).(*models.Issue)
conflictingPR, err := models.GetPullRequestByIssueID(issue.ID)
assert.NoError(t, err)
// Ensure conflictedFiles is populated.
assert.Equal(t, 1, len(conflictingPR.ConflictedFiles))
// Check if status is correct.
assert.Equal(t, models.PullRequestStatusConflict, conflictingPR.Status)
// Ensure that mergeable returns false
assert.False(t, conflictingPR.Mergeable())
})
}

View File

@@ -337,7 +337,7 @@ func GetFeeds(opts GetFeedsOptions) ([]*Action, error) {
actions := make([]*Action, 0, setting.UI.FeedPagingNum)
if err := db.GetEngine(db.DefaultContext).Limit(setting.UI.FeedPagingNum).Desc("created_unix").Where(cond).Find(&actions); err != nil {
if err := db.GetEngine(db.DefaultContext).Limit(setting.UI.FeedPagingNum).Desc("`action`.created_unix").Where(cond).Join("INNER", "repository", "`repository`.id = `action`.repo_id").Find(&actions); err != nil {
return nil, fmt.Errorf("Find: %v", err)
}
@@ -401,7 +401,7 @@ func activityQueryCondition(opts GetFeedsOptions) (builder.Cond, error) {
cond = cond.And(builder.Eq{"act_user_id": opts.RequestedUser.ID})
}
if !opts.IncludePrivate {
cond = cond.And(builder.Eq{"is_private": false})
cond = cond.And(builder.Eq{"`action`.is_private": false})
}
if !opts.IncludeDeleted {
cond = cond.And(builder.Eq{"is_deleted": false})
@@ -414,8 +414,8 @@ func activityQueryCondition(opts GetFeedsOptions) (builder.Cond, error) {
} else {
dateHigh := dateLow.Add(86399000000000) // 23h59m59s
cond = cond.And(builder.Gte{"created_unix": dateLow.Unix()})
cond = cond.And(builder.Lte{"created_unix": dateHigh.Unix()})
cond = cond.And(builder.Gte{"`action`.created_unix": dateLow.Unix()})
cond = cond.And(builder.Lte{"`action`.created_unix": dateHigh.Unix()})
}
}

View File

@@ -129,3 +129,20 @@ func TestNotifyWatchers(t *testing.T) {
OpType: action.OpType,
})
}
func TestGetFeedsCorrupted(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User)
unittest.AssertExistsAndLoadBean(t, &Action{
ID: 8,
RepoID: 1700,
})
actions, err := GetFeeds(GetFeedsOptions{
RequestedUser: user,
Actor: user,
IncludePrivate: true,
})
assert.NoError(t, err)
assert.Len(t, actions, 0)
}

View File

@@ -58,7 +58,7 @@ func (key *DeployKey) GetContent() error {
return nil
}
// IsReadOnly checks if the key can only be used for read operations
// IsReadOnly checks if the key can only be used for read operations, used by template
func (key *DeployKey) IsReadOnly() bool {
return key.Mode == perm.AccessModeRead
}
@@ -203,12 +203,6 @@ func UpdateDeployKeyCols(key *DeployKey, cols ...string) error {
return err
}
// UpdateDeployKey updates deploy key information.
func UpdateDeployKey(key *DeployKey) error {
_, err := db.GetEngine(db.DefaultContext).ID(key.ID).AllCols().Update(key)
return err
}
// ListDeployKeysOptions are options for ListDeployKeys
type ListDeployKeysOptions struct {
db.ListOptions

View File

@@ -9,6 +9,7 @@ import (
"code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/setting"
"xorm.io/builder"
)
@@ -247,3 +248,23 @@ func FixIssueLabelWithOutsideLabels() (int64, error) {
return res.RowsAffected()
}
// CountActionCreatedUnixString count actions where created_unix is an empty string
func CountActionCreatedUnixString() (int64, error) {
if setting.Database.UseSQLite3 {
return db.GetEngine(db.DefaultContext).Where(`created_unix = ""`).Count(new(Action))
}
return 0, nil
}
// FixActionCreatedUnixString set created_unix to zero if it is an empty string
func FixActionCreatedUnixString() (int64, error) {
if setting.Database.UseSQLite3 {
res, err := db.GetEngine(db.DefaultContext).Exec(`UPDATE action SET created_unix = 0 WHERE created_unix = ""`)
if err != nil {
return 0, err
}
return res.RowsAffected()
}
return 0, nil
}

View File

@@ -9,6 +9,7 @@ import (
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/unittest"
"code.gitea.io/gitea/modules/setting"
"github.com/stretchr/testify/assert"
)
@@ -33,3 +34,46 @@ func TestDeleteOrphanedObjects(t *testing.T) {
assert.NoError(t, err)
assert.EqualValues(t, countBefore, countAfter)
}
func TestConsistencyUpdateAction(t *testing.T) {
if !setting.Database.UseSQLite3 {
t.Skip("Test is only for SQLite database.")
}
assert.NoError(t, unittest.PrepareTestDatabase())
id := 8
unittest.AssertExistsAndLoadBean(t, &Action{
ID: int64(id),
})
_, err := db.GetEngine(db.DefaultContext).Exec(`UPDATE action SET created_unix = "" WHERE id = ?`, id)
assert.NoError(t, err)
actions := make([]*Action, 0, 1)
//
// XORM returns an error when created_unix is a string
//
err = db.GetEngine(db.DefaultContext).Where("id = ?", id).Find(&actions)
if assert.Error(t, err) {
assert.Contains(t, err.Error(), "type string to a int64: invalid syntax")
}
//
// Get rid of incorrectly set created_unix
//
count, err := CountActionCreatedUnixString()
assert.NoError(t, err)
assert.EqualValues(t, 1, count)
count, err = FixActionCreatedUnixString()
assert.NoError(t, err)
assert.EqualValues(t, 1, count)
count, err = CountActionCreatedUnixString()
assert.NoError(t, err)
assert.EqualValues(t, 0, count)
count, err = FixActionCreatedUnixString()
assert.NoError(t, err)
assert.EqualValues(t, 0, count)
//
// XORM must be happy now
//
assert.NoError(t, db.GetEngine(db.DefaultContext).Where("id = ?", id).Find(&actions))
unittest.CheckConsistencyFor(t, &Action{})
}

View File

@@ -332,7 +332,6 @@ type ErrInvalidCloneAddr struct {
IsProtocolInvalid bool
IsPermissionDenied bool
LocalPath bool
NotResolvedIP bool
}
// IsErrInvalidCloneAddr checks if an error is a ErrInvalidCloneAddr.
@@ -342,9 +341,6 @@ func IsErrInvalidCloneAddr(err error) bool {
}
func (err *ErrInvalidCloneAddr) Error() string {
if err.NotResolvedIP {
return fmt.Sprintf("migration/cloning from '%s' is not allowed: unknown hostname", err.Host)
}
if err.IsInvalidPath {
return fmt.Sprintf("migration/cloning from '%s' is not allowed: the provided path is invalid", err.Host)
}

View File

@@ -56,3 +56,11 @@
repo_id: 8
is_private: false
created_unix: 1603011540 # grouped with id:7
- id: 8
user_id: 1
op_type: 12 # close issue
act_user_id: 1
repo_id: 1700 # dangling intentional
is_private: false
created_unix: 1603011541

View File

@@ -23,8 +23,8 @@ const (
EnvPusherName = "GITEA_PUSHER_NAME"
EnvPusherEmail = "GITEA_PUSHER_EMAIL"
EnvPusherID = "GITEA_PUSHER_ID"
EnvKeyID = "GITEA_KEY_ID"
EnvIsDeployKey = "GITEA_IS_DEPLOY_KEY"
EnvKeyID = "GITEA_KEY_ID" // public key ID
EnvDeployKeyID = "GITEA_DEPLOY_KEY_ID"
EnvPRID = "GITEA_PR_ID"
EnvIsInternal = "GITEA_INTERNAL_PUSH"
EnvAppURL = "GITEA_ROOT_URL"

View File

@@ -1165,7 +1165,8 @@ func GetIssuesByIDs(issueIDs []int64) ([]*Issue, error) {
// IssuesOptions represents options of an issue.
type IssuesOptions struct {
db.ListOptions
RepoIDs []int64 // include all repos if empty
RepoID int64 // overwrites RepoCond if not 0
RepoCond builder.Cond
AssigneeID int64
PosterID int64
MentionedID int64
@@ -1238,7 +1239,7 @@ func sortIssuesSession(sess *xorm.Session, sortType string, priorityRepoID int64
}
}
func (opts *IssuesOptions) setupSession(sess *xorm.Session) {
func (opts *IssuesOptions) setupSessionWithLimit(sess *xorm.Session) {
if opts.Page >= 0 && opts.PageSize > 0 {
var start int
if opts.Page == 0 {
@@ -1248,20 +1249,23 @@ func (opts *IssuesOptions) setupSession(sess *xorm.Session) {
}
sess.Limit(opts.PageSize, start)
}
opts.setupSessionNoLimit(sess)
}
func (opts *IssuesOptions) setupSessionNoLimit(sess *xorm.Session) {
if len(opts.IssueIDs) > 0 {
sess.In("issue.id", opts.IssueIDs)
}
if len(opts.RepoIDs) > 0 {
applyReposCondition(sess, opts.RepoIDs)
if opts.RepoID != 0 {
opts.RepoCond = builder.Eq{"issue.repo_id": opts.RepoID}
}
if opts.RepoCond != nil {
sess.And(opts.RepoCond)
}
switch opts.IsClosed {
case util.OptionalBoolTrue:
sess.And("issue.is_closed=?", true)
case util.OptionalBoolFalse:
sess.And("issue.is_closed=?", false)
if !opts.IsClosed.IsNone() {
sess.And("issue.is_closed=?", opts.IsClosed.IsTrue())
}
if opts.AssigneeID > 0 {
@@ -1342,9 +1346,7 @@ func (opts *IssuesOptions) setupSession(sess *xorm.Session) {
}
if opts.User != nil {
sess.And(
issuePullAccessibleRepoCond("issue.repo_id", opts.User.ID, opts.Org, opts.Team, opts.IsPull.IsTrue()),
)
sess.And(issuePullAccessibleRepoCond("issue.repo_id", opts.User.ID, opts.Org, opts.Team, opts.IsPull.IsTrue()))
}
}
@@ -1380,10 +1382,6 @@ func issuePullAccessibleRepoCond(repoIDstr string, userID int64, org *Organizati
return cond
}
func applyReposCondition(sess *xorm.Session, repoIDs []int64) *xorm.Session {
return sess.In("issue.repo_id", repoIDs)
}
func applyAssigneeCondition(sess *xorm.Session, assigneeID int64) *xorm.Session {
return sess.Join("INNER", "issue_assignees", "issue.id = issue_assignees.issue_id").
And("issue_assignees.assignee_id = ?", assigneeID)
@@ -1413,8 +1411,7 @@ func CountIssuesByRepo(opts *IssuesOptions) (map[int64]int64, error) {
e := db.GetEngine(db.DefaultContext)
sess := e.Join("INNER", "repository", "`issue`.repo_id = `repository`.id")
opts.setupSession(sess)
opts.setupSessionNoLimit(sess)
countsSlice := make([]*struct {
RepoID int64
@@ -1424,7 +1421,7 @@ func CountIssuesByRepo(opts *IssuesOptions) (map[int64]int64, error) {
Select("issue.repo_id AS repo_id, COUNT(*) AS count").
Table("issue").
Find(&countsSlice); err != nil {
return nil, err
return nil, fmt.Errorf("unable to CountIssuesByRepo: %w", err)
}
countMap := make(map[int64]int64, len(countsSlice))
@@ -1440,15 +1437,14 @@ func GetRepoIDsForIssuesOptions(opts *IssuesOptions, user *user_model.User) ([]i
e := db.GetEngine(db.DefaultContext)
sess := e.Join("INNER", "repository", "`issue`.repo_id = `repository`.id")
opts.setupSession(sess)
opts.setupSessionNoLimit(sess)
accessCond := accessibleRepositoryCondition(user)
if err := sess.Where(accessCond).
Distinct("issue.repo_id").
Table("issue").
Find(&repoIDs); err != nil {
return nil, err
return nil, fmt.Errorf("unable to GetRepoIDsForIssuesOptions: %w", err)
}
return repoIDs, nil
@@ -1459,17 +1455,16 @@ func Issues(opts *IssuesOptions) ([]*Issue, error) {
e := db.GetEngine(db.DefaultContext)
sess := e.Join("INNER", "repository", "`issue`.repo_id = `repository`.id")
opts.setupSession(sess)
opts.setupSessionWithLimit(sess)
sortIssuesSession(sess, opts.SortType, opts.PriorityRepoID)
issues := make([]*Issue, 0, opts.ListOptions.PageSize)
if err := sess.Find(&issues); err != nil {
return nil, fmt.Errorf("Find: %v", err)
return nil, fmt.Errorf("unable to query Issues: %w", err)
}
sess.Close()
if err := IssueList(issues).LoadAttributes(); err != nil {
return nil, fmt.Errorf("LoadAttributes: %v", err)
return nil, fmt.Errorf("unable to LoadAttributes for Issues: %w", err)
}
return issues, nil
@@ -1480,18 +1475,18 @@ func CountIssues(opts *IssuesOptions) (int64, error) {
e := db.GetEngine(db.DefaultContext)
countsSlice := make([]*struct {
RepoID int64
Count int64
Count int64
}, 0, 1)
sess := e.Select("COUNT(issue.id) AS count").Table("issue")
sess.Join("INNER", "repository", "`issue`.repo_id = `repository`.id")
opts.setupSession(sess)
opts.setupSessionNoLimit(sess)
if err := sess.Find(&countsSlice); err != nil {
return 0, fmt.Errorf("Find: %v", err)
return 0, fmt.Errorf("unable to CountIssues: %w", err)
}
if len(countsSlice) < 1 {
return 0, fmt.Errorf("there is less than one result sql record")
if len(countsSlice) != 1 {
return 0, fmt.Errorf("unable to get one row result when CountIssues, row count=%d", len(countsSlice))
}
return countsSlice[0].Count, nil
}
@@ -1551,6 +1546,7 @@ const (
FilterModeCreate
FilterModeMention
FilterModeReviewRequested
FilterModeYourRepositories
)
func parseCountResult(results []map[string][]byte) int64 {
@@ -1695,6 +1691,7 @@ type UserIssueStatsOptions struct {
IssueIDs []int64
IsArchived util.OptionalBool
LabelIDs []int64
RepoCond builder.Cond
Org *Organization
Team *Team
}
@@ -1712,6 +1709,9 @@ func GetUserIssueStats(opts UserIssueStatsOptions) (*IssueStats, error) {
if len(opts.IssueIDs) > 0 {
cond = cond.And(builder.In("issue.id", opts.IssueIDs))
}
if opts.RepoCond != nil {
cond = cond.And(opts.RepoCond)
}
if opts.UserID > 0 {
cond = cond.And(issuePullAccessibleRepoCond("issue.repo_id", opts.UserID, opts.Org, opts.Team, opts.IsPull))
@@ -1733,7 +1733,7 @@ func GetUserIssueStats(opts UserIssueStatsOptions) (*IssueStats, error) {
}
switch opts.FilterMode {
case FilterModeAll:
case FilterModeAll, FilterModeYourRepositories:
stats.OpenCount, err = sess(cond).
And("issue.is_closed = ?", false).
Count(new(Issue))

View File

@@ -101,12 +101,9 @@ func (label *Label) CalOpenIssues() {
// CalOpenOrgIssues calculates the open issues of a label for a specific repo
func (label *Label) CalOpenOrgIssues(repoID, labelID int64) {
repoIDs := []int64{repoID}
labelIDs := []int64{labelID}
counts, _ := CountIssuesByRepo(&IssuesOptions{
RepoIDs: repoIDs,
LabelIDs: labelIDs,
RepoID: repoID,
LabelIDs: []int64{labelID},
})
for _, count := range counts {

View File

@@ -17,6 +17,7 @@ import (
user_model "code.gitea.io/gitea/models/user"
"github.com/stretchr/testify/assert"
"xorm.io/builder"
)
func TestIssue_ReplaceLabels(t *testing.T) {
@@ -153,7 +154,7 @@ func TestIssues(t *testing.T) {
},
{
IssuesOptions{
RepoIDs: []int64{1, 3},
RepoCond: builder.In("repo_id", 1, 3),
SortType: "oldest",
ListOptions: db.ListOptions{
Page: 1,
@@ -340,7 +341,7 @@ func TestGetRepoIDsForIssuesOptions(t *testing.T) {
},
{
IssuesOptions{
RepoIDs: []int64{1, 2},
RepoCond: builder.In("repo_id", 1, 2),
},
[]int64{1, 2},
},

View File

@@ -453,7 +453,7 @@ Please try upgrading to a lower version first (suggested v1.6.4), then upgrade t
// Downgrading Gitea's database version not supported
if int(v-minDBVersion) > len(migrations) {
msg := fmt.Sprintf("Your database (migration version: %d) is for a newer Gita, you can not use the newer database for this old Gitea release (%d).", v, minDBVersion+len(migrations))
msg := fmt.Sprintf("Your database (migration version: %d) is for a newer Gitea, you can not use the newer database for this old Gitea release (%d).", v, minDBVersion+len(migrations))
msg += "\nGitea will exit to keep your database safe and unchanged. Please use the correct Gitea release, do not change the migration version manually (incorrect manual operation may lose data)."
if !setting.IsProd {
msg += fmt.Sprintf("\nIf you are in development and really know what you're doing, you can force changing the migration version by executing: UPDATE version SET version=%d WHERE id=1;", minDBVersion+len(migrations))

View File

@@ -19,6 +19,7 @@ import (
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
"xorm.io/builder"
)
@@ -776,8 +777,45 @@ func DeleteTeam(t *Team) error {
return err
}
if err := t.removeAllRepositories(ctx); err != nil {
return err
// update branch protections
{
protections := make([]*ProtectedBranch, 0, 10)
err := sess.In("repo_id",
builder.Select("id").From("repository").Where(builder.Eq{"owner_id": t.OrgID})).
Find(&protections)
if err != nil {
return fmt.Errorf("findProtectedBranches: %v", err)
}
for _, p := range protections {
var matched1, matched2, matched3 bool
if len(p.WhitelistTeamIDs) != 0 {
p.WhitelistTeamIDs, matched1 = util.RemoveIDFromList(
p.WhitelistTeamIDs, t.ID)
}
if len(p.ApprovalsWhitelistTeamIDs) != 0 {
p.ApprovalsWhitelistTeamIDs, matched2 = util.RemoveIDFromList(
p.ApprovalsWhitelistTeamIDs, t.ID)
}
if len(p.MergeWhitelistTeamIDs) != 0 {
p.MergeWhitelistTeamIDs, matched3 = util.RemoveIDFromList(
p.MergeWhitelistTeamIDs, t.ID)
}
if matched1 || matched2 || matched3 {
if _, err = sess.ID(p.ID).Cols(
"whitelist_team_i_ds",
"merge_whitelist_team_i_ds",
"approvals_whitelist_team_i_ds",
).Update(p); err != nil {
return fmt.Errorf("updateProtectedBranches: %v", err)
}
}
}
}
if !t.IncludesAllRepositories {
if err := t.removeAllRepositories(ctx); err != nil {
return err
}
}
// Delete team-user.
@@ -902,11 +940,6 @@ func AddTeamMember(team *Team, userID int64) error {
return err
}
// Get team and its repositories.
if err := team.GetRepositories(&SearchOrgTeamOptions{}); err != nil {
return err
}
ctx, committer, err := db.TxContext()
if err != nil {
return err
@@ -928,17 +961,51 @@ func AddTeamMember(team *Team, userID int64) error {
team.NumMembers++
// Give access to team repositories.
for _, repo := range team.Repos {
if err := recalculateUserAccess(ctx, repo, userID); err != nil {
return err
}
if setting.Service.AutoWatchNewRepos {
if err = repo_model.WatchRepoCtx(ctx, userID, repo.ID, true); err != nil {
return err
// update exist access if mode become bigger
subQuery := builder.Select("repo_id").From("team_repo").
Where(builder.Eq{"team_id": team.ID})
if _, err := sess.Where("user_id=?", userID).
In("repo_id", subQuery).
And("mode < ?", team.AccessMode).
SetExpr("mode", team.AccessMode).
Update(new(Access)); err != nil {
return fmt.Errorf("update user accesses: %v", err)
}
// for not exist access
var repoIDs []int64
accessSubQuery := builder.Select("repo_id").From("access").Where(builder.Eq{"user_id": userID})
if err := sess.SQL(subQuery.And(builder.NotIn("repo_id", accessSubQuery))).Find(&repoIDs); err != nil {
return fmt.Errorf("select id accesses: %v", err)
}
accesses := make([]*Access, 0, 100)
for i, repoID := range repoIDs {
accesses = append(accesses, &Access{RepoID: repoID, UserID: userID, Mode: team.AccessMode})
if (i%100 == 0 || i == len(repoIDs)-1) && len(accesses) > 0 {
if err = db.Insert(ctx, accesses); err != nil {
return fmt.Errorf("insert new user accesses: %v", err)
}
accesses = accesses[:0]
}
}
// watch could be failed, so run it in a goroutine
if setting.Service.AutoWatchNewRepos {
// Get team and its repositories.
if err := team.GetRepositories(&SearchOrgTeamOptions{}); err != nil {
log.Error("getRepositories failed: %v", err)
}
go func(repos []*repo_model.Repository) {
for _, repo := range repos {
if err = repo_model.WatchRepoCtx(db.DefaultContext, userID, repo.ID, true); err != nil {
log.Error("watch repo failed: %v", err)
}
}
}(team.Repos)
}
return committer.Commit()
}

View File

@@ -222,22 +222,19 @@ func (pr *PullRequest) loadProtectedBranch(ctx context.Context) (err error) {
}
// GetDefaultMergeMessage returns default message used when merging pull request
func (pr *PullRequest) GetDefaultMergeMessage() string {
func (pr *PullRequest) GetDefaultMergeMessage() (string, error) {
if pr.HeadRepo == nil {
var err error
pr.HeadRepo, err = repo_model.GetRepositoryByID(pr.HeadRepoID)
if err != nil {
log.Error("GetRepositoryById[%d]: %v", pr.HeadRepoID, err)
return ""
return "", fmt.Errorf("GetRepositoryById[%d]: %v", pr.HeadRepoID, err)
}
}
if err := pr.LoadIssue(); err != nil {
log.Error("Cannot load issue %d for PR id %d: Error: %v", pr.IssueID, pr.ID, err)
return ""
return "", fmt.Errorf("Cannot load issue %d for PR id %d: Error: %v", pr.IssueID, pr.ID, err)
}
if err := pr.LoadBaseRepo(); err != nil {
log.Error("LoadBaseRepo: %v", err)
return ""
return "", fmt.Errorf("LoadBaseRepo: %v", err)
}
issueReference := "#"
@@ -246,10 +243,10 @@ func (pr *PullRequest) GetDefaultMergeMessage() string {
}
if pr.BaseRepoID == pr.HeadRepoID {
return fmt.Sprintf("Merge pull request '%s' (%s%d) from %s into %s", pr.Issue.Title, issueReference, pr.Issue.Index, pr.HeadBranch, pr.BaseBranch)
return fmt.Sprintf("Merge pull request '%s' (%s%d) from %s into %s", pr.Issue.Title, issueReference, pr.Issue.Index, pr.HeadBranch, pr.BaseBranch), nil
}
return fmt.Sprintf("Merge pull request '%s' (%s%d) from %s:%s into %s", pr.Issue.Title, issueReference, pr.Issue.Index, pr.HeadRepo.FullName(), pr.HeadBranch, pr.BaseBranch)
return fmt.Sprintf("Merge pull request '%s' (%s%d) from %s:%s into %s", pr.Issue.Title, issueReference, pr.Issue.Index, pr.HeadRepo.FullName(), pr.HeadBranch, pr.BaseBranch), nil
}
// ReviewCount represents a count of Reviews
@@ -335,19 +332,17 @@ func (pr *PullRequest) getReviewedByLines(writer io.Writer) error {
}
// GetDefaultSquashMessage returns default message used when squash and merging pull request
func (pr *PullRequest) GetDefaultSquashMessage() string {
func (pr *PullRequest) GetDefaultSquashMessage() (string, error) {
if err := pr.LoadIssue(); err != nil {
log.Error("LoadIssue: %v", err)
return ""
return "", fmt.Errorf("LoadIssue: %v", err)
}
if err := pr.LoadBaseRepo(); err != nil {
log.Error("LoadBaseRepo: %v", err)
return ""
return "", fmt.Errorf("LoadBaseRepo: %v", err)
}
if pr.BaseRepo.UnitEnabled(unit.TypeExternalTracker) {
return fmt.Sprintf("%s (!%d)", pr.Issue.Title, pr.Issue.Index)
return fmt.Sprintf("%s (!%d)", pr.Issue.Title, pr.Issue.Index), nil
}
return fmt.Sprintf("%s (#%d)", pr.Issue.Title, pr.Issue.Index)
return fmt.Sprintf("%s (#%d)", pr.Issue.Title, pr.Issue.Index), nil
}
// GetGitRefName returns git ref for hidden pull request branch
@@ -702,3 +697,14 @@ func (pr *PullRequest) GetHeadBranchHTMLURL() string {
}
return pr.HeadRepo.HTMLURL() + "/src/branch/" + util.PathEscapeSegments(pr.HeadBranch)
}
// Mergeable returns if the pullrequest is mergeable.
func (pr *PullRequest) Mergeable() bool {
// If a pull request isn't mergable if it's:
// - Being conflict checked.
// - Has a conflict.
// - Received a error while being conflict checked.
// - Is a work-in-progress pull request.
return pr.Status != PullRequestStatusChecking && pr.Status != PullRequestStatusConflict &&
pr.Status != PullRequestStatusError && !pr.IsWorkInProgress()
}

View File

@@ -261,11 +261,15 @@ func TestPullRequest_GetDefaultMergeMessage_InternalTracker(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
pr := unittest.AssertExistsAndLoadBean(t, &PullRequest{ID: 2}).(*PullRequest)
assert.Equal(t, "Merge pull request 'issue3' (#3) from branch2 into master", pr.GetDefaultMergeMessage())
msg, err := pr.GetDefaultMergeMessage()
assert.NoError(t, err)
assert.Equal(t, "Merge pull request 'issue3' (#3) from branch2 into master", msg)
pr.BaseRepoID = 1
pr.HeadRepoID = 2
assert.Equal(t, "Merge pull request 'issue3' (#3) from user2/repo1:branch2 into master", pr.GetDefaultMergeMessage())
msg, err = pr.GetDefaultMergeMessage()
assert.NoError(t, err)
assert.Equal(t, "Merge pull request 'issue3' (#3) from user2/repo1:branch2 into master", msg)
}
func TestPullRequest_GetDefaultMergeMessage_ExternalTracker(t *testing.T) {
@@ -283,9 +287,13 @@ func TestPullRequest_GetDefaultMergeMessage_ExternalTracker(t *testing.T) {
pr := unittest.AssertExistsAndLoadBean(t, &PullRequest{ID: 2, BaseRepo: baseRepo}).(*PullRequest)
assert.Equal(t, "Merge pull request 'issue3' (!3) from branch2 into master", pr.GetDefaultMergeMessage())
msg, err := pr.GetDefaultMergeMessage()
assert.NoError(t, err)
assert.Equal(t, "Merge pull request 'issue3' (!3) from branch2 into master", msg)
pr.BaseRepoID = 1
pr.HeadRepoID = 2
assert.Equal(t, "Merge pull request 'issue3' (!3) from user2/repo1:branch2 into master", pr.GetDefaultMergeMessage())
msg, err = pr.GetDefaultMergeMessage()
assert.NoError(t, err)
assert.Equal(t, "Merge pull request 'issue3' (!3) from user2/repo1:branch2 into master", msg)
}

View File

@@ -132,7 +132,7 @@ func CheckRepoUnitUser(repo *repo_model.Repository, user *user_model.User, unitT
}
func checkRepoUnitUser(ctx context.Context, repo *repo_model.Repository, user *user_model.User, unitType unit.Type) bool {
if user.IsAdmin {
if user != nil && user.IsAdmin {
return true
}
perm, err := getUserRepoPermission(ctx, repo, user)

View File

@@ -6,6 +6,7 @@
package repo
import (
"context"
"errors"
"fmt"
"time"
@@ -115,6 +116,13 @@ func UpdateMirror(m *Mirror) error {
return updateMirror(db.GetEngine(db.DefaultContext), m)
}
// TouchMirror updates the mirror updatedUnix
func TouchMirror(ctx context.Context, m *Mirror) error {
m.UpdatedUnix = timeutil.TimeStampNow()
_, err := db.GetEngine(ctx).ID(m.ID).Cols("updated_unix").Update(m)
return err
}
// DeleteMirrorByRepoID deletes a mirror by repoID
func DeleteMirrorByRepoID(repoID int64) error {
_, err := db.GetEngine(db.DefaultContext).Delete(&Mirror{RepoID: repoID})

View File

@@ -233,14 +233,28 @@ func teamUnitsRepoCond(id string, userID, orgID, teamID int64, units ...unit.Typ
builder.Select("repo_id").From("team_repo").Where(
builder.Eq{
"team_id": teamID,
}.And(
}.And(builder.Or(
// Check if the user is member of the team.
builder.In(
"team_id", builder.Select("team_id").From("team_user").Where(
builder.Eq{
"uid": userID,
},
),
)).And(
),
// Check if the user is in the owner team of the organisation.
builder.Exists(builder.Select("team_id").From("team_user").
Where(builder.Eq{
"org_id": orgID,
"team_id": builder.Select("id").From("team").Where(
builder.Eq{
"org_id": orgID,
"lower_name": strings.ToLower(ownerTeamName),
}),
"uid": userID,
}),
),
)).And(
builder.In(
"team_id", builder.Select("team_id").From("team_unit").Where(
builder.Eq{

View File

@@ -175,8 +175,10 @@ func init() {
checkForActionConsistency := func(t assert.TestingT, bean interface{}) {
action := reflectionWrap(bean)
repoRow := AssertExistsAndLoadMap(t, "repository", builder.Eq{"id": action.int("RepoID")})
assert.Equal(t, parseBool(repoRow["is_private"]), action.bool("IsPrivate"), "action: %+v", action)
if action.int("RepoID") != 1700 { // dangling intentional
repoRow := AssertExistsAndLoadMap(t, "repository", builder.Eq{"id": action.int("RepoID")})
assert.Equal(t, parseBool(repoRow["is_private"]), action.bool("IsPrivate"), "action: %+v", action)
}
}
consistencyCheckMap["user"] = checkForUserConsistency

View File

@@ -13,11 +13,13 @@ import (
_ "image/jpeg" // Needed for jpeg support
asymkey_model "code.gitea.io/gitea/models/asymkey"
auth_model "code.gitea.io/gitea/models/auth"
"code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/util"
"xorm.io/builder"
)
@@ -82,6 +84,11 @@ func DeleteUser(ctx context.Context, u *user_model.User) (err error) {
}
// ***** END: Follow *****
if _, err := db.GetEngine(ctx).In("grant_id", builder.Select("id").From("oauth2_grant").Where(builder.Eq{"oauth2_grant.user_id": u.ID})).
Delete(&auth_model.OAuth2AuthorizationCode{}); err != nil {
return err
}
if err = deleteBeans(e,
&AccessToken{UID: u.ID},
&Collaboration{UserID: u.ID},
@@ -99,6 +106,8 @@ func DeleteUser(ctx context.Context, u *user_model.User) (err error) {
&Collaboration{UserID: u.ID},
&Stopwatch{UserID: u.ID},
&user_model.Setting{UserID: u.ID},
&auth_model.OAuth2Application{UID: u.ID},
&auth_model.OAuth2Grant{UserID: u.ID},
); err != nil {
return fmt.Errorf("deleteBeans: %v", err)
}
@@ -130,6 +139,50 @@ func DeleteUser(ctx context.Context, u *user_model.User) (err error) {
}
}
// ***** START: Branch Protections *****
{
const batchSize = 50
for start := 0; ; start += batchSize {
protections := make([]*ProtectedBranch, 0, batchSize)
// @perf: We can't filter on DB side by u.ID, as those IDs are serialized as JSON strings.
// We could filter down with `WHERE repo_id IN (reposWithPushPermission(u))`,
// though that query will be quite complex and tricky to maintain (compare `getRepoAssignees()`).
// Also, as we didn't update branch protections when removing entries from `access` table,
// it's safer to iterate all protected branches.
if err = e.Limit(batchSize, start).Find(&protections); err != nil {
return fmt.Errorf("findProtectedBranches: %v", err)
}
if len(protections) == 0 {
break
}
for _, p := range protections {
var matched1, matched2, matched3 bool
if len(p.WhitelistUserIDs) != 0 {
p.WhitelistUserIDs, matched1 = util.RemoveIDFromList(
p.WhitelistUserIDs, u.ID)
}
if len(p.ApprovalsWhitelistUserIDs) != 0 {
p.ApprovalsWhitelistUserIDs, matched2 = util.RemoveIDFromList(
p.ApprovalsWhitelistUserIDs, u.ID)
}
if len(p.MergeWhitelistUserIDs) != 0 {
p.MergeWhitelistUserIDs, matched3 = util.RemoveIDFromList(
p.MergeWhitelistUserIDs, u.ID)
}
if matched1 || matched2 || matched3 {
if _, err = e.ID(p.ID).Cols(
"whitelist_user_i_ds",
"merge_whitelist_user_i_ds",
"approvals_whitelist_user_i_ds",
).Update(p); err != nil {
return fmt.Errorf("updateProtectedBranches: %v", err)
}
}
}
}
}
// ***** END: Branch Protections *****
// ***** START: PublicKey *****
if _, err = e.Delete(&asymkey_model.PublicKey{OwnerID: u.ID}); err != nil {
return fmt.Errorf("deletePublicKeys: %v", err)

View File

@@ -622,7 +622,14 @@ func IsUsableUsername(name string) error {
// CreateUserOverwriteOptions are an optional options who overwrite system defaults on user creation
type CreateUserOverwriteOptions struct {
Visibility structs.VisibleType
KeepEmailPrivate util.OptionalBool
Visibility *structs.VisibleType
AllowCreateOrganization util.OptionalBool
EmailNotificationsPreference *string
MaxRepoCreation *int
Theme *string
IsRestricted util.OptionalBool
IsActive util.OptionalBool
}
// CreateUser creates record of a new user.
@@ -638,10 +645,36 @@ func CreateUser(u *User, overwriteDefault ...*CreateUserOverwriteOptions) (err e
u.EmailNotificationsPreference = setting.Admin.DefaultEmailNotification
u.MaxRepoCreation = -1
u.Theme = setting.UI.DefaultTheme
u.IsRestricted = setting.Service.DefaultUserIsRestricted
u.IsActive = !(setting.Service.RegisterEmailConfirm || setting.Service.RegisterManualConfirm)
// overwrite defaults if set
if len(overwriteDefault) != 0 && overwriteDefault[0] != nil {
u.Visibility = overwriteDefault[0].Visibility
overwrite := overwriteDefault[0]
if !overwrite.KeepEmailPrivate.IsNone() {
u.KeepEmailPrivate = overwrite.KeepEmailPrivate.IsTrue()
}
if overwrite.Visibility != nil {
u.Visibility = *overwrite.Visibility
}
if !overwrite.AllowCreateOrganization.IsNone() {
u.AllowCreateOrganization = overwrite.AllowCreateOrganization.IsTrue()
}
if overwrite.EmailNotificationsPreference != nil {
u.EmailNotificationsPreference = *overwrite.EmailNotificationsPreference
}
if overwrite.MaxRepoCreation != nil {
u.MaxRepoCreation = *overwrite.MaxRepoCreation
}
if overwrite.Theme != nil {
u.Theme = *overwrite.Theme
}
if !overwrite.IsRestricted.IsNone() {
u.IsRestricted = overwrite.IsRestricted.IsTrue()
}
if !overwrite.IsActive.IsNone() {
u.IsActive = overwrite.IsActive.IsTrue()
}
}
// validate data

View File

@@ -497,14 +497,19 @@ func GetSystemOrDefaultWebhook(id int64) (*Webhook, error) {
}
// GetSystemWebhooks returns all admin system webhooks.
func GetSystemWebhooks() ([]*Webhook, error) {
return getSystemWebhooks(db.GetEngine(db.DefaultContext))
func GetSystemWebhooks(isActive util.OptionalBool) ([]*Webhook, error) {
return getSystemWebhooks(db.GetEngine(db.DefaultContext), isActive)
}
func getSystemWebhooks(e db.Engine) ([]*Webhook, error) {
func getSystemWebhooks(e db.Engine, isActive util.OptionalBool) ([]*Webhook, error) {
webhooks := make([]*Webhook, 0, 5)
if isActive.IsNone() {
return webhooks, e.
Where("repo_id=? AND org_id=? AND is_system_webhook=?", 0, 0, true).
Find(&webhooks)
}
return webhooks, e.
Where("repo_id=? AND org_id=? AND is_system_webhook=?", 0, 0, true).
Where("repo_id=? AND org_id=? AND is_system_webhook=? AND is_active = ?", 0, 0, true, isActive.IsTrue()).
Find(&webhooks)
}

View File

@@ -288,6 +288,7 @@ func APIContexter() func(http.Handler) http.Handler {
},
Org: &APIOrganization{},
}
defer ctx.Close()
ctx.Req = WithAPIContext(WithContext(req, ctx.Context), &ctx)
ctx.csrf = Csrfer(csrfOpts, ctx.Context)

View File

@@ -71,6 +71,16 @@ type Context struct {
Org *Organization
}
// Close frees all resources hold by Context
func (ctx *Context) Close() error {
var err error
if ctx.Req != nil && ctx.Req.MultipartForm != nil {
err = ctx.Req.MultipartForm.RemoveAll() // remove the temp files buffered to tmp directory
}
// TODO: close opened repo, and more
return err
}
// TrHTMLEscapeArgs runs Tr but pre-escapes all arguments with html.EscapeString.
// This is useful if the locale message is intended to only produce HTML content.
func (ctx *Context) TrHTMLEscapeArgs(msg string, args ...string) string {
@@ -181,6 +191,12 @@ func (ctx *Context) RedirectToFirst(location ...string) {
continue
}
// Unfortunately browsers consider a redirect Location with preceding "//" and "/\" as meaning redirect to "http(s)://REST_OF_PATH"
// Therefore we should ignore these redirect locations to prevent open redirects
if len(loc) > 1 && loc[0] == '/' && (loc[1] == '/' || loc[1] == '\\') {
continue
}
u, err := url.Parse(loc)
if err != nil || ((u.Scheme != "" || u.Host != "") && !strings.HasPrefix(strings.ToLower(loc), strings.ToLower(setting.AppURL))) {
continue
@@ -637,6 +653,8 @@ func Contexter() func(next http.Handler) http.Handler {
"RunModeIsProd": setting.IsProd,
},
}
defer ctx.Close()
// PageData is passed by reference, and it will be rendered to `window.config.pageData` in `head.tmpl` for JavaScript modules
ctx.PageData = map[string]interface{}{}
ctx.Data["PageData"] = ctx.PageData

View File

@@ -229,6 +229,7 @@ func Csrfer(opt CsrfOptions, ctx *Context) CSRF {
}
}
needsNew = needsNew || ctx.Req.Method == "GET" // If this request is a Get request, it will generate a new token, make sure the token is always up-to-date.
if needsNew {
// FIXME: actionId.
x.Token = GenerateToken(x.Secret, x.ID, "POST")

View File

@@ -70,12 +70,6 @@ func HandleOrgAssignment(ctx *Context, args ...bool) {
org := ctx.Org.Organization
ctx.Data["Org"] = org
teams, err := org.LoadTeams()
if err != nil {
ctx.ServerError("LoadTeams", err)
}
ctx.Data["OrgTeams"] = teams
// Admin has super access.
if ctx.IsSigned && ctx.User.IsAdmin {
ctx.Org.IsOwner = true

View File

@@ -38,6 +38,8 @@ func PrivateContexter() func(http.Handler) http.Handler {
Data: map[string]interface{}{},
},
}
defer ctx.Close()
ctx.Req = WithPrivateContext(req, ctx)
next.ServeHTTP(ctx.Resp, ctx.Req)
})

View File

@@ -410,6 +410,12 @@ func RepoIDAssignment() func(ctx *Context) {
// RepoAssignment returns a middleware to handle repository assignment
func RepoAssignment(ctx *Context) (cancel context.CancelFunc) {
if _, repoAssignmentOnce := ctx.Data["repoAssignmentExecuted"]; repoAssignmentOnce {
log.Trace("RepoAssignment was exec already, skipping second call ...")
return
}
ctx.Data["repoAssignmentExecuted"] = true
var (
owner *user_model.User
err error
@@ -440,6 +446,26 @@ func RepoAssignment(ctx *Context) (cancel context.CancelFunc) {
ctx.Repo.Owner = owner
ctx.Data["Username"] = ctx.Repo.Owner.Name
// redirect link to wiki
if strings.HasSuffix(repoName, ".wiki") {
// ctx.Req.URL.Path does not have the preceding appSubURL - any redirect must have this added
// Now we happen to know that all of our paths are: /:username/:reponame/whatever_else
originalRepoName := ctx.Params(":reponame")
redirectRepoName := strings.TrimSuffix(repoName, ".wiki")
redirectRepoName += originalRepoName[len(redirectRepoName)+5:]
redirectPath := strings.Replace(
ctx.Req.URL.EscapedPath(),
url.PathEscape(userName)+"/"+url.PathEscape(originalRepoName),
url.PathEscape(userName)+"/"+url.PathEscape(redirectRepoName)+"/wiki",
1,
)
if ctx.Req.URL.RawQuery != "" {
redirectPath += "?" + ctx.Req.URL.RawQuery
}
ctx.Redirect(path.Join(setting.AppSubURL, redirectPath))
return
}
// Get repository.
repo, err := repo_model.GetRepositoryByName(owner.ID, repoName)
if err != nil {
@@ -572,6 +598,9 @@ func RepoAssignment(ctx *Context) (cancel context.CancelFunc) {
ctx.ServerError("RepoAssignment Invalid repo "+repo_model.RepoPath(userName, repoName), err)
return
}
if ctx.Repo.GitRepo != nil {
ctx.Repo.GitRepo.Close()
}
ctx.Repo.GitRepo = gitRepo
// We opened it, we should close it

View File

@@ -67,6 +67,7 @@ func ToAPIPullRequest(pr *models.PullRequest, doer *user_model.User) *api.PullRe
PatchURL: pr.Issue.PatchURL(),
HasMerged: pr.HasMerged,
MergeBase: pr.MergeBase,
Mergeable: pr.Mergeable(),
Deadline: apiIssue.Deadline,
Created: pr.Issue.CreatedUnix.AsTimePtr(),
Updated: pr.Issue.UpdatedUnix.AsTimePtr(),
@@ -190,10 +191,6 @@ func ToAPIPullRequest(pr *models.PullRequest, doer *user_model.User) *api.PullRe
}
}
if pr.Status != models.PullRequestStatusChecking {
mergeable := !(pr.Status == models.PullRequestStatusConflict || pr.Status == models.PullRequestStatusError) && !pr.IsWorkInProgress()
apiPullRequest.Mergeable = mergeable
}
if pr.HasMerged {
apiPullRequest.Merged = pr.MergedUnix.AsTimePtr()
apiPullRequest.MergedCommitID = &pr.MergedCommitID

View File

@@ -71,8 +71,8 @@ func checkAuthorizedKeys(logger log.Logger, autofix bool) error {
"authorized_keys file %q is out of date.\nRegenerate it with:\n\t\"%s\"\nor\n\t\"%s\"",
fPath,
"gitea admin regenerate keys",
"gitea doctor --run authorized_keys --fix")
return fmt.Errorf(`authorized_keys is out of date and should be regenerated with "gitea admin regenerate keys" or "gitea doctor --run authorized_keys --fix"`)
"gitea doctor --run authorized-keys --fix")
return fmt.Errorf(`authorized_keys is out of date and should be regenerated with "gitea admin regenerate keys" or "gitea doctor --run authorized-keys --fix"`)
}
logger.Warn("authorized_keys is out of date. Attempting rewrite...")
err = asymkey_model.RewriteAllPublicKeys()

View File

@@ -142,6 +142,12 @@ func checkDBConsistency(logger log.Logger, autofix bool) error {
Fixer: models.FixIssueLabelWithOutsideLabels,
FixedMessage: "Removed",
},
{
Name: "Action with created_unix set as an empty string",
Counter: models.CountActionCreatedUnixString,
Fixer: models.FixActionCreatedUnixString,
FixedMessage: "Set to zero",
},
}
// TODO: function to recalc all counters
@@ -177,6 +183,18 @@ func checkDBConsistency(logger log.Logger, autofix bool) error {
// find access without repository
genericOrphanCheck("Access entries without existing repository",
"access", "repository", "access.repo_id=repository.id"),
// find action without repository
genericOrphanCheck("Action entries without existing repository",
"action", "repository", "action.repo_id=repository.id"),
// find OAuth2Grant without existing user
genericOrphanCheck("Orphaned OAuth2Grant without existing User",
"oauth2_grant", "user", "oauth2_grant.user_id=user.id"),
// find OAuth2Application without existing user
genericOrphanCheck("Orphaned OAuth2Application without existing User",
"oauth2_application", "user", "oauth2_application.uid=user.id"),
// find OAuth2AuthorizationCode without existing OAuth2Grant
genericOrphanCheck("Orphaned OAuth2AuthorizationCode without existing OAuth2Grant",
"oauth2_authorization_code", "oauth2_grant", "oauth2_authorization_code.grant_id=oauth2_grant.id"),
)
for _, c := range consistencyChecks {

View File

@@ -54,6 +54,12 @@ func CatFileBatchCheck(ctx context.Context, repoPath string) (WriteCloserError,
<-closed
}
// Ensure cancel is called as soon as the provided context is cancelled
go func() {
<-ctx.Done()
cancel()
}()
_, filename, line, _ := runtime.Caller(2)
filename = strings.TrimPrefix(filename, callerPrefix)
@@ -93,6 +99,12 @@ func CatFileBatch(ctx context.Context, repoPath string) (WriteCloserError, *bufi
<-closed
}
// Ensure cancel is called as soon as the provided context is cancelled
go func() {
<-ctx.Done()
cancel()
}()
_, filename, line, _ := runtime.Caller(2)
filename = strings.TrimPrefix(filename, callerPrefix)

View File

@@ -17,6 +17,7 @@ import (
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/process"
"code.gitea.io/gitea/modules/util"
)
var (
@@ -32,10 +33,11 @@ const DefaultLocale = "C"
// Command represents a command with its subcommands or arguments.
type Command struct {
name string
args []string
parentContext context.Context
desc string
name string
args []string
parentContext context.Context
desc string
globalArgsLength int
}
func (c *Command) String() string {
@@ -56,9 +58,10 @@ func NewCommandContext(ctx context.Context, args ...string) *Command {
cargs := make([]string, len(GlobalCommandArgs))
copy(cargs, GlobalCommandArgs)
return &Command{
name: GitExecutable,
args: append(cargs, args...),
parentContext: ctx,
name: GitExecutable,
args: append(cargs, args...),
parentContext: ctx,
globalArgsLength: len(GlobalCommandArgs),
}
}
@@ -145,7 +148,21 @@ func (c *Command) RunWithContext(rc *RunContext) error {
desc := c.desc
if desc == "" {
desc = fmt.Sprintf("%s %s [repo_path: %s]", c.name, strings.Join(c.args, " "), rc.Dir)
args := c.args[c.globalArgsLength:]
var argSensitiveURLIndexes []int
for i, arg := range c.args {
if strings.Contains(arg, "://") && strings.Contains(arg, "@") {
argSensitiveURLIndexes = append(argSensitiveURLIndexes, i)
}
}
if len(argSensitiveURLIndexes) > 0 {
args = make([]string, len(c.args))
copy(args, c.args)
for _, urlArgIndex := range argSensitiveURLIndexes {
args[urlArgIndex] = util.NewStringURLSanitizer(args[urlArgIndex], true).Replace(args[urlArgIndex])
}
}
desc = fmt.Sprintf("%s %s [repo_path: %s]", c.name, strings.Join(args, " "), rc.Dir)
}
ctx, cancel, finished := process.GetManager().AddContextTimeout(c.parentContext, rc.Timeout, desc)

View File

@@ -112,8 +112,8 @@ func SetExecutablePath(path string) error {
// VersionInfo returns git version information
func VersionInfo() string {
var format = "Git Version: %s"
var args = []interface{}{gitVersion.Original()}
format := "Git Version: %s"
args := []interface{}{gitVersion.Original()}
// Since git wire protocol has been released from git v2.18
if setting.Git.EnableAutoGitWireProtocol && CheckGitVersionAtLeast("2.18") == nil {
format += ", Wire Protocol %s Enabled"
@@ -148,7 +148,7 @@ func Init(ctx context.Context) error {
// By default partial clones are disabled, enable them from git v2.22
if !setting.Git.DisablePartialClone && CheckGitVersionAtLeast("2.22") == nil {
GlobalCommandArgs = append(GlobalCommandArgs, "-c", "uploadpack.allowfilter=true")
GlobalCommandArgs = append(GlobalCommandArgs, "-c", "uploadpack.allowfilter=true", "-c", "uploadpack.allowAnySHA1InWant=true")
}
// Save current git version on init to gitVersion otherwise it would require an RWMutex

View File

@@ -19,6 +19,7 @@ import (
"time"
"code.gitea.io/gitea/modules/proxy"
"code.gitea.io/gitea/modules/util"
)
// GPGSettings represents the default GPG settings for this repository
@@ -97,15 +98,16 @@ func (repo *Repository) IsEmpty() (bool, error) {
// CloneRepoOptions options when clone a repository
type CloneRepoOptions struct {
Timeout time.Duration
Mirror bool
Bare bool
Quiet bool
Branch string
Shared bool
NoCheckout bool
Depth int
Filter string
Timeout time.Duration
Mirror bool
Bare bool
Quiet bool
Branch string
Shared bool
NoCheckout bool
Depth int
Filter string
SkipTLSVerify bool
}
// Clone clones original repository to target path.
@@ -128,6 +130,9 @@ func CloneWithArgs(ctx context.Context, from, to string, args []string, opts Clo
}
cmd := NewCommandContextNoGlobals(ctx, args...).AddArguments("clone")
if opts.SkipTLSVerify {
cmd.AddArguments("-c", "http.sslVerify=false")
}
if opts.Mirror {
cmd.AddArguments("--mirror")
}
@@ -154,6 +159,12 @@ func CloneWithArgs(ctx context.Context, from, to string, args []string, opts Clo
}
cmd.AddArguments("--", from, to)
if strings.Contains(from, "://") && strings.Contains(from, "@") {
cmd.SetDescription(fmt.Sprintf("clone branch %s from %s to %s (shared: %t, mirror: %t, depth: %d)", opts.Branch, util.NewStringURLSanitizer(from, true).Replace(from), to, opts.Shared, opts.Mirror, opts.Depth))
} else {
cmd.SetDescription(fmt.Sprintf("clone branch %s from %s to %s (shared: %t, mirror: %t, depth: %d)", opts.Branch, from, to, opts.Shared, opts.Mirror, opts.Depth))
}
if opts.Timeout <= 0 {
opts.Timeout = -1
}
@@ -230,6 +241,11 @@ func Push(ctx context.Context, repoPath string, opts PushOptions) error {
if len(opts.Branch) > 0 {
cmd.AddArguments(opts.Branch)
}
if strings.Contains(opts.Remote, "://") && strings.Contains(opts.Remote, "@") {
cmd.SetDescription(fmt.Sprintf("push branch %s to %s (force: %t, mirror: %t)", opts.Branch, util.NewStringURLSanitizer(opts.Remote, true).Replace(opts.Remote), opts.Force, opts.Mirror))
} else {
cmd.SetDescription(fmt.Sprintf("push branch %s to %s (force: %t, mirror: %t)", opts.Branch, opts.Remote, opts.Force, opts.Mirror))
}
var outbuf, errbuf strings.Builder
if opts.Timeout == 0 {

View File

@@ -119,12 +119,10 @@ type CheckAttributeReader struct {
env []string
ctx context.Context
cancel context.CancelFunc
running chan struct{}
}
// Init initializes the cmd
func (c *CheckAttributeReader) Init(ctx context.Context) error {
c.running = make(chan struct{})
cmdArgs := []string{"check-attr", "--stdin", "-z"}
if len(c.IndexFile) > 0 && CheckGitVersionAtLeast("1.7.8") == nil {
@@ -183,14 +181,7 @@ func (c *CheckAttributeReader) Run() error {
_ = c.stdOut.Close()
}()
stdErr := new(bytes.Buffer)
err := c.cmd.RunInDirTimeoutEnvFullPipelineFunc(c.env, -1, c.Repo.Path, c.stdOut, stdErr, c.stdinReader, func(_ context.Context, _ context.CancelFunc) error {
select {
case <-c.running:
default:
close(c.running)
}
return nil
})
err := c.cmd.RunInDirTimeoutEnvFullPipeline(c.env, -1, c.Repo.Path, c.stdOut, stdErr, c.stdinReader)
if err != nil && // If there is an error we need to return but:
c.ctx.Err() != err && // 1. Ignore the context error if the context is cancelled or exceeds the deadline (RunWithContext could return c.ctx.Err() which is Canceled or DeadlineExceeded)
err.Error() != "signal: killed" { // 2. We should not pass up errors due to the program being killed
@@ -210,7 +201,7 @@ func (c *CheckAttributeReader) CheckPath(path string) (rs map[string]string, err
select {
case <-c.ctx.Done():
return nil, c.ctx.Err()
case <-c.running:
default:
}
if _, err = c.stdinWriter.Write([]byte(path + "\x00")); err != nil {
@@ -237,11 +228,6 @@ func (c *CheckAttributeReader) CheckPath(path string) (rs map[string]string, err
func (c *CheckAttributeReader) Close() error {
c.cancel()
err := c.stdinWriter.Close()
select {
case <-c.running:
default:
close(c.running)
}
return err
}

View File

@@ -13,6 +13,7 @@ import (
"strings"
"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/storer"
)
// IsObjectExist returns true if given reference exists in the repository.
@@ -82,7 +83,8 @@ func (repo *Repository) GetBranchNames(skip, limit int) ([]string, int, error) {
}
// WalkReferences walks all the references from the repository
func WalkReferences(ctx context.Context, repoPath string, walkfn func(string) error) (int, error) {
// refType should be empty, ObjectTag or ObjectBranch. All other values are equivalent to empty.
func WalkReferences(ctx context.Context, repoPath string, walkfn func(sha1, refname string) error) (int, error) {
repo, err := OpenRepositoryCtx(ctx, repoPath)
if err != nil {
return 0, err
@@ -97,9 +99,45 @@ func WalkReferences(ctx context.Context, repoPath string, walkfn func(string) er
defer iter.Close()
err = iter.ForEach(func(ref *plumbing.Reference) error {
err := walkfn(string(ref.Name()))
err := walkfn(ref.Hash().String(), string(ref.Name()))
i++
return err
})
return i, err
}
// WalkReferences walks all the references from the repository
func (repo *Repository) WalkReferences(arg ObjectType, skip, limit int, walkfn func(sha1, refname string) error) (int, error) {
i := 0
var iter storer.ReferenceIter
var err error
switch arg {
case ObjectTag:
iter, err = repo.gogitRepo.Tags()
case ObjectBranch:
iter, err = repo.gogitRepo.Branches()
default:
iter, err = repo.gogitRepo.References()
}
if err != nil {
return i, err
}
defer iter.Close()
err = iter.ForEach(func(ref *plumbing.Reference) error {
if i < skip {
i++
return nil
}
err := walkfn(ref.Hash().String(), string(ref.Name()))
i++
if err != nil {
return err
}
if limit != 0 && i >= skip+limit {
return storer.ErrStop
}
return nil
})
return i, err
}

View File

@@ -68,13 +68,29 @@ func (repo *Repository) GetBranchNames(skip, limit int) ([]string, int, error) {
}
// WalkReferences walks all the references from the repository
func WalkReferences(ctx context.Context, repoPath string, walkfn func(string) error) (int, error) {
func WalkReferences(ctx context.Context, repoPath string, walkfn func(sha1, refname string) error) (int, error) {
return walkShowRef(ctx, repoPath, "", 0, 0, walkfn)
}
// WalkReferences walks all the references from the repository
// refType should be empty, ObjectTag or ObjectBranch. All other values are equivalent to empty.
func (repo *Repository) WalkReferences(refType ObjectType, skip, limit int, walkfn func(sha1, refname string) error) (int, error) {
var arg string
switch refType {
case ObjectTag:
arg = "--tags"
case ObjectBranch:
arg = "--heads"
default:
arg = ""
}
return walkShowRef(repo.Ctx, repo.Path, arg, skip, limit, walkfn)
}
// callShowRef return refs, if limit = 0 it will not limit
func callShowRef(ctx context.Context, repoPath, prefix, arg string, skip, limit int) (branchNames []string, countAll int, err error) {
countAll, err = walkShowRef(ctx, repoPath, arg, skip, limit, func(branchName string) error {
countAll, err = walkShowRef(ctx, repoPath, arg, skip, limit, func(_, branchName string) error {
branchName = strings.TrimPrefix(branchName, prefix)
branchNames = append(branchNames, branchName)
@@ -83,7 +99,7 @@ func callShowRef(ctx context.Context, repoPath, prefix, arg string, skip, limit
return
}
func walkShowRef(ctx context.Context, repoPath, arg string, skip, limit int, walkfn func(string) error) (countAll int, err error) {
func walkShowRef(ctx context.Context, repoPath, arg string, skip, limit int, walkfn func(sha1, refname string) error) (countAll int, err error) {
stdoutReader, stdoutWriter := io.Pipe()
defer func() {
_ = stdoutReader.Close()
@@ -125,11 +141,7 @@ func walkShowRef(ctx context.Context, repoPath, arg string, skip, limit int, wal
for limit == 0 || i < skip+limit {
// The output of show-ref is simply a list:
// <sha> SP <ref> LF
_, err := bufReader.ReadSlice(' ')
for err == bufio.ErrBufferFull {
// This shouldn't happen but we'll tolerate it for the sake of peace
_, err = bufReader.ReadSlice(' ')
}
sha, err := bufReader.ReadString(' ')
if err == io.EOF {
return i, nil
}
@@ -149,7 +161,12 @@ func walkShowRef(ctx context.Context, repoPath, arg string, skip, limit int, wal
if len(branchName) > 0 {
branchName = branchName[:len(branchName)-1]
}
err = walkfn(branchName)
if len(sha) > 0 {
sha = sha[:len(sha)-1]
}
err = walkfn(sha, branchName)
if err != nil {
return i, err
}

View File

@@ -0,0 +1,21 @@
// Copyright 2022 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 git
import (
"context"
"fmt"
)
// WriteCommitGraph write commit graph to speed up repo access
// this requires git v2.18 to be installed
func WriteCommitGraph(ctx context.Context, repoPath string) error {
if CheckGitVersionAtLeast("2.18") == nil {
if _, err := NewCommandContext(ctx, "commit-graph", "write").RunInDir(repoPath); err != nil {
return fmt.Errorf("unable to write commit-graph for '%s' : %w", repoPath, err)
}
}
return nil
}

View File

@@ -10,7 +10,6 @@ import (
"fmt"
"strings"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/util"
)
@@ -34,69 +33,6 @@ func (repo *Repository) CreateAnnotatedTag(name, message, revision string) error
return err
}
func (repo *Repository) getTag(tagID SHA1, name string) (*Tag, error) {
t, ok := repo.tagCache.Get(tagID.String())
if ok {
log.Debug("Hit cache: %s", tagID)
tagClone := *t.(*Tag)
tagClone.Name = name // This is necessary because lightweight tags may have same id
return &tagClone, nil
}
tp, err := repo.GetTagType(tagID)
if err != nil {
return nil, err
}
// Get the commit ID and tag ID (may be different for annotated tag) for the returned tag object
commitIDStr, err := repo.GetTagCommitID(name)
if err != nil {
// every tag should have a commit ID so return all errors
return nil, err
}
commitID, err := NewIDFromString(commitIDStr)
if err != nil {
return nil, err
}
// If type is "commit, the tag is a lightweight tag
if ObjectType(tp) == ObjectCommit {
commit, err := repo.GetCommit(commitIDStr)
if err != nil {
return nil, err
}
tag := &Tag{
Name: name,
ID: tagID,
Object: commitID,
Type: tp,
Tagger: commit.Committer,
Message: commit.Message(),
}
repo.tagCache.Set(tagID.String(), tag)
return tag, nil
}
// The tag is an annotated tag with a message.
data, err := NewCommandContext(repo.Ctx, "cat-file", "-p", tagID.String()).RunInDirBytes(repo.Path)
if err != nil {
return nil, err
}
tag, err := parseTagData(data)
if err != nil {
return nil, err
}
tag.Name = name
tag.ID = tagID
tag.Type = tp
repo.tagCache.Set(tagID.String(), tag)
return tag, nil
}
// GetTagNameBySHA returns the name of a tag from its tag object SHA or commit SHA
func (repo *Repository) GetTagNameBySHA(sha string) (string, error) {
if len(sha) < 5 {
@@ -159,6 +95,20 @@ func (repo *Repository) GetTag(name string) (*Tag, error) {
return tag, nil
}
// GetTagWithID returns a Git tag by given name and ID
func (repo *Repository) GetTagWithID(idStr, name string) (*Tag, error) {
id, err := NewIDFromString(idStr)
if err != nil {
return nil, err
}
tag, err := repo.getTag(id, name)
if err != nil {
return nil, err
}
return tag, nil
}
// GetTagInfos returns all tag infos of the repository.
func (repo *Repository) GetTagInfos(page, pageSize int) ([]*Tag, int, error) {
// TODO this a slow implementation, makes one git command per tag
@@ -192,19 +142,6 @@ func (repo *Repository) GetTagInfos(page, pageSize int) ([]*Tag, int, error) {
return tags, tagsTotal, nil
}
// GetTagType gets the type of the tag, either commit (simple) or tag (annotated)
func (repo *Repository) GetTagType(id SHA1) (string, error) {
// Get tag type
stdout, err := NewCommandContext(repo.Ctx, "cat-file", "-t", id.String()).RunInDir(repo.Path)
if err != nil {
return "", err
}
if len(stdout) == 0 {
return "", ErrNotExist{ID: id.String()}
}
return strings.TrimSpace(stdout), nil
}
// GetAnnotatedTag returns a Git tag by its SHA, must be an annotated tag
func (repo *Repository) GetAnnotatedTag(sha string) (*Tag, error) {
id, err := NewIDFromString(sha)

View File

@@ -11,6 +11,8 @@ package git
import (
"strings"
"code.gitea.io/gitea/modules/log"
"github.com/go-git/go-git/v5/plumbing"
)
@@ -53,3 +55,83 @@ func (repo *Repository) GetTags(skip, limit int) ([]string, error) {
return tagNames, nil
}
// GetTagType gets the type of the tag, either commit (simple) or tag (annotated)
func (repo *Repository) GetTagType(id SHA1) (string, error) {
// Get tag type
obj, err := repo.gogitRepo.Object(plumbing.AnyObject, id)
if err != nil {
if err == plumbing.ErrReferenceNotFound {
return "", &ErrNotExist{ID: id.String()}
}
return "", err
}
return obj.Type().String(), nil
}
func (repo *Repository) getTag(tagID SHA1, name string) (*Tag, error) {
t, ok := repo.tagCache.Get(tagID.String())
if ok {
log.Debug("Hit cache: %s", tagID)
tagClone := *t.(*Tag)
tagClone.Name = name // This is necessary because lightweight tags may have same id
return &tagClone, nil
}
tp, err := repo.GetTagType(tagID)
if err != nil {
return nil, err
}
// Get the commit ID and tag ID (may be different for annotated tag) for the returned tag object
commitIDStr, err := repo.GetTagCommitID(name)
if err != nil {
// every tag should have a commit ID so return all errors
return nil, err
}
commitID, err := NewIDFromString(commitIDStr)
if err != nil {
return nil, err
}
// If type is "commit, the tag is a lightweight tag
if ObjectType(tp) == ObjectCommit {
commit, err := repo.GetCommit(commitIDStr)
if err != nil {
return nil, err
}
tag := &Tag{
Name: name,
ID: tagID,
Object: commitID,
Type: tp,
Tagger: commit.Committer,
Message: commit.Message(),
}
repo.tagCache.Set(tagID.String(), tag)
return tag, nil
}
gogitTag, err := repo.gogitRepo.TagObject(tagID)
if err != nil {
if err == plumbing.ErrReferenceNotFound {
return nil, &ErrNotExist{ID: tagID.String()}
}
return nil, err
}
tag := &Tag{
Name: name,
ID: tagID,
Object: gogitTag.Target,
Type: tp,
Tagger: &gogitTag.Tagger,
Message: gogitTag.Message,
}
repo.tagCache.Set(tagID.String(), tag)
return tag, nil
}

View File

@@ -8,6 +8,13 @@
package git
import (
"errors"
"io"
"code.gitea.io/gitea/modules/log"
)
// IsTagExist returns true if given tag exists in the repository.
func (repo *Repository) IsTagExist(name string) bool {
if name == "" {
@@ -23,3 +30,104 @@ func (repo *Repository) GetTags(skip, limit int) (tags []string, err error) {
tags, _, err = callShowRef(repo.Ctx, repo.Path, TagPrefix, "--tags", skip, limit)
return
}
// GetTagType gets the type of the tag, either commit (simple) or tag (annotated)
func (repo *Repository) GetTagType(id SHA1) (string, error) {
wr, rd, cancel := repo.CatFileBatchCheck(repo.Ctx)
defer cancel()
_, err := wr.Write([]byte(id.String() + "\n"))
if err != nil {
return "", err
}
_, typ, _, err := ReadBatchLine(rd)
if IsErrNotExist(err) {
return "", ErrNotExist{ID: id.String()}
}
return typ, nil
}
func (repo *Repository) getTag(tagID SHA1, name string) (*Tag, error) {
t, ok := repo.tagCache.Get(tagID.String())
if ok {
log.Debug("Hit cache: %s", tagID)
tagClone := *t.(*Tag)
tagClone.Name = name // This is necessary because lightweight tags may have same id
return &tagClone, nil
}
tp, err := repo.GetTagType(tagID)
if err != nil {
return nil, err
}
// Get the commit ID and tag ID (may be different for annotated tag) for the returned tag object
commitIDStr, err := repo.GetTagCommitID(name)
if err != nil {
// every tag should have a commit ID so return all errors
return nil, err
}
commitID, err := NewIDFromString(commitIDStr)
if err != nil {
return nil, err
}
// If type is "commit, the tag is a lightweight tag
if ObjectType(tp) == ObjectCommit {
commit, err := repo.GetCommit(commitIDStr)
if err != nil {
return nil, err
}
tag := &Tag{
Name: name,
ID: tagID,
Object: commitID,
Type: tp,
Tagger: commit.Committer,
Message: commit.Message(),
}
repo.tagCache.Set(tagID.String(), tag)
return tag, nil
}
// The tag is an annotated tag with a message.
wr, rd, cancel := repo.CatFileBatch(repo.Ctx)
defer cancel()
if _, err := wr.Write([]byte(tagID.String() + "\n")); err != nil {
return nil, err
}
_, typ, size, err := ReadBatchLine(rd)
if err != nil {
if errors.Is(err, io.EOF) || IsErrNotExist(err) {
return nil, ErrNotExist{ID: tagID.String()}
}
return nil, err
}
if typ != "tag" {
return nil, ErrNotExist{ID: tagID.String()}
}
// then we need to parse the tag
// and load the commit
data, err := io.ReadAll(io.LimitReader(rd, size))
if err != nil {
return nil, err
}
_, err = rd.Discard(1)
if err != nil {
return nil, err
}
tag, err := parseTagData(data)
if err != nil {
return nil, err
}
tag.Name = name
tag.ID = tagID
tag.Type = tp
repo.tagCache.Set(tagID.String(), tag)
return tag, nil
}

View File

@@ -40,20 +40,19 @@ steps:
- go test -v -race -coverprofile=coverage.txt -covermode=atomic
`,
want: []string{
`<span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l">pipeline</span>`,
`<span class="w"></span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">default</span>`,
`<span class="w">
</span>`,
`<span class="w"></span><span class="nt">steps</span><span class="p">:</span>`,
`<span class="w"></span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">test</span>`,
`<span class="w"> </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l">golang:1.13</span>`,
`<span class="w"> </span><span class="nt">environment</span><span class="p">:</span>`,
`<span class="w"></span><span class="w"> </span><span class="nt">GOPROXY</span><span class="p">:</span><span class="w"> </span><span class="l">https://goproxy.cn</span>`,
`<span class="w"> </span><span class="nt">commands</span><span class="p">:</span>`,
`<span class="w"></span><span class="w"> </span>- <span class="l">go get -u</span>`,
`<span class="w"> </span>- <span class="l">go build -v</span>`,
`<span class="w"> </span>- <span class="l">go test -v -race -coverprofile=coverage.txt -covermode=atomic</span><span class="w">
</span>`,
`<span class="line"><span class="cl"><span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l">pipeline</span>`,
`</span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">default</span>`,
`</span></span><span class="line"><span class="cl">`,
`</span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">steps</span><span class="p">:</span>`,
`</span></span><span class="line"><span class="cl"><span class="w"></span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">test</span>`,
`</span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l">golang:1.13</span>`,
`</span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">environment</span><span class="p">:</span>`,
`</span></span><span class="line"><span class="cl"><span class="w"></span><span class="w"> </span><span class="nt">GOPROXY</span><span class="p">:</span><span class="w"> </span><span class="l">https://goproxy.cn</span>`,
`</span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">commands</span><span class="p">:</span>`,
`</span></span><span class="line"><span class="cl"><span class="w"></span><span class="w"> </span>- <span class="l">go get -u</span>`,
`</span></span><span class="line"><span class="cl"><span class="w"> </span>- <span class="l">go build -v</span>`,
`</span></span><span class="line"><span class="cl"><span class="w"> </span>- <span class="l">go test -v -race -coverprofile=coverage.txt -covermode=atomic</span><span class="w">
</span></span></span>`,
`<span class="w">
</span>`,
},
@@ -76,20 +75,19 @@ steps:
- go test -v -race -coverprofile=coverage.txt -covermode=atomic
`,
want: []string{
`<span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l">pipeline</span>`,
`<span class="w"></span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">default </span>`,
`<span class="w">
</span>`,
`<span class="w"></span><span class="nt">steps</span><span class="p">:</span>`,
`<span class="w"></span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">test</span>`,
`<span class="w"> </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l">golang:1.13</span>`,
`<span class="w"> </span><span class="nt">environment</span><span class="p">:</span>`,
`<span class="w"></span><span class="w"> </span><span class="nt">GOPROXY</span><span class="p">:</span><span class="w"> </span><span class="l">https://goproxy.cn</span>`,
`<span class="w"> </span><span class="nt">commands</span><span class="p">:</span>`,
`<span class="w"></span><span class="w"> </span>- <span class="l">go get -u</span>`,
`<span class="w"> </span>- <span class="l">go build -v</span>`,
`<span class="w"> </span>- <span class="l">go test -v -race -coverprofile=coverage.txt -covermode=atomic</span>`,
`<span class="w"> </span>`,
`<span class="line"><span class="cl"><span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l">pipeline</span>`,
`</span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">default </span>`,
`</span></span><span class="line"><span class="cl">`,
`</span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">steps</span><span class="p">:</span>`,
`</span></span><span class="line"><span class="cl"><span class="w"></span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">test</span>`,
`</span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l">golang:1.13</span>`,
`</span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">environment</span><span class="p">:</span>`,
`</span></span><span class="line"><span class="cl"><span class="w"></span><span class="w"> </span><span class="nt">GOPROXY</span><span class="p">:</span><span class="w"> </span><span class="l">https://goproxy.cn</span>`,
`</span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">commands</span><span class="p">:</span>`,
`</span></span><span class="line"><span class="cl"><span class="w"></span><span class="w"> </span>- <span class="l">go get -u</span>`,
`</span></span><span class="line"><span class="cl"><span class="w"> </span>- <span class="l">go build -v</span>`,
`</span></span><span class="line"><span class="cl"><span class="w"> </span>- <span class="l">go test -v -race -coverprofile=coverage.txt -covermode=atomic</span>`,
`</span></span><span class="line"><span class="cl"><span class="w"> </span></span></span>`,
},
},
}

View File

@@ -127,13 +127,18 @@ func (hl *HostMatchList) checkIP(ip net.IP) bool {
// MatchHostName checks if the host matches an allow/deny(block) list
func (hl *HostMatchList) MatchHostName(host string) bool {
hostname, _, err := net.SplitHostPort(host)
if err != nil {
hostname = host
}
if hl == nil {
return false
}
if hl.checkPattern(host) {
if hl.checkPattern(hostname) {
return true
}
if ip := net.ParseIP(host); ip != nil {
if ip := net.ParseIP(hostname); ip != nil {
return hl.checkIP(ip)
}
return false

View File

@@ -38,6 +38,7 @@ func TestHostOrIPMatchesList(t *testing.T) {
{"", net.ParseIP("10.0.1.1"), true},
{"10.0.1.1", nil, true},
{"10.0.1.1:8080", nil, true},
{"", net.ParseIP("192.168.1.1"), true},
{"192.168.1.1", nil, true},
{"", net.ParseIP("fd00::1"), true},
@@ -48,6 +49,7 @@ func TestHostOrIPMatchesList(t *testing.T) {
{"mydomain.com", net.IPv4zero, false},
{"sub.mydomain.com", net.IPv4zero, true},
{"sub.mydomain.com:8080", net.IPv4zero, true},
{"", net.ParseIP("169.254.1.1"), true},
{"169.254.1.1", nil, true},

View File

@@ -130,7 +130,7 @@ func Init() {
log.Info("PID: %d Repository Indexer closed", os.Getpid())
})
waitChannel := make(chan time.Duration)
waitChannel := make(chan time.Duration, 1)
// Create the Queue
switch setting.Indexer.RepoType {

View File

@@ -98,7 +98,7 @@ var (
// InitIssueIndexer initialize issue indexer, syncReindex is true then reindex until
// all issue index done.
func InitIssueIndexer(syncReindex bool) {
waitChannel := make(chan time.Duration)
waitChannel := make(chan time.Duration, 1)
// Create the Queue
switch setting.Indexer.IssueType {
@@ -272,7 +272,7 @@ func populateIssueIndexer(ctx context.Context) {
// UpdateRepoIndexer add/update all issues of the repositories
func UpdateRepoIndexer(repo *repo_model.Repository) {
is, err := models.Issues(&models.IssuesOptions{
RepoIDs: []int64{repo.ID},
RepoID: repo.ID,
IsClosed: util.OptionalBoolNone,
IsPull: util.OptionalBoolNone,
})

View File

@@ -5,12 +5,15 @@
package stats
import (
"context"
"path/filepath"
"testing"
"time"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unittest"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/queue"
"code.gitea.io/gitea/modules/setting"
_ "code.gitea.io/gitea/models"
@@ -24,6 +27,10 @@ func TestMain(m *testing.M) {
}
func TestRepoStatsIndex(t *testing.T) {
if err := git.Init(context.Background()); !assert.NoError(t, err) {
return
}
assert.NoError(t, unittest.PrepareTestDatabase())
setting.Cfg = ini.Empty()
@@ -32,10 +39,14 @@ func TestRepoStatsIndex(t *testing.T) {
err := Init()
assert.NoError(t, err)
time.Sleep(5 * time.Second)
repo, err := repo_model.GetRepositoryByID(1)
assert.NoError(t, err)
err = UpdateRepoIndexer(repo)
assert.NoError(t, err)
queue.GetManager().FlushAll(context.Background(), 5*time.Second)
status, err := repo_model.GetIndexerStatus(repo, repo_model.RepoIndexerTypeStats)
assert.NoError(t, err)
assert.Equal(t, "65f1bf27bc3bf70f64657658635e66094edbcb4d", status.CommitSha)

View File

@@ -205,7 +205,7 @@ func (b *footnoteBlockParser) Open(parent ast.Node, reader text.Reader, pc parse
}
open := pos + 1
closes := 0
closure := util.FindClosure(line[pos+1:], '[', ']', false, false)
closure := util.FindClosure(line[pos+1:], '[', ']', false, false) //nolint
closes = pos + 1 + closure
next := closes + 1
if closure > -1 {
@@ -296,7 +296,7 @@ func (s *footnoteParser) Parse(parent ast.Node, block text.Reader, pc parser.Con
return nil
}
open := pos
closure := util.FindClosure(line[pos:], '[', ']', false, false)
closure := util.FindClosure(line[pos:], '[', ']', false, false) //nolint
if closure < 0 {
return nil
}

View File

@@ -197,6 +197,11 @@ func testAnswers(baseURLContent, baseURLImages string) []string {
</li>
</ol>
</div>
`, `<ul>
<li class="task-list-item"><input type="checkbox" disabled="" data-source-position="3"/> If you want to rebase/retry this PR, click this checkbox.</li>
</ul>
<hr/>
<p>This PR has been generated by <a href="https://github.com/renovatebot/renovate" rel="nofollow">Renovate Bot</a>.</p>
`,
}
}
@@ -269,6 +274,14 @@ Here is a simple footnote,[^1] and here is a longer one.[^bignote]
Add as many paragraphs as you like.
`,
`
- [ ] <!-- rebase-check --> If you want to rebase/retry this PR, click this checkbox.
---
This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
<!-- test-comment -->`,
}
func TestTotal_RenderWiki(t *testing.T) {

View File

@@ -77,9 +77,9 @@ func HelloWorld() {
}
#+end_src
`, `<div class="src src-go">
<pre><code class="chroma language-go"><span class="c1">// HelloWorld prints &#34;Hello World&#34;
</span><span class="c1"></span><span class="kd">func</span> <span class="nf">HelloWorld</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">&#34;Hello World&#34;</span><span class="p">)</span>
<span class="p">}</span></code></pre>
<pre><code class="chroma language-go"><span class="line"><span class="cl"><span class="c1">// HelloWorld prints &#34;Hello World&#34;
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">func</span> <span class="nf">HelloWorld</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">&#34;Hello World&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre>
</div>`)
}

View File

@@ -56,7 +56,7 @@ type HookOptions struct {
GitQuarantinePath string
GitPushOptions GitPushOptions
PullRequestID int64
IsDeployKey bool
DeployKeyID int64 // if the pusher is a DeployKey, then UserID is the repo's org user.
IsWiki bool
}

View File

@@ -46,9 +46,9 @@ func ServNoCommand(ctx context.Context, keyID int64) (*asymkey_model.PublicKey,
// ServCommandResults are the results of a call to the private route serv
type ServCommandResults struct {
IsWiki bool
IsDeployKey bool
KeyID int64
KeyName string
DeployKeyID int64
KeyID int64 // public key
KeyName string // this field is ambiguous, it can be the name of DeployKey, or the name of the PublicKey
UserName string
UserEmail string
UserID int64

View File

@@ -19,6 +19,10 @@ import (
// they use to detect if there is a block and will grow and shrink in
// response to demand as per configuration.
type WorkerPool struct {
// This field requires to be the first one in the struct.
// This is to allow 64 bit atomic operations on 32-bit machines.
// See: https://pkg.go.dev/sync/atomic#pkg-note-BUG & Gitea issue 19518
numInQueue int64
lock sync.Mutex
baseCtx context.Context
baseCtxCancel context.CancelFunc
@@ -32,7 +36,6 @@ type WorkerPool struct {
blockTimeout time.Duration
boostTimeout time.Duration
boostWorkers int
numInQueue int64
}
// WorkerPoolConfiguration is the basic configuration for a WorkerPool

View File

@@ -43,7 +43,7 @@ var defaultTransformers = []transformer{
{Name: "PASCAL", Transform: xstrings.ToCamelCase},
{Name: "LOWER", Transform: strings.ToLower},
{Name: "UPPER", Transform: strings.ToUpper},
{Name: "TITLE", Transform: strings.Title},
{Name: "TITLE", Transform: strings.Title}, // nolint
}
func generateExpansion(src string, templateRepo, generateRepo *repo_model.Repository) string {
@@ -62,7 +62,7 @@ func generateExpansion(src string, templateRepo, generateRepo *repo_model.Reposi
{Name: "TEMPLATE_SSH_URL", Value: templateRepo.CloneLink().SSH, Transformers: nil},
}
var expansionMap = make(map[string]string)
expansionMap := make(map[string]string)
for _, e := range expansions {
expansionMap[e.Name] = e.Value
for _, tr := range e.Transformers {
@@ -159,7 +159,7 @@ func generateRepoCommit(repo, templateRepo, generateRepo *repo_model.Repository,
if err := os.WriteFile(path,
[]byte(generateExpansion(string(content), templateRepo, generateRepo)),
0644); err != nil {
0o644); err != nil {
return err
}
break

View File

@@ -72,13 +72,18 @@ func MigrateRepositoryGitData(ctx context.Context, u *user_model.User,
}
if err = git.CloneWithContext(ctx, opts.CloneAddr, repoPath, git.CloneRepoOptions{
Mirror: true,
Quiet: true,
Timeout: migrateTimeout,
Mirror: true,
Quiet: true,
Timeout: migrateTimeout,
SkipTLSVerify: setting.Migrations.SkipTLSVerify,
}); err != nil {
return repo, fmt.Errorf("Clone: %v", err)
}
if err := git.WriteCommitGraph(ctx, repoPath); err != nil {
return repo, err
}
if opts.Wiki {
wikiPath := repo_model.WikiPath(u.Name, opts.RepoName)
wikiRemotePath := WikiRemoteURL(opts.CloneAddr)
@@ -87,16 +92,21 @@ func MigrateRepositoryGitData(ctx context.Context, u *user_model.User,
return repo, fmt.Errorf("Failed to remove %s: %v", wikiPath, err)
}
if err = git.CloneWithContext(ctx, wikiRemotePath, wikiPath, git.CloneRepoOptions{
Mirror: true,
Quiet: true,
Timeout: migrateTimeout,
Branch: "master",
if err := git.CloneWithContext(ctx, wikiRemotePath, wikiPath, git.CloneRepoOptions{
Mirror: true,
Quiet: true,
Timeout: migrateTimeout,
Branch: "master",
SkipTLSVerify: setting.Migrations.SkipTLSVerify,
}); err != nil {
log.Warn("Clone wiki: %v", err)
if err := util.RemoveAll(wikiPath); err != nil {
return repo, fmt.Errorf("Failed to remove %s: %v", wikiPath, err)
}
} else {
if err := git.WriteCommitGraph(ctx, wikiPath); err != nil {
return repo, err
}
}
}
}
@@ -276,23 +286,25 @@ func SyncReleasesWithTags(repo *repo_model.Repository, gitRepo *git.Repository)
}
}
}
tags, err := gitRepo.GetTags(0, 0)
if err != nil {
return fmt.Errorf("unable to GetTags in Repo[%d:%s/%s]: %w", repo.ID, repo.OwnerName, repo.Name, err)
}
for _, tagName := range tags {
if _, ok := existingRelTags[strings.ToLower(tagName)]; !ok {
if err := PushUpdateAddTag(repo, gitRepo, tagName); err != nil {
return fmt.Errorf("unable to PushUpdateAddTag: %q to Repo[%d:%s/%s]: %w", tagName, repo.ID, repo.OwnerName, repo.Name, err)
}
_, err := gitRepo.WalkReferences(git.ObjectTag, 0, 0, func(sha1, refname string) error {
tagName := strings.TrimPrefix(refname, git.TagPrefix)
if _, ok := existingRelTags[strings.ToLower(tagName)]; ok {
return nil
}
}
return nil
if err := PushUpdateAddTag(repo, gitRepo, tagName, sha1, refname); err != nil {
return fmt.Errorf("unable to PushUpdateAddTag: %q to Repo[%d:%s/%s]: %w", tagName, repo.ID, repo.OwnerName, repo.Name, err)
}
return nil
})
return err
}
// PushUpdateAddTag must be called for any push actions to add tag
func PushUpdateAddTag(repo *repo_model.Repository, gitRepo *git.Repository, tagName string) error {
tag, err := gitRepo.GetTag(tagName)
func PushUpdateAddTag(repo *repo_model.Repository, gitRepo *git.Repository, tagName, sha1, refname string) error {
tag, err := gitRepo.GetTagWithID(sha1, tagName)
if err != nil {
return fmt.Errorf("unable to GetTag: %w", err)
}
@@ -310,7 +322,7 @@ func PushUpdateAddTag(repo *repo_model.Repository, gitRepo *git.Repository, tagN
}
var author *user_model.User
var createdAt = time.Unix(1, 0)
createdAt := time.Unix(1, 0)
if sig != nil {
author, err = user_model.GetUserByEmail(sig.Email)
@@ -325,7 +337,7 @@ func PushUpdateAddTag(repo *repo_model.Repository, gitRepo *git.Repository, tagN
return fmt.Errorf("unable to get CommitsCount: %w", err)
}
var rel = models.Release{
rel := models.Release{
RepoID: repo.ID,
TagName: tagName,
LowerTagName: strings.ToLower(tagName),

View File

@@ -15,13 +15,17 @@ import (
"code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/log"
"golang.org/x/text/cases"
"golang.org/x/text/language"
ini "gopkg.in/ini.v1"
)
var filenameSuffix = ""
var descriptionLock = sync.RWMutex{}
var logDescriptions = make(map[string]*LogDescription)
var (
filenameSuffix = ""
descriptionLock = sync.RWMutex{}
logDescriptions = make(map[string]*LogDescription)
)
// GetLogDescriptions returns a race safe set of descriptions
func GetLogDescriptions() map[string]*LogDescription {
@@ -86,7 +90,7 @@ func RemoveSubLogDescription(key, name string) bool {
type defaultLogOptions struct {
levelName string // LogLevel
flags string
filename string //path.Join(LogRootPath, "gitea.log")
filename string // path.Join(LogRootPath, "gitea.log")
bufferLength int64
disableConsole bool
}
@@ -243,7 +247,7 @@ func generateNamedLogger(key string, options defaultLogOptions) *LogDescription
Provider: provider,
Config: config,
})
log.Info("%s Log: %s(%s:%s)", strings.Title(key), strings.Title(name), provider, levelName)
log.Info("%s Log: %s(%s:%s)", cases.Title(language.English).String(key), cases.Title(language.English).String(name), provider, levelName)
}
AddLogDescription(key, &description)
@@ -327,7 +331,7 @@ func newLogService() {
Provider: provider,
Config: config,
})
log.Info("Gitea Log Mode: %s(%s:%s)", strings.Title(name), strings.Title(provider), levelName)
log.Info("Gitea Log Mode: %s(%s:%s)", cases.Title(language.English).String(name), cases.Title(language.English).String(provider), levelName)
}
AddLogDescription(log.DEFAULT, &description)

View File

@@ -8,7 +8,6 @@ package setting
import (
"encoding/base64"
"fmt"
"io"
"math"
"net"
"net/url"
@@ -30,6 +29,8 @@ import (
"github.com/unknwon/com"
gossh "golang.org/x/crypto/ssh"
"golang.org/x/text/cases"
"golang.org/x/text/language"
ini "gopkg.in/ini.v1"
)
@@ -90,13 +91,15 @@ var (
// AppDataPath is the default path for storing data.
// It maps to ini:"APP_DATA_PATH" and defaults to AppWorkPath + "/data"
AppDataPath string
// LocalURL is the url for locally running applications to contact Gitea. It always has a '/' suffix
// It maps to ini:"LOCAL_ROOT_URL"
LocalURL string
// Server settings
Protocol Scheme
Domain string
HTTPAddr string
HTTPPort string
LocalURL string
RedirectOtherPort bool
PortToRedirect string
OfflineMode bool
@@ -637,7 +640,7 @@ func loadFromConf(allowEmpty bool, extraConfig string) {
}
UnixSocketPermissionRaw := sec.Key("UNIX_SOCKET_PERMISSION").MustString("666")
UnixSocketPermissionParsed, err := strconv.ParseUint(UnixSocketPermissionRaw, 8, 32)
if err != nil || UnixSocketPermissionParsed > 0777 {
if err != nil || UnixSocketPermissionParsed > 0o777 {
log.Fatal("Failed to parse unixSocketPermission: %s", UnixSocketPermissionRaw)
}
@@ -710,6 +713,7 @@ func loadFromConf(allowEmpty bool, extraConfig string) {
}
}
LocalURL = sec.Key("LOCAL_ROOT_URL").MustString(defaultLocalURL)
LocalURL = strings.TrimRight(LocalURL, "/") + "/"
RedirectOtherPort = sec.Key("REDIRECT_OTHER_PORT").MustBool(false)
PortToRedirect = sec.Key("PORT_TO_REDIRECT").MustString("80")
OfflineMode = sec.Key("OFFLINE_MODE").MustBool()
@@ -793,16 +797,16 @@ func loadFromConf(allowEmpty bool, extraConfig string) {
SSH.AuthorizedPrincipalsAllow, SSH.AuthorizedPrincipalsEnabled = parseAuthorizedPrincipalsAllow(sec.Key("SSH_AUTHORIZED_PRINCIPALS_ALLOW").Strings(","))
if !SSH.Disabled && !SSH.StartBuiltinServer {
if err := os.MkdirAll(SSH.RootPath, 0700); err != nil {
if err := os.MkdirAll(SSH.RootPath, 0o700); err != nil {
log.Fatal("Failed to create '%s': %v", SSH.RootPath, err)
} else if err = os.MkdirAll(SSH.KeyTestPath, 0644); err != nil {
} else if err = os.MkdirAll(SSH.KeyTestPath, 0o644); err != nil {
log.Fatal("Failed to create '%s': %v", SSH.KeyTestPath, err)
}
if len(trustedUserCaKeys) > 0 && SSH.AuthorizedPrincipalsEnabled {
fname := sec.Key("SSH_TRUSTED_USER_CA_KEYS_FILENAME").MustString(filepath.Join(SSH.RootPath, "gitea-trusted-user-ca-keys.pem"))
if err := os.WriteFile(fname,
[]byte(strings.Join(trustedUserCaKeys, "\n")), 0600); err != nil {
[]byte(strings.Join(trustedUserCaKeys, "\n")), 0o600); err != nil {
log.Fatal("Failed to create '%s': %v", fname, err)
}
}
@@ -943,8 +947,9 @@ func loadFromConf(allowEmpty bool, extraConfig string) {
// The following is a purposefully undocumented option. Please do not run Gitea as root. It will only cause future headaches.
// Please don't use root as a bandaid to "fix" something that is broken, instead the broken thing should instead be fixed properly.
unsafeAllowRunAsRoot := Cfg.Section("").Key("I_AM_BEING_UNSAFE_RUNNING_AS_ROOT").MustBool(false)
RunMode = Cfg.Section("").Key("RUN_MODE").MustString("prod")
IsProd = strings.EqualFold(RunMode, "prod")
RunMode = Cfg.Section("").Key("RUN_MODE").MustString("Prod")
RunMode = cases.Title(language.English).String(strings.ToLower(RunMode))
IsProd = RunMode == "Prod"
// Does not check run user when the install lock is off.
if InstallLock {
currentUser, match := IsRunUserMatchCurrentUser(RunUser)
@@ -1004,7 +1009,7 @@ func loadFromConf(allowEmpty bool, extraConfig string) {
UI.ShowUserEmail = Cfg.Section("ui").Key("SHOW_USER_EMAIL").MustBool(true)
UI.DefaultShowFullName = Cfg.Section("ui").Key("DEFAULT_SHOW_FULL_NAME").MustBool(false)
UI.SearchRepoDescription = Cfg.Section("ui").Key("SEARCH_REPO_DESCRIPTION").MustBool(true)
UI.UseServiceWorker = Cfg.Section("ui").Key("USE_SERVICE_WORKER").MustBool(true)
UI.UseServiceWorker = Cfg.Section("ui").Key("USE_SERVICE_WORKER").MustBool(false)
HasRobotsTxt, err = util.IsFile(path.Join(CustomPath, "robots.txt"))
if err != nil {
@@ -1074,28 +1079,22 @@ func loadInternalToken(sec *ini.Section) string {
}
switch tempURI.Scheme {
case "file":
fp, err := os.OpenFile(tempURI.RequestURI(), os.O_RDWR, 0600)
if err != nil {
buf, err := os.ReadFile(tempURI.RequestURI())
if err != nil && !os.IsNotExist(err) {
log.Fatal("Failed to open InternalTokenURI (%s): %v", uri, err)
}
defer fp.Close()
buf, err := io.ReadAll(fp)
if err != nil {
log.Fatal("Failed to read InternalTokenURI (%s): %v", uri, err)
}
// No token in the file, generate one and store it.
if len(buf) == 0 {
token, err := generate.NewInternalToken()
if err != nil {
log.Fatal("Error generate internal token: %v", err)
}
if _, err := io.WriteString(fp, token); err != nil {
err = os.WriteFile(tempURI.RequestURI(), []byte(token), 0o600)
if err != nil {
log.Fatal("Error writing to InternalTokenURI (%s): %v", uri, err)
}
return token
}
return strings.TrimSpace(string(buf))
default:
log.Fatal("Unsupported URI-Scheme %q (INTERNAL_TOKEN_URI = %q)", tempURI.Scheme, uri)

View File

@@ -317,64 +317,7 @@ func Listen(host string, port int, ciphers, keyExchanges, macs []string) {
}
}
// Workaround slightly broken behaviour in x/crypto/ssh/handshake.go:458-463
//
// Fundamentally the issue here is that HostKeyAlgos make the incorrect assumption
// that the PublicKey().Type() matches the signature algorithm.
//
// Therefore we need to add duplicates for the RSA with different signing algorithms.
signers := make([]ssh.Signer, 0, len(srv.HostSigners))
for _, signer := range srv.HostSigners {
if signer.PublicKey().Type() == "ssh-rsa" {
signers = append(signers,
&wrapSigner{
Signer: signer,
algorithm: gossh.SigAlgoRSASHA2512,
},
&wrapSigner{
Signer: signer,
algorithm: gossh.SigAlgoRSASHA2256,
},
)
}
signers = append(signers, signer)
}
srv.HostSigners = signers
go listen(&srv)
}
// wrapSigner wraps a signer and overrides its public key type with the provided algorithm
type wrapSigner struct {
ssh.Signer
algorithm string
}
// PublicKey returns an associated PublicKey instance.
func (s *wrapSigner) PublicKey() gossh.PublicKey {
return &wrapPublicKey{
PublicKey: s.Signer.PublicKey(),
algorithm: s.algorithm,
}
}
// Sign returns raw signature for the given data. This method
// will apply the hash specified for the keytype to the data using
// the algorithm assigned for this key
func (s *wrapSigner) Sign(rand io.Reader, data []byte) (*gossh.Signature, error) {
return s.Signer.(gossh.AlgorithmSigner).SignWithAlgorithm(rand, data, s.algorithm)
}
// wrapPublicKey wraps a PublicKey and overrides its type
type wrapPublicKey struct {
gossh.PublicKey
algorithm string
}
// Type returns the algorithm
func (k *wrapPublicKey) Type() string {
return k.algorithm
}
// GenKeyPair make a pair of public and private keys for SSH access.

View File

@@ -6,7 +6,6 @@ package storage
import (
"context"
"errors"
"io"
"net/url"
"os"
@@ -18,8 +17,6 @@ import (
"code.gitea.io/gitea/modules/util"
)
// ErrLocalPathNotSupported represents an error that path is not supported
var ErrLocalPathNotSupported = errors.New("local path is not supported")
var _ ObjectStorage = &LocalStorage{}
// LocalStorageType is the type descriptor for local storage
@@ -62,21 +59,18 @@ func NewLocalStorage(ctx context.Context, cfg interface{}) (ObjectStorage, error
}, nil
}
func (l *LocalStorage) buildLocalPath(p string) string {
return filepath.Join(l.dir, path.Clean("/" + strings.ReplaceAll(p, "\\", "/"))[1:])
}
// Open a file
func (l *LocalStorage) Open(path string) (Object, error) {
if !isLocalPathValid(path) {
return nil, ErrLocalPathNotSupported
}
return os.Open(filepath.Join(l.dir, path))
return os.Open(l.buildLocalPath(path))
}
// Save a file
func (l *LocalStorage) Save(path string, r io.Reader, size int64) (int64, error) {
if !isLocalPathValid(path) {
return 0, ErrLocalPathNotSupported
}
p := filepath.Join(l.dir, path)
p := l.buildLocalPath(path)
if err := os.MkdirAll(filepath.Dir(p), os.ModePerm); err != nil {
return 0, err
}
@@ -116,24 +110,12 @@ func (l *LocalStorage) Save(path string, r io.Reader, size int64) (int64, error)
// Stat returns the info of the file
func (l *LocalStorage) Stat(path string) (os.FileInfo, error) {
return os.Stat(filepath.Join(l.dir, path))
}
func isLocalPathValid(p string) bool {
a := path.Clean(p)
if strings.HasPrefix(a, "../") || strings.HasPrefix(a, "..\\") {
return false
}
return a == p
return os.Stat(l.buildLocalPath(path))
}
// Delete delete a file
func (l *LocalStorage) Delete(path string) error {
if !isLocalPathValid(path) {
return ErrLocalPathNotSupported
}
p := filepath.Join(l.dir, path)
return util.Remove(p)
return util.Remove(l.buildLocalPath(path))
}
// URL gets the redirect URL to a file

View File

@@ -10,36 +10,44 @@ import (
"github.com/stretchr/testify/assert"
)
func TestLocalPathIsValid(t *testing.T) {
func TestBuildLocalPath(t *testing.T) {
kases := []struct {
path string
valid bool
localDir string
path string
expected string
}{
{
"a",
"0/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14",
"a/0/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14",
true,
},
{
"../a/0/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14",
false,
"a",
"../0/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14",
"a/0/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14",
},
{
"a\\0\\a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14",
true,
"a",
"0\\a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14",
"a/0/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14",
},
{
"b/../a/0/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14",
false,
"b",
"a/../0/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14",
"b/0/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14",
},
{
"..\\a/0/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14",
false,
"b",
"a\\..\\0/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14",
"b/0/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14",
},
}
for _, k := range kases {
t.Run(k.path, func(t *testing.T) {
assert.EqualValues(t, k.valid, isLocalPathValid(k.path))
l := LocalStorage{dir: k.localDir}
assert.EqualValues(t, k.expected, l.buildLocalPath(k.path))
})
}
}

View File

@@ -117,7 +117,7 @@ func NewMinioStorage(ctx context.Context, cfg interface{}) (ObjectStorage, error
}
func (m *MinioStorage) buildMinioPath(p string) string {
return strings.TrimPrefix(path.Join(m.basePath, p), "/")
return strings.TrimPrefix(path.Join(m.basePath, path.Clean("/" + strings.ReplaceAll(p, "\\", "/"))[1:]), "/")
}
// Open open a file

View File

@@ -19,6 +19,7 @@ type CreateUserOption struct {
Password string `json:"password" binding:"Required;MaxSize(255)"`
MustChangePassword *bool `json:"must_change_password"`
SendNotify bool `json:"send_notify"`
Restricted *bool `json:"restricted"`
Visibility string `json:"visibility" binding:"In(,public,limited,private)"`
}

View File

@@ -183,6 +183,8 @@ type EditRepoOption struct {
Archived *bool `json:"archived,omitempty"`
// set to a string like `8h30m0s` to set the mirror interval time
MirrorInterval *string `json:"mirror_interval,omitempty"`
// enable prune - remove obsolete remote-tracking references
EnablePrune *bool `json:"enable_prune,omitempty"`
}
// GenerateRepoOption options when creating repository using a template

View File

@@ -38,6 +38,8 @@ import (
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/services/gitdiff"
"golang.org/x/text/cases"
"golang.org/x/text/language"
"github.com/editorconfig/editorconfig-core-go/v2"
)
@@ -49,7 +51,7 @@ var mailSubjectSplit = regexp.MustCompile(`(?m)^-{3,}[\s]*$`)
func NewFuncMap() []template.FuncMap {
return []template.FuncMap{map[string]interface{}{
"GoVer": func() string {
return strings.Title(runtime.Version())
return cases.Title(language.English).String(runtime.Version())
},
"UseHTTPS": func() bool {
return strings.HasPrefix(setting.AppURL, "https")
@@ -285,7 +287,7 @@ func NewFuncMap() []template.FuncMap {
return util.MergeInto(dict, values...)
},
"percentage": func(n int, values ...int) float32 {
var sum = 0
sum := 0
for i := 0; i < len(values); i++ {
sum += values[i]
}
@@ -378,6 +380,7 @@ func NewFuncMap() []template.FuncMap {
},
"Join": strings.Join,
"QueryEscape": url.QueryEscape,
"DotEscape": DotEscape,
}}
}
@@ -386,7 +389,7 @@ func NewFuncMap() []template.FuncMap {
func NewTextFuncMap() []texttmpl.FuncMap {
return []texttmpl.FuncMap{map[string]interface{}{
"GoVer": func() string {
return strings.Title(runtime.Version())
return cases.Title(language.English).String(runtime.Version())
},
"AppName": func() string {
return setting.AppName
@@ -477,7 +480,7 @@ func NewTextFuncMap() []texttmpl.FuncMap {
return dict, nil
},
"percentage": func(n int, values ...int) float32 {
var sum = 0
sum := 0
for i := 0; i < len(values); i++ {
sum += values[i]
}
@@ -501,8 +504,10 @@ func NewTextFuncMap() []texttmpl.FuncMap {
}}
}
var widthRe = regexp.MustCompile(`width="[0-9]+?"`)
var heightRe = regexp.MustCompile(`height="[0-9]+?"`)
var (
widthRe = regexp.MustCompile(`width="[0-9]+?"`)
heightRe = regexp.MustCompile(`height="[0-9]+?"`)
)
func parseOthers(defaultSize int, defaultClass string, others ...interface{}) (int, string) {
size := defaultSize
@@ -629,6 +634,11 @@ func JSEscape(raw string) string {
return template.JSEscapeString(raw)
}
// DotEscape wraps a dots in names with ZWJ [U+200D] in order to prevent autolinkers from detecting these as urls
func DotEscape(raw string) string {
return strings.ReplaceAll(raw, ".", "\u200d.\u200d")
}
// Sha1 returns sha1 sum of string
func Sha1(str string) string {
return base.EncodeSha1(str)
@@ -736,7 +746,7 @@ func RenderEmoji(text string) template.HTML {
return template.HTML(renderedText)
}
//ReactionToEmoji renders emoji for use in reactions
// ReactionToEmoji renders emoji for use in reactions
func ReactionToEmoji(reaction string) template.HTML {
val := emoji.FromCode(reaction)
if val != nil {

View File

@@ -39,6 +39,7 @@ func MockContext(t *testing.T, path string) *context.Context {
Resp: context.NewResponse(resp),
Locale: &mockLocale{},
}
defer ctx.Close()
requestURL, err := url.Parse(path)
assert.NoError(t, err)

View File

@@ -8,7 +8,7 @@ import (
"net"
)
// IsIPPrivate for net.IP.IsPrivate. TODO: replace with `ip.IsPrivate()` if min go version is bumped to 1.17
// IsIPPrivate for net.IP.IsPrivate.
func IsIPPrivate(ip net.IP) bool {
if ip4 := ip.To4(); ip4 != nil {
return ip4[0] == 10 ||

18
modules/util/slice.go Normal file
View File

@@ -0,0 +1,18 @@
// Copyright 2022 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package util
// RemoveIDFromList removes the given ID from the slice, if found.
// It does not preserve order, and assumes the ID is unique.
func RemoveIDFromList(list []int64, id int64) ([]int64, bool) {
n := len(list) - 1
for i, item := range list {
if item == id {
list[i] = list[n]
return list[:n], true
}
}
return list, false
}

View File

@@ -1435,7 +1435,7 @@ pulls.manually_merged=Слито вручную
pulls.manually_merged_as=Запрос на слияние был объединён вручную, как <a rel="nofollow" class="ui sha" href="%[1]s"><code>%[2]s</code></a>.
pulls.is_closed=Запрос на слияние был закрыт.
pulls.has_merged=Слияние этого запроса успешно завершено.
pulls.title_wip_desc=`<a href="#">Добавьте <strong>%s</strong> в начало заголовка</a> для защиты от случайного досрочного принятия запроса на слияние
pulls.title_wip_desc=`<a href="#">Добавьте <strong>%s</strong> в начало заголовка</a> для защиты от случайного досрочного принятия запроса на слияние`
pulls.cannot_merge_work_in_progress=Этот запрос на слияние помечен как в процессе работы.
pulls.still_in_progress=Всё ещё в процессе?
pulls.add_prefix=Добавить <strong>%s</strong> префикс

View File

@@ -22,6 +22,7 @@ import (
"code.gitea.io/gitea/modules/password"
"code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/routers/api/v1/user"
"code.gitea.io/gitea/routers/api/v1/utils"
@@ -81,7 +82,6 @@ func CreateUser(ctx *context.APIContext) {
Email: form.Email,
Passwd: form.Password,
MustChangePassword: true,
IsActive: true,
LoginType: auth.Plain,
}
if form.MustChangePassword != nil {
@@ -107,11 +107,17 @@ func CreateUser(ctx *context.APIContext) {
return
}
var overwriteDefault *user_model.CreateUserOverwriteOptions
overwriteDefault := &user_model.CreateUserOverwriteOptions{
IsActive: util.OptionalBoolTrue,
}
if form.Restricted != nil {
overwriteDefault.IsRestricted = util.OptionalBoolOf(*form.Restricted)
}
if form.Visibility != "" {
overwriteDefault = &user_model.CreateUserOverwriteOptions{
Visibility: api.VisibilityModes[form.Visibility],
}
visibility := api.VisibilityModes[form.Visibility]
overwriteDefault.Visibility = &visibility
}
if err := user_model.CreateUser(u, overwriteDefault); err != nil {

View File

@@ -35,6 +35,8 @@ func createContext(req *http.Request) (*context.Context, *httptest.ResponseRecor
Render: rnd,
Data: make(map[string]interface{}),
}
defer c.Close()
return c, resp
}

View File

@@ -214,7 +214,7 @@ func ReadRepoNotifications(ctx *context.APIContext) {
targetStatus = models.NotificationStatusRead
}
changed := make([]*structs.NotificationThread, len(nl))
changed := make([]*structs.NotificationThread, 0, len(nl))
for _, n := range nl {
notif, err := models.SetNotificationStatus(n.ID, ctx.User, targetStatus)

View File

@@ -177,23 +177,18 @@ func CreateBranch(ctx *context.APIContext) {
}
err := repo_service.CreateNewBranch(ctx.User, ctx.Repo.Repository, opt.OldBranchName, opt.BranchName)
if err != nil {
if models.IsErrBranchDoesNotExist(err) {
ctx.Error(http.StatusNotFound, "", "The old branch does not exist")
}
if models.IsErrTagAlreadyExists(err) {
ctx.Error(http.StatusConflict, "", "The branch with the same tag already exists.")
} else if models.IsErrBranchAlreadyExists(err) || git.IsErrPushOutOfDate(err) {
ctx.Error(http.StatusConflict, "", "The branch already exists.")
} else if models.IsErrBranchNameConflict(err) {
ctx.Error(http.StatusConflict, "", "The branch with the same name already exists.")
} else {
ctx.Error(http.StatusInternalServerError, "CreateRepoBranch", err)
}
return
}
@@ -263,10 +258,15 @@ func ListBranches(ctx *context.APIContext) {
return
}
apiBranches := make([]*api.Branch, len(branches))
apiBranches := make([]*api.Branch, 0, len(branches))
for i := range branches {
c, err := branches[i].GetCommit()
if err != nil {
// Skip if this branch doesn't exist anymore.
if git.IsErrNotExist(err) {
totalNumOfBranches--
continue
}
ctx.Error(http.StatusInternalServerError, "GetCommit", err)
return
}
@@ -275,11 +275,12 @@ func ListBranches(ctx *context.APIContext) {
ctx.Error(http.StatusInternalServerError, "GetBranchProtection", err)
return
}
apiBranches[i], err = convert.ToBranch(ctx.Repo.Repository, branches[i], c, branchProtection, ctx.User, ctx.Repo.IsAdmin())
apiBranch, err := convert.ToBranch(ctx.Repo.Repository, branches[i], c, branchProtection, ctx.User, ctx.Repo.IsAdmin())
if err != nil {
ctx.Error(http.StatusInternalServerError, "convert.ToBranch", err)
return
}
apiBranches = append(apiBranches, apiBranch)
}
ctx.SetLinkHeader(totalNumOfBranches, listOptions.PageSize)
@@ -532,7 +533,6 @@ func CreateBranchProtection(ctx *context.APIContext) {
}
ctx.JSON(http.StatusCreated, convert.ToBranchProtection(bp))
}
// EditBranchProtection edits a branch protection for a repo

View File

@@ -173,6 +173,7 @@ func SearchIssues(ctx *context.APIContext) {
opts.TeamID = team.ID
}
repoCond := models.SearchRepositoryCondition(opts)
repoIDs, _, err := models.SearchRepositoryIDs(opts)
if err != nil {
ctx.Error(http.StatusInternalServerError, "SearchRepositoryByName", err)
@@ -233,7 +234,7 @@ func SearchIssues(ctx *context.APIContext) {
Page: ctx.FormInt("page"),
PageSize: limit,
},
RepoIDs: repoIDs,
RepoCond: repoCond,
IsClosed: isClosed,
IssueIDs: issueIDs,
IncludedLabelNames: includedLabelNames,
@@ -245,18 +246,23 @@ func SearchIssues(ctx *context.APIContext) {
UpdatedAfterUnix: since,
}
ctxUserID := int64(0)
if ctx.IsSigned {
ctxUserID = ctx.User.ID
}
// Filter for: Created by User, Assigned to User, Mentioning User, Review of User Requested
if ctx.FormBool("created") {
issuesOpt.PosterID = ctx.User.ID
issuesOpt.PosterID = ctxUserID
}
if ctx.FormBool("assigned") {
issuesOpt.AssigneeID = ctx.User.ID
issuesOpt.AssigneeID = ctxUserID
}
if ctx.FormBool("mentioned") {
issuesOpt.MentionedID = ctx.User.ID
issuesOpt.MentionedID = ctxUserID
}
if ctx.FormBool("review_requested") {
issuesOpt.ReviewRequestedID = ctx.User.ID
issuesOpt.ReviewRequestedID = ctxUserID
}
if issues, err = models.Issues(issuesOpt); err != nil {
@@ -455,7 +461,7 @@ func ListIssues(ctx *context.APIContext) {
if len(keyword) == 0 || len(issueIDs) > 0 || len(labelIDs) > 0 {
issuesOpt := &models.IssuesOptions{
ListOptions: listOptions,
RepoIDs: []int64{ctx.Repo.Repository.ID},
RepoID: ctx.Repo.Repository.ID,
IsClosed: isClosed,
IssueIDs: issueIDs,
LabelIDs: labelIDs,
@@ -599,7 +605,7 @@ func CreateIssue(ctx *context.APIContext) {
DeadlineUnix: deadlineUnix,
}
var assigneeIDs = make([]int64, 0)
assigneeIDs := make([]int64, 0)
var err error
if ctx.Repo.CanWrite(unit.TypeIssues) {
issue.MilestoneID = form.Milestone

View File

@@ -144,7 +144,7 @@ func GetDeployKey(ctx *context.APIContext) {
// "200":
// "$ref": "#/responses/DeployKey"
key, err := asymkey_model.GetDeployKeyByID(db.DefaultContext, ctx.ParamsInt64(":id"))
key, err := asymkey_model.GetDeployKeyByID(ctx, ctx.ParamsInt64(":id"))
if err != nil {
if asymkey_model.IsErrDeployKeyNotExist(err) {
ctx.NotFound()

View File

@@ -95,7 +95,6 @@ func ListPullRequests(ctx *context.APIContext) {
Labels: ctx.FormStrings("labels"),
MilestoneID: ctx.FormInt64("milestone"),
})
if err != nil {
ctx.Error(http.StatusInternalServerError, "PullRequests", err)
return
@@ -724,13 +723,12 @@ func MergePullRequest(ctx *context.APIContext) {
return
}
if err = pr.LoadHeadRepo(); err != nil {
if err := pr.LoadHeadRepo(); err != nil {
ctx.Error(http.StatusInternalServerError, "LoadHeadRepo", err)
return
}
err = pr.LoadIssue()
if err != nil {
if err := pr.LoadIssue(); err != nil {
ctx.Error(http.StatusInternalServerError, "LoadIssue", err)
return
}
@@ -744,29 +742,33 @@ func MergePullRequest(ctx *context.APIContext) {
}
}
if pr.Issue.IsClosed {
ctx.NotFound()
return
}
manuallMerge := repo_model.MergeStyle(form.Do) == repo_model.MergeStyleManuallyMerged
force := form.ForceMerge != nil && *form.ForceMerge
allowedMerge, err := pull_service.IsUserAllowedToMerge(pr, ctx.Repo.Permission, ctx.User)
if err != nil {
ctx.Error(http.StatusInternalServerError, "IsUSerAllowedToMerge", err)
return
}
if !allowedMerge {
ctx.Error(http.StatusMethodNotAllowed, "Merge", "User not allowed to merge PR")
return
}
if pr.HasMerged {
ctx.Error(http.StatusMethodNotAllowed, "PR already merged", "")
if err := pull_service.CheckPullMergable(ctx, ctx.User, &ctx.Repo.Permission, pr, manuallMerge, force); err != nil {
if errors.Is(err, pull_service.ErrIsClosed) {
ctx.NotFound()
} else if errors.Is(err, pull_service.ErrUserNotAllowedToMerge) {
ctx.Error(http.StatusMethodNotAllowed, "Merge", "User not allowed to merge PR")
} else if errors.Is(err, pull_service.ErrHasMerged) {
ctx.Error(http.StatusMethodNotAllowed, "PR already merged", "")
} else if errors.Is(err, pull_service.ErrIsWorkInProgress) {
ctx.Error(http.StatusMethodNotAllowed, "PR is a work in progress", "Work in progress PRs cannot be merged")
} else if errors.Is(err, pull_service.ErrNotMergableState) {
ctx.Error(http.StatusMethodNotAllowed, "PR not in mergeable state", "Please try again later")
} else if models.IsErrNotAllowedToMerge(err) {
ctx.Error(http.StatusMethodNotAllowed, "PR is not ready to be merged", err)
} else if asymkey_service.IsErrWontSign(err) {
ctx.Error(http.StatusMethodNotAllowed, fmt.Sprintf("Protected branch %s requires signed commits but this merge would not be signed", pr.BaseBranch), err)
} else {
ctx.InternalServerError(err)
}
return
}
// handle manually-merged mark
if repo_model.MergeStyle(form.Do) == repo_model.MergeStyleManuallyMerged {
if err = pull_service.MergedManually(pr, ctx.User, ctx.Repo.GitRepo, form.MergeCommitID); err != nil {
if manuallMerge {
if err := pull_service.MergedManually(pr, ctx.User, ctx.Repo.GitRepo, form.MergeCommitID); err != nil {
if models.IsErrInvalidMergeStyle(err) {
ctx.Error(http.StatusMethodNotAllowed, "Invalid merge style", fmt.Errorf("%s is not allowed an allowed merge style for this repository", repo_model.MergeStyle(form.Do)))
return
@@ -782,63 +784,13 @@ func MergePullRequest(ctx *context.APIContext) {
return
}
if !pr.CanAutoMerge() {
ctx.Error(http.StatusMethodNotAllowed, "PR not in mergeable state", "Please try again later")
// set defaults to propagate needed fields
if err := form.SetDefaults(pr); err != nil {
ctx.ServerError("SetDefaults", fmt.Errorf("SetDefaults: %v", err))
return
}
if pr.IsWorkInProgress() {
ctx.Error(http.StatusMethodNotAllowed, "PR is a work in progress", "Work in progress PRs cannot be merged")
return
}
if err := pull_service.CheckPRReadyToMerge(pr, false); err != nil {
if !models.IsErrNotAllowedToMerge(err) {
ctx.Error(http.StatusInternalServerError, "CheckPRReadyToMerge", err)
return
}
if form.ForceMerge != nil && *form.ForceMerge {
if isRepoAdmin, err := models.IsUserRepoAdmin(pr.BaseRepo, ctx.User); err != nil {
ctx.Error(http.StatusInternalServerError, "IsUserRepoAdmin", err)
return
} else if !isRepoAdmin {
ctx.Error(http.StatusMethodNotAllowed, "Merge", "Only repository admin can merge if not all checks are ok (force merge)")
}
} else {
ctx.Error(http.StatusMethodNotAllowed, "PR is not ready to be merged", err)
return
}
}
if _, err := pull_service.IsSignedIfRequired(pr, ctx.User); err != nil {
if !asymkey_service.IsErrWontSign(err) {
ctx.Error(http.StatusInternalServerError, "IsSignedIfRequired", err)
return
}
ctx.Error(http.StatusMethodNotAllowed, fmt.Sprintf("Protected branch %s requires signed commits but this merge would not be signed", pr.BaseBranch), err)
return
}
if len(form.Do) == 0 {
form.Do = string(repo_model.MergeStyleMerge)
}
message := strings.TrimSpace(form.MergeTitleField)
if len(message) == 0 {
if repo_model.MergeStyle(form.Do) == repo_model.MergeStyleMerge {
message = pr.GetDefaultMergeMessage()
}
if repo_model.MergeStyle(form.Do) == repo_model.MergeStyleSquash {
message = pr.GetDefaultSquashMessage()
}
}
form.MergeMessageField = strings.TrimSpace(form.MergeMessageField)
if len(form.MergeMessageField) > 0 {
message += "\n\n" + form.MergeMessageField
}
if err := pull_service.Merge(pr, ctx.User, ctx.Repo.GitRepo, repo_model.MergeStyle(form.Do), form.HeadCommitID, message); err != nil {
if err := pull_service.Merge(pr, ctx.User, ctx.Repo.GitRepo, repo_model.MergeStyle(form.Do), form.HeadCommitID, form.MergeTitleField); err != nil {
if models.IsErrInvalidMergeStyle(err) {
ctx.Error(http.StatusMethodNotAllowed, "Invalid merge style", fmt.Errorf("%s is not allowed an allowed merge style for this repository", repo_model.MergeStyle(form.Do)))
return

View File

@@ -160,7 +160,7 @@ func Search(ctx *context.APIContext) {
opts.Collaborate = util.OptionalBoolFalse
}
var mode = ctx.FormString("mode")
mode := ctx.FormString("mode")
switch mode {
case "source":
opts.Fork = util.OptionalBoolFalse
@@ -186,9 +186,9 @@ func Search(ctx *context.APIContext) {
opts.IsPrivate = util.OptionalBoolOf(ctx.FormBool("is_private"))
}
var sortMode = ctx.FormString("sort")
sortMode := ctx.FormString("sort")
if len(sortMode) > 0 {
var sortOrder = ctx.FormString("order")
sortOrder := ctx.FormString("order")
if len(sortOrder) == 0 {
sortOrder = "asc"
}
@@ -264,7 +264,8 @@ func CreateUserRepo(ctx *context.APIContext, owner *user_model.User, opt api.Cre
if repo_model.IsErrRepoAlreadyExist(err) {
ctx.Error(http.StatusConflict, "", "The repository with the same name already exists.")
} else if db.IsErrNameReserved(err) ||
db.IsErrNamePatternNotAllowed(err) {
db.IsErrNamePatternNotAllowed(err) ||
models.IsErrIssueLabelTemplateLoad(err) {
ctx.Error(http.StatusUnprocessableEntity, "", err)
} else {
ctx.Error(http.StatusInternalServerError, "CreateRepository", err)
@@ -624,7 +625,7 @@ func Edit(ctx *context.APIContext) {
}
if opts.MirrorInterval != nil {
if err := updateMirrorInterval(ctx, opts); err != nil {
if err := updateMirror(ctx, opts); err != nil {
return
}
}
@@ -949,37 +950,67 @@ func updateRepoArchivedState(ctx *context.APIContext, opts api.EditRepoOption) e
return nil
}
// updateMirrorInterval updates the repo's mirror Interval
func updateMirrorInterval(ctx *context.APIContext, opts api.EditRepoOption) error {
// updateMirror updates a repo's mirror Interval and EnablePrune
func updateMirror(ctx *context.APIContext, opts api.EditRepoOption) error {
repo := ctx.Repo.Repository
// only update mirror if interval or enable prune are provided
if opts.MirrorInterval == nil && opts.EnablePrune == nil {
return nil
}
// these values only make sense if the repo is a mirror
if !repo.IsMirror {
err := fmt.Errorf("repo is not a mirror, can not change mirror interval")
ctx.Error(http.StatusUnprocessableEntity, err.Error(), err)
return err
}
// get the mirror from the repo
mirror, err := repo_model.GetMirrorByRepoID(repo.ID)
if err != nil {
log.Error("Failed to get mirror: %s", err)
ctx.Error(http.StatusInternalServerError, "MirrorInterval", err)
return err
}
// update MirrorInterval
if opts.MirrorInterval != nil {
if !repo.IsMirror {
err := fmt.Errorf("repo is not a mirror, can not change mirror interval")
ctx.Error(http.StatusUnprocessableEntity, err.Error(), err)
return err
}
mirror, err := repo_model.GetMirrorByRepoID(repo.ID)
// MirrorInterval should be a duration
interval, err := time.ParseDuration(*opts.MirrorInterval)
if err != nil {
log.Error("Failed to get mirror: %s", err)
ctx.Error(http.StatusInternalServerError, "MirrorInterval", err)
return err
}
if interval, err := time.ParseDuration(*opts.MirrorInterval); err == nil {
mirror.Interval = interval
mirror.Repo = repo
if err := repo_model.UpdateMirror(mirror); err != nil {
log.Error("Failed to Set Mirror Interval: %s", err)
ctx.Error(http.StatusUnprocessableEntity, "MirrorInterval", err)
return err
}
log.Trace("Repository %s/%s Mirror Interval was Updated to %s", ctx.Repo.Owner.Name, repo.Name, interval)
} else {
log.Error("Wrong format for MirrorInternal Sent: %s", err)
ctx.Error(http.StatusUnprocessableEntity, "MirrorInterval", err)
return err
}
// Ensure the provided duration is not too short
if interval != 0 && interval < setting.Mirror.MinInterval {
err := fmt.Errorf("invalid mirror interval: %s is below minimum interval: %s", interval, setting.Mirror.MinInterval)
ctx.Error(http.StatusUnprocessableEntity, "MirrorInterval", err)
return err
}
mirror.Interval = interval
mirror.Repo = repo
mirror.ScheduleNextUpdate()
log.Trace("Repository %s Mirror[%d] Set Interval: %s NextUpdateUnix: %s", repo.FullName(), mirror.ID, interval, mirror.NextUpdateUnix)
}
// update EnablePrune
if opts.EnablePrune != nil {
mirror.EnablePrune = *opts.EnablePrune
log.Trace("Repository %s Mirror[%d] Set EnablePrune: %t", repo.FullName(), mirror.ID, mirror.EnablePrune)
}
// finally update the mirror in the DB
if err := repo_model.UpdateMirror(mirror); err != nil {
log.Error("Failed to Set Mirror Interval: %s", err)
ctx.Error(http.StatusUnprocessableEntity, "MirrorInterval", err)
return err
}
return nil
}

Some files were not shown because too many files have changed in this diff Show More