Compare commits

...

111 Commits

Author SHA1 Message Date
6543 f48fda8eef Changelog v1.17.3 (#21456) 2022-10-15 15:08:17 +02:00
6543 cd48a007bb improve code quality (#21464) (#21463)
Backport #21464 and #21465

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2022-10-15 14:24:39 +02:00
zeripath 6afbef5a8b Do DB update after merge in hammer context (#21401) (#21416)
Backport #21401

When merge was changed to run in the background context, the db updates
were still running in request context. This means that the merge could
be successful but the db not be updated.

This PR changes both these to run in the hammer context, this is not
complete rollback protection but it's much better.

Fix #21332

Signed-off-by: Andrew Thornton <art27@cantab.net>
2022-10-12 15:52:21 +08:00
Gusted d745780014 Add Num{Issues,Pulls} stats checks (#21404) (#21414)
Backport #21404

Currently `repository.Num{Issues,Pulls}` weren't checked and could
become out-of-consistency. Adds these two checks to `CheckRepoStats`.

Fix incorrect SQL query for `repository.NumClosedPulls`, the check
should be for `repo_num_pulls`.

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2022-10-12 14:47:48 +08:00
Gusted 652abf0ae0 Bump golang.org/x/text (#21412) (#21413)
- Backport #21412
- Update the `golang.org/x/text` dependency, this fixes [a security
issue](https://groups.google.com/g/golang-announce/c/-hjNw559_tE/m/KlGTfid5CAAJ).
2022-10-11 20:00:55 +01:00
zeripath 1f804d35ca Stop logging CheckPath returns error: context canceled (#21064) (#21405)
Backport #21064

We should only log CheckPath errors if they are not simply due to
context cancellation - and we should add a little more context to the
error message.

Fix #20709

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

Signed-off-by: Andrew Thornton <art27@cantab.net>
2022-10-11 16:35:29 +08:00
KN4CK3R c83a05f114 Set SemverCompatible to false for Conan packages (#21275) (#21366)
Backport of #21275
2022-10-10 20:46:09 +08:00
KN4CK3R a3c75ac438 Make NuGet service index publicly accessible (#21242) (#21277)
Backport of #21242

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: 6543 <6543@obermui.de>
2022-10-08 16:23:41 +01:00
M Hickford 14bc4d79c1 Parse OAuth Authorization header when request omits client secret (#21351) (#21374)
Backport #21351

This fixes error "unauthorized_client: invalid client secret" when
client includes secret in Authorization header rather than request body.
OAuth spec permits both:
https://www.rfc-editor.org/rfc/rfc6749#section-2.3.1

Clients in possession of a client password MAY use the HTTP Basic
authentication scheme ... Alternatively, the authorization server MAY
support including the client credentials in the request-body

Sanity validation that client id and client secret in request are
consistent with Authorization header.

Improve error descriptions. Error codes remain the same.

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: zeripath <art27@cantab.net>
2022-10-08 16:53:17 +08:00
M Hickford 672d54fafa Ignore port for OAuth2 loopback redirect URIs (#21293) (#21373)
Backport #21293

Following https://datatracker.ietf.org/doc/html/rfc8252#section-7.3

Fixes #21285
2022-10-08 09:52:35 +08:00
Jason Song 0495544b8a Tag list should include draft releases with existing tags (#21263) (#21365)
Backport #21263.

Before, a tag for a draft release disappeared in the tag list, fix #21262.

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2022-10-07 18:59:42 +08:00
John Olheiser 1fbc56d732 Fix linked account translation (#21331) (#21334) 2022-10-05 10:25:34 -04:00
wxiaoguang 1a9ba1c65d Fix missing m.Run() in TestMain (#21341)
Backport #21340, add the missing m.Run()
2022-10-05 12:17:16 +08:00
techknowlogick cbebcc1c26 Foreign ID conflicts if ID is 0 for each item (#21271) (#21272)
The default is 0 if not defined, and that causes dupe index errors

Backport of #21271
2022-10-02 17:43:30 -04:00
6543 0e677d7b41 Update bluemonday (#21281) (#21287)
Backport #21281

https://github.com/microcosm-cc/bluemonday/releases/tag/v1.0.20

Co-authored-by: Lauris BH <lauris@nix.lv>
2022-09-28 16:15:22 +02:00
KN4CK3R 790770aef3 Fix empty container layer history and UI (#21251) (#21278)
Backport of #21251
2022-09-27 23:10:19 +08:00
KN4CK3R 43b4c38d4f Use absolute links in feeds (#21229) (#21265)
Backport of #21229

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: techknowlogick <techknowlogick@gitea.io>
2022-09-26 13:49:22 -04:00
wxiaoguang e79a10793f Use en-US as fallback when using other default language (#21200) (#21256)
Only en-US has complete translations. When use other language as
default, the en-US should still be used as fallback.

Backport #21200, Close #21199
2022-09-25 22:14:57 +08:00
wxiaoguang be5411d6b5 Make Clone in VSCode link get updated correctly (#21225) (#21226)
Backport #21225, fix for #21128 (also in 1.17.3), close #21224

The indent was incorrect before, so this PR did some formatting work. 

Bypass Golang's template bug for JS string interpolation. And since
there are JS lint rules for templates, so the string interpolation is
also a must.
2022-09-23 12:10:26 +08:00
KN4CK3R bdf3be53b0 Respect REQUIRE_SIGNIN_VIEW for packages (#20873) (#21232)
Backport of #20873

When REQUIRE_SIGNIN_VIEW = true, even with public repositories, you can only see them after you login. The packages should not be accessed without login.

Co-authored-by: Lauris BH <lauris@nix.lv>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: techknowlogick <techknowlogick@gitea.io>
2022-09-23 11:25:53 +08:00
delvh e50473e6bb Prevent invalid behavior for file reviewing when loading more files (#21230) (#21234)
Backport of #21230

The problem was that many PR review components loaded by `Show more`
received the same ID as previous batches, which confuses browsers (when
clicked). All such occurrences should now be fixed.

Additionally improved the background of the `viewed` checkbox.

Fixes #21228.
Fixes #20681.

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2022-09-22 20:45:51 -04:00
wxiaoguang 20c135cd46 Use Go 1.19 fmt for Gitea 1.17, sync emoji data (#21239)
The images used by Gitea's drone pipeline were upgraded to Go 1.19.x
It causes the lint fails because Go 1.19 uses new code format.

This PR partially backport #20758 (including the emoji-data sync),
partially fix the format manually.
2022-09-22 21:58:31 +08:00
wxiaoguang 937ef6fa90 Treat git object mode 40755 as directory (#21195) (#21218)
Backport #21195

Git uses 040000 for tree object, but some users may get 040755 for
unknown reasons, fix #21190

Co-authored-by: techknowlogick <techknowlogick@gitea.io>
2022-09-20 12:40:23 -04:00
Abdul Monim 54d4e664c2 Make the vscode clone link respect transport protocol (#20557) (#21128)
Backports #20557

Co-authored-by: Norwin <noerw@users.noreply.github.com>
Co-authored-by: Munim Munna <6266677+monim67@users.noreply.github.com>
2022-09-20 22:01:24 +08:00
KN4CK3R c571ac6fd3 Allow uppercase ASCII alphabet in PyPI package names (#21095) (#21217)
Backport of #21095

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2022-09-20 17:37:24 +08:00
Lunny Xiao f663773200 Fix limited user cannot view himself's profile (#21212)
backport #21210, fix #21206

If user and viewer are equal the method should return true.
Also the common organization check was wrong as count can never be less then 0.

Tests are on main branch.
2022-09-20 16:00:46 +08:00
Lunny Xiao a28677273b Fix template bug of admin monitor (#21209)
backport #21208
2022-09-20 08:15:08 +08:00
Jason Song c8d687997d Fix reaction of issues (#21185) (#21196)
Backport #21185.

Fix #20860.

`CommentID` in `FindReactionsOptions` should be -1 to search reactions
with zero comment id.



https://github.com/go-gitea/gitea/blob/8351172b6e5221290dc5b2c81e159e2eec0b43c8/models/issues/reaction.go#L108-L121

Co-authored-by: Lauris BH <lauris@nix.lv>
2022-09-18 12:04:09 +08:00
wxiaoguang 5cb1037cb7 Fix CSV diff for added/deleted files (#21189) (#21193)
Backport #21189
Fixes #21184
Regression of #19552

Instead of using `GetBlobByPath`, use the already existing instances.
2022-09-17 18:53:04 +08:00
Tyrone Yeh 2dcea782c5 Fix pagination limit parameter problem (#21111)
backport #21109

Co-authored-by: 6543 <6543@obermui.de>
2022-09-08 20:00:42 +08:00
wxiaoguang 31842f12a4 Add MD5 back to template helper functions to avoid breaking (#21102)
In #20932 the MD5 helper function was removed from template context,
it breaks user's customized templates.

This PR adds the MD5 helper function back.
2022-09-07 19:30:52 +08:00
Lunny Xiao 32eef4aa2e Add changelog for v1.17.2 (#21089)
Co-authored-by: John Olheiser <john+github@jolheiser.com>
Co-authored-by: 6543 <6543@obermui.de>
Co-authored-by: delvh <dev.lh@web.de>
Co-authored-by: techknowlogick <techknowlogick@gitea.io>
2022-09-06 17:32:20 -04:00
Tyrone Yeh 449b39ea0e Fix sub folder in repository missing add file dropdown (#21069) (#21083)
Backport #21069

In repository sub folder missing add file dropdown menu, Probably broken since #20602
2022-09-06 09:42:05 +01:00
zeripath 06f968d662 Fix hard-coded timeout and error panic in API archive download endpoint (#20925) (#21051)
Backport #20925

This commit updates the `GET /api/v1/repos/{owner}/{repo}/archive/{archive}`
endpoint which prior to this PR had a couple of issues.

1. The endpoint had a hard-coded 20s timeout for the archiver to complete after
   which a 500 (Internal Server Error) was returned to client. For a scripted
   API client there was no clear way of telling that the operation timed out and
   that it should retry.

2. Whenever the timeout _did occur_, the code used to panic. This was caused by
   the API endpoint "delegating" to the same call path as the web, which uses a
   slightly different way of reporting errors (HTML rather than JSON for
   example).

   More specifically, `api/v1/repo/file.go#GetArchive` just called through to
   `web/repo/repo.go#Download`, which expects the `Context` to have a `Render`
   field set, but which is `nil` for API calls. Hence, a `nil` pointer error.

The code addresses (1) by dropping the hard-coded timeout. Instead, any
timeout/cancelation on the incoming `Context` is used.

The code addresses (2) by updating the API endpoint to use a separate call path
for the API-triggered archive download. This avoids producing HTML-errors on
errors (it now produces JSON errors).

Signed-off-by: Peter Gardfjäll <peter.gardfjall.work@gmail.com>

Signed-off-by: Peter Gardfjäll <peter.gardfjall.work@gmail.com>
Signed-off-by: Andrew Thornton <art27@cantab.net>
Co-authored-by: Peter Gardfjäll <peter.gardfjall.work@gmail.com>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2022-09-06 07:54:47 +01:00
Lunny Xiao 084797b4dc Fix delete user missed some comments (#21067) (#21068) 2022-09-06 06:48:57 +08:00
zeripath 7888a55e8c Delete unreferenced packages when deleting a package version (#20977) (#21060)
Backport #20977

Delete a package if its last version got deleted. Otherwise removing the owner works only after the clean up job ran.

Fix #20969

Co-authored-by: KN4CK3R <admin@oldschoolhack.me>
2022-09-04 12:17:48 -04:00
zeripath ea416d7d0e Redirect if user does not exist on admin pages (#20981) (#21059)
Backport #20981

When on /admin/users/ endpoints if the user is no longer in the DB,
redirect instead of causing a http 500.

Co-authored-by: KN4CK3R <admin@oldschoolhack.me>
2022-09-04 12:17:35 -04:00
zeripath 0db6add5c0 Set uploadpack.allowFilter etc on gitea serv to enable partial clones with ssh (#20902) (#21058)
Backport #20902

When setting.Git.DisablePartialClone is set to false then the web server will add filter support to web http. It does this by using`-c` command arguments but this will not work on gitea serv as the upload-pack and receive-pack commands do not support this.

Instead we move these options into the .gitconfig instead.

Fix #20400

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

Signed-off-by: Andrew Thornton <art27@cantab.net>
2022-09-04 12:17:27 -04:00
qwerty287 0ecbb71bee Fix 500 on time in timeline API (#21052) (#21057)
Backport #21052

Before converting a TrackedTime for the API we need to load its attributes - otherwise we get an NPE.

Fix #21041
2022-09-04 16:12:37 +01:00
Jason Song ea38455e1f Fill the specified ref in webhook test payload (#20961) (#21055)
Backport #20961

The webhook payload should use the right ref when it‘s specified in the testing request.

The compare URL should not be empty, a URL like `compare/A...A` seems useless in most cases but is helpful when testing.
2022-09-04 16:12:01 +01:00
zeripath 8fc80b34a0 Add another index for Action table on postgres (#21033) (#21054)
Backport #21033

In #21031 we have discovered that on very big tables postgres will use a
search involving the sort term in preference to the restrictive index.

Therefore we add another index for postgres and update the original migration.

Fix #21031

Signed-off-by: Andrew Thornton <art27@cantab.net>
2022-09-04 16:11:02 +01:00
zeripath 71aa64ae25 fix broken insecureskipverify handling in rediss connection uris (#20967) (#21053)
Backport #20967

Currently, it's impossible to connect to self-signed TLS encrypted redis instances. The problem lies in inproper error handling, when building redis tls options - only invalid booleans are allowed to be used in `tlsConfig` builder. The problem is, when `strconv.ParseBool(...)` returns error, it always defaults to false - meaning it's impossible to set `tlsOptions.InsecureSkipVerify` to true.

Fixes #19213

Co-authored-by: Igor Rzegocki <ajgon@users.noreply.github.com>
2022-09-04 14:59:20 +01:00
zeripath 3aba72c613 Add more checks in migration code (#21011) (#21050)
Backport #21011

When migrating add several more important sanity checks:

* SHAs must be SHAs
* Refs must be valid Refs
* URLs must be reasonable

Signed-off-by: Andrew Thornton <art27@cantab.net>
2022-09-04 08:41:21 -05:00
José Carlos bd1412c3af Add Dev, Peer and Optional dependencies to npm PackageMetadataVersion (#21017) (#21044)
Backport #21017

Set DevDependencies, PeerDependencies & OptionalDependencies in npm package metadatas

Fix https://github.com/go-gitea/gitea/issues/21013
2022-09-03 21:11:03 +02:00
silverwind 3973ce36d9 Improve arc-green code theme (#21039) (#21042)
Backport #21039

- Increase contrasts overall
- Add various missing theme classes
- Ensure strings and constants are colored the same across languages
2022-09-03 19:51:09 +02:00
Tyrone Yeh fbde31fb1e Add down key check has tribute container (#21016) (#21038)
Backport #21016 

Fixes an issue where users would not be able to select by pressing the down arrow when using @TAG above a message

Bug videos:

https://user-images.githubusercontent.com/1255041/188095999-c4ccde18-e53b-4251-8a14-d90c4042d768.mp4
2022-09-03 14:36:27 +01:00
zeripath 2f0a1eb0d5 Do not add links to Posters or Assignees with ID < 0 (#20577) (#21037)
Backport #20577

There are several places in templates/repo/issue/view_content/comments.tmpl where links are made to Posters or Assignees who are Ghosts or have IDs <0.

Fix #20559

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

Signed-off-by: Andrew Thornton <art27@cantab.net>
2022-09-03 20:51:10 +08:00
Lucas Azevedo e3697efbb0 Fix modified due date message (#20388) (#21032)
Backport #20388
2022-09-02 15:18:34 -04:00
Lunny Xiao 989dd5502c Fix missed sort bug (#21006)
Co-authored-by: John Olheiser <john.olheiser@gmail.com>
2022-08-31 23:40:29 +08:00
John Olheiser 54c0fe62cc Fix input.value attr for RequiredClaimName/Value (#20946) (#21001)
Values set for RequiredClaimName and RequiredClaimValue do not show up on UI.
Fix typo `values` to `value`.

Co-authored-by: soumyadey <soumya.dey@gmail.com>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2022-08-31 09:57:03 -05:00
Jason Song 2e2133d33f fix: remove redundant if (#20997) 2022-08-30 16:16:33 -05:00
John Olheiser 0d869c574e Translations for repo buttons (#20834)
* Translations

Signed-off-by: jolheiser <john.olheiser@gmail.com>

* Update locale_de-DE.ini

* Update locales

Signed-off-by: jolheiser <john.olheiser@gmail.com>

Signed-off-by: jolheiser <john.olheiser@gmail.com>
Co-authored-by: Lauris BH <lauris@nix.lv>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: 6543 <6543@obermui.de>
2022-08-29 16:37:53 +02:00
Lunny Xiao 04105dbb7c Fix download archiver of a commit (#20962) (#20971) 2022-08-28 13:29:34 +02:00
silverwind 0a0cd75071 Change review buttons to icons to make space for text (#20934) (#20978)
The layout on the review code view was broken depending on length of the text. Change all three buttons to icons with tooltip to make more space for these long texts.

Fixes: #20922
2022-08-27 23:52:00 +03:00
silverwind 85f829fb3c Enable contenthash in filename for dynamic assets (#20813) (#20932)
This should solve the main problem of dynamic assets getting stale after
a version upgrade. Everything not affected will use query-string based
cache busting, which includes files loaded via HTML or worker scripts.
2022-08-25 07:16:20 +01:00
zeripath 5ebd26d306 Return 404 NotFound if requested attachment does not exist (#20886) (#20941)
Backport #20886

Add code to test if GetAttachmentByID returns an ErrAttachmentNotExist error
and return NotFound instead of InternalServerError

Fix #20884

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

Signed-off-by: Andrew Thornton <art27@cantab.net>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2022-08-25 11:30:41 +08:00
zeripath bc7a4375be Disable doctor logging on panic (#20847) (#20898)
Backport #20847

If permissions are incorrect for writing to the doctor log simply disable the log file
instead of panicing.

Related #20570

Signed-off-by: Andrew Thornton <art27@cantab.net>
Co-authored-by: delvh <dev.lh@web.de>
2022-08-24 15:04:41 +01:00
zeripath fbcb42488f Set no-tags in git fetch on compare (#20893) (#20936)
Backport #20893

In the compare endpoint the git fetch is restricted to a certain branch however,
this does not completely prevent tag acquisition/pollution as git fetch will collect
any tags on that branch.

This causes pollution of the tag namespace and could cause confusion by users.

This PR adds `--no-tags` to the `git fetch` call.

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

Signed-off-by: Andrew Thornton <art27@cantab.net>
2022-08-23 16:42:55 -04:00
zeripath 0230f1e1aa In PushMirrorsIterate and MirrorsIterate if limit is negative do not set it (#20837) (#20899)
Backport #20837

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: techknowlogick <techknowlogick@gitea.io>
2022-08-23 12:38:52 -04:00
zeripath 6779c351b1 Fix mirror address setting not working (#20850) (#20904)
Backport #20850

This patch fixes the issue that the mirror address field is ignored from the repo setting form.

Co-authored-by: Gary Wang <wzc782970009@gmail.com>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2022-08-23 10:14:02 -04:00
KN4CK3R c1889f5b01 Allow multiple metadata files for Maven packages (#20674) (#20916)
* Allow file overwrite for meta files.

* Added tests.

* lint

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

Co-authored-by: Lauris BH <lauris@nix.lv>
Co-authored-by: techknowlogick <techknowlogick@gitea.io>
2022-08-23 10:00:58 +08:00
Gusted c0754e9d19 Don't open new page for ext wiki on same repository (#20725) (#20910)
* Don't open new page for ext wiki on same repository (#20725)

- Backport of #20725
  - When the external wiki has been set to a file on the repository, don't open the page on a tab.
  - Resolves #20657

* Gofmt

* Fix line

Co-authored-by: zeripath <art27@cantab.net>
2022-08-22 19:58:11 -04:00
zeripath bf41958c16 Pad GPG Key ID with preceding zeroes (#20878) (#20885)
Backport #20878

The go crypto library does not pad keyIDs to 16 characters with preceding zeroes. This
is a somewhat confusing thing for most users who expect these to have preceding zeroes.

This PR prefixes any sub 16 length KeyID with preceding zeroes and removes preceding
zeroes from KeyIDs inputted on the API.

Fix #20876

Signed-off-by: Andrew Thornton <art27@cantab.net>
2022-08-22 19:35:18 +01:00
zeripath 033178f2fc Increase Content field size of gpg_key and public_key to MEDIUMTEXT (#20896) (#20911)
Backport #20896

Unfortunately some keys are too big to fix within the 65535 limit of TEXT on MySQL
this causes issues with these large keys.

Therefore increase these fields to MEDIUMTEXT.

Unfortunately the migration in #20896 cannot be backported to 1.17 so
affected users will have to use `gitea doctor recreate-table gpg_key public_key`

Fix #20894

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

Signed-off-by: Andrew Thornton <art27@cantab.net>
2022-08-22 15:17:21 +01:00
zeripath ebc8801fb2 Fix push mirror address backend get error Address cause setting page display error (#20593) (#20901) 2022-08-22 02:14:48 -04:00
zeripath 37458bffbf Fix panic when an invalid oauth2 name is passed (#20820) (#20900) 2022-08-21 23:23:48 -04:00
zeripath ec9b43ba16 Remove calls to load Mirrors in user.Dashboard (#20855) (#20897)
Backport #20855

Whilst looking at #20840 I noticed that the Mirrors data doesn't appear
to be being used therefore we can remove this and in fact none of the
related code is used elsewhere so it can also be removed.

Related #20840
Related #20804

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

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

Signed-off-by: Andrew Thornton <art27@cantab.net>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2022-08-22 09:46:56 +08:00
Gusted e6ec411491 Fix SQL Query for SearchTeam (#20844) (#20872)
Backport #20844

Currently the function takes in the UserID option, but isn't being used within the SQL query. This patch fixes that by checking that only teams are being returned that the user belongs to.
 
Fix  #20829
2022-08-21 19:31:51 +01:00
silverwind 17d3a474e0 Update codemirror to 5.65.8 (#20875)
Includes fix for https://github.com/codemirror/codemirror5/issues/6893.
2022-08-21 17:25:46 +01:00
zeripath 9e8b1c6630 Double check CloneURL is acceptable (#20869) (#20892)
Backport #20869

Some Migration Downloaders provide re-writing of CloneURLs that may point to
unallowed urls. Recheck after the CloneURL is rewritten.

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

Signed-off-by: Andrew Thornton <art27@cantab.net>
2022-08-21 09:42:48 -05:00
JonRB eee51d8366 Ensure that graceful start-up is informed of unused SSH listener (#20877)
The graceful manager waits for 4 listeners to be created or to be told that they are not needed. If it is not told about them it will indefinitely and timeout. 

This leads to SVC hosts not being told of being in the readyState but on Unix would lead to the termination of the process.

There was an unfortunate regression in #20299 which missed this subtly and in the case whereby SSH is disabled the `builtinUnused()` is not called.

This PR adds a call to `builtinUnused()` when not using the builtin ssh to allow `createServerWaitGroup.Done()` to be called. 

In addition it was noted that the if/else clauses for timeout informing of the SVC host were in the wrong order. These have been swapped.

Fix #20609
2022-08-21 20:18:22 +08:00
silverwind c61ed6fad4 Rework repo buttons (#20602, #20718) (#20719)
* Rework repo buttons (#20602)

* Rework repo buttons

- Replace "New PR" and "Go to File" button with Icon Button
- Move all "Add File" actions into a dropdown button
- Remove most custom styling of clone buttons
- Margin and wiki tweaks

Buttons are now all equal height, mobile layout wraps gracefully.

Fixes: https://github.com/go-gitea/gitea/issues/13671
Replaces: https://github.com/go-gitea/gitea/pull/20375

* Restore history button and hide add button when unable to add (#20718)

Fix two regressions from #20602:

- Restore the 'History' button that was previously unable to render
  because it's show condition was never hit
- Hide the 'Add File' button when there would be no items in the
  dropdown.

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2022-08-20 15:49:16 +01:00
wxiaoguang b88a4b4854 Fix the mode of custom dir to 0700 in docker-rootless (#20861) (#20867) 2022-08-19 23:54:12 -04:00
wxiaoguang 399917a2d4 Fix UI mis-align for PR commit history (#20845) (#20859) 2022-08-19 16:54:33 +08:00
techknowlogick 68cceb5321 update changelog 2022-08-18 15:34:24 -04:00
zeripath 15b61dac98 Prevent 500 is head repo does not have PullRequest unit in IsUserAllowedToUpdate (#20839) (#20848)
Backport #20621

Some repositories do not have the PullRequest unit present in their configuration
and unfortunately the way that IsUserAllowedToUpdate currently works assumes
that this is an error instead of just returning false.

This PR simply swallows this error allowing the function to return false.

Fix #20621

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

Signed-off-by: Andrew Thornton <art27@cantab.net>
2022-08-18 14:55:34 -04:00
zeripath 35ca651c80 Fix owners cannot create organization repos bug (#20841) (#20854)
Backport #20841

* Fix owners cannot create organization repos bug

* Fix api

* Update routers/api/v1/org/team.go

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

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Gusted <williamzijl7@hotmail.com>
Co-authored-by: John Olheiser <john.olheiser@gmail.com>
2022-08-18 14:54:48 -04:00
zeripath 737486152c Changelog 1.17.1 (#20833)
* Changelog 1.17.1

 ## [1.17.1](https://github.com/go-gitea/gitea/releases/tag/1.17.1) - 2022-08-17

* SECURITY
  * Correctly escape within tribute.js (#20831) (#20832)
* FEATURES
  * Add support for NuGet API keys (#20721) (#20734)
* ENHANCEMENTS
  * Display project in issue list (#20583)
  * Add disable download source configuration (#20548) (#20579)
* BUGFIXES
  * Use the total issue count for UI (#20785) (#20827)
  * Add proxy host into allow list (#20798) (#20819)
  * Add missing translation for queue flush workers (#20791) (#20792)
  * Improve comment header for mobile (#20781) (#20789)
  * Fix git.Init for doctor sub-command (#20782) (#20783)
  * Check webhooks slice length before calling xorm (#20642) (#20768)
  * Remove manual rollback for failed generated repositories (#20639) (#20762)
  * Use correct field name in npm template (#20675) (#20760)
  * Keep download count on Container tag overwrite (#20728) (#20735)
  * Fix v220 migration to be compatible for MSSQL 2008 r2 (#20702) (#20707)
  * Use request timeout for git service rpc (#20689) (#20693)
  * Send correct NuGet status codes (#20647) (#20677)
  * Use correct context to get package content (#20673) (#20676)
  * Fix the JS error "EventSource is not defined" caused by some non-standard browsers (#20584) (#20663)
  * Add default commit messages to PR for squash merge (#20618) (#20645)
  * Fix package upload for files >32mb (#20622) (#20635)
  * Fix the new-line copy-paste for rendered code (#20612)
  * Clean up and fix clone button script (#20415 & #20600) (#20599)
  *  Fix default merge style (#20564) (#20565)
  * Add repository condition for issue count (#20454) (#20496)
* MISC
  * Make branch icon stand out more (#20726) (#20774)
  * Fix loading button with invalid form (#20754) (#20759)
  * Add username check to doctor (#20140) (#20671)
  * Enable Wire 2 for Internal SSH Server (#20616) (#20617)
  *  Fix SecToTime edge-cases (#20610) (#20611)

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

* Apply suggestions from code review

Co-authored-by: John Olheiser <john+github@jolheiser.com>

* Update CHANGELOG.md

Co-authored-by: delvh <dev.lh@web.de>

* Update CHANGELOG.md

* Update CHANGELOG.md

* update changelog

* Update CHANGELOG.md

Co-authored-by: John Olheiser <john+github@jolheiser.com>

Signed-off-by: Andrew Thornton <art27@cantab.net>
Co-authored-by: techknowlogick <matti@mdranta.net>
Co-authored-by: John Olheiser <john+github@jolheiser.com>
Co-authored-by: delvh <dev.lh@web.de>
Co-authored-by: Lauris BH <lauris@nix.lv>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: techknowlogick <techknowlogick@gitea.io>
2022-08-18 14:52:04 -04:00
Lunny Xiao c40c753613 Check Mirror exists before linking its Repo (#20840) (#20842)
In MirrorRepositoryList.loadAttributes there is some code to load the Mirror entries
from the database. This assumes that every Repository which has IsMirror set has
a Mirror associated in the DB. This association is incorrect in the case of
Mirror repository under creation when there is no Mirror entry in the DB until
completion.

Unfortunately LoadAttributes makes this incorrect assumption and presumes that a
Mirror will always be loaded. This then causes a panic.

This PR simply double checks if there a Mirror before attempting to link back to
its Repo. Unfortunately it should be expected that there may be other cases where
this incorrect assumption causes further problems.

Fix #20804

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

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

Signed-off-by: Andrew Thornton <art27@cantab.net>
Co-authored-by: zeripath <art27@cantab.net>
2022-08-18 11:57:40 +03:00
Lunny Xiao 7a9b01a2dd Add migrate repo archiver and packages storage support on command line (#20757) (#20806)
* Add migrate repo archiver and packages storage support on command line (#20757)

* Add migrate repo archiver and packages storage support on command line

* Fix typo

* Use stdCtx

* Use packageblob and fix command description

* Add migrate packages unit tests

* Fix comment year

* Fix the migrate storage command line description

* Update cmd/migrate_storage.go

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

* Update cmd/migrate_storage.go

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

* Update cmd/migrate_storage.go

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

* Fix test

Co-authored-by: 6543 <6543@obermui.de>
Co-authored-by: zeripath <art27@cantab.net>

* bug fix

Co-authored-by: 6543 <6543@obermui.de>
Co-authored-by: zeripath <art27@cantab.net>
2022-08-18 09:27:56 +08:00
zeripath b43d7e1254 Check issue labels slice length before calling xorm Insert(#20655) (#20836)
Backport #20655

Fix #20654

Co-authored-by: Gabriel Vasile <gabriel.vasile@email.com>
Co-authored-by: 6543 <6543@obermui.de>
Co-authored-by: Lauris BH <lauris@nix.lv>
Co-authored-by: techknowlogick <techknowlogick@gitea.io>
2022-08-17 23:36:56 +01:00
zeripath 987798a3a9 Executable check always returns true for windows (#20637) (#20835)
Backport #20637

Windows doesn't have the concept of "executable" POSIX bits so for now always return true to minimise doctor and logging noise. Addresses #20636

Co-authored-by: silverwind <me@silverwind.io>

Co-authored-by: JonRB <4564448+eeyrjmr@users.noreply.github.com>
Co-authored-by: silverwind <me@silverwind.io>
2022-08-17 23:34:29 +01:00
zeripath 13b74accda Correctly escape within tribute.js (#20831) (#20832)
Backport #20831

When writing html in tribute.js ensure that strings are properly escaped.

Signed-off-by: Andrew Thornton <art27@cantab.net>
2022-08-17 21:09:28 +01:00
parnic 79fa1c15a4 Use the total issue count for UI (#20785) (#20827)
Backport #20785

This fixes a problem where the "All" line item on the Issues or Pull Requests page was only showing the count of the selected repos instead of the total of all issues/prs in all repos.

The "total number of shown issues" number is now stashed in a different context variable in case it wants to be used by the frontend later. It's currently not being used.

Fixes #20574
2022-08-17 13:25:07 -04:00
Lunny Xiao 78dabdd9ae fix merge (#20819) 2022-08-17 11:33:26 -04:00
Gusted e5d2031828 Improve comment header for mobile (#20781) (#20789)
- Backport #20781
  - Since b9e8fa5 the avatar will be inlined into the comment header, so there's more room for the actual comment container(thus more text per line in the comment body). However this didn't take into consideration that the flex didn't allow any wrapping and thus was shrinking the avatar. Well this isn't a perfect solution, as you ideally all want these elements to be individually wrapped(such that comment-header-right can be on the same line as comment-header-left, which now causes a new line in certain situations). It's a better solution than the current CSS and to not mess with the desktop CSS/HTML.

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2022-08-15 14:09:46 +03:00
Gusted c3b4f3f7e9 Add missing translation for queue flush workers (#20791) (#20792)
- Backport #20791
  - Add a missing translation key and value for the flush worker indication
  - Resolves #20770
2022-08-14 16:03:04 -04:00
wxiaoguang 9bccfe9856 Fix git.Init for doctor sub-command (#20782) (#20783) 2022-08-14 00:32:44 +08:00
Gusted 85034564c2 Make branch icon stand out more (#20726) (#20774)
- Backport #20726
  - Currently the branch icon is "squashed" between the two branch names and feels a bit "amateur-ish" to my feeling(relative to other UI elements).
  - This patch tries to improve that by making the icon bigger and by adding some margin to not have a "squashed" icon.
  - This patch also includes a "fix", for some reason this symbol is not centering correctly. So apply allign-items: center to the top div
2022-08-12 15:38:17 -04:00
Lunny Xiao eacab6b10d Add disable download source configuration (#20548) (#20579)
* Add disable download source configuration (#20548)

Add configuration to enable/disable download source from UI.

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

* Fix BaseVars not used in renderering

* Fix disabled open in vscode menu when disabling download source from UI

Co-authored-by: zeripath <art27@cantab.net>
Co-authored-by: Lauris BH <lauris@nix.lv>
2022-08-12 23:53:10 +08:00
Lunny Xiao ac9792c0c7 Check webhooks slice length before calling xorm (#20642) (#20768)
Fixes: #20641

Co-authored-by: Lauris BH <lauris@nix.lv>
Co-authored-by: John Olheiser <john.olheiser@gmail.com>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Gabriel Vasile <gabriel.vasile@email.com>
2022-08-12 11:36:45 +03:00
wxiaoguang f7c874cb1a Remove manual rollback for failed generated repositories (#20639) (#20762)
Generating repositories from a template is done inside a transaction.
Manual rollback on error is not needed and it always results in error
"repository does not exist".

Co-authored-by: Gabriel Vasile <gabriel.vasile@email.com>
2022-08-11 13:11:49 +03:00
silverwind d19c2c9fcb Fix loading button with invalid form (#20754) (#20759)
Previously, if a invalid form was submitted (for example issue with no
title), the form could not be re-submitted again because the button
would not stay stuck in loading state. Fix that by hooking the 'submit'
event instead which triggers only when the form is valid.
2022-08-11 16:26:09 +08:00
KN4CK3R 59228d8a71 Use correct field name. (#20675) (#20760)
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2022-08-11 10:43:18 +03:00
KN4CK3R 67701771af Add support for NuGet API keys (#20721) (#20734)
Co-authored-by: delvh <dev.lh@web.de>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Lauris BH <lauris@nix.lv>
2022-08-10 00:56:18 +03:00
KN4CK3R 113d13a026 Keep download count on Container tag overwrite (#20728) (#20735)
Co-authored-by: 6543 <6543@obermui.de>
2022-08-09 17:33:45 +02:00
Lunny Xiao 9ec1c8812e Fix v220 migration to be compatible for MSSQL 2008 r2 (#20702) (#20707) 2022-08-08 17:58:11 +02:00
Gusted e1e43333cf Fix SecToTime edge-cases (#20610) (#20611) 2022-08-08 13:09:12 +08:00
Maxim Slipenko cedf4fef0a Update issues.ref_closing_from in locale_ru-RU.ini (#20699) 2022-08-07 18:32:07 +08:00
parnic a04fc567b4 Use request timeout for git service rpc (#20689) (#20693)
This enables git.Command's Run to optionally use the given context directly so its deadline will be respected. Otherwise, it falls back to the previous behavior of using the supplied timeout or a default timeout value of 360 seconds.

repo's serviceRPC() calls now use the context's deadline (which is unset/unlimited) instead of the default 6-minute timeout. This means that large repo clones will no longer arbitrarily time out on the upload-pack step, and pushes can take longer than 6 minutes on the receive-pack step.

Fixes #20680
2022-08-07 10:37:48 +08:00
KN4CK3R 92d79b556b Use correct context to get package content (#20673) (#20676)
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2022-08-05 14:55:16 -04:00
KN4CK3R 65176fdaf3 Send correct NuGet status codes (#20647) (#20677)
* Fixed status codes.

* Fixed status codes.
2022-08-05 09:38:04 +08:00
John Olheiser aac905dcfb Add username check to doctor (#20140) (#20671)
* Add username check to doctor

- Add a new breaking change detector to Gitea's doctor, which checks if
all users still have a valid username according to Gitea. Given from
time-to-time we need to make changes, either due to new routes or due to
security, it's for a instance's admin to check if all users still have a
valid username.

* Fix extra argument

* Apply suggestions from code review

* Apply suggestions from code review
2022-08-04 11:07:07 -05:00
wxiaoguang 5ce8fdbc37 Fix the JS error "EventSource is not defined" caused by some non-standard browsers (#20584) (#20663) 2022-08-04 19:20:54 +08:00
wxiaoguang 76accb51ed Add default commit messages to PR for squash merge (#20618) (#20645)
Keep the same behavior as 1.16

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

Co-authored-by: Tyrone Yeh <tyrone_yeh@draytek.com>
Co-authored-by: John Olheiser <john.olheiser@gmail.com>
2022-08-04 11:11:59 +08:00
KN4CK3R bd2218e14c Fix package upload for files >32mb (#20622) (#20635)
* Rewind file before first read.
* Added tests.

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2022-08-03 01:45:38 +03:00
wxiaoguang 0747592865 Adjust line detection in highlight.go (#20612)
The code for detection of lines in highlight.go is somewhat too complex
and doesn't take account of how Chroma is actually splitting things into
lines for us.

Remove both the .line and .cl classes from Chroma's HTML which made
the old conditional work again. This fixed Copy of YAML files while also 
reducing the amount of rendered HTML nodes.

Co-authored-by: zeripath <art27@cantab.net>
Co-authored-by: Lauris BH <lauris@nix.lv>
2022-08-03 01:37:28 +08:00
aceArt-GmbH 07d140625e Display project in issue list (#20583)
Co-authored-by: lukas <lukas.walter@aceart.de>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2022-08-02 17:14:31 +03:00
Gusted a6c2a1a117 Enable Wire 2 for Internal SSH Server (#20616) (#20617)
- Backport of #20616
  - Git only decides to use the Wire 2 protocol when `git {receive,upload}-pack` receive the `GIT_PROTOCOL` environment with as value `version=2`. Currently the internal SSH Server wasn't passing this environment through. The `gitea serv` code already passed all received environments to the git command, so no code changes there.
  - This is mentioned in Git manual, https://git-scm.com/docs/git#Documentation/git.txt-codeGITPROTOCOLcode
2022-08-02 15:58:57 +08:00
silverwind 56b99551ae Clean up and fix clone button script (#20415 & #20600) (#20599)
* Clean up and fix clone button script (#20415)

The button 'primary' class needs to be set in a synchronous script to prevent flicker of the button which was regressed recently, fixed that.

Additionally, reduced the two script tags to just one, the previous scripts were actually initializing the buttons thrice on the empty repo page, now it only initializes once. Finally, removed duplicate code and re-used the inline function in the update code as well.

I had to split out the script into a separate template as on the empty repo page, the script needs access to the clone URL span in the example text, which is rendered below the clone buttons, so buttons and script could not be combined.

* Add default value for clone URLs

Default clone URLs to HTTP(S) in DOM rendering. JS will immediately
replace this if the user preference is SSH.

Fixes: https://github.com/go-gitea/gitea/issues/20558
2022-08-02 12:31:38 +08:00
wxiaoguang 51c8c0f3fe Fix default merge style for pull requests (#20564) (#20565) 2022-07-31 22:41:06 +08:00
251 changed files with 4700 additions and 5228 deletions
+119
View File
@@ -4,6 +4,125 @@ 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.17.3](https://github.com/go-gitea/gitea/releases/tag/v1.17.3) - 2022-10-15
* SECURITY
* Sanitize and Escape refs in git backend (#21464) (#21463)
* Bump `golang.org/x/text` (#21412) (#21413)
* Update bluemonday (#21281) (#21287)
* ENHANCEMENTS
* Fix empty container layer history and UI (#21251) (#21278)
* Use en-US as fallback when using other default language (#21200) (#21256)
* Make the vscode clone link respect transport protocol (#20557) (#21128)
* BUGFIXES
* Do DB update after merge in hammer context (#21401) (#21416)
* Add Num{Issues,Pulls} stats checks (#21404) (#21414)
* Stop logging CheckPath returns error: context canceled (#21064) (#21405)
* Parse OAuth Authorization header when request omits client secret (#21351) (#21374)
* Ignore port for loopback redirect URIs (#21293) (#21373)
* Set SemverCompatible to false for Conan packages (#21275) (#21366)
* Tag list should include draft releases with existing tags (#21263) (#21365)
* Fix linked account translation (#21331) (#21334)
* Make NuGet service index publicly accessible (#21242) (#21277)
* Foreign ID conflicts if ID is 0 for each item (#21271) (#21272)
* Use absolute links in feeds (#21229) (#21265)
* Prevent invalid behavior for file reviewing when loading more files (#21230) (#21234)
* Respect `REQUIRE_SIGNIN_VIEW` for packages (#20873) (#21232)
* Treat git object mode 40755 as directory (#21195) (#21218)
* Allow uppercase ASCII alphabet in PyPI package names (#21095) (#21217)
* Fix limited user cannot view himself's profile (#21212)
* Fix template bug of admin monitor (#21209)
* Fix reaction of issues (#21185) (#21196)
* Fix CSV diff for added/deleted files (#21189) (#21193)
* Fix pagination limit parameter problem (#21111)
* TESTING
* Fix missing m.Run() in TestMain (#21341)
* BUILD
* Use Go 1.19 fmt for Gitea 1.17, sync emoji data (#21239)
## [1.17.2](https://github.com/go-gitea/gitea/releases/tag/v1.17.2) - 2022-09-06
* SECURITY
* Double check CloneURL is acceptable (#20869) (#20892)
* Add more checks in migration code (#21011) (#21050)
* ENHANCEMENTS
* Fix hard-coded timeout and error panic in API archive download endpoint (#20925) (#21051)
* Improve arc-green code theme (#21039) (#21042)
* Enable contenthash in filename for dynamic assets (#20813) (#20932)
* Don't open new page for ext wiki on same repository (#20725) (#20910)
* Disable doctor logging on panic (#20847) (#20898)
* Remove calls to load Mirrors in user.Dashboard (#20855) (#20897)
* Update codemirror to 5.65.8 (#20875)
* Rework repo buttons (#20602, #20718) (#20719)
* BUGFIXES
* Ensure delete user deletes all comments (#21067) (#21068)
* Delete unreferenced packages when deleting a package version (#20977) (#21060)
* Redirect if user does not exist on admin pages (#20981) (#21059)
* Set uploadpack.allowFilter etc on gitea serv to enable partial clones with ssh (#20902) (#21058)
* Fix 500 on time in timeline API (#21052) (#21057)
* Fill the specified ref in webhook test payload (#20961) (#21055)
* Add another index for Action table on postgres (#21033) (#21054)
* Fix broken insecureskipverify handling in redis connection uris (#20967) (#21053)
* Add Dev, Peer and Optional dependencies to npm PackageMetadataVersion (#21017) (#21044)
* Do not add links to Posters or Assignees with ID < 0 (#20577) (#21037)
* Fix modified due date message (#20388) (#21032)
* Fix missed sort bug (#21006)
* Fix input.value attr for RequiredClaimName/Value (#20946) (#21001)
* Change review buttons to icons to make space for text (#20934) (#20978)
* Fix download archiver of a commit (#20962) (#20971)
* Return 404 NotFound if requested attachment does not exist (#20886) (#20941)
* Set no-tags in git fetch on compare (#20893) (#20936)
* Allow multiple metadata files for Maven packages (#20674) (#20916)
* Increase Content field size of gpg_key and public_key to MEDIUMTEXT (#20896) (#20911)
* Fix mirror address setting not working (#20850) (#20904)
* Fix push mirror address backend get error Address cause setting page display error (#20593) (#20901)
* Fix panic when an invalid oauth2 name is passed (#20820) (#20900)
* In PushMirrorsIterate and MirrorsIterate if limit is negative do not set it (#20837) (#20899)
* Ensure that graceful start-up is informed of unused SSH listener (#20877) (#20888)
* Pad GPG Key ID with preceding zeroes (#20878) (#20885)
* Fix SQL Query for `SearchTeam` (#20844) (#20872)
* Fix the mode of custom dir to 0700 in docker-rootless (#20861) (#20867)
* Fix UI mis-align for PR commit history (#20845) (#20859)
## [1.17.1](https://github.com/go-gitea/gitea/releases/tag/1.17.1) - 2022-08-17
* SECURITY
* Correctly escape within tribute.js (#20831) (#20832)
* ENHANCEMENTS
* Add support for NuGet API keys (#20721) (#20734)
* Display project in issue list (#20583)
* Add disable download source configuration (#20548) (#20579)
* Add username check to doctor (#20140) (#20671)
* Enable Wire 2 for Internal SSH Server (#20616) (#20617)
* BUGFIXES
* Use the total issue count for UI (#20785) (#20827)
* Add proxy host into allow list (#20798) (#20819)
* Add missing translation for queue flush workers (#20791) (#20792)
* Improve comment header for mobile (#20781) (#20789)
* Fix git.Init for doctor sub-command (#20782) (#20783)
* Check webhooks slice length before calling xorm (#20642) (#20768)
* Remove manual rollback for failed generated repositories (#20639) (#20762)
* Use correct field name in npm template (#20675) (#20760)
* Keep download count on Container tag overwrite (#20728) (#20735)
* Fix v220 migration to be compatible for MSSQL 2008 r2 (#20702) (#20707)
* Use request timeout for git service rpc (#20689) (#20693)
* Send correct NuGet status codes (#20647) (#20677)
* Use correct context to get package content (#20673) (#20676)
* Fix the JS error "EventSource is not defined" caused by some non-standard browsers (#20584) (#20663)
* Add default commit messages to PR for squash merge (#20618) (#20645)
* Fix package upload for files >32mb (#20622) (#20635)
* Fix the new-line copy-paste for rendered code (#20612)
* Clean up and fix clone button script (#20415 & #20600) (#20599)
* Fix default merge style (#20564) (#20565)
* Add repository condition for issue count (#20454) (#20496)
* Make branch icon stand out more (#20726) (#20774)
* Fix loading button with invalid form (#20754) (#20759)
* Fix SecToTime edge-cases (#20610) (#20611)
* Executable check always returns true for windows (#20637) (#20835)
* Check issue labels slice length before calling xorm Insert (#20655) (#20836)
* Fix owners cannot create organization repos bug (#20841) (#20854)
* Prevent 500 is head repo does not have PullRequest unit in IsUserAllowedToUpdate (#20839) (#20848)
## [1.17.0](https://github.com/go-gitea/gitea/releases/tag/v1.17.0) - 2022-07-30
* BREAKING
+1 -1
View File
@@ -33,7 +33,7 @@ GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.3.1
GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.46.0
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
SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@v0.30.0
XGO_PACKAGE ?= src.techknowlogick.com/xgo@latest
DOCKER_IMAGE ?= gitea/gitea
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -2
View File
@@ -214,8 +214,7 @@ const hdr = `
package emoji
// Code generated by gen.go. DO NOT EDIT.
// Code generated by build/generate-emoji.go. DO NOT EDIT.
// Sourced from %s
//
var GemojiData = %#v
`
+43 -12
View File
@@ -5,6 +5,7 @@
package cmd
import (
"errors"
"fmt"
golog "log"
"os"
@@ -123,6 +124,47 @@ func runRecreateTable(ctx *cli.Context) error {
})
}
func setDoctorLogger(ctx *cli.Context) {
logFile := ctx.String("log-file")
if !ctx.IsSet("log-file") {
logFile = "doctor.log"
}
colorize := log.CanColorStdout
if ctx.IsSet("color") {
colorize = ctx.Bool("color")
}
if len(logFile) == 0 {
log.NewLogger(1000, "doctor", "console", fmt.Sprintf(`{"level":"NONE","stacktracelevel":"NONE","colorize":%t}`, colorize))
return
}
defer func() {
recovered := recover()
if recovered == nil {
return
}
err, ok := recovered.(error)
if !ok {
panic(recovered)
}
if errors.Is(err, os.ErrPermission) {
fmt.Fprintf(os.Stderr, "ERROR: Unable to write logs to provided file due to permissions error: %s\n %v\n", logFile, err)
} else {
fmt.Fprintf(os.Stderr, "ERROR: Unable to write logs to provided file: %s\n %v\n", logFile, err)
}
fmt.Fprintf(os.Stderr, "WARN: Logging will be disabled\n Use `--log-file` to configure log file location\n")
log.NewLogger(1000, "doctor", "console", fmt.Sprintf(`{"level":"NONE","stacktracelevel":"NONE","colorize":%t}`, colorize))
}()
if logFile == "-" {
log.NewLogger(1000, "doctor", "console", fmt.Sprintf(`{"level":"trace","stacktracelevel":"NONE","colorize":%t}`, colorize))
} else {
log.NewLogger(1000, "doctor", "file", fmt.Sprintf(`{"filename":%q,"level":"trace","stacktracelevel":"NONE"}`, logFile))
}
}
func runDoctor(ctx *cli.Context) error {
// Silence the default loggers
log.DelNamedLogger("console")
@@ -132,24 +174,13 @@ func runDoctor(ctx *cli.Context) error {
defer cancel()
// Now setup our own
logFile := ctx.String("log-file")
if !ctx.IsSet("log-file") {
logFile = "doctor.log"
}
setDoctorLogger(ctx)
colorize := log.CanColorStdout
if ctx.IsSet("color") {
colorize = ctx.Bool("color")
}
if len(logFile) == 0 {
log.NewLogger(1000, "doctor", "console", fmt.Sprintf(`{"level":"NONE","stacktracelevel":"NONE","colorize":%t}`, colorize))
} else if logFile == "-" {
log.NewLogger(1000, "doctor", "console", fmt.Sprintf(`{"level":"trace","stacktracelevel":"NONE","colorize":%t}`, colorize))
} else {
log.NewLogger(1000, "doctor", "file", fmt.Sprintf(`{"filename":%q,"level":"trace","stacktracelevel":"NONE"}`, logFile))
}
// Finally redirect the default golog to here
golog.SetFlags(0)
golog.SetPrefix("")
+23
View File
@@ -0,0 +1,23 @@
// 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 cmd
import (
"testing"
"code.gitea.io/gitea/models/unittest"
"code.gitea.io/gitea/modules/setting"
)
func init() {
setting.SetCustomPathAndConf("", "", "")
setting.LoadForTest()
}
func TestMain(m *testing.M) {
unittest.MainTest(m, &unittest.TestOptions{
GiteaRootPath: "..",
})
}
+47 -37
View File
@@ -12,9 +12,11 @@ import (
"code.gitea.io/gitea/models/db"
git_model "code.gitea.io/gitea/models/git"
"code.gitea.io/gitea/models/migrations"
packages_model "code.gitea.io/gitea/models/packages"
repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/log"
packages_module "code.gitea.io/gitea/modules/packages"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/storage"
@@ -25,13 +27,13 @@ import (
var CmdMigrateStorage = cli.Command{
Name: "migrate-storage",
Usage: "Migrate the storage",
Description: "This is a command for migrating storage.",
Description: "Copies stored files from storage configured in app.ini to parameter-configured storage",
Action: runMigrateStorage,
Flags: []cli.Flag{
cli.StringFlag{
Name: "type, t",
Value: "",
Usage: "Kinds of files to migrate, currently only 'attachments' is supported",
Usage: "Type of stored files to copy. Allowed types: 'attachments', 'lfs', 'avatars', 'repo-avatars', 'repo-archivers', 'packages'",
},
cli.StringFlag{
Name: "storage, s",
@@ -80,34 +82,50 @@ var CmdMigrateStorage = cli.Command{
},
}
func migrateAttachments(dstStorage storage.ObjectStorage) error {
return repo_model.IterateAttachment(func(attach *repo_model.Attachment) error {
func migrateAttachments(ctx context.Context, dstStorage storage.ObjectStorage) error {
return db.IterateObjects(ctx, func(attach *repo_model.Attachment) error {
_, err := storage.Copy(dstStorage, attach.RelativePath(), storage.Attachments, attach.RelativePath())
return err
})
}
func migrateLFS(dstStorage storage.ObjectStorage) error {
return git_model.IterateLFS(func(mo *git_model.LFSMetaObject) error {
func migrateLFS(ctx context.Context, dstStorage storage.ObjectStorage) error {
return db.IterateObjects(ctx, func(mo *git_model.LFSMetaObject) error {
_, err := storage.Copy(dstStorage, mo.RelativePath(), storage.LFS, mo.RelativePath())
return err
})
}
func migrateAvatars(dstStorage storage.ObjectStorage) error {
return user_model.IterateUser(func(user *user_model.User) error {
func migrateAvatars(ctx context.Context, dstStorage storage.ObjectStorage) error {
return db.IterateObjects(ctx, func(user *user_model.User) error {
_, err := storage.Copy(dstStorage, user.CustomAvatarRelativePath(), storage.Avatars, user.CustomAvatarRelativePath())
return err
})
}
func migrateRepoAvatars(dstStorage storage.ObjectStorage) error {
return repo_model.IterateRepository(func(repo *repo_model.Repository) error {
func migrateRepoAvatars(ctx context.Context, dstStorage storage.ObjectStorage) error {
return db.IterateObjects(ctx, func(repo *repo_model.Repository) error {
_, err := storage.Copy(dstStorage, repo.CustomAvatarRelativePath(), storage.RepoAvatars, repo.CustomAvatarRelativePath())
return err
})
}
func migrateRepoArchivers(ctx context.Context, dstStorage storage.ObjectStorage) error {
return db.IterateObjects(ctx, func(archiver *repo_model.RepoArchiver) error {
p := archiver.RelativePath()
_, err := storage.Copy(dstStorage, p, storage.RepoArchives, p)
return err
})
}
func migratePackages(ctx context.Context, dstStorage storage.ObjectStorage) error {
return db.IterateObjects(ctx, func(pb *packages_model.PackageBlob) error {
p := packages_module.KeyToRelativePath(packages_module.BlobHash256Key(pb.HashSHA256))
_, err := storage.Copy(dstStorage, p, storage.Packages, p)
return err
})
}
func runMigrateStorage(ctx *cli.Context) error {
stdCtx, cancel := installSignals()
defer cancel()
@@ -127,8 +145,6 @@ func runMigrateStorage(ctx *cli.Context) error {
return err
}
goCtx := context.Background()
if err := storage.Init(); err != nil {
return err
}
@@ -145,13 +161,13 @@ func runMigrateStorage(ctx *cli.Context) error {
return nil
}
dstStorage, err = storage.NewLocalStorage(
goCtx,
stdCtx,
storage.LocalStorageConfig{
Path: p,
})
case string(storage.MinioStorageType):
dstStorage, err = storage.NewMinioStorage(
goCtx,
stdCtx,
storage.MinioStorageConfig{
Endpoint: ctx.String("minio-endpoint"),
AccessKeyID: ctx.String("minio-access-key-id"),
@@ -162,35 +178,29 @@ func runMigrateStorage(ctx *cli.Context) error {
UseSSL: ctx.Bool("minio-use-ssl"),
})
default:
return fmt.Errorf("Unsupported storage type: %s", ctx.String("storage"))
return fmt.Errorf("unsupported storage type: %s", ctx.String("storage"))
}
if err != nil {
return err
}
tp := strings.ToLower(ctx.String("type"))
switch tp {
case "attachments":
if err := migrateAttachments(dstStorage); err != nil {
return err
}
case "lfs":
if err := migrateLFS(dstStorage); err != nil {
return err
}
case "avatars":
if err := migrateAvatars(dstStorage); err != nil {
return err
}
case "repo-avatars":
if err := migrateRepoAvatars(dstStorage); err != nil {
return err
}
default:
return fmt.Errorf("Unsupported storage: %s", ctx.String("type"))
migratedMethods := map[string]func(context.Context, storage.ObjectStorage) error{
"attachments": migrateAttachments,
"lfs": migrateLFS,
"avatars": migrateAvatars,
"repo-avatars": migrateRepoAvatars,
"repo-archivers": migrateRepoArchivers,
"packages": migratePackages,
}
log.Warn("All files have been copied to the new placement but old files are still on the original placement.")
tp := strings.ToLower(ctx.String("type"))
if m, ok := migratedMethods[tp]; ok {
if err := m(stdCtx, dstStorage); err != nil {
return err
}
log.Info("%s files have successfully been copied to the new storage.", tp)
return nil
}
return nil
return fmt.Errorf("unsupported storage: %s", ctx.String("type"))
}
+74
View File
@@ -0,0 +1,74 @@
// 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 cmd
import (
"context"
"os"
"strings"
"testing"
"code.gitea.io/gitea/models/packages"
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
packages_module "code.gitea.io/gitea/modules/packages"
"code.gitea.io/gitea/modules/storage"
packages_service "code.gitea.io/gitea/services/packages"
"github.com/stretchr/testify/assert"
)
func TestMigratePackages(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
creator := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User)
content := "package main\n\nfunc main() {\nfmt.Println(\"hi\")\n}\n"
buf, err := packages_module.CreateHashedBufferFromReader(strings.NewReader(content), 1024)
assert.NoError(t, err)
defer buf.Close()
v, f, err := packages_service.CreatePackageAndAddFile(&packages_service.PackageCreationInfo{
PackageInfo: packages_service.PackageInfo{
Owner: creator,
PackageType: packages.TypeGeneric,
Name: "test",
Version: "1.0.0",
},
Creator: creator,
SemverCompatible: true,
VersionProperties: map[string]string{},
}, &packages_service.PackageFileCreationInfo{
PackageFileInfo: packages_service.PackageFileInfo{
Filename: "a.go",
},
Data: buf,
IsLead: true,
})
assert.NoError(t, err)
assert.NotNil(t, v)
assert.NotNil(t, f)
ctx := context.Background()
p, err := os.MkdirTemp(os.TempDir(), "migrated_packages")
assert.NoError(t, err)
dstStorage, err := storage.NewLocalStorage(
ctx,
storage.LocalStorageConfig{
Path: p,
})
assert.NoError(t, err)
err = migratePackages(ctx, dstStorage)
assert.NoError(t, err)
entries, err := os.ReadDir(p)
assert.NoError(t, err)
assert.EqualValues(t, 2, len(entries))
assert.EqualValues(t, "01", entries[0].Name())
assert.EqualValues(t, "tmp", entries[1].Name())
}
+3
View File
@@ -892,6 +892,9 @@ ROUTER = console
;; Allow deletion of unadopted repositories
;ALLOW_DELETION_OF_UNADOPTED_REPOSITORIES = false
;; Don't allow download source archive files from UI
;DISABLE_DOWNLOAD_SOURCE_ARCHIVES = false
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;[repository.editor]
@@ -5,7 +5,7 @@ mkdir -p ${HOME} && chmod 0700 ${HOME}
if [ ! -w ${HOME} ]; then echo "${HOME} is not writable"; exit 1; fi
# Prepare custom folder
mkdir -p ${GITEA_CUSTOM} && chmod 0500 ${GITEA_CUSTOM}
mkdir -p ${GITEA_CUSTOM} && chmod 0700 ${GITEA_CUSTOM}
# Prepare temp folder
mkdir -p ${GITEA_TEMP} && chmod 0700 ${GITEA_TEMP}
@@ -78,6 +78,7 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`.
- `DEFAULT_BRANCH`: **main**: Default branch name of all repositories.
- `ALLOW_ADOPTION_OF_UNADOPTED_REPOSITORIES`: **false**: Allow non-admin users to adopt unadopted repositories
- `ALLOW_DELETION_OF_UNADOPTED_REPOSITORIES`: **false**: Allow non-admin users to delete unadopted repositories
- `DISABLE_DOWNLOAD_SOURCE_ARCHIVES`: **false**: Don't allow download source archive files from UI
### Repository - Editor (`repository.editor`)
+2
View File
@@ -47,6 +47,8 @@ For example:
dotnet nuget add source --name gitea --username testuser --password password123 https://gitea.example.com/api/packages/testuser/nuget/index.json
```
You can add the source without credentials and use the [`--api-key`](https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-nuget-push) parameter when publishing packages. In this case you need to provide a [personal access token]({{< relref "doc/developers/api-usage.en-us.md#authentication" >}}).
## Publish a package
Publish a package by running the following command:
+6 -7
View File
@@ -64,7 +64,7 @@ require (
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.19
github.com/microcosm-cc/bluemonday v1.0.20
github.com/minio/minio-go/v7 v7.0.26
github.com/msteinert/pam v1.0.0
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
@@ -91,11 +91,11 @@ require (
go.jolheiser.com/hcaptcha v0.0.4
go.jolheiser.com/pwn v0.0.3
golang.org/x/crypto v0.0.0-20220507011949-2cf3adece122
golang.org/x/net v0.0.0-20220630215102-69896b714898
golang.org/x/net v0.0.0-20220927171203-f486391704dc
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a
golang.org/x/text v0.3.7
golang.org/x/tools v0.1.10
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10
golang.org/x/text v0.3.8
golang.org/x/tools v0.1.12
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
gopkg.in/ini.v1 v1.66.4
gopkg.in/yaml.v2 v2.4.0
@@ -271,9 +271,8 @@ require (
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.8.0 // indirect
go.uber.org/zap v1.21.0 // indirect
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
golang.org/x/time v0.0.0-20220411224347-583f2d630306 // indirect
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa // indirect
google.golang.org/grpc v1.43.0 // indirect
+13 -14
View File
@@ -1146,8 +1146,8 @@ github.com/mholt/acmez v1.0.2 h1:C8wsEBIUVi6e0DYoxqCcFuXtwc4AWXL/jgcDjF7mjVo=
github.com/mholt/acmez v1.0.2/go.mod h1:8qnn8QA/Ewx8E3ZSsmscqsIjhhpxuy9vqdgbX2ceceM=
github.com/mholt/archiver/v3 v3.5.1 h1:rDjOBX9JSF5BvoJGvjqK479aL70qh9DIpZCl+k7Clwo=
github.com/mholt/archiver/v3 v3.5.1/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnonssnDhppzS1L4=
github.com/microcosm-cc/bluemonday v1.0.19 h1:OI7hoF5FY4pFz2VA//RN8TfM0YJ2dJcl4P4APrCWy6c=
github.com/microcosm-cc/bluemonday v1.0.19/go.mod h1:QNzV2UbLK2/53oIIwTOyLUSABMkjZ4tqiyC1g/DyqxE=
github.com/microcosm-cc/bluemonday v1.0.20 h1:flpzsq4KU3QIYAYGV/szUat7H+GPOXR0B2JU5A1Wp8Y=
github.com/microcosm-cc/bluemonday v1.0.20/go.mod h1:yfBmMi8mxvaZut3Yytv+jTXRY8mxyjJ0/kQBTElld50=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
@@ -1716,8 +1716,8 @@ golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o=
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -1788,8 +1788,8 @@ golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qx
golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220630215102-69896b714898 h1:K7wO6V1IrczY9QOQ2WkVpw4JQSwCd52UsxVEirZUfiw=
golang.org/x/net v0.0.0-20220630215102-69896b714898/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220927171203-f486391704dc h1:FxpXZdoBqT8RjqTy6i1E8nXHhW21wK7ptQ/EPIGxzPQ=
golang.org/x/net v0.0.0-20220927171203-f486391704dc/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -1824,8 +1824,8 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -1936,8 +1936,8 @@ golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 h1:WIoqL4EROvwiPdUtaip4VcDdpZ4kha7wBWZrbVKCIZg=
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
@@ -1950,8 +1950,9 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -2045,16 +2046,14 @@ golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.10 h1:QjFRCZxdOhBJ/UNgnBZLbNV13DlbnK0quyivTnXJM20=
golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f h1:GGU+dLjvlC3qDwqYgL6UgRmHXhOOgns0bZu2Ty5mm6U=
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.5.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
+1 -1
View File
@@ -266,7 +266,7 @@ func TestPackageConan(t *testing.T) {
pd, err := packages.GetPackageDescriptor(db.DefaultContext, pvs[0])
assert.NoError(t, err)
assert.NotNil(t, pd.SemVer)
assert.Nil(t, pd.SemVer)
assert.Equal(t, name, pd.Package.Name)
assert.Equal(t, version1, pd.Version.Version)
assert.IsType(t, &conan_module.Metadata{}, pd.Metadata)
+13 -1
View File
@@ -275,11 +275,23 @@ func TestPackageContainer(t *testing.T) {
}
}
// Overwrite existing tag
req = NewRequest(t, "GET", fmt.Sprintf("%s/manifests/%s", url, tag))
addTokenAuthHeader(req, userToken)
MakeRequest(t, req, http.StatusOK)
pv, err = packages_model.GetVersionByNameAndVersion(db.DefaultContext, user.ID, packages_model.TypeContainer, image, tag)
assert.NoError(t, err)
assert.EqualValues(t, 1, pv.DownloadCount)
// Overwrite existing tag should keep the download count
req = NewRequestWithBody(t, "PUT", fmt.Sprintf("%s/manifests/%s", url, tag), strings.NewReader(manifestContent))
addTokenAuthHeader(req, userToken)
req.Header.Set("Content-Type", oci.MediaTypeDockerManifest)
MakeRequest(t, req, http.StatusCreated)
pv, err = packages_model.GetVersionByNameAndVersion(db.DefaultContext, user.ID, packages_model.TypeContainer, image, tag)
assert.NoError(t, err)
assert.EqualValues(t, 1, pv.DownloadCount)
})
t.Run("HeadManifest", func(t *testing.T) {
+13
View File
@@ -14,6 +14,7 @@ import (
"code.gitea.io/gitea/models/packages"
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/setting"
"github.com/stretchr/testify/assert"
)
@@ -79,6 +80,18 @@ func TestPackageGeneric(t *testing.T) {
assert.Equal(t, int64(1), pvs[0].DownloadCount)
})
t.Run("RequireSignInView", func(t *testing.T) {
defer PrintCurrentTest(t)()
setting.Service.RequireSignInView = true
defer func() {
setting.Service.RequireSignInView = false
}()
req := NewRequest(t, "GET", url)
MakeRequest(t, req, http.StatusUnauthorized)
})
t.Run("Delete", func(t *testing.T) {
defer PrintCurrentTest(t)()
+17 -5
View File
@@ -42,6 +42,7 @@ func TestPackageMaven(t *testing.T) {
defer PrintCurrentTest(t)()
putFile(t, fmt.Sprintf("/%s/%s", packageVersion, filename), "test", http.StatusCreated)
putFile(t, fmt.Sprintf("/%s/%s", packageVersion, filename), "test", http.StatusBadRequest)
putFile(t, "/maven-metadata.xml", "test", http.StatusOK)
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeMaven)
@@ -135,12 +136,14 @@ func TestPackageMaven(t *testing.T) {
pfs, err := packages.GetFilesByVersionID(db.DefaultContext, pvs[0].ID)
assert.NoError(t, err)
assert.Len(t, pfs, 2)
i := 0
if strings.HasSuffix(pfs[1].Name, ".pom") {
i = 1
for _, pf := range pfs {
if strings.HasSuffix(pf.Name, ".pom") {
assert.Equal(t, filename+".pom", pf.Name)
assert.True(t, pf.IsLead)
} else {
assert.False(t, pf.IsLead)
}
}
assert.Equal(t, filename+".pom", pfs[i].Name)
assert.True(t, pfs[i].IsLead)
})
t.Run("DownloadPOM", func(t *testing.T) {
@@ -202,4 +205,13 @@ func TestPackageMaven(t *testing.T) {
assert.Equal(t, checksum, resp.Body.String())
}
})
t.Run("UploadSnapshot", func(t *testing.T) {
snapshotVersion := packageVersion + "-SNAPSHOT"
putFile(t, fmt.Sprintf("/%s/%s", snapshotVersion, filename), "test", http.StatusCreated)
putFile(t, "/maven-metadata.xml", "test", http.StatusOK)
putFile(t, fmt.Sprintf("/%s/maven-metadata.xml", snapshotVersion), "test", http.StatusCreated)
putFile(t, fmt.Sprintf("/%s/maven-metadata.xml", snapshotVersion), "test-overwrite", http.StatusCreated)
})
}
+60 -29
View File
@@ -19,14 +19,22 @@ import (
user_model "code.gitea.io/gitea/models/user"
nuget_module "code.gitea.io/gitea/modules/packages/nuget"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/routers/api/packages/nuget"
"github.com/stretchr/testify/assert"
)
func addNuGetAPIKeyHeader(request *http.Request, token string) *http.Request {
request.Header.Set("X-NuGet-ApiKey", token)
return request
}
func TestPackageNuGet(t *testing.T) {
defer prepareTestEnv(t)()
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
token := getUserToken(t, user.Name)
packageName := "test.package"
packageVersion := "1.0.3"
@@ -58,35 +66,58 @@ func TestPackageNuGet(t *testing.T) {
t.Run("ServiceIndex", func(t *testing.T) {
defer PrintCurrentTest(t)()
req := NewRequest(t, "GET", fmt.Sprintf("%s/index.json", url))
req = AddBasicAuthHeader(req, user.Name)
resp := MakeRequest(t, req, http.StatusOK)
privateUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{Visibility: structs.VisibleTypePrivate}).(*user_model.User)
var result nuget.ServiceIndexResponse
DecodeJSON(t, resp, &result)
cases := []struct {
Owner string
UseBasicAuth bool
UseTokenAuth bool
}{
{privateUser.Name, false, false},
{privateUser.Name, true, false},
{privateUser.Name, false, true},
{user.Name, false, false},
{user.Name, true, false},
{user.Name, false, true},
}
assert.Equal(t, "3.0.0", result.Version)
assert.NotEmpty(t, result.Resources)
for _, c := range cases {
url := fmt.Sprintf("/api/packages/%s/nuget", c.Owner)
root := setting.AppURL + url[1:]
for _, r := range result.Resources {
switch r.Type {
case "SearchQueryService":
fallthrough
case "SearchQueryService/3.0.0-beta":
fallthrough
case "SearchQueryService/3.0.0-rc":
assert.Equal(t, root+"/query", r.ID)
case "RegistrationsBaseUrl":
fallthrough
case "RegistrationsBaseUrl/3.0.0-beta":
fallthrough
case "RegistrationsBaseUrl/3.0.0-rc":
assert.Equal(t, root+"/registration", r.ID)
case "PackageBaseAddress/3.0.0":
assert.Equal(t, root+"/package", r.ID)
case "PackagePublish/2.0.0":
assert.Equal(t, root, r.ID)
req := NewRequest(t, "GET", fmt.Sprintf("%s/index.json", url))
if c.UseBasicAuth {
req = AddBasicAuthHeader(req, user.Name)
} else if c.UseTokenAuth {
req = addNuGetAPIKeyHeader(req, token)
}
resp := MakeRequest(t, req, http.StatusOK)
var result nuget.ServiceIndexResponse
DecodeJSON(t, resp, &result)
assert.Equal(t, "3.0.0", result.Version)
assert.NotEmpty(t, result.Resources)
root := setting.AppURL + url[1:]
for _, r := range result.Resources {
switch r.Type {
case "SearchQueryService":
fallthrough
case "SearchQueryService/3.0.0-beta":
fallthrough
case "SearchQueryService/3.0.0-rc":
assert.Equal(t, root+"/query", r.ID)
case "RegistrationsBaseUrl":
fallthrough
case "RegistrationsBaseUrl/3.0.0-beta":
fallthrough
case "RegistrationsBaseUrl/3.0.0-rc":
assert.Equal(t, root+"/registration", r.ID)
case "PackageBaseAddress/3.0.0":
assert.Equal(t, root+"/package", r.ID)
case "PackagePublish/2.0.0":
assert.Equal(t, root, r.ID)
}
}
}
})
@@ -122,7 +153,7 @@ func TestPackageNuGet(t *testing.T) {
req = NewRequestWithBody(t, "PUT", url, bytes.NewReader(content))
req = AddBasicAuthHeader(req, user.Name)
MakeRequest(t, req, http.StatusBadRequest)
MakeRequest(t, req, http.StatusConflict)
})
t.Run("SymbolPackage", func(t *testing.T) {
@@ -208,7 +239,7 @@ AAAjQmxvYgAAAGm7ENm9SGxMtAFVvPUsPJTF6PbtAAAAAFcVogEJAAAAAQAAAA==`)
req = NewRequestWithBody(t, "PUT", fmt.Sprintf("%s/symbolpackage", url), createPackage(packageName, "SymbolsPackage"))
req = AddBasicAuthHeader(req, user.Name)
MakeRequest(t, req, http.StatusBadRequest)
MakeRequest(t, req, http.StatusConflict)
})
})
@@ -352,7 +383,7 @@ AAAjQmxvYgAAAGm7ENm9SGxMtAFVvPUsPJTF6PbtAAAAAFcVogEJAAAAAQAAAA==`)
req := NewRequest(t, "DELETE", fmt.Sprintf("%s/%s/%s", url, packageName, packageVersion))
req = AddBasicAuthHeader(req, user.Name)
MakeRequest(t, req, http.StatusOK)
MakeRequest(t, req, http.StatusNoContent)
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeNuGet)
assert.NoError(t, err)
+1 -1
View File
@@ -223,7 +223,7 @@ func TestAPITeamSearch(t *testing.T) {
defer prepareTestEnv(t)()
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
org := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}).(*user_model.User)
org := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 17}).(*user_model.User)
var results TeamSearchResults
+22
View File
@@ -26,8 +26,19 @@ func TestUserOrgs(t *testing.T) {
orgs := getUserOrgs(t, adminUsername, normalUsername)
user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "user3"}).(*user_model.User)
user17 := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "user17"}).(*user_model.User)
assert.Equal(t, []*api.Organization{
{
ID: 17,
UserName: user17.Name,
FullName: user17.FullName,
AvatarURL: user17.AvatarLink(),
Description: "",
Website: "",
Location: "",
Visibility: "public",
},
{
ID: 3,
UserName: user3.Name,
@@ -82,8 +93,19 @@ func TestMyOrgs(t *testing.T) {
var orgs []*api.Organization
DecodeJSON(t, resp, &orgs)
user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "user3"}).(*user_model.User)
user17 := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "user17"}).(*user_model.User)
assert.Equal(t, []*api.Organization{
{
ID: 17,
UserName: user17.Name,
FullName: user17.FullName,
AvatarURL: user17.AvatarLink(),
Description: "",
Website: "",
Location: "",
Visibility: "public",
},
{
ID: 3,
UserName: user3.Name,
+5 -5
View File
@@ -179,8 +179,8 @@ func TestOrgRestrictedUser(t *testing.T) {
func TestTeamSearch(t *testing.T) {
defer prepareTestEnv(t)()
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
org := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}).(*user_model.User)
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 15}).(*user_model.User)
org := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 17}).(*user_model.User)
var results TeamSearchResults
@@ -190,9 +190,9 @@ func TestTeamSearch(t *testing.T) {
req.Header.Add("X-Csrf-Token", csrf)
resp := session.MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &results)
assert.NotEmpty(t, results.Data)
assert.Len(t, results.Data, 1)
assert.Equal(t, "test_team", results.Data[0].Name)
assert.Len(t, results.Data, 2)
assert.Equal(t, "review_team", results.Data[0].Name)
assert.Equal(t, "test_team", results.Data[1].Name)
// no access if not organization member
user5 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}).(*user_model.User)
+1 -1
View File
@@ -1,7 +1,7 @@
export default {
rootDir: 'web_src',
setupFilesAfterEnv: ['jest-extended/all'],
testEnvironment: '@happy-dom/jest-environment',
testEnvironment: 'jest-environment-jsdom',
testMatch: ['<rootDir>/**/*.test.js'],
testTimeout: 20000,
transform: {
+14 -2
View File
@@ -98,7 +98,14 @@ func (a *Action) TableIndices() []*schemas.Index {
actUserIndex := schemas.NewIndex("au_r_c_u_d", schemas.IndexType)
actUserIndex.AddColumn("act_user_id", "repo_id", "created_unix", "user_id", "is_deleted")
return []*schemas.Index{actUserIndex, repoIndex}
indices := []*schemas.Index{actUserIndex, repoIndex}
if setting.Database.UsePostgreSQL {
cudIndex := schemas.NewIndex("c_u_d", schemas.IndexType)
cudIndex.AddColumn("created_unix", "user_id", "is_deleted")
indices = append(indices, cudIndex)
}
return indices
}
// GetOpType gets the ActionType of this action.
@@ -211,6 +218,11 @@ func (a *Action) GetRepoLink() string {
return path.Join(setting.AppSubURL, "/", url.PathEscape(a.GetRepoUserName()), url.PathEscape(a.GetRepoName()))
}
// GetRepoAbsoluteLink returns the absolute link to action repository.
func (a *Action) GetRepoAbsoluteLink() string {
return setting.AppURL + url.PathEscape(a.GetRepoUserName()) + "/" + url.PathEscape(a.GetRepoName())
}
// GetRepositoryFromMatch returns a *repo_model.Repository from a username and repo strings
func GetRepositoryFromMatch(ownerName, repoName string) (*repo_model.Repository, error) {
var err error
@@ -275,7 +287,7 @@ func (a *Action) GetRefLink() string {
return a.GetRepoLink() + "/src/branch/" + util.PathEscapeSegments(strings.TrimPrefix(a.RefName, git.BranchPrefix))
case strings.HasPrefix(a.RefName, git.TagPrefix):
return a.GetRepoLink() + "/src/tag/" + util.PathEscapeSegments(strings.TrimPrefix(a.RefName, git.TagPrefix))
case len(a.RefName) == 40 && git.SHAPattern.MatchString(a.RefName):
case len(a.RefName) == 40 && git.IsValidSHAPattern(a.RefName):
return a.GetRepoLink() + "/src/commit/" + a.RefName
default:
// FIXME: we will just assume it's a branch - this was the old way - at some point we may want to enforce that there is always a ref here.
+7 -3
View File
@@ -9,6 +9,7 @@ import (
"testing"
"code.gitea.io/gitea/models/db"
issue_model "code.gitea.io/gitea/models/issues"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
@@ -19,7 +20,7 @@ import (
func TestAction_GetRepoPath(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{}).(*repo_model.Repository)
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository)
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User)
action := &Action{RepoID: repo.ID}
assert.Equal(t, path.Join(owner.Name, repo.Name), action.GetRepoPath())
@@ -27,12 +28,15 @@ func TestAction_GetRepoPath(t *testing.T) {
func TestAction_GetRepoLink(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{}).(*repo_model.Repository)
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository)
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User)
action := &Action{RepoID: repo.ID}
comment := unittest.AssertExistsAndLoadBean(t, &issue_model.Comment{ID: 2}).(*issue_model.Comment)
action := &Action{RepoID: repo.ID, CommentID: comment.ID}
setting.AppSubURL = "/suburl"
expected := path.Join(setting.AppSubURL, owner.Name, repo.Name)
assert.Equal(t, expected, action.GetRepoLink())
assert.Equal(t, repo.HTMLURL(), action.GetRepoAbsoluteLink())
assert.Equal(t, comment.HTMLURL(), action.GetCommentLink())
}
func TestGetFeeds(t *testing.T) {
+10 -1
View File
@@ -33,7 +33,7 @@ type GPGKey struct {
OwnerID int64 `xorm:"INDEX NOT NULL"`
KeyID string `xorm:"INDEX CHAR(16) NOT NULL"`
PrimaryKeyID string `xorm:"CHAR(16)"`
Content string `xorm:"TEXT NOT NULL"`
Content string `xorm:"MEDIUMTEXT NOT NULL"`
CreatedUnix timeutil.TimeStamp `xorm:"created"`
ExpiredUnix timeutil.TimeStamp
AddedUnix timeutil.TimeStamp
@@ -63,6 +63,15 @@ func (key *GPGKey) AfterLoad(session *xorm.Session) {
}
}
// PaddedKeyID show KeyID padded to 16 characters
func (key *GPGKey) PaddedKeyID() string {
if len(key.KeyID) > 15 {
return key.KeyID
}
zeros := "0000000000000000"
return zeros[0:16-len(key.KeyID)] + key.KeyID
}
// ListGPGKeys returns a list of public keys belongs to given user.
func ListGPGKeys(ctx context.Context, uid int64, listOptions db.ListOptions) ([]*GPGKey, error) {
sess := db.GetEngine(ctx).Table(&GPGKey{}).Where("owner_id=? AND primary_key_id=''", uid)
+1 -1
View File
@@ -41,7 +41,7 @@ type PublicKey struct {
OwnerID int64 `xorm:"INDEX NOT NULL"`
Name string `xorm:"NOT NULL"`
Fingerprint string `xorm:"INDEX NOT NULL"`
Content string `xorm:"TEXT NOT NULL"`
Content string `xorm:"MEDIUMTEXT NOT NULL"`
Mode perm.AccessMode `xorm:"NOT NULL DEFAULT 2"`
Type KeyType `xorm:"NOT NULL DEFAULT 1"`
LoginSourceID int64 `xorm:"NOT NULL DEFAULT 0"`
+18 -1
View File
@@ -10,6 +10,7 @@ import (
"encoding/base32"
"encoding/base64"
"fmt"
"net"
"net/url"
"strings"
@@ -56,6 +57,18 @@ func (app *OAuth2Application) PrimaryRedirectURI() string {
// ContainsRedirectURI checks if redirectURI is allowed for app
func (app *OAuth2Application) ContainsRedirectURI(redirectURI string) bool {
uri, err := url.Parse(redirectURI)
// ignore port for http loopback uris following https://datatracker.ietf.org/doc/html/rfc8252#section-7.3
if err == nil && uri.Scheme == "http" && uri.Port() != "" {
ip := net.ParseIP(uri.Hostname())
if ip != nil && ip.IsLoopback() {
// strip port
uri.Host = uri.Hostname()
if util.IsStringInSlice(uri.String(), app.RedirectURIs, true) {
return true
}
}
}
return util.IsStringInSlice(redirectURI, app.RedirectURIs, true)
}
@@ -512,10 +525,14 @@ func GetActiveOAuth2ProviderSources() ([]*Source, error) {
func GetActiveOAuth2SourceByName(name string) (*Source, error) {
authSource := new(Source)
has, err := db.GetEngine(db.DefaultContext).Where("name = ? and type = ? and is_active = ?", name, OAuth2, true).Get(authSource)
if !has || err != nil {
if err != nil {
return nil, err
}
if !has {
return nil, fmt.Errorf("oauth2 source not found, name: %q", name)
}
return authSource, nil
}
+20
View File
@@ -42,6 +42,26 @@ func TestOAuth2Application_ContainsRedirectURI(t *testing.T) {
assert.False(t, app.ContainsRedirectURI("d"))
}
func TestOAuth2Application_ContainsRedirectURI_WithPort(t *testing.T) {
app := &OAuth2Application{
RedirectURIs: []string{"http://127.0.0.1/", "http://::1/", "http://192.168.0.1/", "http://intranet/", "https://127.0.0.1/"},
}
// http loopback uris should ignore port
// https://datatracker.ietf.org/doc/html/rfc8252#section-7.3
assert.True(t, app.ContainsRedirectURI("http://127.0.0.1:3456/"))
assert.True(t, app.ContainsRedirectURI("http://127.0.0.1/"))
assert.True(t, app.ContainsRedirectURI("http://[::1]:3456/"))
// not http
assert.False(t, app.ContainsRedirectURI("https://127.0.0.1:3456/"))
// not loopback
assert.False(t, app.ContainsRedirectURI("http://192.168.0.1:9954/"))
assert.False(t, app.ContainsRedirectURI("http://intranet:3456/"))
// unparseable
assert.False(t, app.ContainsRedirectURI(":"))
}
func TestOAuth2Application_ValidateClientSecret(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
app := unittest.AssertExistsAndLoadBean(t, &OAuth2Application{ID: 1}).(*OAuth2Application)
+34
View File
@@ -0,0 +1,34 @@
// 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 db
import (
"context"
"code.gitea.io/gitea/modules/setting"
)
// IterateObjects iterate all the Bean object
func IterateObjects[Object any](ctx context.Context, f func(repo *Object) error) error {
var start int
batchSize := setting.Database.IterateBufferSize
sess := GetEngine(ctx)
for {
repos := make([]*Object, 0, batchSize)
if err := sess.Limit(batchSize, start).Find(&repos); err != nil {
return err
}
if len(repos) == 0 {
return nil
}
start += len(repos)
for _, repo := range repos {
if err := f(repo); err != nil {
return err
}
}
}
}
+6
View File
@@ -63,3 +63,9 @@
uid: 29
org_id: 17
is_public: true
-
id: 12
uid: 2
org_id: 17
is_public: true
+1 -1
View File
@@ -309,7 +309,7 @@
avatar_email: user17@example.com
num_repos: 2
is_active: true
num_members: 3
num_members: 4
num_teams: 3
-
-23
View File
@@ -278,29 +278,6 @@ func LFSAutoAssociate(metas []*LFSMetaObject, user *user_model.User, repoID int6
return committer.Commit()
}
// IterateLFS iterates lfs object
func IterateLFS(f func(mo *LFSMetaObject) error) error {
var start int
const batchSize = 100
e := db.GetEngine(db.DefaultContext)
for {
mos := make([]*LFSMetaObject, 0, batchSize)
if err := e.Limit(batchSize, start).Find(&mos); err != nil {
return err
}
if len(mos) == 0 {
return nil
}
start += len(mos)
for _, mo := range mos {
if err := f(mo); err != nil {
return err
}
}
}
}
// CopyLFS copies LFS data from one repo to another
func CopyLFS(ctx context.Context, newRepo, oldRepo *repo_model.Repository) error {
var lfsObjects []*LFSMetaObject
+45
View File
@@ -9,6 +9,7 @@ import (
"fmt"
"code.gitea.io/gitea/models/db"
project_model "code.gitea.io/gitea/models/project"
repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/container"
@@ -222,6 +223,46 @@ func (issues IssueList) loadMilestones(ctx context.Context) error {
return nil
}
func (issues IssueList) getProjectIDs() []int64 {
ids := make(map[int64]struct{}, len(issues))
for _, issue := range issues {
projectID := issue.ProjectID()
if _, ok := ids[projectID]; !ok {
ids[projectID] = struct{}{}
}
}
return container.KeysInt64(ids)
}
func (issues IssueList) loadProjects(ctx context.Context) error {
projectIDs := issues.getProjectIDs()
if len(projectIDs) == 0 {
return nil
}
projectMaps := make(map[int64]*project_model.Project, len(projectIDs))
left := len(projectIDs)
for left > 0 {
limit := db.DefaultMaxInSize
if left < limit {
limit = left
}
err := db.GetEngine(ctx).
In("id", projectIDs[:limit]).
Find(&projectMaps)
if err != nil {
return err
}
left -= limit
projectIDs = projectIDs[limit:]
}
for _, issue := range issues {
issue.Project = projectMaps[issue.ProjectID()]
}
return nil
}
func (issues IssueList) loadAssignees(ctx context.Context) error {
if len(issues) == 0 {
return nil
@@ -495,6 +536,10 @@ func (issues IssueList) loadAttributes(ctx context.Context) error {
return fmt.Errorf("issue.loadAttributes: loadMilestones: %v", err)
}
if err := issues.loadProjects(ctx); err != nil {
return fmt.Errorf("issue.loadAttributes: loadProjects: %v", err)
}
if err := issues.loadAssignees(ctx); err != nil {
return fmt.Errorf("issue.loadAttributes: loadAssignees: %v", err)
}
+2
View File
@@ -68,6 +68,7 @@ func LoadIssuesFromBoard(b *project_model.Board) (IssueList, error) {
issues, err := Issues(&IssuesOptions{
ProjectBoardID: b.ID,
ProjectID: b.ProjectID,
SortType: "project-column-sorting",
})
if err != nil {
return nil, err
@@ -79,6 +80,7 @@ func LoadIssuesFromBoard(b *project_model.Board) (IssueList, error) {
issues, err := Issues(&IssuesOptions{
ProjectBoardID: -1, // Issues without ProjectBoardID
ProjectID: b.ProjectID,
SortType: "project-column-sorting",
})
if err != nil {
return nil, err
+15 -4
View File
@@ -181,6 +181,10 @@ func createReaction(ctx context.Context, opts *ReactionOptions) (*Reaction, erro
Reaction: opts.Type,
UserID: opts.DoerID,
}
if findOpts.CommentID == 0 {
// explicit search of Issue Reactions where CommentID = 0
findOpts.CommentID = -1
}
existingR, _, err := FindReactions(ctx, findOpts)
if err != nil {
@@ -256,16 +260,23 @@ func DeleteReaction(ctx context.Context, opts *ReactionOptions) error {
CommentID: opts.CommentID,
}
_, err := db.GetEngine(ctx).Where("original_author_id = 0").Delete(reaction)
sess := db.GetEngine(ctx).Where("original_author_id = 0")
if opts.CommentID == -1 {
reaction.CommentID = 0
sess.MustCols("comment_id")
}
_, err := sess.Delete(reaction)
return err
}
// DeleteIssueReaction deletes a reaction on issue.
func DeleteIssueReaction(doerID, issueID int64, content string) error {
return DeleteReaction(db.DefaultContext, &ReactionOptions{
Type: content,
DoerID: doerID,
IssueID: issueID,
Type: content,
DoerID: doerID,
IssueID: issueID,
CommentID: -1,
})
}
+8 -1
View File
@@ -5,6 +5,7 @@
package migrations
import (
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/timeutil"
"xorm.io/xorm"
@@ -37,8 +38,14 @@ func (*improveActionTableIndicesAction) TableIndices() []*schemas.Index {
actUserIndex := schemas.NewIndex("au_r_c_u_d", schemas.IndexType)
actUserIndex.AddColumn("act_user_id", "repo_id", "created_unix", "user_id", "is_deleted")
indices := []*schemas.Index{actUserIndex, repoIndex}
if setting.Database.UsePostgreSQL {
cudIndex := schemas.NewIndex("c_u_d", schemas.IndexType)
cudIndex.AddColumn("created_unix", "user_id", "is_deleted")
indices = append(indices, cudIndex)
}
return []*schemas.Index{actUserIndex, repoIndex}
return indices
}
func improveActionTableIndices(x *xorm.Engine) error {
+9 -10
View File
@@ -12,18 +12,17 @@ import (
"xorm.io/xorm/schemas"
)
func addContainerRepositoryProperty(x *xorm.Engine) error {
func addContainerRepositoryProperty(x *xorm.Engine) (err error) {
switch x.Dialect().URI().DBType {
case schemas.SQLITE:
_, err := x.Exec("INSERT INTO package_property (ref_type, ref_id, name, value) SELECT ?, p.id, ?, u.lower_name || '/' || p.lower_name FROM package p JOIN `user` u ON p.owner_id = u.id WHERE p.type = ?", packages_model.PropertyTypePackage, container_module.PropertyRepository, packages_model.TypeContainer)
if err != nil {
return err
}
_, err = x.Exec("INSERT INTO package_property (ref_type, ref_id, name, value) SELECT ?, p.id, ?, u.lower_name || '/' || p.lower_name FROM package p JOIN `user` u ON p.owner_id = u.id WHERE p.type = ?",
packages_model.PropertyTypePackage, container_module.PropertyRepository, packages_model.TypeContainer)
case schemas.MSSQL:
_, err = x.Exec("INSERT INTO package_property (ref_type, ref_id, name, value) SELECT ?, p.id, ?, u.lower_name + '/' + p.lower_name FROM package p JOIN `user` u ON p.owner_id = u.id WHERE p.type = ?",
packages_model.PropertyTypePackage, container_module.PropertyRepository, packages_model.TypeContainer)
default:
_, err := x.Exec("INSERT INTO package_property (ref_type, ref_id, name, value) SELECT ?, p.id, ?, CONCAT(u.lower_name, '/', p.lower_name) FROM package p JOIN `user` u ON p.owner_id = u.id WHERE p.type = ?", packages_model.PropertyTypePackage, container_module.PropertyRepository, packages_model.TypeContainer)
if err != nil {
return err
}
_, err = x.Exec("INSERT INTO package_property (ref_type, ref_id, name, value) SELECT ?, p.id, ?, CONCAT(u.lower_name, '/', p.lower_name) FROM package p JOIN `user` u ON p.owner_id = u.id WHERE p.type = ?",
packages_model.PropertyTypePackage, container_module.PropertyRepository, packages_model.TypeContainer)
}
return nil
return err
}
+25 -11
View File
@@ -96,16 +96,7 @@ type SearchTeamOptions struct {
IncludeDesc bool
}
// SearchTeam search for teams. Caller is responsible to check permissions.
func SearchTeam(opts *SearchTeamOptions) ([]*Team, int64, error) {
if opts.Page <= 0 {
opts.Page = 1
}
if opts.PageSize == 0 {
// Default limit
opts.PageSize = 10
}
func (opts *SearchTeamOptions) toCond() builder.Cond {
cond := builder.NewCond()
if len(opts.Keyword) > 0 {
@@ -117,10 +108,28 @@ func SearchTeam(opts *SearchTeamOptions) ([]*Team, int64, error) {
cond = cond.And(keywordCond)
}
cond = cond.And(builder.Eq{"org_id": opts.OrgID})
if opts.OrgID > 0 {
cond = cond.And(builder.Eq{"`team`.org_id": opts.OrgID})
}
if opts.UserID > 0 {
cond = cond.And(builder.Eq{"team_user.uid": opts.UserID})
}
return cond
}
// SearchTeam search for teams. Caller is responsible to check permissions.
func SearchTeam(opts *SearchTeamOptions) ([]*Team, int64, error) {
sess := db.GetEngine(db.DefaultContext)
opts.SetDefaultValues()
cond := opts.toCond()
if opts.UserID > 0 {
sess = sess.Join("INNER", "team_user", "team_user.team_id = team.id")
}
count, err := sess.
Where(cond).
Count(new(Team))
@@ -128,6 +137,10 @@ func SearchTeam(opts *SearchTeamOptions) ([]*Team, int64, error) {
return nil, 0, err
}
if opts.UserID > 0 {
sess = sess.Join("INNER", "team_user", "team_user.team_id = team.id")
}
sess = sess.Where(cond)
if opts.PageSize == -1 {
opts.PageSize = int(count)
@@ -137,6 +150,7 @@ func SearchTeam(opts *SearchTeamOptions) ([]*Team, int64, error) {
teams := make([]*Team, 0, opts.PageSize)
if err = sess.
Where(cond).
OrderBy("lower_name").
Find(&teams); err != nil {
return nil, 0, err
+9 -2
View File
@@ -214,9 +214,16 @@ func FindUnreferencedPackages(ctx context.Context) ([]*Package, error) {
Find(&ps)
}
// HasOwnerPackages tests if a user/org has packages
// HasOwnerPackages tests if a user/org has accessible packages
func HasOwnerPackages(ctx context.Context, ownerID int64) (bool, error) {
return db.GetEngine(ctx).Where("owner_id = ?", ownerID).Exist(&Package{})
return db.GetEngine(ctx).
Table("package_version").
Join("INNER", "package", "package.id = package_version.package_id").
Where(builder.Eq{
"package_version.is_internal": false,
"package.owner_id": ownerID,
}).
Exist(&PackageVersion{})
}
// HasRepositoryPackages tests if a repository has packages
+69
View File
@@ -0,0 +1,69 @@
// 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 packages_test
import (
"path/filepath"
"testing"
"code.gitea.io/gitea/models/db"
packages_model "code.gitea.io/gitea/models/packages"
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
_ "code.gitea.io/gitea/models"
"github.com/stretchr/testify/assert"
)
func TestMain(m *testing.M) {
unittest.MainTest(m, &unittest.TestOptions{
GiteaRootPath: filepath.Join("..", ".."),
})
}
func TestHasOwnerPackages(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User)
p, err := packages_model.TryInsertPackage(db.DefaultContext, &packages_model.Package{
OwnerID: owner.ID,
LowerName: "package",
})
assert.NotNil(t, p)
assert.NoError(t, err)
// A package without package versions gets automatically cleaned up and should return false
has, err := packages_model.HasOwnerPackages(db.DefaultContext, owner.ID)
assert.False(t, has)
assert.NoError(t, err)
pv, err := packages_model.GetOrInsertVersion(db.DefaultContext, &packages_model.PackageVersion{
PackageID: p.ID,
LowerVersion: "internal",
IsInternal: true,
})
assert.NotNil(t, pv)
assert.NoError(t, err)
// A package with an internal package version gets automaticaly cleaned up and should return false
has, err = packages_model.HasOwnerPackages(db.DefaultContext, owner.ID)
assert.False(t, has)
assert.NoError(t, err)
pv, err = packages_model.GetOrInsertVersion(db.DefaultContext, &packages_model.PackageVersion{
PackageID: p.ID,
LowerVersion: "normal",
IsInternal: false,
})
assert.NotNil(t, pv)
assert.NoError(t, err)
// A package with a normal package version should return true
has, err = packages_model.HasOwnerPackages(db.DefaultContext, owner.ID)
assert.True(t, has)
assert.NoError(t, err)
}
+8
View File
@@ -170,6 +170,7 @@ type FindReleasesOptions struct {
IsPreRelease util.OptionalBool
IsDraft util.OptionalBool
TagNames []string
HasSha1 util.OptionalBool // useful to find draft releases which are created with existing tags
}
func (opts *FindReleasesOptions) toConds(repoID int64) builder.Cond {
@@ -191,6 +192,13 @@ func (opts *FindReleasesOptions) toConds(repoID int64) builder.Cond {
if !opts.IsDraft.IsNone() {
cond = cond.And(builder.Eq{"is_draft": opts.IsDraft.IsTrue()})
}
if !opts.HasSha1.IsNone() {
if opts.HasSha1.IsTrue() {
cond = cond.And(builder.Neq{"sha1": ""})
} else {
cond = cond.And(builder.Eq{"sha1": ""})
}
}
return cond
}
+14 -3
View File
@@ -385,8 +385,7 @@ func DeleteRepository(doer *user_model.User, uid, repoID int64) error {
archivePaths := make([]string, 0, len(archives))
for _, v := range archives {
p, _ := v.RelativePath()
archivePaths = append(archivePaths, p)
archivePaths = append(archivePaths, v.RelativePath())
}
if _, err := db.DeleteByBean(ctx, &repo_model.RepoArchiver{RepoID: repoID}); err != nil {
@@ -606,15 +605,27 @@ func CheckRepoStats(ctx context.Context) error {
repoStatsCorrectNumStars,
"repository count 'num_stars'",
},
// Repository.NumIssues
{
statsQuery("SELECT repo.id FROM `repository` repo WHERE repo.num_issues!=(SELECT COUNT(*) FROM `issue` WHERE repo_id=repo.id AND is_closed=? AND is_pull=?)", false, false),
repoStatsCorrectNumIssues,
"repository count 'num_issues'",
},
// Repository.NumClosedIssues
{
statsQuery("SELECT repo.id FROM `repository` repo WHERE repo.num_closed_issues!=(SELECT COUNT(*) FROM `issue` WHERE repo_id=repo.id AND is_closed=? AND is_pull=?)", true, false),
repoStatsCorrectNumClosedIssues,
"repository count 'num_closed_issues'",
},
// Repository.NumPulls
{
statsQuery("SELECT repo.id FROM `repository` repo WHERE repo.num_pulls!=(SELECT COUNT(*) FROM `issue` WHERE repo_id=repo.id AND is_closed=? AND is_pull=?)", false, true),
repoStatsCorrectNumPulls,
"repository count 'num_pulls'",
},
// Repository.NumClosedPulls
{
statsQuery("SELECT repo.id FROM `repository` repo WHERE repo.num_closed_issues!=(SELECT COUNT(*) FROM `issue` WHERE repo_id=repo.id AND is_closed=? AND is_pull=?)", true, true),
statsQuery("SELECT repo.id FROM `repository` repo WHERE repo.num_closed_pulls!=(SELECT COUNT(*) FROM `issue` WHERE repo_id=repo.id AND is_closed=? AND is_pull=?)", true, true),
repoStatsCorrectNumClosedPulls,
"repository count 'num_closed_pulls'",
},
+3 -3
View File
@@ -39,9 +39,9 @@ func init() {
db.RegisterModel(new(RepoArchiver))
}
// RelativePath returns relative path
func (archiver *RepoArchiver) RelativePath() (string, error) {
return fmt.Sprintf("%d/%s/%s.%s", archiver.RepoID, archiver.CommitID[:2], archiver.CommitID, archiver.Type.String()), nil
// RelativePath returns the archive path relative to the archive storage root.
func (archiver *RepoArchiver) RelativePath() string {
return fmt.Sprintf("%d/%s/%s.%s", archiver.RepoID, archiver.CommitID[:2], archiver.CommitID, archiver.Type.String())
}
var delRepoArchiver = new(RepoArchiver)
-22
View File
@@ -226,28 +226,6 @@ func DeleteAttachmentsByRelease(releaseID int64) error {
return err
}
// IterateAttachment iterates attachments; it should not be used when Gitea is servicing users.
func IterateAttachment(f func(attach *Attachment) error) error {
var start int
const batchSize = 100
for {
attachments := make([]*Attachment, 0, batchSize)
if err := db.GetEngine(db.DefaultContext).Limit(batchSize, start).Find(&attachments); err != nil {
return err
}
if len(attachments) == 0 {
return nil
}
start += len(attachments)
for _, attach := range attachments {
if err := f(attach); err != nil {
return err
}
}
}
}
// CountOrphanedAttachments returns the number of bad attachments
func CountOrphanedAttachments() (int64, error) {
return db.GetEngine(db.DefaultContext).Where("(issue_id > 0 and issue_id not in (select id from issue)) or (release_id > 0 and release_id not in (select id from `release`))").
+6 -55
View File
@@ -8,7 +8,6 @@ package repo
import (
"context"
"errors"
"fmt"
"time"
"code.gitea.io/gitea/models/db"
@@ -108,12 +107,14 @@ func DeleteMirrorByRepoID(repoID int64) error {
// MirrorsIterate iterates all mirror repositories.
func MirrorsIterate(limit int, f func(idx int, bean interface{}) error) error {
return db.GetEngine(db.DefaultContext).
sess := db.GetEngine(db.DefaultContext).
Where("next_update_unix<=?", time.Now().Unix()).
And("next_update_unix!=0").
OrderBy("updated_unix ASC").
Limit(limit).
Iterate(new(Mirror), f)
OrderBy("updated_unix ASC")
if limit > 0 {
sess = sess.Limit(limit)
}
return sess.Iterate(new(Mirror), f)
}
// InsertMirror inserts a mirror to database
@@ -121,53 +122,3 @@ func InsertMirror(ctx context.Context, mirror *Mirror) error {
_, err := db.GetEngine(ctx).Insert(mirror)
return err
}
// MirrorRepositoryList contains the mirror repositories
type MirrorRepositoryList []*Repository
func (repos MirrorRepositoryList) loadAttributes(ctx context.Context) error {
if len(repos) == 0 {
return nil
}
// Load mirrors.
repoIDs := make([]int64, 0, len(repos))
for i := range repos {
if !repos[i].IsMirror {
continue
}
repoIDs = append(repoIDs, repos[i].ID)
}
mirrors := make([]*Mirror, 0, len(repoIDs))
if err := db.GetEngine(ctx).
Where("id > 0").
In("repo_id", repoIDs).
Find(&mirrors); err != nil {
return fmt.Errorf("find mirrors: %v", err)
}
set := make(map[int64]*Mirror)
for i := range mirrors {
set[mirrors[i].RepoID] = mirrors[i]
}
for i := range repos {
repos[i].Mirror = set[repos[i].ID]
repos[i].Mirror.Repo = repos[i]
}
return nil
}
// LoadAttributes loads the attributes for the given MirrorRepositoryList
func (repos MirrorRepositoryList) LoadAttributes() error {
return repos.loadAttributes(db.DefaultContext)
}
// GetUserMirrorRepositories returns a list of mirror repositories of given user.
func GetUserMirrorRepositories(userID int64) ([]*Repository, error) {
repos := make([]*Repository, 0, 10)
return repos, db.GetEngine(db.DefaultContext).
Where("owner_id = ?", userID).
And("is_mirror = ?", true).
Find(&repos)
}
+6 -4
View File
@@ -95,10 +95,12 @@ func GetPushMirrorsByRepoID(repoID int64) ([]*PushMirror, error) {
// PushMirrorsIterate iterates all push-mirror repositories.
func PushMirrorsIterate(limit int, f func(idx int, bean interface{}) error) error {
return db.GetEngine(db.DefaultContext).
sess := db.GetEngine(db.DefaultContext).
Where("last_update + (`interval` / ?) <= ?", time.Second, time.Now().Unix()).
And("`interval` != 0").
OrderBy("last_update ASC").
Limit(limit).
Iterate(new(PushMirror), f)
OrderBy("last_update ASC")
if limit > 0 {
sess = sess.Limit(limit)
}
return sess.Iterate(new(PushMirror), f)
}
-24
View File
@@ -14,36 +14,12 @@ import (
"code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/container"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/util"
"xorm.io/builder"
)
// IterateRepository iterate repositories
func IterateRepository(f func(repo *Repository) error) error {
var start int
batchSize := setting.Database.IterateBufferSize
sess := db.GetEngine(db.DefaultContext)
for {
repos := make([]*Repository, 0, batchSize)
if err := sess.Limit(batchSize, start).Find(&repos); err != nil {
return err
}
if len(repos) == 0 {
return nil
}
start += len(repos)
for _, repo := range repos {
if err := f(repo); err != nil {
return err
}
}
}
}
// FindReposMapByIDs find repos as map
func FindReposMapByIDs(repoIDs []int64, res map[int64]*Repository) error {
return db.GetEngine(db.DefaultContext).In("id", repoIDs).Find(&res)
+3 -3
View File
@@ -100,9 +100,9 @@ func DeleteUser(ctx context.Context, u *user_model.User) (err error) {
// Delete Comments
const batchSize = 50
for start := 0; ; start += batchSize {
for {
comments := make([]*issues_model.Comment, 0, batchSize)
if err = e.Where("type=? AND poster_id=?", issues_model.CommentTypeComment, u.ID).Limit(batchSize, start).Find(&comments); err != nil {
if err = e.Where("type=? AND poster_id=?", issues_model.CommentTypeComment, u.ID).Limit(batchSize, 0).Find(&comments); err != nil {
return err
}
if len(comments) == 0 {
@@ -200,7 +200,7 @@ func DeleteUser(ctx context.Context, u *user_model.User) (err error) {
// ***** END: ExternalLoginUser *****
if _, err = e.ID(u.ID).Delete(new(user_model.User)); err != nil {
return fmt.Errorf("Delete: %v", err)
return fmt.Errorf("delete: %v", err)
}
return nil
-23
View File
@@ -9,7 +9,6 @@ import (
"strings"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/util"
@@ -125,28 +124,6 @@ func SearchUsers(opts *SearchUserOptions) (users []*User, _ int64, _ error) {
return users, count, sessQuery.Find(&users)
}
// IterateUser iterate users
func IterateUser(f func(user *User) error) error {
var start int
batchSize := setting.Database.IterateBufferSize
for {
users := make([]*User, 0, batchSize)
if err := db.GetEngine(db.DefaultContext).Limit(batchSize, start).Find(&users); err != nil {
return err
}
if len(users) == 0 {
return nil
}
start += len(users)
for _, user := range users {
if err := f(user); err != nil {
return err
}
}
}
}
// BuildCanSeeUserCondition creates a condition which can be used to restrict results to users/orgs the actor can see
func BuildCanSeeUserCondition(actor *User) builder.Cond {
if actor != nil {
+2 -2
View File
@@ -1265,7 +1265,7 @@ func isUserVisibleToViewerCond(viewer *User) builder.Cond {
// IsUserVisibleToViewer check if viewer is able to see user profile
func IsUserVisibleToViewer(ctx context.Context, u, viewer *User) bool {
if viewer != nil && viewer.IsAdmin {
if viewer != nil && (viewer.IsAdmin || viewer.ID == u.ID) {
return true
}
@@ -1304,7 +1304,7 @@ func IsUserVisibleToViewer(ctx context.Context, u, viewer *User) bool {
return false
}
if count < 0 {
if count == 0 {
// No common organization
return false
}
+4
View File
@@ -399,6 +399,10 @@ func CreateWebhook(ctx context.Context, w *Webhook) error {
// CreateWebhooks creates multiple web hooks
func CreateWebhooks(ctx context.Context, ws []*Webhook) error {
// xorm returns err "no element on slice when insert" for empty slices.
if len(ws) == 0 {
return nil
}
for i := 0; i < len(ws); i++ {
ws[i].Type = strings.TrimSpace(ws[i].Type)
}
+194 -193
View File
@@ -36,20 +36,20 @@ func drawBlock(img *image.Paletted, x, y, size, angle int, points []int) {
// blank
//
// --------
// | |
// | |
// | |
// --------
// --------
// | |
// | |
// | |
// --------
func b0(img *image.Paletted, x, y, size, angle int) {}
// full-filled
//
// --------
// |######|
// |######|
// |######|
// --------
// --------
// |######|
// |######|
// |######|
// --------
func b1(img *image.Paletted, x, y, size, angle int) {
for i := x; i < x+size; i++ {
for j := y; j < y+size; j++ {
@@ -59,12 +59,13 @@ func b1(img *image.Paletted, x, y, size, angle int) {
}
// a small block
// ----------
// | |
// | #### |
// | #### |
// | |
// ----------
//
// ----------
// | |
// | #### |
// | #### |
// | |
// ----------
func b2(img *image.Paletted, x, y, size, angle int) {
l := size / 4
x += l
@@ -79,15 +80,15 @@ func b2(img *image.Paletted, x, y, size, angle int) {
// diamond
//
// ---------
// | # |
// | ### |
// | ##### |
// |#######|
// | ##### |
// | ### |
// | # |
// ---------
// ---------
// | # |
// | ### |
// | ##### |
// |#######|
// | ##### |
// | ### |
// | # |
// ---------
func b3(img *image.Paletted, x, y, size, angle int) {
m := size / 2
drawBlock(img, x, y, size, 0, []int{
@@ -101,13 +102,13 @@ func b3(img *image.Paletted, x, y, size, angle int) {
// b4
//
// -------
// |#####|
// |#### |
// |### |
// |## |
// |# |
// |------
// -------
// |#####|
// |#### |
// |### |
// |## |
// |# |
// |------
func b4(img *image.Paletted, x, y, size, angle int) {
drawBlock(img, x, y, size, angle, []int{
0, 0,
@@ -119,11 +120,11 @@ func b4(img *image.Paletted, x, y, size, angle int) {
// b5
//
// ---------
// | # |
// | ### |
// | ##### |
// |#######|
// ---------
// | # |
// | ### |
// | ##### |
// |#######|
func b5(img *image.Paletted, x, y, size, angle int) {
m := size / 2
drawBlock(img, x, y, size, angle, []int{
@@ -136,11 +137,11 @@ func b5(img *image.Paletted, x, y, size, angle int) {
// b6
//
// --------
// |### |
// |### |
// |### |
// --------
// --------
// |### |
// |### |
// |### |
// --------
func b6(img *image.Paletted, x, y, size, angle int) {
m := size / 2
drawBlock(img, x, y, size, angle, []int{
@@ -154,12 +155,12 @@ func b6(img *image.Paletted, x, y, size, angle int) {
// b7 italic cone
//
// ---------
// | # |
// | ## |
// | #####|
// | ####|
// |--------
// ---------
// | # |
// | ## |
// | #####|
// | ####|
// |--------
func b7(img *image.Paletted, x, y, size, angle int) {
m := size / 2
drawBlock(img, x, y, size, angle, []int{
@@ -173,14 +174,14 @@ func b7(img *image.Paletted, x, y, size, angle int) {
// b8 three small triangles
//
// -----------
// | # |
// | ### |
// | ##### |
// | # # |
// | ### ### |
// |#########|
// -----------
// -----------
// | # |
// | ### |
// | ##### |
// | # # |
// | ### ### |
// |#########|
// -----------
func b8(img *image.Paletted, x, y, size, angle int) {
m := size / 2
mm := m / 2
@@ -212,13 +213,13 @@ func b8(img *image.Paletted, x, y, size, angle int) {
// b9 italic triangle
//
// ---------
// |# |
// | #### |
// | #####|
// | #### |
// | # |
// ---------
// ---------
// |# |
// | #### |
// | #####|
// | #### |
// | # |
// ---------
func b9(img *image.Paletted, x, y, size, angle int) {
m := size / 2
drawBlock(img, x, y, size, angle, []int{
@@ -231,16 +232,16 @@ func b9(img *image.Paletted, x, y, size, angle int) {
// b10
//
// ----------
// | ####|
// | ### |
// | ## |
// | # |
// |#### |
// |### |
// |## |
// |# |
// ----------
// ----------
// | ####|
// | ### |
// | ## |
// | # |
// |#### |
// |### |
// |## |
// |# |
// ----------
func b10(img *image.Paletted, x, y, size, angle int) {
m := size / 2
drawBlock(img, x, y, size, angle, []int{
@@ -260,13 +261,13 @@ func b10(img *image.Paletted, x, y, size, angle int) {
// b11
//
// ----------
// |#### |
// |#### |
// |#### |
// | |
// | |
// ----------
// ----------
// |#### |
// |#### |
// |#### |
// | |
// | |
// ----------
func b11(img *image.Paletted, x, y, size, angle int) {
m := size / 2
drawBlock(img, x, y, size, angle, []int{
@@ -280,13 +281,13 @@ func b11(img *image.Paletted, x, y, size, angle int) {
// b12
//
// -----------
// | |
// | |
// |#########|
// | ##### |
// | # |
// -----------
// -----------
// | |
// | |
// |#########|
// | ##### |
// | # |
// -----------
func b12(img *image.Paletted, x, y, size, angle int) {
m := size / 2
drawBlock(img, x, y, size, angle, []int{
@@ -299,13 +300,13 @@ func b12(img *image.Paletted, x, y, size, angle int) {
// b13
//
// -----------
// | |
// | |
// | # |
// | ##### |
// |#########|
// -----------
// -----------
// | |
// | |
// | # |
// | ##### |
// |#########|
// -----------
func b13(img *image.Paletted, x, y, size, angle int) {
m := size / 2
drawBlock(img, x, y, size, angle, []int{
@@ -318,13 +319,13 @@ func b13(img *image.Paletted, x, y, size, angle int) {
// b14
//
// ---------
// | # |
// | ### |
// |#### |
// | |
// | |
// ---------
// ---------
// | # |
// | ### |
// |#### |
// | |
// | |
// ---------
func b14(img *image.Paletted, x, y, size, angle int) {
m := size / 2
drawBlock(img, x, y, size, angle, []int{
@@ -337,13 +338,13 @@ func b14(img *image.Paletted, x, y, size, angle int) {
// b15
//
// ----------
// |##### |
// |### |
// |# |
// | |
// | |
// ----------
// ----------
// |##### |
// |### |
// |# |
// | |
// | |
// ----------
func b15(img *image.Paletted, x, y, size, angle int) {
m := size / 2
drawBlock(img, x, y, size, angle, []int{
@@ -356,14 +357,14 @@ func b15(img *image.Paletted, x, y, size, angle int) {
// b16
//
// ---------
// | # |
// | ##### |
// |#######|
// | # |
// | ##### |
// |#######|
// ---------
// ---------
// | # |
// | ##### |
// |#######|
// | # |
// | ##### |
// |#######|
// ---------
func b16(img *image.Paletted, x, y, size, angle int) {
m := size / 2
drawBlock(img, x, y, size, angle, []int{
@@ -383,13 +384,13 @@ func b16(img *image.Paletted, x, y, size, angle int) {
// b17
//
// ----------
// |##### |
// |### |
// |# |
// | ##|
// | ##|
// ----------
// ----------
// |##### |
// |### |
// |# |
// | ##|
// | ##|
// ----------
func b17(img *image.Paletted, x, y, size, angle int) {
m := size / 2
@@ -412,13 +413,13 @@ func b17(img *image.Paletted, x, y, size, angle int) {
// b18
//
// ----------
// |##### |
// |#### |
// |### |
// |## |
// |# |
// ----------
// ----------
// |##### |
// |#### |
// |### |
// |## |
// |# |
// ----------
func b18(img *image.Paletted, x, y, size, angle int) {
m := size / 2
@@ -432,13 +433,13 @@ func b18(img *image.Paletted, x, y, size, angle int) {
// b19
//
// ----------
// |########|
// |### ###|
// |# #|
// |### ###|
// |########|
// ----------
// ----------
// |########|
// |### ###|
// |# #|
// |### ###|
// |########|
// ----------
func b19(img *image.Paletted, x, y, size, angle int) {
m := size / 2
@@ -473,13 +474,13 @@ func b19(img *image.Paletted, x, y, size, angle int) {
// b20
//
// ----------
// | ## |
// |### |
// |## |
// |## |
// |# |
// ----------
// ----------
// | ## |
// |### |
// |## |
// |## |
// |# |
// ----------
func b20(img *image.Paletted, x, y, size, angle int) {
m := size / 2
q := size / 4
@@ -494,13 +495,13 @@ func b20(img *image.Paletted, x, y, size, angle int) {
// b21
//
// ----------
// | #### |
// |## #####|
// |## ##|
// |## |
// |# |
// ----------
// ----------
// | #### |
// |## #####|
// |## ##|
// |## |
// |# |
// ----------
func b21(img *image.Paletted, x, y, size, angle int) {
m := size / 2
q := size / 4
@@ -522,13 +523,13 @@ func b21(img *image.Paletted, x, y, size, angle int) {
// b22
//
// ----------
// | #### |
// |## ### |
// |## ##|
// |## ##|
// |# #|
// ----------
// ----------
// | #### |
// |## ### |
// |## ##|
// |## ##|
// |# #|
// ----------
func b22(img *image.Paletted, x, y, size, angle int) {
m := size / 2
q := size / 4
@@ -550,13 +551,13 @@ func b22(img *image.Paletted, x, y, size, angle int) {
// b23
//
// ----------
// | #######|
// |### #|
// |## |
// |## |
// |# |
// ----------
// ----------
// | #######|
// |### #|
// |## |
// |## |
// |# |
// ----------
func b23(img *image.Paletted, x, y, size, angle int) {
m := size / 2
q := size / 4
@@ -578,13 +579,13 @@ func b23(img *image.Paletted, x, y, size, angle int) {
// b24
//
// ----------
// | ## ###|
// |### ###|
// |## ## |
// |## ## |
// |# # |
// ----------
// ----------
// | ## ###|
// |### ###|
// |## ## |
// |## ## |
// |# # |
// ----------
func b24(img *image.Paletted, x, y, size, angle int) {
m := size / 2
q := size / 4
@@ -606,13 +607,13 @@ func b24(img *image.Paletted, x, y, size, angle int) {
// b25
//
// ----------
// |# #|
// |## ###|
// |## ## |
// |###### |
// |#### |
// ----------
// ----------
// |# #|
// |## ###|
// |## ## |
// |###### |
// |#### |
// ----------
func b25(img *image.Paletted, x, y, size, angle int) {
m := size / 2
q := size / 4
@@ -634,13 +635,13 @@ func b25(img *image.Paletted, x, y, size, angle int) {
// b26
//
// ----------
// |# #|
// |### ###|
// | #### |
// |### ###|
// |# #|
// ----------
// ----------
// |# #|
// |### ###|
// | #### |
// |### ###|
// |# #|
// ----------
func b26(img *image.Paletted, x, y, size, angle int) {
m := size / 2
q := size / 4
@@ -676,13 +677,13 @@ func b26(img *image.Paletted, x, y, size, angle int) {
// b27
//
// ----------
// |########|
// |## ###|
// |# #|
// |### ##|
// |########|
// ----------
// ----------
// |########|
// |## ###|
// |# #|
// |### ##|
// |########|
// ----------
func b27(img *image.Paletted, x, y, size, angle int) {
m := size / 2
q := size / 4
+1 -1
View File
@@ -224,7 +224,7 @@ func (ctx *Context) HTML(status int, name base.TplName) {
ctx.Data["TemplateLoadTimes"] = func() string {
return strconv.FormatInt(time.Since(tmplStartTime).Nanoseconds()/1e6, 10) + "ms"
}
if err := ctx.Render.HTML(ctx.Resp, status, string(name), ctx.Data); err != nil {
if err := ctx.Render.HTML(ctx.Resp, status, string(name), templates.BaseVars().Merge(ctx.Data)); err != nil {
if status == http.StatusInternalServerError && name == base.TplName("status/500") {
ctx.PlainText(http.StatusInternalServerError, "Unable to find status/500 template")
return
+57 -41
View File
@@ -13,6 +13,7 @@ import (
"code.gitea.io/gitea/models/perm"
"code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/structs"
)
@@ -52,47 +53,11 @@ func packageAssignment(ctx *Context, errCb func(int, string, interface{})) {
Owner: ctx.ContextUser,
}
if ctx.Package.Owner.IsOrganization() {
org := organization.OrgFromUser(ctx.Package.Owner)
// 1. Get user max authorize level for the org (may be none, if user is not member of the org)
if ctx.Doer != nil {
var err error
ctx.Package.AccessMode, err = org.GetOrgUserMaxAuthorizeLevel(ctx.Doer.ID)
if err != nil {
errCb(http.StatusInternalServerError, "GetOrgUserMaxAuthorizeLevel", err)
return
}
// If access mode is less than write check every team for more permissions
if ctx.Package.AccessMode < perm.AccessModeWrite {
teams, err := organization.GetUserOrgTeams(ctx, org.ID, ctx.Doer.ID)
if err != nil {
errCb(http.StatusInternalServerError, "GetUserOrgTeams", err)
return
}
for _, t := range teams {
perm := t.UnitAccessModeCtx(ctx, unit.TypePackages)
if ctx.Package.AccessMode < perm {
ctx.Package.AccessMode = perm
}
}
}
}
// 2. If authorize level is none, check if org is visible to user
if ctx.Package.AccessMode == perm.AccessModeNone && organization.HasOrgOrUserVisible(ctx, ctx.Package.Owner, ctx.Doer) {
ctx.Package.AccessMode = perm.AccessModeRead
}
} else {
if ctx.Doer != nil && !ctx.Doer.IsGhost() {
// 1. Check if user is package owner
if ctx.Doer.ID == ctx.Package.Owner.ID {
ctx.Package.AccessMode = perm.AccessModeOwner
} else if ctx.Package.Owner.Visibility == structs.VisibleTypePublic || ctx.Package.Owner.Visibility == structs.VisibleTypeLimited { // 2. Check if package owner is public or limited
ctx.Package.AccessMode = perm.AccessModeRead
}
} else if ctx.Package.Owner.Visibility == structs.VisibleTypePublic { // 3. Check if package owner is public
ctx.Package.AccessMode = perm.AccessModeRead
}
var err error
ctx.Package.AccessMode, err = determineAccessMode(ctx)
if err != nil {
errCb(http.StatusInternalServerError, "determineAccessMode", err)
return
}
packageType := ctx.Params("type")
@@ -117,6 +82,57 @@ func packageAssignment(ctx *Context, errCb func(int, string, interface{})) {
}
}
func determineAccessMode(ctx *Context) (perm.AccessMode, error) {
accessMode := perm.AccessModeNone
if setting.Service.RequireSignInView && ctx.Doer == nil {
return accessMode, nil
}
if ctx.Package.Owner.IsOrganization() {
org := organization.OrgFromUser(ctx.Package.Owner)
// 1. Get user max authorize level for the org (may be none, if user is not member of the org)
if ctx.Doer != nil {
var err error
accessMode, err = org.GetOrgUserMaxAuthorizeLevel(ctx.Doer.ID)
if err != nil {
return accessMode, err
}
// If access mode is less than write check every team for more permissions
if accessMode < perm.AccessModeWrite {
teams, err := organization.GetUserOrgTeams(ctx, org.ID, ctx.Doer.ID)
if err != nil {
return accessMode, err
}
for _, t := range teams {
perm := t.UnitAccessModeCtx(ctx, unit.TypePackages)
if accessMode < perm {
accessMode = perm
}
}
}
}
// 2. If authorize level is none, check if org is visible to user
if accessMode == perm.AccessModeNone && organization.HasOrgOrUserVisible(ctx, ctx.Package.Owner, ctx.Doer) {
accessMode = perm.AccessModeRead
}
} else {
if ctx.Doer != nil && !ctx.Doer.IsGhost() {
// 1. Check if user is package owner
if ctx.Doer.ID == ctx.Package.Owner.ID {
accessMode = perm.AccessModeOwner
} else if ctx.Package.Owner.Visibility == structs.VisibleTypePublic || ctx.Package.Owner.Visibility == structs.VisibleTypeLimited { // 2. Check if package owner is public or limited
accessMode = perm.AccessModeRead
}
} else if ctx.Package.Owner.Visibility == structs.VisibleTypePublic { // 3. Check if package owner is public
accessMode = perm.AccessModeRead
}
}
return accessMode, nil
}
// PackageContexter initializes a package context for a request.
func PackageContexter() func(next http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
+5 -2
View File
@@ -118,7 +118,7 @@ type CanCommitToBranchResults struct {
}
// CanCommitToBranch returns true if repository is editable and user has proper access level
// and branch is not protected for push
// and branch is not protected for push
func (r *Repository) CanCommitToBranch(ctx context.Context, doer *user_model.User) (CanCommitToBranchResults, error) {
protectedBranch, err := git_model.GetProtectedBranchBy(ctx, r.Repository.ID, r.BranchName)
if err != nil {
@@ -524,7 +524,9 @@ func RepoAssignment(ctx *Context) (cancel context.CancelFunc) {
}
ctx.Data["NumTags"], err = models.GetReleaseCountByRepoID(ctx.Repo.Repository.ID, models.FindReleasesOptions{
IncludeTags: true,
IncludeDrafts: true,
IncludeTags: true,
HasSha1: util.OptionalBoolTrue, // only draft releases which are created with existing tags
})
if err != nil {
ctx.ServerError("GetReleaseCountByRepoID", err)
@@ -986,6 +988,7 @@ func RepoRefByType(refType RepoRefType, ignoreNotExistErr ...bool) func(*Context
}
ctx.Data["BranchName"] = ctx.Repo.BranchName
ctx.Data["RefName"] = ctx.Repo.RefName
ctx.Data["BranchNameSubURL"] = ctx.Repo.BranchNameSubURL()
ctx.Data["TagName"] = ctx.Repo.TagName
ctx.Data["CommitID"] = ctx.Repo.CommitID
+6
View File
@@ -101,6 +101,12 @@ func ToTimelineComment(c *issues_model.Comment, doer *user_model.User) *api.Time
}
if c.Time != nil {
err = c.Time.LoadAttributes()
if err != nil {
log.Error("Time.LoadAttributes: %v", err)
return nil
}
comment.TrackedTime = ToTrackedTime(c.Time)
}
+1 -1
View File
@@ -322,7 +322,7 @@ func TestGuessDelimiter(t *testing.T) {
},
// case 3 - tab delimited
{
csv: "1 2",
csv: "1\t2",
expectedDelimiter: '\t',
},
// case 4 - pipe delimited
+30
View File
@@ -58,6 +58,29 @@ func checkUserEmail(ctx context.Context, logger log.Logger, _ bool) error {
return nil
}
// From time to time Gitea makes changes to the reserved usernames and which symbols
// are allowed for various reasons. This check helps with detecting users that, according
// to our reserved names, don't have a valid username.
func checkUserName(ctx context.Context, logger log.Logger, _ bool) error {
var invalidUserCount int64
if err := iterateUserAccounts(ctx, func(u *user.User) error {
if err := user.IsUsableUsername(u.Name); err != nil {
invalidUserCount++
logger.Warn("User[id=%d] does not have a valid username: %v", u.ID, err)
}
return nil
}); err != nil {
return fmt.Errorf("iterateUserAccounts: %v", err)
}
if invalidUserCount == 0 {
logger.Info("All users have a valid username.")
} else {
logger.Warn("%d user(s) have a non-valid username.", invalidUserCount)
}
return nil
}
func init() {
Register(&Check{
Title: "Check if users has an valid email address",
@@ -66,4 +89,11 @@ func init() {
Run: checkUserEmail,
Priority: 9,
})
Register(&Check{
Title: "Check if users have a valid username",
Name: "check-user-names",
IsDefault: false,
Run: checkUserName,
Priority: 9,
})
}
+6 -1
View File
@@ -11,6 +11,7 @@ import (
"strings"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
)
@@ -49,7 +50,11 @@ func initDBDisableConsole(ctx context.Context, disableConsole bool) error {
setting.NewXORMLogService(disableConsole)
if err := db.InitEngine(ctx); err != nil {
return fmt.Errorf("models.SetEngine: %v", err)
return fmt.Errorf("db.InitEngine: %w", err)
}
// some doctor sub-commands need to use git command
if err := git.InitOnceWithSync(ctx); err != nil {
return fmt.Errorf("git.InitOnceWithSync: %w", err)
}
return nil
}
File diff suppressed because it is too large Load Diff
+44 -9
View File
@@ -40,6 +40,7 @@ type Command struct {
parentContext context.Context
desc string
globalArgsLength int
brokenArgs []string
}
func (c *Command) String() string {
@@ -50,6 +51,7 @@ func (c *Command) String() string {
}
// NewCommand creates and returns a new Git Command based on given command and arguments.
// Each argument should be safe to be trusted. User-provided arguments should be passed to AddDynamicArguments instead.
func NewCommand(ctx context.Context, args ...string) *Command {
// Make an explicit copy of globalCommandArgs, otherwise append might overwrite it
cargs := make([]string, len(globalCommandArgs))
@@ -63,11 +65,13 @@ func NewCommand(ctx context.Context, args ...string) *Command {
}
// NewCommandNoGlobals creates and returns a new Git Command based on given command and arguments only with the specify args and don't care global command args
// Each argument should be safe to be trusted. User-provided arguments should be passed to AddDynamicArguments instead.
func NewCommandNoGlobals(args ...string) *Command {
return NewCommandContextNoGlobals(DefaultContext, args...)
}
// NewCommandContextNoGlobals creates and returns a new Git Command based on given command and arguments only with the specify args and don't care global command args
// Each argument should be safe to be trusted. User-provided arguments should be passed to AddDynamicArguments instead.
func NewCommandContextNoGlobals(ctx context.Context, args ...string) *Command {
return &Command{
name: GitExecutable,
@@ -89,20 +93,37 @@ func (c *Command) SetDescription(desc string) *Command {
return c
}
// AddArguments adds new argument(s) to the command.
// AddArguments adds new argument(s) to the command. Each argument must be safe to be trusted.
// User-provided arguments should be passed to AddDynamicArguments instead.
func (c *Command) AddArguments(args ...string) *Command {
c.args = append(c.args, args...)
return c
}
// RunOpts represents parameters to run the command
// AddDynamicArguments adds new dynamic argument(s) to the command.
// The arguments may come from user input and can not be trusted, so no leading '-' is allowed to avoid passing options
func (c *Command) AddDynamicArguments(args ...string) *Command {
for _, arg := range args {
if arg != "" && arg[0] == '-' {
c.brokenArgs = append(c.brokenArgs, arg)
}
}
if len(c.brokenArgs) != 0 {
return c
}
c.args = append(c.args, args...)
return c
}
// RunOpts represents parameters to run the command. If UseContextTimeout is specified, then Timeout is ignored.
type RunOpts struct {
Env []string
Timeout time.Duration
Dir string
Stdout, Stderr io.Writer
Stdin io.Reader
PipelineFunc func(context.Context, context.CancelFunc) error
Env []string
Timeout time.Duration
UseContextTimeout bool
Dir string
Stdout, Stderr io.Writer
Stdin io.Reader
PipelineFunc func(context.Context, context.CancelFunc) error
}
func commonBaseEnvs() []string {
@@ -137,8 +158,14 @@ func CommonCmdServEnvs() []string {
return commonBaseEnvs()
}
var ErrBrokenCommand = errors.New("git command is broken")
// Run runs the command with the RunOpts
func (c *Command) Run(opts *RunOpts) error {
if len(c.brokenArgs) != 0 {
log.Error("git command is broken: %s, broken args: %s", c.String(), strings.Join(c.brokenArgs, " "))
return ErrBrokenCommand
}
if opts == nil {
opts = &RunOpts{}
}
@@ -171,7 +198,15 @@ func (c *Command) Run(opts *RunOpts) error {
desc = fmt.Sprintf("%s %s [repo_path: %s]", c.name, strings.Join(args, " "), opts.Dir)
}
ctx, cancel, finished := process.GetManager().AddContextTimeout(c.parentContext, opts.Timeout, desc)
var ctx context.Context
var cancel context.CancelFunc
var finished context.CancelFunc
if opts.UseContextTimeout {
ctx, cancel, finished = process.GetManager().AddContext(c.parentContext, desc)
} else {
ctx, cancel, finished = process.GetManager().AddContextTimeout(c.parentContext, opts.Timeout, desc)
}
defer finished()
cmd := exec.CommandContext(ctx, c.name, c.args...)
+15
View File
@@ -26,4 +26,19 @@ func TestRunWithContextStd(t *testing.T) {
assert.Contains(t, err.Error(), "exit status 129 - unknown option:")
assert.Empty(t, stdout)
}
cmd = NewCommand(context.Background())
cmd.AddDynamicArguments("-test")
assert.ErrorIs(t, cmd.Run(&RunOpts{}), ErrBrokenCommand)
cmd = NewCommand(context.Background())
cmd.AddDynamicArguments("--test")
assert.ErrorIs(t, cmd.Run(&RunOpts{}), ErrBrokenCommand)
subCmd := "version"
cmd = NewCommand(context.Background()).AddDynamicArguments(subCmd) // for test purpose only, the sub-command should never be dynamic for production
stdout, stderr, err = cmd.RunStdString(&RunOpts{})
assert.NoError(t, err)
assert.Empty(t, stderr)
assert.Contains(t, stdout, "git version")
}
+1 -1
View File
@@ -163,7 +163,7 @@ func AllCommitsCount(ctx context.Context, repoPath string, hidePRRefs bool, file
// CommitsCountFiles returns number of total commits of until given revision.
func CommitsCountFiles(ctx context.Context, repoPath string, revision, relpath []string) (int64, error) {
cmd := NewCommand(ctx, "rev-list", "--count")
cmd.AddArguments(revision...)
cmd.AddDynamicArguments(revision...)
if len(relpath) > 0 {
cmd.AddArguments("--")
cmd.AddArguments(relpath...)
+2 -4
View File
@@ -68,8 +68,7 @@ func NewParser(r io.Reader, format Format) *Parser {
//
// It could, for example return something like:
//
// { "objecttype": "tag", "refname:short": "v1.16.4", "object": "f460b7543ed500e49c133c2cd85c8c55ee9dbe27" }
//
// { "objecttype": "tag", "refname:short": "v1.16.4", "object": "f460b7543ed500e49c133c2cd85c8c55ee9dbe27" }
func (p *Parser) Next() map[string]string {
if !p.scanner.Scan() {
return nil
@@ -89,8 +88,7 @@ func (p *Parser) Err() error {
// parseRef parses out all key-value pairs from a single reference block, such as
//
// "objecttype tag\0refname:short v1.16.4\0object f460b7543ed500e49c133c2cd85c8c55ee9dbe27"
//
// "objecttype tag\0refname:short v1.16.4\0object f460b7543ed500e49c133c2cd85c8c55ee9dbe27"
func (p *Parser) parseRef(refBlock string) (map[string]string, error) {
if refBlock == "" {
// must be at EOF
+14 -1
View File
@@ -287,7 +287,20 @@ func syncGitConfig() (err error) {
}
}
return nil
// By default partial clones are disabled, enable them from git v2.22
if !setting.Git.DisablePartialClone && CheckGitVersionAtLeast("2.22") == nil {
if err = configSet("uploadpack.allowfilter", "true"); err != nil {
return err
}
err = configSet("uploadpack.allowAnySHA1InWant", "true")
} else {
if err = configUnsetAll("uploadpack.allowfilter", "true"); err != nil {
return err
}
err = configUnsetAll("uploadpack.allowAnySHA1InWant", "true")
}
return err
}
// CheckGitVersionAtLeast check git version is at least the constraint version
+2 -2
View File
@@ -44,7 +44,7 @@ func parseTreeEntries(data []byte, ptree *Tree) ([]*TreeEntry, error) {
case "160000":
entry.entryMode = EntryModeCommit
pos += 14 // skip over "160000 object "
case "040000":
case "040000", "040755": // git uses 040000 for tree object, but some users may get 040755 for unknown reasons
entry.entryMode = EntryModeTree
pos += 12 // skip over "040000 tree "
default:
@@ -119,7 +119,7 @@ loop:
entry.entryMode = EntryModeSymlink
case "160000":
entry.entryMode = EntryModeCommit
case "40000":
case "40000", "40755": // git uses 40000 for tree object, but some users may get 40755 for unknown reasons
entry.entryMode = EntryModeTree
default:
log.Debug("Unknown mode: %v", string(mode))
+27 -1
View File
@@ -4,7 +4,10 @@
package git
import "strings"
import (
"regexp"
"strings"
)
const (
// RemotePrefix is the base directory of the remotes information of git.
@@ -15,6 +18,29 @@ const (
pullLen = len(PullPrefix)
)
// refNamePatternInvalid is regular expression with unallowed characters in git reference name
// They cannot have ASCII control characters (i.e. bytes whose values are lower than \040, or \177 DEL), space, tilde ~, caret ^, or colon : anywhere.
// They cannot have question-mark ?, asterisk *, or open bracket [ anywhere
var refNamePatternInvalid = regexp.MustCompile(
`[\000-\037\177 \\~^:?*[]|` + // No absolutely invalid characters
`(?:^[/.])|` + // Not HasPrefix("/") or "."
`(?:/\.)|` + // no "/."
`(?:\.lock$)|(?:\.lock/)|` + // No ".lock/"" or ".lock" at the end
`(?:\.\.)|` + // no ".." anywhere
`(?://)|` + // no "//" anywhere
`(?:@{)|` + // no "@{"
`(?:[/.]$)|` + // no terminal '/' or '.'
`(?:^@$)`) // Not "@"
// IsValidRefPattern ensures that the provided string could be a valid reference
func IsValidRefPattern(name string) bool {
return !refNamePatternInvalid.MatchString(name)
}
func SanitizeRefPattern(name string) string {
return refNamePatternInvalid.ReplaceAllString(name, "_")
}
// Reference represents a Git ref.
type Reference struct {
Name string
+2 -2
View File
@@ -191,8 +191,8 @@ func (c *CheckAttributeReader) Run() error {
// CheckPath check attr for given path
func (c *CheckAttributeReader) CheckPath(path string) (rs map[string]string, err error) {
defer func() {
if err != nil {
log.Error("CheckPath returns error: %v", err)
if err != nil && err != c.ctx.Err() {
log.Error("Unexpected error when checking path %s in %s. Error: %v", path, c.Repo.Path, err)
}
}()
+10 -9
View File
@@ -158,7 +158,7 @@ func (repo *Repository) searchCommits(id SHA1, opts SearchCommitsOptions) ([]*Co
// add previous arguments except for --grep and --all
hashCmd.AddArguments(args...)
// add keyword as <commit>
hashCmd.AddArguments(v)
hashCmd.AddDynamicArguments(v)
// search with given constraints for commit matching sha hash of v
hashMatching, _, err := hashCmd.RunStdBytes(&RunOpts{Dir: repo.Path})
@@ -208,14 +208,15 @@ func (repo *Repository) CommitsByFileAndRange(revision, file string, page int) (
}()
go func() {
stderr := strings.Builder{}
err := NewCommand(repo.Ctx, "log", revision, "--follow",
"--max-count="+strconv.Itoa(setting.Git.CommitsRangeSize*page),
prettyLogFormat, "--", file).
Run(&RunOpts{
Dir: repo.Path,
Stdout: stdoutWriter,
Stderr: &stderr,
})
gitCmd := NewCommand(repo.Ctx, "log", prettyLogFormat, "--follow",
"--max-count="+strconv.Itoa(setting.Git.CommitsRangeSize*page))
gitCmd.AddDynamicArguments(revision)
gitCmd.AddArguments("--", file)
err := gitCmd.Run(&RunOpts{
Dir: repo.Path,
Stdout: stdoutWriter,
Stderr: &stderr,
})
if err != nil {
_ = stdoutWriter.CloseWithError(ConcatenateError(err, (&stderr).String()))
} else {
+1 -1
View File
@@ -138,7 +138,7 @@ func (repo *Repository) getCommitFromBatchReader(rd *bufio.Reader, id SHA1) (*Co
// ConvertToSHA1 returns a Hash object from a potential ID string
func (repo *Repository) ConvertToSHA1(commitID string) (SHA1, error) {
if len(commitID) == 40 && SHAPattern.MatchString(commitID) {
if len(commitID) == 40 && IsValidSHAPattern(commitID) {
sha1, err := NewIDFromString(commitID)
if err == nil {
return sha1, nil
+1 -1
View File
@@ -40,7 +40,7 @@ func (repo *Repository) GetMergeBase(tmpRemote, base, head string) (string, stri
if tmpRemote != "origin" {
tmpBaseName := RemotePrefix + tmpRemote + "/tmp_" + base
// Fetch commit into a temporary branch in order to be able to handle commits and tags
_, _, err := NewCommand(repo.Ctx, "fetch", tmpRemote, base+":"+tmpBaseName).RunStdString(&RunOpts{Dir: repo.Path})
_, _, err := NewCommand(repo.Ctx, "fetch", "--no-tags", tmpRemote, "--", base+":"+tmpBaseName).RunStdString(&RunOpts{Dir: repo.Path})
if err == nil {
base = tmpBaseName
}
+4 -4
View File
@@ -59,15 +59,15 @@ func (repo *Repository) GetCodeActivityStats(fromTime time.Time, branch string)
_ = stdoutWriter.Close()
}()
args := []string{"log", "--numstat", "--no-merges", "--pretty=format:---%n%h%n%aN%n%aE%n", "--date=iso", fmt.Sprintf("--since='%s'", since)}
gitCmd := NewCommand(repo.Ctx, "log", "--numstat", "--no-merges", "--pretty=format:---%n%h%n%aN%n%aE%n", "--date=iso", fmt.Sprintf("--since='%s'", since))
if len(branch) == 0 {
args = append(args, "--branches=*")
gitCmd.AddArguments("--branches=*")
} else {
args = append(args, "--first-parent", branch)
gitCmd.AddArguments("--first-parent").AddDynamicArguments(branch)
}
stderr := new(strings.Builder)
err = NewCommand(repo.Ctx, args...).Run(&RunOpts{
err = gitCmd.Run(&RunOpts{
Env: []string{},
Dir: repo.Path,
Stdout: stdoutWriter,
+6 -1
View File
@@ -19,7 +19,12 @@ const EmptySHA = "0000000000000000000000000000000000000000"
const EmptyTreeSHA = "4b825dc642cb6eb9a060e54bf8d69288fbee4904"
// SHAPattern can be used to determine if a string is an valid sha
var SHAPattern = regexp.MustCompile(`^[0-9a-f]{4,40}$`)
var shaPattern = regexp.MustCompile(`^[0-9a-f]{4,40}$`)
// IsValidSHAPattern will check if the provided string matches the SHA Pattern
func IsValidSHAPattern(sha string) bool {
return shaPattern.MatchString(sha)
}
// MustID always creates a new SHA1 from a [20]byte array with no validation of input.
func MustID(b []byte) SHA1 {
+4 -2
View File
@@ -19,8 +19,10 @@ import (
type Signature = object.Signature
// Helper to get a signature from the commit line, which looks like these:
// author Patrick Gundlach <gundlach@speedata.de> 1378823654 +0200
// author Patrick Gundlach <gundlach@speedata.de> Thu, 07 Apr 2005 22:13:13 +0200
//
// author Patrick Gundlach <gundlach@speedata.de> 1378823654 +0200
// author Patrick Gundlach <gundlach@speedata.de> Thu, 07 Apr 2005 22:13:13 +0200
//
// but without the "author " at the beginning (this method should)
// be used for author and committer.
//
+4 -2
View File
@@ -37,8 +37,10 @@ func (s *Signature) Decode(b []byte) {
}
// Helper to get a signature from the commit line, which looks like these:
// author Patrick Gundlach <gundlach@speedata.de> 1378823654 +0200
// author Patrick Gundlach <gundlach@speedata.de> Thu, 07 Apr 2005 22:13:13 +0200
//
// author Patrick Gundlach <gundlach@speedata.de> 1378823654 +0200
// author Patrick Gundlach <gundlach@speedata.de> Thu, 07 Apr 2005 22:13:13 +0200
//
// but without the "author " at the beginning (this method should)
// be used for author and committer.
func newSignatureFromCommitline(line []byte) (sig *Signature, err error) {
+7 -12
View File
@@ -24,19 +24,17 @@ func GetCommitGraph(r *git.Repository, page, maxAllowedColors int, hidePRRefs bo
page = 1
}
args := make([]string, 0, 12+len(branches)+len(files))
args = append(args, "--graph", "--date-order", "--decorate=full")
graphCmd := git.NewCommand(r.Ctx, "log", "--graph", "--date-order", "--decorate=full")
if hidePRRefs {
args = append(args, "--exclude="+git.PullPrefix+"*")
graphCmd.AddArguments("--exclude=" + git.PullPrefix + "*")
}
if len(branches) == 0 {
args = append(args, "--all")
graphCmd.AddArguments("--all")
}
args = append(args,
graphCmd.AddArguments(
"-C",
"-M",
fmt.Sprintf("-n %d", setting.UI.GraphMaxCommitNum*page),
@@ -44,15 +42,12 @@ func GetCommitGraph(r *git.Repository, page, maxAllowedColors int, hidePRRefs bo
fmt.Sprintf("--pretty=format:%s", format))
if len(branches) > 0 {
args = append(args, branches...)
graphCmd.AddDynamicArguments(branches...)
}
args = append(args, "--")
if len(files) > 0 {
args = append(args, files...)
graphCmd.AddArguments("--")
graphCmd.AddArguments(files...)
}
graphCmd := git.NewCommand(r.Ctx, "log")
graphCmd.AddArguments(args...)
graph := NewGraph()
stderr := new(strings.Builder)
+2 -2
View File
@@ -114,9 +114,9 @@ func (g *Manager) start() {
// Execute makes Manager implement svc.Handler
func (g *Manager) Execute(args []string, changes <-chan svc.ChangeRequest, status chan<- svc.Status) (svcSpecificEC bool, exitCode uint32) {
if setting.StartupTimeout > 0 {
status <- svc.Status{State: svc.StartPending}
} else {
status <- svc.Status{State: svc.StartPending, WaitHint: uint32(setting.StartupTimeout / time.Millisecond)}
} else {
status <- svc.Status{State: svc.StartPending}
}
log.Trace("Awaiting server start-up")
+21 -24
View File
@@ -26,7 +26,7 @@ import (
)
// don't index files larger than this many bytes for performance purposes
const sizeLimit = 1000000
const sizeLimit = 1024 * 1024
var (
// For custom user mapping
@@ -58,7 +58,7 @@ func NewContext() {
func Code(fileName, language, code string) string {
NewContext()
// diff view newline will be passed as empty, change to literal \n so it can be copied
// diff view newline will be passed as empty, change to literal '\n' so it can be copied
// preserve literal newline in blame view
if code == "" || code == "\n" {
return "\n"
@@ -104,6 +104,11 @@ func Code(fileName, language, code string) string {
return CodeFromLexer(lexer, code)
}
type nopPreWrapper struct{}
func (nopPreWrapper) Start(code bool, styleAttr string) string { return "" }
func (nopPreWrapper) End(code bool) string { return "" }
// CodeFromLexer returns a HTML version of code string with chroma syntax highlighting classes
func CodeFromLexer(lexer chroma.Lexer, code string) string {
formatter := html.New(html.WithClasses(true),
@@ -126,9 +131,9 @@ func CodeFromLexer(lexer chroma.Lexer, code string) string {
return code
}
htmlw.Flush()
_ = htmlw.Flush()
// Chroma will add newlines for certain lexers in order to highlight them properly
// Once highlighted, strip them here so they don't cause copy/paste trouble in HTML output
// Once highlighted, strip them here, so they don't cause copy/paste trouble in HTML output
return strings.TrimSuffix(htmlbuf.String(), "\n")
}
@@ -141,7 +146,7 @@ func File(numLines int, fileName, language string, code []byte) []string {
}
formatter := html.New(html.WithClasses(true),
html.WithLineNumbers(false),
html.PreventSurroundingPre(true),
html.WithPreWrapper(nopPreWrapper{}),
)
if formatter == nil {
@@ -189,27 +194,19 @@ func File(numLines int, fileName, language string, code []byte) []string {
return plainText(string(code), numLines)
}
htmlw.Flush()
_ = htmlw.Flush()
finalNewLine := false
if len(code) > 0 {
finalNewLine = code[len(code)-1] == '\n'
}
m := make([]string, 0, numLines)
for _, v := range strings.SplitN(htmlbuf.String(), "\n", numLines) {
content := string(v)
// need to keep lines that are only \n so copy/paste works properly in browser
if content == "" {
content = "\n"
} else if content == `</span><span class="w">` {
content += "\n</span>"
} else if content == `</span></span><span class="line"><span class="cl">` {
content += "\n"
}
content = strings.TrimSuffix(content, `<span class="w">`)
content = strings.TrimPrefix(content, `</span>`)
m = append(m, content)
m := strings.SplitN(htmlbuf.String(), `</span></span><span class="line"><span class="cl">`, numLines)
if len(m) > 0 {
m[0] = m[0][len(`<span class="line"><span class="cl">`):]
last := m[len(m)-1]
m[len(m)-1] = last[:len(last)-len(`</span></span>`)]
}
if finalNewLine {
m = append(m, "<span class=\"w\">\n</span>")
}
@@ -219,14 +216,14 @@ func File(numLines int, fileName, language string, code []byte) []string {
// return unhiglighted map
func plainText(code string, numLines int) []string {
m := make([]string, 0, numLines)
for _, v := range strings.SplitN(string(code), "\n", numLines) {
content := string(v)
m := strings.SplitN(code, "\n", numLines)
for i, content := range m {
// need to keep lines that are only \n so copy/paste works properly in browser
if content == "" {
content = "\n"
}
m = append(m, gohtml.EscapeString(content))
m[i] = gohtml.EscapeString(content)
}
return m
}
+47 -25
View File
@@ -43,18 +43,29 @@ func TestFile(t *testing.T) {
- go test -v -race -coverprofile=coverage.txt -covermode=atomic
`),
want: util.Dedent(`
<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="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l">pipeline</span><span class="w">
</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="w"></span><span class="nt">steps</span><span class="p">:</span><span class="w">
</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="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="w"> </span><span class="nt">environment</span><span class="p">:</span><span class="w">
</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="w"> </span><span class="nt">commands</span><span class="p">:</span><span class="w">
</span>
<span class="w"></span><span class="w"> </span>- <span class="l">go get -u</span><span class="w">
</span>
<span class="w"> </span>- <span class="l">go build -v</span><span class="w">
</span>
<span class="w"> </span>- <span class="l">go test -v -race -coverprofile=coverage.txt -covermode=atomic</span>
`),
},
{
@@ -76,19 +87,30 @@ func TestFile(t *testing.T) {
- go test -v -race -coverprofile=coverage.txt -covermode=atomic
`)+"\n", "name: default", "name: default ", 1),
want: util.Dedent(`
<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="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l">pipeline</span><span class="w">
</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="w"></span><span class="nt">steps</span><span class="p">:</span><span class="w">
</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="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="w"> </span><span class="nt">environment</span><span class="p">:</span><span class="w">
</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="w"> </span><span class="nt">commands</span><span class="p">:</span><span class="w">
</span>
<span class="w"></span><span class="w"> </span>- <span class="l">go get -u</span><span class="w">
</span>
<span class="w"> </span>- <span class="l">go build -v</span><span class="w">
</span>
<span class="w"> </span>- <span class="l">go test -v -race -coverprofile=coverage.txt -covermode=atomic</span><span class="w">
</span>
<span class="w">
</span>
`),
+5
View File
@@ -78,6 +78,11 @@ func (hl *HostMatchList) AppendBuiltin(builtin string) {
hl.builtins = append(hl.builtins, builtin)
}
// AppendPattern appends more pattern to match
func (hl *HostMatchList) AppendPattern(pattern string) {
hl.patterns = append(hl.patterns, pattern)
}
// IsEmpty checks if the checklist is empty
func (hl *HostMatchList) IsEmpty() bool {
return hl == nil || (len(hl.builtins) == 0 && len(hl.patterns) == 0 && len(hl.ipNets) == 0)
+1
View File
@@ -93,6 +93,7 @@ func NewFileLogger() LoggerProvider {
// Init file logger with json config.
// config like:
//
// {
// "filename":"log/gogs.log",
// "maxsize":1<<30,
+3 -3
View File
@@ -33,7 +33,7 @@ func newLogger(name string, buffer int64) *MultiChannelledLogger {
func (l *MultiChannelledLogger) SetLogger(name, provider, config string) error {
eventLogger, err := NewChannelledLog(l.ctx, name, provider, config, l.bufferLength)
if err != nil {
return fmt.Errorf("Failed to create sublogger (%s): %v", name, err)
return fmt.Errorf("failed to create sublogger (%s): %w", name, err)
}
l.MultiChannelledLog.DelLogger(name)
@@ -41,9 +41,9 @@ func (l *MultiChannelledLogger) SetLogger(name, provider, config string) error {
err = l.MultiChannelledLog.AddLogger(eventLogger)
if err != nil {
if IsErrDuplicateName(err) {
return fmt.Errorf("Duplicate named sublogger %s %v", name, l.MultiChannelledLog.GetEventLoggerNames())
return fmt.Errorf("%w other names: %v", err, l.MultiChannelledLog.GetEventLoggerNames())
}
return fmt.Errorf("Failed to add sublogger (%s): %v", name, err)
return fmt.Errorf("failed to add sublogger (%s): %w", name, err)
}
return nil
+1
View File
@@ -48,6 +48,7 @@ func NewSMTPLogger() LoggerProvider {
// Init smtp writer with json config.
// config like:
//
// {
// "Username":"example@gmail.com",
// "password:"password",
+3 -1
View File
@@ -7,6 +7,7 @@ package markup_test
import (
"context"
"io"
"os"
"strings"
"testing"
@@ -32,6 +33,7 @@ func TestMain(m *testing.M) {
if err := git.InitSimple(context.Background()); err != nil {
log.Fatal("git init failed, err: %v", err)
}
os.Exit(m.Run())
}
func TestRender_Commits(t *testing.T) {
@@ -336,7 +338,7 @@ func TestRender_emoji(t *testing.T) {
`<p>Some text with <span class="emoji" aria-label="grinning face with smiling eyes">😄</span><span class="emoji" aria-label="grinning face with smiling eyes">😄</span> 2 emoji next to each other</p>`)
test(
"😎🤪🔐🤑❓",
`<p><span class="emoji" aria-label="smiling face with sunglasses">😎</span><span class="emoji" aria-label="zany face">🤪</span><span class="emoji" aria-label="locked with key">🔐</span><span class="emoji" aria-label="money-mouth face">🤑</span><span class="emoji" aria-label="question mark">❓</span></p>`)
`<p><span class="emoji" aria-label="smiling face with sunglasses">😎</span><span class="emoji" aria-label="zany face">🤪</span><span class="emoji" aria-label="locked with key">🔐</span><span class="emoji" aria-label="money-mouth face">🤑</span><span class="emoji" aria-label="red question mark">❓</span></p>`)
// should match nothing
test(
+2
View File
@@ -6,6 +6,7 @@ package markdown_test
import (
"context"
"os"
"strings"
"testing"
@@ -37,6 +38,7 @@ func TestMain(m *testing.M) {
if err := git.InitSimple(context.Background()); err != nil {
log.Fatal("git init failed, err: %v", err)
}
os.Exit(m.Run())
}
func TestRender_StandardLinks(t *testing.T) {
+2 -2
View File
@@ -141,7 +141,7 @@ func (r *stripRenderer) AddOptions(...renderer.Option) {
}
// StripMarkdown parses markdown content by removing all markup and code blocks
// in order to extract links and other references
// in order to extract links and other references
func StripMarkdown(rawBytes []byte) (string, []string) {
buf, links := StripMarkdownBytes(rawBytes)
return string(buf), links
@@ -153,7 +153,7 @@ var (
)
// StripMarkdownBytes parses markdown content by removing all markup and code blocks
// in order to extract links and other references
// in order to extract links and other references
func StripMarkdownBytes(rawBytes []byte) ([]byte, []string) {
once.Do(func() {
gdMarkdown := goldmark.New(
+5 -4
View File
@@ -26,7 +26,7 @@ type PullRequest struct {
Updated time.Time
Closed *time.Time
Labels []*Label
PatchURL string `yaml:"patch_url"`
PatchURL string `yaml:"patch_url"` // SECURITY: This must be safe to download directly from
Merged bool
MergedTime *time.Time `yaml:"merged_time"`
MergeCommitSHA string `yaml:"merge_commit_sha"`
@@ -37,6 +37,7 @@ type PullRequest struct {
Reactions []*Reaction
ForeignIndex int64
Context DownloaderContext `yaml:"-"`
EnsuredSafe bool `yaml:"ensured_safe"`
}
func (p *PullRequest) GetLocalIndex() int64 { return p.Number }
@@ -55,9 +56,9 @@ func (p PullRequest) GetGitRefName() string {
// PullRequestBranch represents a pull request branch
type PullRequestBranch struct {
CloneURL string `yaml:"clone_url"`
Ref string
SHA string
CloneURL string `yaml:"clone_url"` // SECURITY: This must be safe to download from
Ref string // SECURITY: this must be a git.IsValidRefPattern
SHA string // SECURITY: this must be a git.IsValidSHAPattern
RepoName string `yaml:"repo_name"`
OwnerName string `yaml:"owner_name"`
}
+5 -4
View File
@@ -18,15 +18,16 @@ type ReleaseAsset struct {
DownloadCount *int `yaml:"download_count"`
Created time.Time
Updated time.Time
DownloadURL *string `yaml:"download_url"`
DownloadURL *string `yaml:"download_url"` // SECURITY: It is the responsibility of downloader to make sure this is safe
// if DownloadURL is nil, the function should be invoked
DownloadFunc func() (io.ReadCloser, error) `yaml:"-"`
DownloadFunc func() (io.ReadCloser, error) `yaml:"-"` // SECURITY: It is the responsibility of downloader to make sure this is safe
}
// Release represents a release
type Release struct {
TagName string `yaml:"tag_name"`
TargetCommitish string `yaml:"target_commitish"`
TagName string `yaml:"tag_name"` // SECURITY: This must pass git.IsValidRefPattern
TargetCommitish string `yaml:"target_commitish"` // SECURITY: This must pass git.IsValidRefPattern
Name string
Body string
Draft bool
+1 -1
View File
@@ -12,7 +12,7 @@ type Repository struct {
IsPrivate bool `yaml:"is_private"`
IsMirror bool `yaml:"is_mirror"`
Description string
CloneURL string `yaml:"clone_url"`
CloneURL string `yaml:"clone_url"` // SECURITY: This must be checked to ensure that is safe to be used
OriginalURL string `yaml:"original_url"`
DefaultBranch string
}
+2 -2
View File
@@ -245,7 +245,7 @@ func getRedisTLSOptions(uri *url.URL) *tls.Config {
if len(skipverify) > 0 {
skipverify, err := strconv.ParseBool(skipverify)
if err != nil {
if err == nil {
tlsConfig.InsecureSkipVerify = skipverify
}
}
@@ -254,7 +254,7 @@ func getRedisTLSOptions(uri *url.URL) *tls.Config {
if len(insecureskipverify) > 0 {
insecureskipverify, err := strconv.ParseBool(insecureskipverify)
if err != nil {
if err == nil {
tlsConfig.InsecureSkipVerify = insecureskipverify
}
}
+18
View File
@@ -27,6 +27,24 @@ func TestRedisPasswordOpt(t *testing.T) {
}
}
func TestSkipVerifyOpt(t *testing.T) {
uri, _ := url.Parse("rediss://myredis/0?skipverify=true")
tlsConfig := getRedisTLSOptions(uri)
if !tlsConfig.InsecureSkipVerify {
t.Fail()
}
}
func TestInsecureSkipVerifyOpt(t *testing.T) {
uri, _ := url.Parse("rediss://myredis/0?insecureskipverify=true")
tlsConfig := getRedisTLSOptions(uri)
if !tlsConfig.InsecureSkipVerify {
t.Fail()
}
}
func TestRedisSentinelUsernameOpt(t *testing.T) {
uri, _ := url.Parse("redis+sentinel://redis:password@myredis/0?sentinelusername=suser&sentinelpassword=spass")
opts := getRedisOptions(uri).Failover()
+3 -1
View File
@@ -95,7 +95,9 @@ func parseOCIImageConfig(r io.Reader) (*Metadata, error) {
if i := strings.Index(cmd, "#(nop) "); i != -1 {
cmd = strings.TrimSpace(cmd[i+7:])
}
imageLayers = append(imageLayers, cmd)
if cmd != "" {
imageLayers = append(imageLayers, cmd)
}
}
metadata := &Metadata{
+5 -5
View File
@@ -27,21 +27,21 @@ func NewContentStore() *ContentStore {
// Get gets a package blob
func (s *ContentStore) Get(key BlobHash256Key) (storage.Object, error) {
return s.store.Open(keyToRelativePath(key))
return s.store.Open(KeyToRelativePath(key))
}
// Save stores a package blob
func (s *ContentStore) Save(key BlobHash256Key, r io.Reader, size int64) error {
_, err := s.store.Save(keyToRelativePath(key), r, size)
_, err := s.store.Save(KeyToRelativePath(key), r, size)
return err
}
// Delete deletes a package blob
func (s *ContentStore) Delete(key BlobHash256Key) error {
return s.store.Delete(keyToRelativePath(key))
return s.store.Delete(KeyToRelativePath(key))
}
// keyToRelativePath converts the sha256 key aabb000000... to aa/bb/aabb000000...
func keyToRelativePath(key BlobHash256Key) string {
// KeyToRelativePath converts the sha256 key aabb000000... to aa/bb/aabb000000...
func KeyToRelativePath(key BlobHash256Key) string {
return path.Join(string(key)[0:2], string(key)[2:4], string(key))
}
+47
View File
@@ -0,0 +1,47 @@
// 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 packages
import (
"fmt"
"io"
"strings"
"testing"
"github.com/stretchr/testify/assert"
)
func TestHashedBuffer(t *testing.T) {
cases := []struct {
MaxMemorySize int
Data string
HashMD5 string
HashSHA1 string
HashSHA256 string
HashSHA512 string
}{
{5, "test", "098f6bcd4621d373cade4e832627b4f6", "a94a8fe5ccb19ba61c4c0873d391e987982fbbd3", "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08", "ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67b143732c304cc5fa9ad8e6f57f50028a8ff"},
{5, "testtest", "05a671c66aefea124cc08b76ea6d30bb", "51abb9636078defbf888d8457a7c76f85c8f114c", "37268335dd6931045bdcdf92623ff819a64244b53d0e746d438797349d4da578", "125d6d03b32c84d492747f79cf0bf6e179d287f341384eb5d6d3197525ad6be8e6df0116032935698f99a09e265073d1d6c32c274591bf1d0a20ad67cba921bc"},
}
for _, c := range cases {
buf, err := CreateHashedBufferFromReader(strings.NewReader(c.Data), c.MaxMemorySize)
assert.NoError(t, err)
assert.EqualValues(t, len(c.Data), buf.Size())
data, err := io.ReadAll(buf)
assert.NoError(t, err)
assert.Equal(t, c.Data, string(data))
hashMD5, hashSHA1, hashSHA256, hashSHA512 := buf.Sums()
assert.Equal(t, c.HashMD5, fmt.Sprintf("%x", hashMD5))
assert.Equal(t, c.HashSHA1, fmt.Sprintf("%x", hashSHA1))
assert.Equal(t, c.HashSHA256, fmt.Sprintf("%x", hashSHA256))
assert.Equal(t, c.HashSHA512, fmt.Sprintf("%x", hashSHA512))
assert.NoError(t, buf.Close())
}
}
+1 -1
View File
@@ -25,7 +25,7 @@ func DumpMemProfileForUsername(pprofDataPath, username string) error {
}
// DumpCPUProfileForUsername dumps a CPU profile at pprofDataPath as cpuprofile_<username>_<temporary id>
// it returns the stop function which stops, writes and closes the CPU profile file
// the stop function it returns stops, writes and closes the CPU profile file
func DumpCPUProfileForUsername(pprofDataPath, username string) (func(), error) {
f, err := os.CreateTemp(pprofDataPath, fmt.Sprintf("cpuprofile_%s_", username))
if err != nil {
+5
View File
@@ -8,6 +8,7 @@ import (
"fmt"
"os"
"path/filepath"
"runtime"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/setting"
@@ -153,6 +154,10 @@ func createDelegateHooks(repoPath string) (err error) {
}
func checkExecutable(filename string) bool {
// windows has no concept of a executable bit
if runtime.GOOS == "windows" {
return true
}
fileInfo, err := os.Stat(filename)
if err != nil {
return false
+2 -2
View File
@@ -31,8 +31,8 @@ import (
)
/*
GitHub, GitLab, Gogs: *.wiki.git
BitBucket: *.git/wiki
GitHub, GitLab, Gogs: *.wiki.git
BitBucket: *.git/wiki
*/
var commonWikiURLSuffixes = []string{".wiki.git", ".git/wiki"}
+1
View File
@@ -48,6 +48,7 @@ var (
DefaultBranch string
AllowAdoptionOfUnadoptedRepositories bool
AllowDeleteOfUnadoptedRepositories bool
DisableDownloadSourceArchives bool
// Repository editor settings
Editor struct {
+3
View File
@@ -91,6 +91,8 @@ var (
// 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
// AssetVersion holds a opaque value that is used for cache-busting assets
AssetVersion string
// Server settings
Protocol Scheme
@@ -749,6 +751,7 @@ func loadFromConf(allowEmpty bool, extraConfig string) {
}
AbsoluteAssetURL = MakeAbsoluteAssetURL(AppURL, StaticURLPrefix)
AssetVersion = strings.ReplaceAll(AppVer, "+", "~") // make sure the version string is clear (no real escaping is needed)
manifestBytes := MakeManifestData(AppName, AppURL, AbsoluteAssetURL)
ManifestData = `application/json;base64,` + base64.StdEncoding.EncodeToString(manifestBytes)

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