Merge remote-tracking branch 'origin/main' into forgejo-federation

This commit is contained in:
Anthony Wang 2023-01-10 18:27:07 +00:00
commit c40dd620a3
Signed by: a
GPG key ID: 42A5B952E6DD8D38
393 changed files with 4192 additions and 3416 deletions

View file

@ -5,6 +5,6 @@ tmp_dir = ".air"
cmd = "make backend"
bin = "gitea"
include_ext = ["go", "tmpl"]
exclude_dir = ["modules/git/tests", "services/gitdiff/testdata", "modules/avatar/testdata"]
include_dir = ["cmd", "models", "modules", "options", "routers", "services", "templates"]
exclude_dir = ["modules/git/tests", "services/gitdiff/testdata", "modules/avatar/testdata", "models/fixtures", "models/migrations/fixtures", "modules/migration/file_format_testdata", "modules/avatar/identicon/testdata"]
include_dir = ["cmd", "models", "modules", "options", "routers", "services"]
exclude_regex = ["_test.go$", "_gen.go$"]

View file

@ -4,7 +4,203 @@ 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.4](https://github.com/go-gitea/gitea/releases/tag/1.17.4) - 2022-12-21
## [1.18.0](https://github.com/go-gitea/gitea/releases/tag/v1.18.0) - 2022-12-29
* SECURITY
* Remove ReverseProxy authentication from the API (#22219) (#22251)
* Support Go Vulnerability Management (#21139)
* Forbid HTML string tooltips (#20935)
* BREAKING
* Rework mailer settings (#18982)
* Remove U2F support (#20141)
* Refactor `i18n` to `locale` (#20153)
* Enable contenthash in filename for dynamic assets (#20813)
* FEATURES
* Add color previews in markdown (#21474)
* Allow package version sorting (#21453)
* Add support for Chocolatey/NuGet v2 API (#21393)
* Add API endpoint to get changed files of a PR (#21177)
* Add filetree on left of diff view (#21012)
* Support Issue forms and PR forms (#20987)
* Add support for Vagrant packages (#20930)
* Add support for `npm unpublish` (#20688)
* Add badge capabilities to users (#20607)
* Add issue filter for Author (#20578)
* Add KaTeX rendering to Markdown. (#20571)
* Add support for Pub packages (#20560)
* Support localized README (#20508)
* Add support mCaptcha as captcha provider (#20458)
* Add team member invite by email (#20307)
* Added email notification option to receive all own messages (#20179)
* Switch Unicode Escaping to a VSCode-like system (#19990)
* Add user/organization code search (#19977)
* Only show relevant repositories on explore page (#19361)
* User keypairs and HTTP signatures for ActivityPub federation using go-ap (#19133)
* Add sitemap support (#18407)
* Allow creation of OAuth2 applications for orgs (#18084)
* Add system setting table with cache and also add cache supports for user setting (#18058)
* Add pages to view watched repos and subscribed issues/PRs (#17156)
* Support Proxy protocol (#12527)
* Implement sync push mirror on commit (#19411)
* API
* Allow empty assignees on pull request edit (#22150) (#22214)
* Make external issue tracker regexp configurable via API (#21338)
* Add name field for org api (#21270)
* Show teams with no members if user is admin (#21204)
* Add latest commit's SHA to content response (#20398)
* Add allow_rebase_update, default_delete_branch_after_merge to repository api response (#20079)
* Add new endpoints for push mirrors management (#19841)
* ENHANCEMENTS
* Add setting to disable the git apply step in test patch (#22130) (#22170)
* Multiple improvements for comment edit diff (#21990) (#22007)
* Fix button in branch list, avoid unexpected page jump before restore branch actually done (#21562) (#21928)
* Fix flex layout for repo list icons (#21896) (#21920)
* Fix vertical align of committer avatar rendered by email address (#21884) (#21918)
* Fix setting HTTP headers after write (#21833) (#21877)
* Color and Style enhancements (#21784, #21799) (#21868)
* Ignore line anchor links with leading zeroes (#21728) (#21776)
* Quick fixes monaco-editor error: "vs.editor.nullLanguage" (#21734) (#21738)
* Use CSS color-scheme instead of invert (#21616) (#21623)
* Respect user's locale when rendering the date range in the repo activity page (#21410)
* Change `commits-table` column width (#21564)
* Refactor git command arguments and make all arguments to be safe to be used (#21535)
* CSS color enhancements (#21534)
* Add link to user profile in markdown mention only if user exists (#21533, #21554)
* Add option to skip index dirs (#21501)
* Diff file tree tweaks (#21446)
* Localize all timestamps (#21440)
* Add `code` highlighting in issue titles (#21432)
* Use Name instead of DisplayName in LFS Lock (#21415)
* Consolidate more CSS colors into variables (#21402)
* Redirect to new repository owner (#21398)
* Use ISO date format instead of hard-coded English date format for date range in repo activity page (#21396)
* Use weighted algorithm for string matching when finding files in repo (#21370)
* Show private data in feeds (#21369)
* Refactor parseTreeEntries, speed up tree list (#21368)
* Add GET and DELETE endpoints for Docker blob uploads (#21367)
* Add nicer error handling on template compile errors (#21350)
* Add `stat` to `ToCommit` function for speed (#21337)
* Support instance-wide OAuth2 applications (#21335)
* Record OAuth client type at registration (#21316)
* Add new CSS variables --color-accent and --color-small-accent (#21305)
* Improve error descriptions for unauthorized_client (#21292)
* Case-insensitive "find files in repo" (#21269)
* Consolidate more CSS rules, fix inline code on arc-green (#21260)
* Log real ip of requests from ssh (#21216)
* Save files in local storage as group readable (#21198)
* Enable fluid page layout on medium size viewports (#21178)
* File header tweaks (#21175)
* Added missing headers on user packages page (#21172)
* Display image digest for container packages (#21170)
* Skip dirty check for team forms (#21154)
* Keep path when creating a new branch (#21153)
* Remove fomantic image module (#21145)
* Make labels clickable in the comments section. (#21137)
* Sort branches and tags by date descending (#21136)
* Better repo API unit checks (#21130)
* Improve commit status icons (#21124)
* Limit length of repo description and repo url input fields (#21119)
* Show .editorconfig errors in frontend (#21088)
* Allow poster to choose reviewers (#21084)
* Remove black labels and CSS cleanup (#21003)
* Make e-mail sanity check more precise (#20991)
* Use native inputs in whitespace dropdown (#20980)
* Enhance package date display (#20928)
* Display total blob size of a package version (#20927)
* Show language name on hover (#20923)
* Show instructions for all generic package files (#20917)
* Refactor AssertExistsAndLoadBean to use generics (#20797)
* Move the official website link at the footer of gitea (#20777)
* Add support for full name in reverse proxy auth (#20776)
* Remove useless JS operation for relative time tooltips (#20756)
* Replace some icons with SVG (#20741)
* Change commit status icons to SVG (#20736)
* Improve single repo action for issue and pull requests (#20730)
* Allow multiple files in generic packages (#20661)
* Add option to create new issue from /issues page (#20650)
* Background color of private list-items updated (#20630)
* Added search input field to issue filter (#20623)
* Increase default item listing size `ISSUE_PAGING_NUM` to 20 (#20547)
* Modify milestone search keywords to be case insensitive again (#20513)
* Show hint to link package to repo when viewing empty repo package list (#20504)
* Add Tar ZSTD support (#20493)
* Make code review checkboxes clickable (#20481)
* Add "X-Gitea-Object-Type" header for GET `/raw/` & `/media/` API (#20438)
* Display project in issue list (#20434)
* Prepend commit message to template content when opening a new PR (#20429)
* Replace fomantic popup module with tippy.js (#20428)
* Allow to specify colors for text in markup (#20363)
* Allow access to the Public Organization Member lists with minimal permissions (#20330)
* Use default values when provided values are empty (#20318)
* Vertical align navbar avatar at middle (#20302)
* Delete cancel button in repo creation page (#21381)
* Include login_name in adminCreateUser response (#20283)
* fix: icon margin in user/settings/repos (#20281)
* Remove blue text on migrate page (#20273)
* Modify milestone search keywords to be case insensitive (#20266)
* Move some files into models' sub packages (#20262)
* Add tooltip to repo icons in explore page (#20241)
* Remove deprecated licenses (#20222)
* Webhook for Wiki changes (#20219)
* Share HTML template renderers and create a watcher framework (#20218)
* Allow enable LDAP source and disable user sync via CLI (#20206)
* Adds a checkbox to select all issues/PRs (#20177)
* Refactor `i18n` to `locale` (#20153)
* Disable status checks in template if none found (#20088)
* Allow manager logging to set SQL (#20064)
* Add order by for assignee no sort issue (#20053)
* Take a stab at porting existing components to Vue3 (#20044)
* Add doctor command to write commit-graphs (#20007)
* Add support for authentication based on reverse proxy email (#19949)
* Enable spellcheck for EasyMDE, use contenteditable mode (#19776)
* Allow specifying SECRET_KEY_URI, similar to INTERNAL_TOKEN_URI (#19663)
* Rework mailer settings (#18982)
* Add option to purge users (#18064)
* Add author search input (#21246)
* Make rss/atom identifier globally unique (#21550)
* BUGFIXES
* Auth interface return error when verify failure (#22119) (#22259)
* Use complete SHA to create and query commit status (#22244) (#22257)
* Update bleve and zapx to fix unaligned atomic (#22031) (#22218)
* Prevent panic in doctor command when running default checks (#21791) (#21807)
* Load GitRepo in API before deleting issue (#21720) (#21796)
* Ignore line anchor links with leading zeroes (#21728) (#21776)
* Set last login when activating account (#21731) (#21755)
* Fix UI language switching bug (#21597) (#21749)
* Quick fixes monaco-editor error: "vs.editor.nullLanguage" (#21734) (#21738)
* Allow local package identifiers for PyPI packages (#21690) (#21727)
* Deal with markdown template without metadata (#21639) (#21654)
* Fix opaque background on mermaid diagrams (#21642) (#21652)
* Fix repository adoption on Windows (#21646) (#21650)
* Sync git hooks when config file path changed (#21619) (#21626)
* Fix 500 on PR files API (#21602) (#21607)
* Fix `Timestamp.IsZero` (#21593) (#21603)
* Fix viewing user subscriptions (#21482)
* Fix mermaid-related bugs (#21431)
* Fix branch dropdown shifting on page load (#21428)
* Fix default theme-auto selector when nologin (#21346)
* Fix and improve incorrect error messages (#21342)
* Fix formatted link for PR review notifications to matrix (#21319)
* Center-aligning content of WebAuthN page (#21127)
* Remove follow from commits by file (#20765)
* Fix commit status popup (#20737)
* Fix init mail render logic (#20704)
* Use correct page size for link header pagination (#20546)
* Preserve unix socket file (#20499)
* Use tippy.js for context popup (#20393)
* Add missing parameter for error in log message (#20144)
* Do not allow organisation owners add themselves as collaborator (#20043)
* Rework file highlight rendering and fix yaml copy-paste (#19967)
* Improve code diff highlight, fix incorrect rendered diff result (#19958)
* TESTING
* Improve OAuth integration tests (#21390)
* Add playwright tests (#20123)
* BUILD
* Switch to building with go1.19 (#20695)
* Update JS dependencies, adjust eslint (#20659)
* Add more linters to improve code readability (#19989)
## [1.17.4](https://github.com/go-gitea/gitea/releases/tag/v1.17.4) - 2022-12-21
* SECURITY
* Do not allow Ghost access to limited visible user/org (#21849) (#21875)

View file

@ -190,6 +190,8 @@ To maintain understandable code and avoid circular dependencies it is important
- **templates:** Golang templates for generating the html output.
- **tests/e2e:** End to end tests
- **tests/integration:** Integration tests
- **tests/gitea-repositories-meta:** Sample repos used in integration tests. Adding a new repo requires editing `models/fixtures/repositories.yml` and `models/fixtures/repo_unit.yml` to match.
- **tests/gitea-lfs-meta:** Sample LFS objects used in integration tests. Adding a new object requires editing `models/fixtures/lfs_meta_object.yml` to match.
- **vendor:** External code that Gitea depends on.
## Documentation
@ -439,7 +441,7 @@ be reviewed by two maintainers and must pass the automatic tests.
Code that you contribute should use the standard copyright header:
```
// Copyright 2022 The Gitea Authors. All rights reserved.
// Copyright <year> The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
```

View file

@ -359,7 +359,7 @@ watch-frontend: node-check node_modules
.PHONY: watch-backend
watch-backend: go-check
$(GO) run $(AIR_PACKAGE) -c .air.toml
GITEA_RUN_MODE=dev $(GO) run $(AIR_PACKAGE) -c .air.toml
.PHONY: test
test: test-frontend test-backend

2
assets/emoji.json generated

File diff suppressed because one or more lines are too long

View file

@ -25,7 +25,7 @@ import (
const (
gemojiURL = "https://raw.githubusercontent.com/github/gemoji/master/db/emoji.json"
maxUnicodeVersion = 12
maxUnicodeVersion = 14
)
var flagOut = flag.String("o", "modules/emoji/emoji_data.go", "out")
@ -189,6 +189,10 @@ func generate() ([]byte, error) {
}
}
sort.Slice(data, func(i, j int) bool {
return data[i].Aliases[0] < data[j].Aliases[0]
})
// add header
str := replacer.Replace(fmt.Sprintf(hdr, gemojiURL, data))

View file

@ -10,13 +10,13 @@ import (
"os"
"strings"
"code.gitea.io/gitea/modules/convert"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
base "code.gitea.io/gitea/modules/migration"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/services/convert"
"code.gitea.io/gitea/services/migrations"
"github.com/urfave/cli"

View file

@ -957,6 +957,9 @@ ROUTER = console
;; Don't allow download source archive files from UI
;DISABLE_DOWNLOAD_SOURCE_ARCHIVES = false
;; Allow fork repositories without maximum number limit
;ALLOW_FORK_WITHOUT_MAXIMUM_LIMIT = true
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;[repository.editor]

View file

@ -18,10 +18,10 @@ params:
description: Git with a cup of tea
author: The Gitea Authors
website: https://docs.gitea.io
version: 1.17.4
version: 1.18.0
minGoVersion: 1.18
goVersion: 1.19
minNodeVersion: 14
minNodeVersion: 16
search: nav
repo: "https://github.com/go-gitea/gitea"
docContentPath: "docs/content"

View file

@ -112,6 +112,7 @@ In addition there is _`StaticRootPath`_ which can be set as a built-in at build
- `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
- `ALLOW_FORK_WITHOUT_MAXIMUM_LIMIT`: **true**: Allow fork repositories without maximum number limit
### Repository - Editor (`repository.editor`)
@ -239,6 +240,10 @@ The following configuration set `Content-Type: application/vnd.android.package-a
- `NOTICE_PAGING_NUM`: **25**: Number of notices that are shown in one page.
- `ORG_PAGING_NUM`: **50**: Number of organizations that are shown in one page.
### UI - User (`ui.user`)
- `REPO_PAGING_NUM`: **15**: Number of repos that are shown in one page.
### UI - Metadata (`ui.meta`)
- `AUTHOR`: **Gitea - Git with a cup of tea**: Author meta tag of the homepage.
@ -777,9 +782,9 @@ and
- `GRAVATAR_SOURCE`: **gravatar**: Can be `gravatar`, `duoshuo` or anything like
`http://cn.gravatar.com/avatar/`.
- `DISABLE_GRAVATAR`: **false**: Enable this to use local avatars only.
- `DISABLE_GRAVATAR`: **false**: Enable this to use local avatars only. **DEPRECATED [v1.18+]** moved to database. Use admin panel to configure.
- `ENABLE_FEDERATED_AVATAR`: **false**: Enable support for federated avatars (see
[http://www.libravatar.org](http://www.libravatar.org)).
[http://www.libravatar.org](http://www.libravatar.org)). **DEPRECATED [v1.18+]** moved to database. Use admin panel to configure.
- `AVATAR_STORAGE_TYPE`: **default**: Storage type defined in `[storage.xxx]`. Default is `default` which will read `[storage]` if no section `[storage]` will be a type `local`.
- `AVATAR_UPLOAD_PATH`: **data/avatars**: Path to store user avatar image files.
@ -1145,7 +1150,7 @@ in this mapping or the filetype using heuristics.
## Time (`time`)
- `FORMAT`: Time format to display on UI. i.e. RFC1123 or 2006-01-02 15:04:05
- `DEFAULT_UI_LOCATION`: Default location of time on the UI, so that we can display correct user's time on UI. i.e. Shanghai/Asia
- `DEFAULT_UI_LOCATION`: Default location of time on the UI, so that we can display correct user's time on UI. i.e. Asia/Shanghai
## Task (`task`)

View file

@ -43,6 +43,14 @@ Arch Linux ARM provides packages for [aarch64](https://archlinuxarm.org/packages
pacman -S gitea
```
## Gentoo Linux
The rolling release distribution has [Gitea](https://packages.gentoo.org/packages/www-apps/gitea) in their official community repository and package updates are provided with new Gitea releases.
```sh
emerge gitea -va
```
## Canonical Snap
There is a [Gitea Snap](https://snapcraft.io/gitea) package which follows the latest stable version.

View file

@ -76,12 +76,15 @@ The following configuration should work with GMail's SMTP server:
```ini
[mailer]
ENABLED = true
HOST = smtp.gmail.com:465 ; Remove this line for Gitea >= 1.18.0
SMTP_ADDR = smtp.gmail.com
SMTP_PORT = 465
FROM = example@gmail.com
USER = example@gmail.com
FROM = example.user@gmail.com
USER = example.user
PASSWD = ***
MAILER_TYPE = smtp
IS_TLS_ENABLED = true
HELO_HOSTNAME = example.com
```
Note that you'll need to create and use an [App password](https://support.google.com/accounts/answer/185833?hl=en) by enabling 2FA on your Google
account. You won't be able to use your Google account password directly.

View file

@ -1,5 +1,5 @@
---
date: "2016-11-08T16:00:00+02:00"
date: "2023-01-07T22:03:00+01:00"
title: "Dokumentation"
slug: "documentation"
url: "/de-de/"
@ -27,11 +27,11 @@ Gitea ist ein [Gogs](http://gogs.io)-Fork.
* 2 CPU Kerne und 1GB RAM sind für kleine Teams/Projekte ausreichend.
* Gitea sollte unter einem seperaten nicht-root Account auf UNIX-Systemen ausgeführt werden.
* Achtung: Gitea verwaltet die `~/.ssh/authorized_keys` Datei. Gitea unter einem normalen Benutzer auszuführen könnte dazu führen, dass dieser sich nicht mehr anmelden kann.
* [Git](https://git-scm.com/) Version 2.0 oder später wird benötigt.
* Wenn git >= 2.1.2. und [Git large file storage](https://git-lfs.github.com/) aktiviert ist, dann wird es auch in Gitea verwendbar sein.
* Wenn git >= 2.18, dann wird das Rendern von Commit-Graphen automatisch aktiviert.
* [Git](https://git-scm.com/) Version 2.0 oder aktueller wird benötigt.
* Wenn Git >= 2.1.2 und [Git LFS](https://git-lfs.github.com/) vorhanden ist, dann wird Git LFS Support automatisch für Gitea aktiviert.
* Wenn Git >= 2.18, dann wird das Rendern von Commit-Graphen automatisch aktiviert.
## Browser Unterstützung
* Letzten 2 Versions von Chrome, Firefox, Safari und Edge
* Die neuesten zwei Versionen von Chrome, Firefox, Safari und Edge
* Firefox ESR

6
go.mod
View file

@ -33,7 +33,7 @@ require (
github.com/gliderlabs/ssh v0.3.5
github.com/go-ap/activitypub v0.0.0-20220917143152-e4e7018838c0
github.com/go-ap/jsonld v0.0.0-20221030091449-f2a191312c73
github.com/go-chi/chi/v5 v5.0.7
github.com/go-chi/chi/v5 v5.0.8
github.com/go-chi/cors v1.2.1
github.com/go-enry/go-enry/v2 v2.8.3
github.com/go-fed/httpsig v1.1.1-0.20201223112313-55836744818e
@ -303,8 +303,6 @@ replace github.com/hashicorp/go-version => github.com/6543/go-version v1.3.1
replace github.com/shurcooL/vfsgen => github.com/lunny/vfsgen v0.0.0-20220105142115-2c99e1ffdfa0
replace github.com/satori/go.uuid v1.2.0 => github.com/gofrs/uuid v4.2.0+incompatible
replace github.com/go-ap/activitypub => gitea.com/xy/activitypub v0.0.0-20221126171442-81405e14ea3b
replace github.com/blevesearch/zapx/v15 v15.3.6 => github.com/zeripath/zapx/v15 v15.3.6-alignment-fix
@ -314,3 +312,5 @@ exclude github.com/gofrs/uuid v3.2.0+incompatible
exclude github.com/gofrs/uuid v4.0.0+incompatible
exclude github.com/goccy/go-json v0.4.11
exclude github.com/satori/go.uuid v1.2.0

5
go.sum
View file

@ -475,8 +475,8 @@ github.com/go-asn1-ber/asn1-ber v1.5.4 h1:vXT6d/FNDiELJnLb6hGNa309LMsrCoYFvpwHDF
github.com/go-asn1-ber/asn1-ber v1.5.4/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
github.com/go-chi/chi/v5 v5.0.1/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
github.com/go-chi/chi/v5 v5.0.4/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
github.com/go-chi/chi/v5 v5.0.7 h1:rDTPXLDHGATaeHvVlLcR4Qe0zftYethFucbjVQ1PxU8=
github.com/go-chi/chi/v5 v5.0.7/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
github.com/go-chi/chi/v5 v5.0.8 h1:lD+NLqFcAi1ovnVZpsnObHGW4xb4J8lNmoYVfECH1Y0=
github.com/go-chi/chi/v5 v5.0.8/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4=
github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
github.com/go-enry/go-enry/v2 v2.8.3 h1:BwvNrN58JqBJhyyVdZSl5QD3xoxEEGYUrRyPh31FGhw=
@ -596,7 +596,6 @@ github.com/goccy/go-json v0.10.0 h1:mXKd9Qw4NuzShiRlOXKews24ufknHO7gx30lsDyokKA=
github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=

View file

@ -272,7 +272,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.IsValidSHAPattern(a.RefName):
case len(a.RefName) == git.SHAFullLength && 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.

View file

@ -141,7 +141,7 @@ func CountNotifications(ctx context.Context, opts *FindNotificationOptions) (int
// CreateRepoTransferNotification creates notification for the user a repository was transferred to
func CreateRepoTransferNotification(ctx context.Context, doer, newOwner *user_model.User, repo *repo_model.Repository) error {
return db.AutoTx(ctx, func(ctx context.Context) error {
return db.WithTx(ctx, func(ctx context.Context) error {
var notify []*Notification
if newOwner.IsOrganization() {

View file

@ -64,11 +64,16 @@ 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
return PaddedKeyID(key.KeyID)
}
// PaddedKeyID show KeyID padded to 16 characters
func PaddedKeyID(keyID string) string {
if len(keyID) > 15 {
return keyID
}
zeros := "0000000000000000"
return zeros[0:16-len(key.KeyID)] + key.KeyID
return zeros[0:16-len(keyID)] + keyID
}
// ListGPGKeys returns a list of public keys belongs to given user.

View file

@ -5,7 +5,6 @@ package asymkey
import (
"context"
"errors"
"fmt"
"strings"
@ -59,9 +58,9 @@ func calcFingerprintSSHKeygen(publicKeyContent string) (string, error) {
if strings.Contains(stderr, "is not a public key file") {
return "", ErrKeyUnableVerify{stderr}
}
return "", fmt.Errorf("'ssh-keygen -lf %s' failed with error '%s': %s", tmpPath, err, stderr)
return "", util.NewInvalidArgumentErrorf("'ssh-keygen -lf %s' failed with error '%s': %s", tmpPath, err, stderr)
} else if len(stdout) < 2 {
return "", errors.New("not enough output for calculating fingerprint: " + stdout)
return "", util.NewInvalidArgumentErrorf("not enough output for calculating fingerprint: %s", stdout)
}
return strings.Split(stdout, " ")[1], nil
}

View file

@ -10,7 +10,6 @@ import (
"encoding/base64"
"encoding/binary"
"encoding/pem"
"errors"
"fmt"
"math/big"
"os"
@ -122,7 +121,7 @@ func parseKeyString(content string) (string, error) {
parts := strings.SplitN(content, " ", 3)
switch len(parts) {
case 0:
return "", errors.New("empty key")
return "", util.NewInvalidArgumentErrorf("empty key")
case 1:
keyContent = parts[0]
case 2:
@ -167,7 +166,7 @@ func CheckPublicKeyString(content string) (_ string, err error) {
content = strings.TrimRight(content, "\n\r")
if strings.ContainsAny(content, "\n\r") {
return "", errors.New("only a single line with a single key please")
return "", util.NewInvalidArgumentErrorf("only a single line with a single key please")
}
// remove any unnecessary whitespace now

View file

@ -4,7 +4,6 @@
package asymkey
import (
"errors"
"fmt"
"strings"
@ -12,6 +11,7 @@ import (
"code.gitea.io/gitea/models/perm"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
)
// __________ .__ .__ .__
@ -70,7 +70,7 @@ func CheckPrincipalKeyString(user *user_model.User, content string) (_ string, e
content = strings.TrimSpace(content)
if strings.ContainsAny(content, "\r\n") {
return "", errors.New("only a single line with a single principal please")
return "", util.NewInvalidArgumentErrorf("only a single line with a single principal please")
}
// check all the allowed principals, email, username or anything

View file

@ -153,8 +153,7 @@ func generateEmailAvatarLink(email string, size int, final bool) string {
return DefaultAvatarLink()
}
enableFederatedAvatarSetting, _ := system_model.GetSetting(system_model.KeyPictureEnableFederatedAvatar)
enableFederatedAvatar := enableFederatedAvatarSetting.GetValueBool()
enableFederatedAvatar := system_model.GetSettingBool(system_model.KeyPictureEnableFederatedAvatar)
var err error
if enableFederatedAvatar && system_model.LibravatarService != nil {
@ -175,9 +174,7 @@ func generateEmailAvatarLink(email string, size int, final bool) string {
return urlStr
}
disableGravatarSetting, _ := system_model.GetSetting(system_model.KeyPictureDisableGravatar)
disableGravatar := disableGravatarSetting.GetValueBool()
disableGravatar := system_model.GetSettingBool(system_model.KeyPictureDisableGravatar)
if !disableGravatar {
// copy GravatarSourceURL, because we will modify its Path.
avatarURLCopy := *system_model.GravatarSourceURL

View file

@ -71,6 +71,14 @@ type Engined interface {
// GetEngine will get a db Engine from this context or return an Engine restricted to this context
func GetEngine(ctx context.Context) Engine {
if e := getEngine(ctx); e != nil {
return e
}
return x.Context(ctx)
}
// getEngine will get a db Engine from this context or return nil
func getEngine(ctx context.Context) Engine {
if engined, ok := ctx.(Engined); ok {
return engined.Engine()
}
@ -78,7 +86,7 @@ func GetEngine(ctx context.Context) Engine {
if enginedInterface != nil {
return enginedInterface.(Engined).Engine()
}
return x.Context(ctx)
return nil
}
// Committer represents an interface to Commit or Close the Context
@ -87,10 +95,34 @@ type Committer interface {
Close() error
}
// TxContext represents a transaction Context
// halfCommitter is a wrapper of Committer.
// It can be closed early, but can't be committed early, it is useful for reusing a transaction.
type halfCommitter struct {
committer Committer
committed bool
}
func (c *halfCommitter) Commit() error {
c.committed = true
// should do nothing, and the parent committer will commit later
return nil
}
func (c *halfCommitter) Close() error {
if c.committed {
// it's "commit and close", should do nothing, and the parent committer will commit later
return nil
}
// it's "rollback and close", let the parent committer rollback right now
return c.committer.Close()
}
// TxContext represents a transaction Context,
// it will reuse the existing transaction in the parent context or create a new one.
func TxContext(parentCtx context.Context) (*Context, Committer, error) {
if InTransaction(parentCtx) {
return nil, nil, ErrAlreadyInTransaction
if sess, ok := inTransaction(parentCtx); ok {
return newContext(parentCtx, sess, true), &halfCommitter{committer: sess}, nil
}
sess := x.NewSession()
@ -102,20 +134,16 @@ func TxContext(parentCtx context.Context) (*Context, Committer, error) {
return newContext(DefaultContext, sess, true), sess, nil
}
// WithTx represents executing database operations on a transaction
// This function will always open a new transaction, if a transaction exist in parentCtx return an error.
func WithTx(parentCtx context.Context, f func(ctx context.Context) error) error {
if InTransaction(parentCtx) {
return ErrAlreadyInTransaction
}
return txWithNoCheck(parentCtx, f)
}
// AutoTx represents executing database operations on a transaction, if the transaction exist,
// WithTx represents executing database operations on a transaction, if the transaction exist,
// this function will reuse it otherwise will create a new one and close it when finished.
func AutoTx(parentCtx context.Context, f func(ctx context.Context) error) error {
if InTransaction(parentCtx) {
return f(newContext(parentCtx, GetEngine(parentCtx), true))
func WithTx(parentCtx context.Context, f func(ctx context.Context) error) error {
if sess, ok := inTransaction(parentCtx); ok {
err := f(newContext(parentCtx, sess, true))
if err != nil {
// rollback immediately, in case the caller ignores returned error and tries to commit the transaction.
_ = sess.Close()
}
return err
}
return txWithNoCheck(parentCtx, f)
}
@ -188,7 +216,10 @@ func EstimateCount(ctx context.Context, bean interface{}) (int64, error) {
case schemas.MYSQL:
_, err = e.Context(ctx).SQL("SELECT table_rows FROM information_schema.tables WHERE tables.table_name = ? AND tables.table_schema = ?;", tablename, x.Dialect().URI().DBName).Get(&rows)
case schemas.POSTGRES:
_, err = e.Context(ctx).SQL("SELECT reltuples AS estimate FROM pg_class WHERE relname = ?;", tablename).Get(&rows)
// the table can live in multiple schemas of a postgres database
// See https://wiki.postgresql.org/wiki/Count_estimate
tablename = x.TableName(bean, true)
_, err = e.Context(ctx).SQL("SELECT reltuples::bigint AS estimate FROM pg_class WHERE oid = ?::regclass;", tablename).Get(&rows)
case schemas.MSSQL:
_, err = e.Context(ctx).SQL("sp_spaceused ?;", tablename).Get(&rows)
default:
@ -199,25 +230,25 @@ func EstimateCount(ctx context.Context, bean interface{}) (int64, error) {
// InTransaction returns true if the engine is in a transaction otherwise return false
func InTransaction(ctx context.Context) bool {
var e Engine
if engined, ok := ctx.(Engined); ok {
e = engined.Engine()
} else {
enginedInterface := ctx.Value(enginedContextKey)
if enginedInterface != nil {
e = enginedInterface.(Engined).Engine()
}
}
_, ok := inTransaction(ctx)
return ok
}
func inTransaction(ctx context.Context) (*xorm.Session, bool) {
e := getEngine(ctx)
if e == nil {
return false
return nil, false
}
switch t := e.(type) {
case *xorm.Engine:
return false
return nil, false
case *xorm.Session:
return t.IsInTx()
if t.IsInTx() {
return t, true
}
return nil, false
default:
return false
return nil, false
}
}

View file

@ -0,0 +1,102 @@
// Copyright 2022 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package db // it's not db_test, because this file is for testing the private type halfCommitter
import (
"fmt"
"testing"
"github.com/stretchr/testify/assert"
)
type MockCommitter struct {
wants []string
gots []string
}
func NewMockCommitter(wants ...string) *MockCommitter {
return &MockCommitter{
wants: wants,
}
}
func (c *MockCommitter) Commit() error {
c.gots = append(c.gots, "commit")
return nil
}
func (c *MockCommitter) Close() error {
c.gots = append(c.gots, "close")
return nil
}
func (c *MockCommitter) Assert(t *testing.T) {
assert.Equal(t, c.wants, c.gots, "want operations %v, but got %v", c.wants, c.gots)
}
func Test_halfCommitter(t *testing.T) {
/*
Do something like:
ctx, committer, err := db.TxContext(db.DefaultContext)
if err != nil {
return nil
}
defer committer.Close()
// ...
if err != nil {
return nil
}
// ...
return committer.Commit()
*/
testWithCommitter := func(committer Committer, f func(committer Committer) error) {
if err := f(&halfCommitter{committer: committer}); err == nil {
committer.Commit()
}
committer.Close()
}
t.Run("commit and close", func(t *testing.T) {
mockCommitter := NewMockCommitter("commit", "close")
testWithCommitter(mockCommitter, func(committer Committer) error {
defer committer.Close()
return committer.Commit()
})
mockCommitter.Assert(t)
})
t.Run("rollback and close", func(t *testing.T) {
mockCommitter := NewMockCommitter("close", "close")
testWithCommitter(mockCommitter, func(committer Committer) error {
defer committer.Close()
if true {
return fmt.Errorf("error")
}
return committer.Commit()
})
mockCommitter.Assert(t)
})
t.Run("close and commit", func(t *testing.T) {
mockCommitter := NewMockCommitter("close", "close")
testWithCommitter(mockCommitter, func(committer Committer) error {
committer.Close()
committer.Commit()
return fmt.Errorf("error")
})
mockCommitter.Assert(t)
})
}

View file

@ -25,8 +25,62 @@ func TestInTransaction(t *testing.T) {
assert.NoError(t, err)
defer committer.Close()
assert.True(t, db.InTransaction(ctx))
assert.Error(t, db.WithTx(ctx, func(ctx context.Context) error {
assert.NoError(t, db.WithTx(ctx, func(ctx context.Context) error {
assert.True(t, db.InTransaction(ctx))
return nil
}))
}
func TestTxContext(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
{ // create new transaction
ctx, committer, err := db.TxContext(db.DefaultContext)
assert.NoError(t, err)
assert.True(t, db.InTransaction(ctx))
assert.NoError(t, committer.Commit())
}
{ // reuse the transaction created by TxContext and commit it
ctx, committer, err := db.TxContext(db.DefaultContext)
engine := db.GetEngine(ctx)
assert.NoError(t, err)
assert.True(t, db.InTransaction(ctx))
{
ctx, committer, err := db.TxContext(ctx)
assert.NoError(t, err)
assert.True(t, db.InTransaction(ctx))
assert.Equal(t, engine, db.GetEngine(ctx))
assert.NoError(t, committer.Commit())
}
assert.NoError(t, committer.Commit())
}
{ // reuse the transaction created by TxContext and close it
ctx, committer, err := db.TxContext(db.DefaultContext)
engine := db.GetEngine(ctx)
assert.NoError(t, err)
assert.True(t, db.InTransaction(ctx))
{
ctx, committer, err := db.TxContext(ctx)
assert.NoError(t, err)
assert.True(t, db.InTransaction(ctx))
assert.Equal(t, engine, db.GetEngine(ctx))
assert.NoError(t, committer.Close())
}
assert.NoError(t, committer.Close())
}
{ // reuse the transaction created by WithTx
assert.NoError(t, db.WithTx(db.DefaultContext, func(ctx context.Context) error {
assert.True(t, db.InTransaction(ctx))
{
ctx, committer, err := db.TxContext(ctx)
assert.NoError(t, err)
assert.True(t, db.InTransaction(ctx))
assert.NoError(t, committer.Commit())
}
return nil
}))
}
}

View file

@ -12,6 +12,8 @@ import (
"code.gitea.io/gitea/models/unittest"
"code.gitea.io/gitea/modules/setting"
_ "code.gitea.io/gitea/cmd" // for TestPrimaryKeys
"github.com/stretchr/testify/assert"
)
@ -51,3 +53,34 @@ func TestDeleteOrphanedObjects(t *testing.T) {
assert.NoError(t, err)
assert.EqualValues(t, countBefore, countAfter)
}
func TestPrimaryKeys(t *testing.T) {
// Some dbs require that all tables have primary keys, see
// https://github.com/go-gitea/gitea/issues/21086
// https://github.com/go-gitea/gitea/issues/16802
// To avoid creating tables without primary key again, this test will check them.
// Import "code.gitea.io/gitea/cmd" to make sure each db.RegisterModel in init functions has been called.
beans, err := db.NamesToBean()
if err != nil {
t.Fatal(err)
}
whitelist := map[string]string{
"the_table_name_to_skip_checking": "Write a note here to explain why",
}
for _, bean := range beans {
table, err := db.TableInfo(bean)
if err != nil {
t.Fatal(err)
}
if why, ok := whitelist[table.Name]; ok {
t.Logf("ignore %q because %q", table.Name, why)
continue
}
if len(table.PrimaryKeys) == 0 {
t.Errorf("table %q has no primary key", table.Name)
}
}
}

View file

@ -4,14 +4,11 @@
package db
import (
"errors"
"fmt"
"code.gitea.io/gitea/modules/util"
)
var ErrAlreadyInTransaction = errors.New("database connection has already been in a transaction")
// ErrCancelled represents an error due to context cancellation
type ErrCancelled struct {
Message string

View file

@ -25,7 +25,7 @@ func TestIterate(t *testing.T) {
return nil
})
assert.NoError(t, err)
assert.EqualValues(t, 80, repoCnt)
assert.EqualValues(t, 81, repoCnt)
err = db.Iterate(db.DefaultContext, nil, func(ctx context.Context, repoUnit *repo_model.RepoUnit) error {
reopUnit2 := repo_model.RepoUnit{ID: repoUnit.ID}

View file

@ -1 +0,0 @@
[] # empty

View file

@ -0,0 +1,32 @@
# These are the LFS objects in user2/lfs.git
-
id: 1
oid: 0b8d8b5f15046343fd32f451df93acc2bdd9e6373be478b968e4cad6b6647351
size: 107
repository_id: 54
created_unix: 1671607299
-
id: 2
oid: 2eccdb43825d2a49d99d542daa20075cff1d97d9d2349a8977efe9c03661737c
size: 107
repository_id: 54
created_unix: 1671607299
-
id: 3
oid: 7b6b2c88dba9f760a1a58469b67fee2b698ef7e9399c4ca4f34a14ccbe39f623
size: 27
repository_id: 54
created_unix: 1671607299
-
id: 4
oid: 9d172e5c64b4f0024b9901ec6afe9ea052f3c9b6ff9f4b07956d8c48c86fca82
size: 25
repository_id: 54
created_unix: 1671607299

View file

@ -550,3 +550,9 @@
repo_id: 53
type: 1
created_unix: 946684810
-
id: 81
repo_id: 54
type: 1
created_unix: 946684810

View file

@ -1585,3 +1585,14 @@
size: 0
is_fsck_enabled: true
close_issues_via_commit_in_any_branch: false
-
id: 54
owner_id: 2
owner_name: user2
lower_name: lfs
name: lfs
is_empty: false
is_archived: false
is_private: true
status: 0

View file

@ -66,7 +66,7 @@
num_followers: 2
num_following: 1
num_stars: 2
num_repos: 9
num_repos: 10
num_teams: 0
num_members: 0
visibility: 0

View file

@ -1,52 +0,0 @@
// Copyright 2022 Gitea. All rights reserved.
// SPDX-License-Identifier: MIT
package foreignreference
import (
"fmt"
"code.gitea.io/gitea/modules/util"
)
// ErrLocalIndexNotExist represents a "LocalIndexNotExist" kind of error.
type ErrLocalIndexNotExist struct {
RepoID int64
ForeignIndex int64
Type string
}
// ErrLocalIndexNotExist checks if an error is a ErrLocalIndexNotExist.
func IsErrLocalIndexNotExist(err error) bool {
_, ok := err.(ErrLocalIndexNotExist)
return ok
}
func (err ErrLocalIndexNotExist) Error() string {
return fmt.Sprintf("repository %d has no LocalIndex for ForeignIndex %d of type %s", err.RepoID, err.ForeignIndex, err.Type)
}
func (err ErrLocalIndexNotExist) Unwrap() error {
return util.ErrNotExist
}
// ErrForeignIndexNotExist represents a "ForeignIndexNotExist" kind of error.
type ErrForeignIndexNotExist struct {
RepoID int64
LocalIndex int64
Type string
}
// ErrForeignIndexNotExist checks if an error is a ErrForeignIndexNotExist.
func IsErrForeignIndexNotExist(err error) bool {
_, ok := err.(ErrForeignIndexNotExist)
return ok
}
func (err ErrForeignIndexNotExist) Error() string {
return fmt.Sprintf("repository %d has no ForeignIndex for LocalIndex %d of type %s", err.RepoID, err.LocalIndex, err.Type)
}
func (err ErrForeignIndexNotExist) Unwrap() error {
return util.ErrNotExist
}

View file

@ -1,31 +0,0 @@
// Copyright 2022 Gitea. All rights reserved.
// SPDX-License-Identifier: MIT
package foreignreference
import (
"code.gitea.io/gitea/models/db"
)
// Type* are valid values for the Type field of ForeignReference
const (
TypeIssue = "issue"
TypePullRequest = "pull_request"
TypeComment = "comment"
TypeReview = "review"
TypeReviewComment = "review_comment"
TypeRelease = "release"
)
// ForeignReference represents external references
type ForeignReference struct {
// RepoID is the first column in all indices. now we only need 2 indices: (repo, local) and (repo, foreign, type)
RepoID int64 `xorm:"UNIQUE(repo_foreign_type) INDEX(repo_local)" `
LocalIndex int64 `xorm:"INDEX(repo_local)"` // the resource key inside Gitea, it can be IssueIndex, or some model ID.
ForeignIndex string `xorm:"INDEX UNIQUE(repo_foreign_type)"`
Type string `xorm:"VARCHAR(16) INDEX UNIQUE(repo_foreign_type)"`
}
func init() {
db.RegisterModel(new(ForeignReference))
}

View file

@ -67,19 +67,19 @@ func (protectBranch *ProtectedBranch) IsProtected() bool {
}
// CanUserPush returns if some user could push to this protected branch
func (protectBranch *ProtectedBranch) CanUserPush(userID int64) bool {
func (protectBranch *ProtectedBranch) CanUserPush(ctx context.Context, userID int64) bool {
if !protectBranch.CanPush {
return false
}
if !protectBranch.EnableWhitelist {
if user, err := user_model.GetUserByID(db.DefaultContext, userID); err != nil {
if user, err := user_model.GetUserByID(ctx, userID); err != nil {
log.Error("GetUserByID: %v", err)
return false
} else if repo, err := repo_model.GetRepositoryByID(db.DefaultContext, protectBranch.RepoID); err != nil {
} else if repo, err := repo_model.GetRepositoryByID(ctx, protectBranch.RepoID); err != nil {
log.Error("repo_model.GetRepositoryByID: %v", err)
return false
} else if writeAccess, err := access_model.HasAccessUnit(db.DefaultContext, user, repo, unit.TypeCode, perm.AccessModeWrite); err != nil {
} else if writeAccess, err := access_model.HasAccessUnit(ctx, user, repo, unit.TypeCode, perm.AccessModeWrite); err != nil {
log.Error("HasAccessUnit: %v", err)
return false
} else {
@ -95,7 +95,7 @@ func (protectBranch *ProtectedBranch) CanUserPush(userID int64) bool {
return false
}
in, err := organization.IsUserInTeams(db.DefaultContext, userID, protectBranch.WhitelistTeamIDs)
in, err := organization.IsUserInTeams(ctx, userID, protectBranch.WhitelistTeamIDs)
if err != nil {
log.Error("IsUserInTeams: %v", err)
return false
@ -320,19 +320,19 @@ func UpdateProtectBranch(ctx context.Context, repo *repo_model.Repository, prote
}
// GetProtectedBranches get all protected branches
func GetProtectedBranches(repoID int64) ([]*ProtectedBranch, error) {
func GetProtectedBranches(ctx context.Context, repoID int64) ([]*ProtectedBranch, error) {
protectedBranches := make([]*ProtectedBranch, 0)
return protectedBranches, db.GetEngine(db.DefaultContext).Find(&protectedBranches, &ProtectedBranch{RepoID: repoID})
return protectedBranches, db.GetEngine(ctx).Find(&protectedBranches, &ProtectedBranch{RepoID: repoID})
}
// IsProtectedBranch checks if branch is protected
func IsProtectedBranch(repoID int64, branchName string) (bool, error) {
func IsProtectedBranch(ctx context.Context, repoID int64, branchName string) (bool, error) {
protectedBranch := &ProtectedBranch{
RepoID: repoID,
BranchName: branchName,
}
has, err := db.GetEngine(db.DefaultContext).Exist(protectedBranch)
has, err := db.GetEngine(ctx).Exist(protectedBranch)
if err != nil {
return true, err
}
@ -413,13 +413,13 @@ func updateTeamWhitelist(ctx context.Context, repo *repo_model.Repository, curre
}
// DeleteProtectedBranch removes ProtectedBranch relation between the user and repository.
func DeleteProtectedBranch(repoID, id int64) (err error) {
func DeleteProtectedBranch(ctx context.Context, repoID, id int64) (err error) {
protectedBranch := &ProtectedBranch{
RepoID: repoID,
ID: id,
}
if affected, err := db.GetEngine(db.DefaultContext).Delete(protectedBranch); err != nil {
if affected, err := db.GetEngine(ctx).Delete(protectedBranch); err != nil {
return err
} else if affected != 1 {
return fmt.Errorf("delete protected branch ID(%v) failed", id)
@ -440,7 +440,7 @@ type DeletedBranch struct {
}
// AddDeletedBranch adds a deleted branch to the database
func AddDeletedBranch(repoID int64, branchName, commit string, deletedByID int64) error {
func AddDeletedBranch(ctx context.Context, repoID int64, branchName, commit string, deletedByID int64) error {
deletedBranch := &DeletedBranch{
RepoID: repoID,
Name: branchName,
@ -448,20 +448,20 @@ func AddDeletedBranch(repoID int64, branchName, commit string, deletedByID int64
DeletedByID: deletedByID,
}
_, err := db.GetEngine(db.DefaultContext).Insert(deletedBranch)
_, err := db.GetEngine(ctx).Insert(deletedBranch)
return err
}
// GetDeletedBranches returns all the deleted branches
func GetDeletedBranches(repoID int64) ([]*DeletedBranch, error) {
func GetDeletedBranches(ctx context.Context, repoID int64) ([]*DeletedBranch, error) {
deletedBranches := make([]*DeletedBranch, 0)
return deletedBranches, db.GetEngine(db.DefaultContext).Where("repo_id = ?", repoID).Desc("deleted_unix").Find(&deletedBranches)
return deletedBranches, db.GetEngine(ctx).Where("repo_id = ?", repoID).Desc("deleted_unix").Find(&deletedBranches)
}
// GetDeletedBranchByID get a deleted branch by its ID
func GetDeletedBranchByID(repoID, id int64) (*DeletedBranch, error) {
func GetDeletedBranchByID(ctx context.Context, repoID, id int64) (*DeletedBranch, error) {
deletedBranch := &DeletedBranch{}
has, err := db.GetEngine(db.DefaultContext).Where("repo_id = ?", repoID).And("id = ?", id).Get(deletedBranch)
has, err := db.GetEngine(ctx).Where("repo_id = ?", repoID).And("id = ?", id).Get(deletedBranch)
if err != nil {
return nil, err
}
@ -472,13 +472,13 @@ func GetDeletedBranchByID(repoID, id int64) (*DeletedBranch, error) {
}
// RemoveDeletedBranchByID removes a deleted branch from the database
func RemoveDeletedBranchByID(repoID, id int64) (err error) {
func RemoveDeletedBranchByID(ctx context.Context, repoID, id int64) (err error) {
deletedBranch := &DeletedBranch{
RepoID: repoID,
ID: id,
}
if affected, err := db.GetEngine(db.DefaultContext).Delete(deletedBranch); err != nil {
if affected, err := db.GetEngine(ctx).Delete(deletedBranch); err != nil {
return err
} else if affected != 1 {
return fmt.Errorf("remove deleted branch ID(%v) failed", id)
@ -498,8 +498,8 @@ func (deletedBranch *DeletedBranch) LoadUser(ctx context.Context) {
}
// RemoveDeletedBranchByName removes all deleted branches
func RemoveDeletedBranchByName(repoID int64, branch string) error {
_, err := db.GetEngine(db.DefaultContext).Where("repo_id=? AND name=?", repoID, branch).Delete(new(DeletedBranch))
func RemoveDeletedBranchByName(ctx context.Context, repoID int64, branch string) error {
_, err := db.GetEngine(ctx).Where("repo_id=? AND name=?", repoID, branch).Delete(new(DeletedBranch))
return err
}
@ -509,7 +509,7 @@ func RemoveOldDeletedBranches(ctx context.Context, olderThan time.Duration) {
log.Trace("Doing: DeletedBranchesCleanup")
deleteBefore := time.Now().Add(-olderThan)
_, err := db.GetEngine(db.DefaultContext).Where("deleted_unix < ?", deleteBefore.Unix()).Delete(new(DeletedBranch))
_, err := db.GetEngine(ctx).Where("deleted_unix < ?", deleteBefore.Unix()).Delete(new(DeletedBranch))
if err != nil {
log.Error("DeletedBranchesCleanup: %v", err)
}
@ -526,19 +526,19 @@ type RenamedBranch struct {
}
// FindRenamedBranch check if a branch was renamed
func FindRenamedBranch(repoID int64, from string) (branch *RenamedBranch, exist bool, err error) {
func FindRenamedBranch(ctx context.Context, repoID int64, from string) (branch *RenamedBranch, exist bool, err error) {
branch = &RenamedBranch{
RepoID: repoID,
From: from,
}
exist, err = db.GetEngine(db.DefaultContext).Get(branch)
exist, err = db.GetEngine(ctx).Get(branch)
return branch, exist, err
}
// RenameBranch rename a branch
func RenameBranch(repo *repo_model.Repository, from, to string, gitAction func(isDefault bool) error) (err error) {
ctx, committer, err := db.TxContext(db.DefaultContext)
func RenameBranch(ctx context.Context, repo *repo_model.Repository, from, to string, gitAction func(isDefault bool) error) (err error) {
ctx, committer, err := db.TxContext(ctx)
if err != nil {
return err
}

View file

@ -20,15 +20,15 @@ func TestAddDeletedBranch(t *testing.T) {
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
firstBranch := unittest.AssertExistsAndLoadBean(t, &git_model.DeletedBranch{ID: 1})
assert.Error(t, git_model.AddDeletedBranch(repo.ID, firstBranch.Name, firstBranch.Commit, firstBranch.DeletedByID))
assert.NoError(t, git_model.AddDeletedBranch(repo.ID, "test", "5655464564554545466464656", int64(1)))
assert.Error(t, git_model.AddDeletedBranch(db.DefaultContext, repo.ID, firstBranch.Name, firstBranch.Commit, firstBranch.DeletedByID))
assert.NoError(t, git_model.AddDeletedBranch(db.DefaultContext, repo.ID, "test", "5655464564554545466464656", int64(1)))
}
func TestGetDeletedBranches(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
branches, err := git_model.GetDeletedBranches(repo.ID)
branches, err := git_model.GetDeletedBranches(db.DefaultContext, repo.ID)
assert.NoError(t, err)
assert.Len(t, branches, 2)
}
@ -65,7 +65,7 @@ func TestRemoveDeletedBranch(t *testing.T) {
firstBranch := unittest.AssertExistsAndLoadBean(t, &git_model.DeletedBranch{ID: 1})
err := git_model.RemoveDeletedBranchByID(repo.ID, 1)
err := git_model.RemoveDeletedBranchByID(db.DefaultContext, repo.ID, 1)
assert.NoError(t, err)
unittest.AssertNotExistsBean(t, firstBranch)
unittest.AssertExistsAndLoadBean(t, &git_model.DeletedBranch{ID: 2})
@ -74,7 +74,7 @@ func TestRemoveDeletedBranch(t *testing.T) {
func getDeletedBranch(t *testing.T, branch *git_model.DeletedBranch) *git_model.DeletedBranch {
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
deletedBranch, err := git_model.GetDeletedBranchByID(repo.ID, branch.ID)
deletedBranch, err := git_model.GetDeletedBranchByID(db.DefaultContext, repo.ID, branch.ID)
assert.NoError(t, err)
assert.Equal(t, branch.ID, deletedBranch.ID)
assert.Equal(t, branch.Name, deletedBranch.Name)
@ -86,12 +86,12 @@ func getDeletedBranch(t *testing.T, branch *git_model.DeletedBranch) *git_model.
func TestFindRenamedBranch(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
branch, exist, err := git_model.FindRenamedBranch(1, "dev")
branch, exist, err := git_model.FindRenamedBranch(db.DefaultContext, 1, "dev")
assert.NoError(t, err)
assert.Equal(t, true, exist)
assert.Equal(t, "master", branch.To)
_, exist, err = git_model.FindRenamedBranch(1, "unknow")
_, exist, err = git_model.FindRenamedBranch(db.DefaultContext, 1, "unknow")
assert.NoError(t, err)
assert.Equal(t, false, exist)
}
@ -110,7 +110,7 @@ func TestRenameBranch(t *testing.T) {
}, git_model.WhitelistOptions{}))
assert.NoError(t, committer.Commit())
assert.NoError(t, git_model.RenameBranch(repo1, "master", "main", func(isDefault bool) error {
assert.NoError(t, git_model.RenameBranch(db.DefaultContext, repo1, "master", "main", func(isDefault bool) error {
_isDefault = isDefault
return nil
}))
@ -144,7 +144,7 @@ func TestOnlyGetDeletedBranchOnCorrectRepo(t *testing.T) {
// is actually on repo with ID 1.
repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2})
deletedBranch, err := git_model.GetDeletedBranchByID(repo2.ID, 1)
deletedBranch, err := git_model.GetDeletedBranchByID(db.DefaultContext, repo2.ID, 1)
// Expect no error, and the returned branch is nil.
assert.NoError(t, err)
@ -154,7 +154,7 @@ func TestOnlyGetDeletedBranchOnCorrectRepo(t *testing.T) {
// This should return the deletedBranch.
repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
deletedBranch, err = git_model.GetDeletedBranchByID(repo1.ID, 1)
deletedBranch, err = git_model.GetDeletedBranchByID(db.DefaultContext, repo1.ID, 1)
// Expect no error, and the returned branch to be not nil.
assert.NoError(t, err)

View file

@ -129,8 +129,8 @@ func (status *CommitStatus) loadAttributes(ctx context.Context) (err error) {
}
// APIURL returns the absolute APIURL to this commit-status.
func (status *CommitStatus) APIURL() string {
_ = status.loadAttributes(db.DefaultContext)
func (status *CommitStatus) APIURL(ctx context.Context) string {
_ = status.loadAttributes(ctx)
return status.Repo.APIURL() + "/statuses/" + url.PathEscape(status.SHA)
}
@ -162,7 +162,7 @@ type CommitStatusOptions struct {
}
// GetCommitStatuses returns all statuses for a given commit.
func GetCommitStatuses(repo *repo_model.Repository, sha string, opts *CommitStatusOptions) ([]*CommitStatus, int64, error) {
func GetCommitStatuses(ctx context.Context, repo *repo_model.Repository, sha string, opts *CommitStatusOptions) ([]*CommitStatus, int64, error) {
if opts.Page <= 0 {
opts.Page = 1
}
@ -170,7 +170,7 @@ func GetCommitStatuses(repo *repo_model.Repository, sha string, opts *CommitStat
opts.Page = setting.ItemsPerPage
}
countSession := listCommitStatusesStatement(repo, sha, opts)
countSession := listCommitStatusesStatement(ctx, repo, sha, opts)
countSession = db.SetSessionPagination(countSession, opts)
maxResults, err := countSession.Count(new(CommitStatus))
if err != nil {
@ -179,14 +179,14 @@ func GetCommitStatuses(repo *repo_model.Repository, sha string, opts *CommitStat
}
statuses := make([]*CommitStatus, 0, opts.PageSize)
findSession := listCommitStatusesStatement(repo, sha, opts)
findSession := listCommitStatusesStatement(ctx, repo, sha, opts)
findSession = db.SetSessionPagination(findSession, opts)
sortCommitStatusesSession(findSession, opts.SortType)
return statuses, maxResults, findSession.Find(&statuses)
}
func listCommitStatusesStatement(repo *repo_model.Repository, sha string, opts *CommitStatusOptions) *xorm.Session {
sess := db.GetEngine(db.DefaultContext).Where("repo_id = ?", repo.ID).And("sha = ?", sha)
func listCommitStatusesStatement(ctx context.Context, repo *repo_model.Repository, sha string, opts *CommitStatusOptions) *xorm.Session {
sess := db.GetEngine(ctx).Where("repo_id = ?", repo.ID).And("sha = ?", sha)
switch opts.State {
case "pending", "success", "error", "failure", "warning":
sess.And("state = ?", opts.State)
@ -241,10 +241,10 @@ func GetLatestCommitStatus(ctx context.Context, repoID int64, sha string, listOp
}
// FindRepoRecentCommitStatusContexts returns repository's recent commit status contexts
func FindRepoRecentCommitStatusContexts(repoID int64, before time.Duration) ([]string, error) {
func FindRepoRecentCommitStatusContexts(ctx context.Context, repoID int64, before time.Duration) ([]string, error) {
start := timeutil.TimeStampNow().AddDuration(-before)
ids := make([]int64, 0, 10)
if err := db.GetEngine(db.DefaultContext).Table("commit_status").
if err := db.GetEngine(ctx).Table("commit_status").
Where("repo_id = ?", repoID).
And("updated_unix >= ?", start).
Select("max( id ) as id").
@ -257,7 +257,7 @@ func FindRepoRecentCommitStatusContexts(repoID int64, before time.Duration) ([]s
if len(ids) == 0 {
return contexts, nil
}
return contexts, db.GetEngine(db.DefaultContext).Select("context").Table("commit_status").In("id", ids).Find(&contexts)
return contexts, db.GetEngine(ctx).Select("context").Table("commit_status").In("id", ids).Find(&contexts)
}
// NewCommitStatusOptions holds options for creating a CommitStatus
@ -269,7 +269,7 @@ type NewCommitStatusOptions struct {
}
// NewCommitStatus save commit statuses into database
func NewCommitStatus(opts NewCommitStatusOptions) error {
func NewCommitStatus(ctx context.Context, opts NewCommitStatusOptions) error {
if opts.Repo == nil {
return fmt.Errorf("NewCommitStatus[nil, %s]: no repository specified", opts.SHA)
}
@ -279,7 +279,11 @@ func NewCommitStatus(opts NewCommitStatusOptions) error {
return fmt.Errorf("NewCommitStatus[%s, %s]: no user specified", repoPath, opts.SHA)
}
ctx, committer, err := db.TxContext(db.DefaultContext)
if _, err := git.NewIDFromString(opts.SHA); err != nil {
return fmt.Errorf("NewCommitStatus[%s, %s]: invalid sha: %w", repoPath, opts.SHA, err)
}
ctx, committer, err := db.TxContext(ctx)
if err != nil {
return fmt.Errorf("NewCommitStatus[repo_id: %d, user_id: %d, sha: %s]: %w", opts.Repo.ID, opts.Creator.ID, opts.SHA, err)
}
@ -318,14 +322,14 @@ type SignCommitWithStatuses struct {
}
// ParseCommitsWithStatus checks commits latest statuses and calculates its worst status state
func ParseCommitsWithStatus(oldCommits []*asymkey_model.SignCommit, repo *repo_model.Repository) []*SignCommitWithStatuses {
func ParseCommitsWithStatus(ctx context.Context, oldCommits []*asymkey_model.SignCommit, repo *repo_model.Repository) []*SignCommitWithStatuses {
newCommits := make([]*SignCommitWithStatuses, 0, len(oldCommits))
for _, c := range oldCommits {
commit := &SignCommitWithStatuses{
SignCommit: c,
}
statuses, _, err := GetLatestCommitStatus(db.DefaultContext, repo.ID, commit.ID.String(), db.ListOptions{})
statuses, _, err := GetLatestCommitStatus(ctx, repo.ID, commit.ID.String(), db.ListOptions{})
if err != nil {
log.Error("GetLatestCommitStatus: %v", err)
} else {
@ -344,8 +348,8 @@ func hashCommitStatusContext(context string) string {
}
// ConvertFromGitCommit converts git commits into SignCommitWithStatuses
func ConvertFromGitCommit(commits []*git.Commit, repo *repo_model.Repository) []*SignCommitWithStatuses {
return ParseCommitsWithStatus(
func ConvertFromGitCommit(ctx context.Context, commits []*git.Commit, repo *repo_model.Repository) []*SignCommitWithStatuses {
return ParseCommitsWithStatus(ctx,
asymkey_model.ParseCommitsWithSignature(
user_model.ValidateCommitsWithEmails(commits),
repo.GetTrustModel(),

View file

@ -22,28 +22,28 @@ func TestGetCommitStatuses(t *testing.T) {
sha1 := "1234123412341234123412341234123412341234"
statuses, maxResults, err := git_model.GetCommitStatuses(repo1, sha1, &git_model.CommitStatusOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 50}})
statuses, maxResults, err := git_model.GetCommitStatuses(db.DefaultContext, repo1, sha1, &git_model.CommitStatusOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 50}})
assert.NoError(t, err)
assert.Equal(t, int(maxResults), 5)
assert.Len(t, statuses, 5)
assert.Equal(t, "ci/awesomeness", statuses[0].Context)
assert.Equal(t, structs.CommitStatusPending, statuses[0].State)
assert.Equal(t, "https://try.gitea.io/api/v1/repos/user2/repo1/statuses/1234123412341234123412341234123412341234", statuses[0].APIURL())
assert.Equal(t, "https://try.gitea.io/api/v1/repos/user2/repo1/statuses/1234123412341234123412341234123412341234", statuses[0].APIURL(db.DefaultContext))
assert.Equal(t, "cov/awesomeness", statuses[1].Context)
assert.Equal(t, structs.CommitStatusWarning, statuses[1].State)
assert.Equal(t, "https://try.gitea.io/api/v1/repos/user2/repo1/statuses/1234123412341234123412341234123412341234", statuses[1].APIURL())
assert.Equal(t, "https://try.gitea.io/api/v1/repos/user2/repo1/statuses/1234123412341234123412341234123412341234", statuses[1].APIURL(db.DefaultContext))
assert.Equal(t, "cov/awesomeness", statuses[2].Context)
assert.Equal(t, structs.CommitStatusSuccess, statuses[2].State)
assert.Equal(t, "https://try.gitea.io/api/v1/repos/user2/repo1/statuses/1234123412341234123412341234123412341234", statuses[2].APIURL())
assert.Equal(t, "https://try.gitea.io/api/v1/repos/user2/repo1/statuses/1234123412341234123412341234123412341234", statuses[2].APIURL(db.DefaultContext))
assert.Equal(t, "ci/awesomeness", statuses[3].Context)
assert.Equal(t, structs.CommitStatusFailure, statuses[3].State)
assert.Equal(t, "https://try.gitea.io/api/v1/repos/user2/repo1/statuses/1234123412341234123412341234123412341234", statuses[3].APIURL())
assert.Equal(t, "https://try.gitea.io/api/v1/repos/user2/repo1/statuses/1234123412341234123412341234123412341234", statuses[3].APIURL(db.DefaultContext))
assert.Equal(t, "deploy/awesomeness", statuses[4].Context)
assert.Equal(t, structs.CommitStatusError, statuses[4].State)
assert.Equal(t, "https://try.gitea.io/api/v1/repos/user2/repo1/statuses/1234123412341234123412341234123412341234", statuses[4].APIURL())
assert.Equal(t, "https://try.gitea.io/api/v1/repos/user2/repo1/statuses/1234123412341234123412341234123412341234", statuses[4].APIURL(db.DefaultContext))
}

View file

@ -135,10 +135,10 @@ var ErrLFSObjectNotExist = db.ErrNotExist{Resource: "LFS Meta object"}
// NewLFSMetaObject stores a given populated LFSMetaObject structure in the database
// if it is not already present.
func NewLFSMetaObject(m *LFSMetaObject) (*LFSMetaObject, error) {
func NewLFSMetaObject(ctx context.Context, m *LFSMetaObject) (*LFSMetaObject, error) {
var err error
ctx, committer, err := db.TxContext(db.DefaultContext)
ctx, committer, err := db.TxContext(ctx)
if err != nil {
return nil, err
}
@ -164,13 +164,13 @@ func NewLFSMetaObject(m *LFSMetaObject) (*LFSMetaObject, error) {
// GetLFSMetaObjectByOid selects a LFSMetaObject entry from database by its OID.
// It may return ErrLFSObjectNotExist or a database error. If the error is nil,
// the returned pointer is a valid LFSMetaObject.
func GetLFSMetaObjectByOid(repoID int64, oid string) (*LFSMetaObject, error) {
func GetLFSMetaObjectByOid(ctx context.Context, repoID int64, oid string) (*LFSMetaObject, error) {
if len(oid) == 0 {
return nil, ErrLFSObjectNotExist
}
m := &LFSMetaObject{Pointer: lfs.Pointer{Oid: oid}, RepositoryID: repoID}
has, err := db.GetEngine(db.DefaultContext).Get(m)
has, err := db.GetEngine(ctx).Get(m)
if err != nil {
return nil, err
} else if !has {
@ -181,18 +181,18 @@ func GetLFSMetaObjectByOid(repoID int64, oid string) (*LFSMetaObject, error) {
// RemoveLFSMetaObjectByOid removes a LFSMetaObject entry from database by its OID.
// It may return ErrLFSObjectNotExist or a database error.
func RemoveLFSMetaObjectByOid(repoID int64, oid string) (int64, error) {
return RemoveLFSMetaObjectByOidFn(repoID, oid, nil)
func RemoveLFSMetaObjectByOid(ctx context.Context, repoID int64, oid string) (int64, error) {
return RemoveLFSMetaObjectByOidFn(ctx, repoID, oid, nil)
}
// RemoveLFSMetaObjectByOidFn removes a LFSMetaObject entry from database by its OID.
// It may return ErrLFSObjectNotExist or a database error. It will run Fn with the current count within the transaction
func RemoveLFSMetaObjectByOidFn(repoID int64, oid string, fn func(count int64) error) (int64, error) {
func RemoveLFSMetaObjectByOidFn(ctx context.Context, repoID int64, oid string, fn func(count int64) error) (int64, error) {
if len(oid) == 0 {
return 0, ErrLFSObjectNotExist
}
ctx, committer, err := db.TxContext(db.DefaultContext)
ctx, committer, err := db.TxContext(ctx)
if err != nil {
return 0, err
}
@ -218,8 +218,8 @@ func RemoveLFSMetaObjectByOidFn(repoID int64, oid string, fn func(count int64) e
}
// GetLFSMetaObjects returns all LFSMetaObjects associated with a repository
func GetLFSMetaObjects(repoID int64, page, pageSize int) ([]*LFSMetaObject, error) {
sess := db.GetEngine(db.DefaultContext)
func GetLFSMetaObjects(ctx context.Context, repoID int64, page, pageSize int) ([]*LFSMetaObject, error) {
sess := db.GetEngine(ctx)
if page >= 0 && pageSize > 0 {
start := 0
@ -233,18 +233,18 @@ func GetLFSMetaObjects(repoID int64, page, pageSize int) ([]*LFSMetaObject, erro
}
// CountLFSMetaObjects returns a count of all LFSMetaObjects associated with a repository
func CountLFSMetaObjects(repoID int64) (int64, error) {
return db.GetEngine(db.DefaultContext).Count(&LFSMetaObject{RepositoryID: repoID})
func CountLFSMetaObjects(ctx context.Context, repoID int64) (int64, error) {
return db.GetEngine(ctx).Count(&LFSMetaObject{RepositoryID: repoID})
}
// LFSObjectAccessible checks if a provided Oid is accessible to the user
func LFSObjectAccessible(user *user_model.User, oid string) (bool, error) {
func LFSObjectAccessible(ctx context.Context, user *user_model.User, oid string) (bool, error) {
if user.IsAdmin {
count, err := db.GetEngine(db.DefaultContext).Count(&LFSMetaObject{Pointer: lfs.Pointer{Oid: oid}})
count, err := db.GetEngine(ctx).Count(&LFSMetaObject{Pointer: lfs.Pointer{Oid: oid}})
return count > 0, err
}
cond := repo_model.AccessibleRepositoryCondition(user, unit.TypeInvalid)
count, err := db.GetEngine(db.DefaultContext).Where(cond).Join("INNER", "repository", "`lfs_meta_object`.repository_id = `repository`.id").Count(&LFSMetaObject{Pointer: lfs.Pointer{Oid: oid}})
count, err := db.GetEngine(ctx).Where(cond).Join("INNER", "repository", "`lfs_meta_object`.repository_id = `repository`.id").Count(&LFSMetaObject{Pointer: lfs.Pointer{Oid: oid}})
return count > 0, err
}
@ -254,8 +254,8 @@ func ExistsLFSObject(ctx context.Context, oid string) (bool, error) {
}
// LFSAutoAssociate auto associates accessible LFSMetaObjects
func LFSAutoAssociate(metas []*LFSMetaObject, user *user_model.User, repoID int64) error {
ctx, committer, err := db.TxContext(db.DefaultContext)
func LFSAutoAssociate(ctx context.Context, metas []*LFSMetaObject, user *user_model.User, repoID int64) error {
ctx, committer, err := db.TxContext(ctx)
if err != nil {
return err
}

View file

@ -42,8 +42,8 @@ func cleanPath(p string) string {
}
// CreateLFSLock creates a new lock.
func CreateLFSLock(repo *repo_model.Repository, lock *LFSLock) (*LFSLock, error) {
dbCtx, committer, err := db.TxContext(db.DefaultContext)
func CreateLFSLock(ctx context.Context, repo *repo_model.Repository, lock *LFSLock) (*LFSLock, error) {
dbCtx, committer, err := db.TxContext(ctx)
if err != nil {
return nil, err
}
@ -98,8 +98,8 @@ func GetLFSLockByID(ctx context.Context, id int64) (*LFSLock, error) {
}
// GetLFSLockByRepoID returns a list of locks of repository.
func GetLFSLockByRepoID(repoID int64, page, pageSize int) ([]*LFSLock, error) {
e := db.GetEngine(db.DefaultContext)
func GetLFSLockByRepoID(ctx context.Context, repoID int64, page, pageSize int) ([]*LFSLock, error) {
e := db.GetEngine(ctx)
if page >= 0 && pageSize > 0 {
start := 0
if page > 0 {
@ -112,12 +112,12 @@ func GetLFSLockByRepoID(repoID int64, page, pageSize int) ([]*LFSLock, error) {
}
// GetTreePathLock returns LSF lock for the treePath
func GetTreePathLock(repoID int64, treePath string) (*LFSLock, error) {
func GetTreePathLock(ctx context.Context, repoID int64, treePath string) (*LFSLock, error) {
if !setting.LFS.StartServer {
return nil, nil
}
locks, err := GetLFSLockByRepoID(repoID, 0, 0)
locks, err := GetLFSLockByRepoID(ctx, repoID, 0, 0)
if err != nil {
return nil, err
}
@ -130,13 +130,13 @@ func GetTreePathLock(repoID int64, treePath string) (*LFSLock, error) {
}
// CountLFSLockByRepoID returns a count of all LFSLocks associated with a repository.
func CountLFSLockByRepoID(repoID int64) (int64, error) {
return db.GetEngine(db.DefaultContext).Count(&LFSLock{RepoID: repoID})
func CountLFSLockByRepoID(ctx context.Context, repoID int64) (int64, error) {
return db.GetEngine(ctx).Count(&LFSLock{RepoID: repoID})
}
// DeleteLFSLockByID deletes a lock by given ID.
func DeleteLFSLockByID(id int64, repo *repo_model.Repository, u *user_model.User, force bool) (*LFSLock, error) {
dbCtx, committer, err := db.TxContext(db.DefaultContext)
func DeleteLFSLockByID(ctx context.Context, id int64, repo *repo_model.Repository, u *user_model.User, force bool) (*LFSLock, error) {
dbCtx, committer, err := db.TxContext(ctx)
if err != nil {
return nil, err
}

View file

@ -57,14 +57,14 @@ func (pt *ProtectedTag) matchString(name string) bool {
}
// InsertProtectedTag inserts a protected tag to database
func InsertProtectedTag(pt *ProtectedTag) error {
_, err := db.GetEngine(db.DefaultContext).Insert(pt)
func InsertProtectedTag(ctx context.Context, pt *ProtectedTag) error {
_, err := db.GetEngine(ctx).Insert(pt)
return err
}
// UpdateProtectedTag updates the protected tag
func UpdateProtectedTag(pt *ProtectedTag) error {
_, err := db.GetEngine(db.DefaultContext).ID(pt.ID).AllCols().Update(pt)
func UpdateProtectedTag(ctx context.Context, pt *ProtectedTag) error {
_, err := db.GetEngine(ctx).ID(pt.ID).AllCols().Update(pt)
return err
}
@ -98,9 +98,9 @@ func GetProtectedTags(ctx context.Context, repoID int64) ([]*ProtectedTag, error
}
// GetProtectedTagByID gets the protected tag with the specific id
func GetProtectedTagByID(id int64) (*ProtectedTag, error) {
func GetProtectedTagByID(ctx context.Context, id int64) (*ProtectedTag, error) {
tag := new(ProtectedTag)
has, err := db.GetEngine(db.DefaultContext).ID(id).Get(tag)
has, err := db.GetEngine(ctx).ID(id).Get(tag)
if err != nil {
return nil, err
}

View file

@ -773,7 +773,7 @@ func (c *Comment) LoadPushCommits(ctx context.Context) (err error) {
}
defer closer.Close()
c.Commits = git_model.ConvertFromGitCommit(gitRepo.GetCommitsFromIDs(data.CommitIDs), c.Issue.Repo)
c.Commits = git_model.ConvertFromGitCommit(ctx, gitRepo.GetCommitsFromIDs(data.CommitIDs), c.Issue.Repo)
c.CommitsNum = int64(len(c.Commits))
}

View file

@ -13,7 +13,6 @@ import (
"strings"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/foreignreference"
"code.gitea.io/gitea/models/organization"
"code.gitea.io/gitea/models/perm"
access_model "code.gitea.io/gitea/models/perm/access"
@ -137,12 +136,11 @@ type Issue struct {
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
ClosedUnix timeutil.TimeStamp `xorm:"INDEX"`
Attachments []*repo_model.Attachment `xorm:"-"`
Comments []*Comment `xorm:"-"`
Reactions ReactionList `xorm:"-"`
TotalTrackedTime int64 `xorm:"-"`
Assignees []*user_model.User `xorm:"-"`
ForeignReference *foreignreference.ForeignReference `xorm:"-"`
Attachments []*repo_model.Attachment `xorm:"-"`
Comments []*Comment `xorm:"-"`
Reactions ReactionList `xorm:"-"`
TotalTrackedTime int64 `xorm:"-"`
Assignees []*user_model.User `xorm:"-"`
// IsLocked limits commenting abilities to users on an issue
// with write access
@ -322,29 +320,6 @@ func (issue *Issue) loadReactions(ctx context.Context) (err error) {
return nil
}
func (issue *Issue) loadForeignReference(ctx context.Context) (err error) {
if issue.ForeignReference != nil {
return nil
}
reference := &foreignreference.ForeignReference{
RepoID: issue.RepoID,
LocalIndex: issue.Index,
Type: foreignreference.TypeIssue,
}
has, err := db.GetEngine(ctx).Get(reference)
if err != nil {
return err
} else if !has {
return foreignreference.ErrForeignIndexNotExist{
RepoID: issue.RepoID,
LocalIndex: issue.Index,
Type: foreignreference.TypeIssue,
}
}
issue.ForeignReference = reference
return nil
}
// LoadMilestone load milestone of this issue.
func (issue *Issue) LoadMilestone(ctx context.Context) (err error) {
if (issue.Milestone == nil || issue.Milestone.ID != issue.MilestoneID) && issue.MilestoneID > 0 {
@ -407,10 +382,6 @@ func (issue *Issue) LoadAttributes(ctx context.Context) (err error) {
}
}
if err = issue.loadForeignReference(ctx); err != nil && !foreignreference.IsErrForeignIndexNotExist(err) {
return err
}
return issue.loadReactions(ctx)
}
@ -1098,26 +1069,6 @@ func GetIssueByIndex(repoID, index int64) (*Issue, error) {
return issue, nil
}
// GetIssueByForeignIndex returns raw issue by foreign ID
func GetIssueByForeignIndex(ctx context.Context, repoID, foreignIndex int64) (*Issue, error) {
reference := &foreignreference.ForeignReference{
RepoID: repoID,
ForeignIndex: strconv.FormatInt(foreignIndex, 10),
Type: foreignreference.TypeIssue,
}
has, err := db.GetEngine(ctx).Get(reference)
if err != nil {
return nil, err
} else if !has {
return nil, foreignreference.ErrLocalIndexNotExist{
RepoID: repoID,
ForeignIndex: foreignIndex,
Type: foreignreference.TypeIssue,
}
}
return GetIssueByIndex(repoID, reference.LocalIndex)
}
// GetIssueWithAttrsByIndex returns issue by index in a repository.
func GetIssueWithAttrsByIndex(repoID, index int64) (*Issue, error) {
issue, err := GetIssueByIndex(repoID, index)
@ -2416,7 +2367,7 @@ func CountOrphanedIssues(ctx context.Context) (int64, error) {
// DeleteOrphanedIssues delete issues without a repo
func DeleteOrphanedIssues(ctx context.Context) error {
var attachmentPaths []string
err := db.AutoTx(ctx, func(ctx context.Context) error {
err := db.WithTx(ctx, func(ctx context.Context) error {
var ids []int64
if err := db.GetEngine(ctx).Table("issue").Distinct("issue.repo_id").

View file

@ -7,13 +7,11 @@ import (
"context"
"fmt"
"sort"
"strconv"
"sync"
"testing"
"time"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/foreignreference"
issues_model "code.gitea.io/gitea/models/issues"
"code.gitea.io/gitea/models/organization"
repo_model "code.gitea.io/gitea/models/repo"
@ -501,38 +499,6 @@ func TestCorrectIssueStats(t *testing.T) {
assert.EqualValues(t, issueStats.OpenCount, issueAmount)
}
func TestIssueForeignReference(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 4})
assert.NotEqualValues(t, issue.Index, issue.ID) // make sure they are different to avoid false positive
// it is fine for an issue to not have a foreign reference
err := issue.LoadAttributes(db.DefaultContext)
assert.NoError(t, err)
assert.Nil(t, issue.ForeignReference)
var foreignIndex int64 = 12345
_, err = issues_model.GetIssueByForeignIndex(context.Background(), issue.RepoID, foreignIndex)
assert.True(t, foreignreference.IsErrLocalIndexNotExist(err))
err = db.Insert(db.DefaultContext, &foreignreference.ForeignReference{
LocalIndex: issue.Index,
ForeignIndex: strconv.FormatInt(foreignIndex, 10),
RepoID: issue.RepoID,
Type: foreignreference.TypeIssue,
})
assert.NoError(t, err)
err = issue.LoadAttributes(db.DefaultContext)
assert.NoError(t, err)
assert.EqualValues(t, issue.ForeignReference.ForeignIndex, strconv.FormatInt(foreignIndex, 10))
found, err := issues_model.GetIssueByForeignIndex(context.Background(), issue.RepoID, foreignIndex)
assert.NoError(t, err)
assert.EqualValues(t, found.Index, issue.Index)
}
func TestMilestoneList_LoadTotalTrackedTimes(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
miles := issues_model.MilestoneList{

View file

@ -83,13 +83,6 @@ func insertIssue(ctx context.Context, issue *issues_model.Issue) error {
}
}
if issue.ForeignReference != nil {
issue.ForeignReference.LocalIndex = issue.Index
if _, err := sess.Insert(issue.ForeignReference); err != nil {
return err
}
}
return nil
}

View file

@ -4,11 +4,9 @@
package models
import (
"strconv"
"testing"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/foreignreference"
issues_model "code.gitea.io/gitea/models/issues"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unittest"
@ -48,7 +46,6 @@ func assertCreateIssues(t *testing.T, isPull bool) {
UserID: owner.ID,
}
foreignIndex := int64(12345)
title := "issuetitle1"
is := &issues_model.Issue{
RepoID: repo.ID,
@ -62,20 +59,11 @@ func assertCreateIssues(t *testing.T, isPull bool) {
IsClosed: true,
Labels: []*issues_model.Label{label},
Reactions: []*issues_model.Reaction{reaction},
ForeignReference: &foreignreference.ForeignReference{
ForeignIndex: strconv.FormatInt(foreignIndex, 10),
RepoID: repo.ID,
Type: foreignreference.TypeIssue,
},
}
err := InsertIssues(is)
assert.NoError(t, err)
i := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{Title: title})
assert.Nil(t, i.ForeignReference)
err = i.LoadAttributes(db.DefaultContext)
assert.NoError(t, err)
assert.EqualValues(t, strconv.FormatInt(foreignIndex, 10), i.ForeignReference.ForeignIndex)
unittest.AssertExistsAndLoadBean(t, &issues_model.Reaction{Type: "heart", UserID: owner.ID, IssueID: i.ID})
}

View file

@ -444,6 +444,8 @@ var migrations = []Migration{
NewMigration("Add index for access_token", v1_19.AddIndexForAccessToken),
// v236 -> v237
NewMigration("Create secrets table", v1_19.CreateSecretsTable),
// v237 -> v238
NewMigration("Drop ForeignReference table", v1_19.DropForeignReferenceTable),
}
// GetCurrentDBVersion returns the current db version

View file

@ -6,7 +6,6 @@ package v1_19 //nolint
import (
"fmt"
"code.gitea.io/gitea/models/webhook"
"code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/secret"
"code.gitea.io/gitea/modules/setting"
@ -56,9 +55,9 @@ func batchProcess[T any](x *xorm.Engine, buf []T, query func(limit, start int) *
func AddHeaderAuthorizationEncryptedColWebhook(x *xorm.Engine) error {
// Add the column to the table
type Webhook struct {
ID int64 `xorm:"pk autoincr"`
Type webhook.HookType `xorm:"VARCHAR(16) 'type'"`
Meta string `xorm:"TEXT"` // store hook-specific attributes
ID int64 `xorm:"pk autoincr"`
Type string `xorm:"VARCHAR(16) 'type'"`
Meta string `xorm:"TEXT"` // store hook-specific attributes
// HeaderAuthorizationEncrypted should be accessed using HeaderAuthorization() and SetHeaderAuthorization()
HeaderAuthorizationEncrypted string `xorm:"TEXT"`

View file

@ -7,10 +7,10 @@ import (
"testing"
"code.gitea.io/gitea/models/migrations/base"
"code.gitea.io/gitea/models/webhook"
"code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/secret"
"code.gitea.io/gitea/modules/setting"
webhook_module "code.gitea.io/gitea/modules/webhook"
"github.com/stretchr/testify/assert"
)
@ -18,9 +18,9 @@ import (
func Test_AddHeaderAuthorizationEncryptedColWebhook(t *testing.T) {
// Create Webhook table
type Webhook struct {
ID int64 `xorm:"pk autoincr"`
Type webhook.HookType `xorm:"VARCHAR(16) 'type'"`
Meta string `xorm:"TEXT"` // store hook-specific attributes
ID int64 `xorm:"pk autoincr"`
Type webhook_module.HookType `xorm:"VARCHAR(16) 'type'"`
Meta string `xorm:"TEXT"` // store hook-specific attributes
// HeaderAuthorizationEncrypted should be accessed using HeaderAuthorization() and SetHeaderAuthorization()
HeaderAuthorizationEncrypted string `xorm:"TEXT"`

View file

@ -0,0 +1,15 @@
// Copyright 2022 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package v1_19 //nolint
import (
"xorm.io/xorm"
)
func DropForeignReferenceTable(x *xorm.Engine) error {
// Drop the table introduced in `v211`, it's considered badly designed and doesn't look like to be used.
// See: https://github.com/go-gitea/gitea/issues/21086#issuecomment-1318217453
type ForeignReference struct{}
return x.DropTables(new(ForeignReference))
}

View file

@ -6,7 +6,6 @@ package models
import (
"context"
"errors"
"fmt"
"strings"
@ -235,7 +234,7 @@ func RemoveRepository(t *organization.Team, repoID int64) error {
// It's caller's responsibility to assign organization ID.
func NewTeam(t *organization.Team) (err error) {
if len(t.Name) == 0 {
return errors.New("empty team name")
return util.NewInvalidArgumentErrorf("empty team name")
}
if err = organization.IsUsableTeamName(t.Name); err != nil {
@ -300,7 +299,7 @@ func NewTeam(t *organization.Team) (err error) {
// UpdateTeam updates information of team.
func UpdateTeam(t *organization.Team, authChanged, includeAllChanged bool) (err error) {
if len(t.Name) == 0 {
return errors.New("empty team name")
return util.NewInvalidArgumentErrorf("empty team name")
}
if len(t.Description) > 255 {

View file

@ -5,7 +5,6 @@ package conan
import (
"context"
"errors"
"strconv"
"strings"
@ -13,13 +12,14 @@ import (
"code.gitea.io/gitea/models/packages"
conan_module "code.gitea.io/gitea/modules/packages/conan"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
"xorm.io/builder"
)
var (
ErrRecipeReferenceNotExist = errors.New("Recipe reference does not exist")
ErrPackageReferenceNotExist = errors.New("Package reference does not exist")
ErrRecipeReferenceNotExist = util.NewNotExistErrorf("recipe reference does not exist")
ErrPackageReferenceNotExist = util.NewNotExistErrorf("package reference does not exist")
)
// RecipeExists checks if a recipe exists

View file

@ -5,7 +5,6 @@ package container
import (
"context"
"errors"
"strings"
"time"
@ -13,11 +12,12 @@ import (
"code.gitea.io/gitea/models/packages"
user_model "code.gitea.io/gitea/models/user"
container_module "code.gitea.io/gitea/modules/packages/container"
"code.gitea.io/gitea/modules/util"
"xorm.io/builder"
)
var ErrContainerBlobNotExist = errors.New("Container blob does not exist")
var ErrContainerBlobNotExist = util.NewNotExistErrorf("container blob does not exist")
type BlobSearchOptions struct {
OwnerID int64

View file

@ -5,11 +5,11 @@ package packages
import (
"context"
"errors"
"fmt"
"strings"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/util"
"xorm.io/builder"
)
@ -20,9 +20,9 @@ func init() {
var (
// ErrDuplicatePackage indicates a duplicated package error
ErrDuplicatePackage = errors.New("Package does exist already")
ErrDuplicatePackage = util.NewAlreadyExistErrorf("package already exists")
// ErrPackageNotExist indicates a package not exist error
ErrPackageNotExist = errors.New("Package does not exist")
ErrPackageNotExist = util.NewNotExistErrorf("package does not exist")
)
// Type of a package

View file

@ -5,15 +5,15 @@ package packages
import (
"context"
"errors"
"time"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
)
// ErrPackageBlobNotExist indicates a package blob not exist error
var ErrPackageBlobNotExist = errors.New("Package blob does not exist")
var ErrPackageBlobNotExist = util.NewNotExistErrorf("package blob does not exist")
func init() {
db.RegisterModel(new(PackageBlob))

View file

@ -5,7 +5,6 @@ package packages
import (
"context"
"errors"
"strings"
"time"
@ -15,7 +14,7 @@ import (
)
// ErrPackageBlobUploadNotExist indicates a package blob upload not exist error
var ErrPackageBlobUploadNotExist = errors.New("Package blob upload does not exist")
var ErrPackageBlobUploadNotExist = util.NewNotExistErrorf("package blob upload does not exist")
func init() {
db.RegisterModel(new(PackageBlobUpload))

View file

@ -5,17 +5,17 @@ package packages
import (
"context"
"errors"
"fmt"
"regexp"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
"xorm.io/builder"
)
var ErrPackageCleanupRuleNotExist = errors.New("Package blob does not exist")
var ErrPackageCleanupRuleNotExist = util.NewNotExistErrorf("package blob does not exist")
func init() {
db.RegisterModel(new(PackageCleanupRule))

View file

@ -5,13 +5,13 @@ package packages
import (
"context"
"errors"
"strconv"
"strings"
"time"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
"xorm.io/builder"
)
@ -22,9 +22,9 @@ func init() {
var (
// ErrDuplicatePackageFile indicates a duplicated package file error
ErrDuplicatePackageFile = errors.New("Package file does exist already")
ErrDuplicatePackageFile = util.NewAlreadyExistErrorf("package file already exists")
// ErrPackageFileNotExist indicates a package file not exist error
ErrPackageFileNotExist = errors.New("Package file does not exist")
ErrPackageFileNotExist = util.NewNotExistErrorf("package file does not exist")
)
// EmptyFileKey is a named constant for an empty file key

View file

@ -5,7 +5,6 @@ package packages
import (
"context"
"errors"
"strconv"
"strings"
@ -17,7 +16,7 @@ import (
)
// ErrDuplicatePackageVersion indicates a duplicated package version error
var ErrDuplicatePackageVersion = errors.New("Package version already exists")
var ErrDuplicatePackageVersion = util.NewAlreadyExistErrorf("package version already exists")
func init() {
db.RegisterModel(new(PackageVersion))

View file

@ -5,7 +5,6 @@ package project
import (
"context"
"errors"
"fmt"
"code.gitea.io/gitea/models/db"
@ -176,7 +175,7 @@ func NewProject(p *Project) error {
}
if !IsTypeValid(p.Type) {
return errors.New("project type is not valid")
return util.NewInvalidArgumentErrorf("project type is not valid")
}
ctx, committer, err := db.TxContext(db.DefaultContext)
@ -301,7 +300,7 @@ func changeProjectStatus(ctx context.Context, p *Project, isClosed bool) error {
// DeleteProjectByID deletes a project from a repository. if it's not in a database
// transaction, it will start a new database transaction
func DeleteProjectByID(ctx context.Context, id int64) error {
return db.AutoTx(ctx, func(ctx context.Context) error {
return db.WithTx(ctx, func(ctx context.Context) error {
p, err := GetProjectByID(ctx, id)
if err != nil {
if IsErrProjectNotExist(err) {

View file

@ -105,7 +105,7 @@ func ChangeCollaborationAccessMode(ctx context.Context, repo *Repository, uid in
return nil
}
return db.AutoTx(ctx, func(ctx context.Context) error {
return db.WithTx(ctx, func(ctx context.Context) error {
e := db.GetEngine(ctx)
collaboration := &Collaboration{

View file

@ -6,16 +6,16 @@ package repo
import (
"context"
"errors"
"time"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
)
// ErrMirrorNotExist mirror does not exist error
var ErrMirrorNotExist = errors.New("Mirror does not exist")
var ErrMirrorNotExist = util.NewNotExistErrorf("Mirror does not exist")
// Mirror represents mirror information of a repository.
type Mirror struct {

View file

@ -5,18 +5,18 @@ package repo
import (
"context"
"errors"
"time"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
"xorm.io/builder"
)
// ErrPushMirrorNotExist mirror does not exist error
var ErrPushMirrorNotExist = errors.New("PushMirror does not exist")
var ErrPushMirrorNotExist = util.NewNotExistErrorf("PushMirror does not exist")
// PushMirror represents mirror information of a repository.
type PushMirror struct {
@ -90,7 +90,7 @@ func DeletePushMirrors(ctx context.Context, opts PushMirrorOptions) error {
_, err := db.GetEngine(ctx).Where(opts.toConds()).Delete(&PushMirror{})
return err
}
return errors.New("repoID required and must be set")
return util.NewInvalidArgumentErrorf("repoID required and must be set")
}
func GetPushMirror(ctx context.Context, opts PushMirrorOptions) (*PushMirror, error) {

View file

@ -6,7 +6,6 @@ package repo
import (
"context"
"errors"
"fmt"
"sort"
"strconv"
@ -156,7 +155,7 @@ func AddReleaseAttachments(ctx context.Context, releaseID int64, attachmentUUIDs
for i := range attachments {
if attachments[i].ReleaseID != 0 {
return errors.New("release permission denied")
return util.NewPermissionDeniedErrorf("release permission denied")
}
attachments[i].ReleaseID = releaseID
// No assign value could be 0, so ignore AllCols().

View file

@ -5,7 +5,6 @@ package repo
import (
"context"
"errors"
"fmt"
"strings"
@ -708,7 +707,7 @@ func GetUserRepositories(opts *SearchRepoOptions) (RepositoryList, int64, error)
cond := builder.NewCond()
if opts.Actor == nil {
return nil, 0, errors.New("GetUserRepositories: Actor is needed but not given")
return nil, 0, util.NewInvalidArgumentErrorf("GetUserRepositories: Actor is needed but not given")
}
cond = cond.And(builder.Eq{"owner_id": opts.Actor.ID})
if !opts.Private {

View file

@ -155,7 +155,7 @@ func TestRepositoryReadyForTransfer(status repo_model.RepositoryStatus) error {
// CreatePendingRepositoryTransfer transfer a repo from one owner to a new one.
// it marks the repository transfer as "pending"
func CreatePendingRepositoryTransfer(ctx context.Context, doer, newOwner *user_model.User, repoID int64, teams []*organization.Team) error {
return db.AutoTx(ctx, func(ctx context.Context) error {
return db.WithTx(ctx, func(ctx context.Context) error {
repo, err := repo_model.GetRepositoryByID(ctx, repoID)
if err != nil {
return err

View file

@ -12,7 +12,7 @@ import (
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/cache"
"code.gitea.io/gitea/modules/setting"
setting_module "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/timeutil"
"strk.kbt.io/projects/go/libravatar"
@ -88,17 +88,17 @@ func GetSettingNoCache(key string) (*Setting, error) {
if len(v) == 0 {
return nil, ErrSettingIsNotExist{key}
}
return v[key], nil
return v[strings.ToLower(key)], nil
}
// GetSetting returns the setting value via the key
func GetSetting(key string) (*Setting, error) {
return cache.Get(genSettingCacheKey(key), func() (*Setting, error) {
func GetSetting(key string) (string, error) {
return cache.GetString(genSettingCacheKey(key), func() (string, error) {
res, err := GetSettingNoCache(key)
if err != nil {
return nil, err
return "", err
}
return res, nil
return res.SettingValue, nil
})
}
@ -106,7 +106,8 @@ func GetSetting(key string) (*Setting, error) {
// none existing keys and errors are ignored and result in false
func GetSettingBool(key string) bool {
s, _ := GetSetting(key)
return s.GetValueBool()
v, _ := strconv.ParseBool(s)
return v
}
// GetSettings returns specific settings
@ -130,7 +131,7 @@ func GetSettings(keys []string) (map[string]*Setting, error) {
type AllSettings map[string]*Setting
func (settings AllSettings) Get(key string) Setting {
if v, ok := settings[key]; ok {
if v, ok := settings[strings.ToLower(key)]; ok {
return *v
}
return Setting{}
@ -183,14 +184,17 @@ func SetSettingNoVersion(key, value string) error {
// SetSetting updates a users' setting for a specific key
func SetSetting(setting *Setting) error {
_, err := cache.Set(genSettingCacheKey(setting.SettingKey), func() (*Setting, error) {
return setting, upsertSettingValue(strings.ToLower(setting.SettingKey), setting.SettingValue, setting.Version)
})
if err != nil {
if err := upsertSettingValue(strings.ToLower(setting.SettingKey), setting.SettingValue, setting.Version); err != nil {
return err
}
setting.Version++
cc := cache.GetCache()
if cc != nil {
return cc.Put(genSettingCacheKey(setting.SettingKey), setting.SettingValue, setting_module.CacheService.TTLSeconds())
}
return nil
}
@ -242,7 +246,7 @@ func Init() error {
var disableGravatar bool
disableGravatarSetting, err := GetSettingNoCache(KeyPictureDisableGravatar)
if IsErrSettingIsNotExist(err) {
disableGravatar = setting.GetDefaultDisableGravatar()
disableGravatar = setting_module.GetDefaultDisableGravatar()
disableGravatarSetting = &Setting{SettingValue: strconv.FormatBool(disableGravatar)}
} else if err != nil {
return err
@ -253,7 +257,7 @@ func Init() error {
var enableFederatedAvatar bool
enableFederatedAvatarSetting, err := GetSettingNoCache(KeyPictureEnableFederatedAvatar)
if IsErrSettingIsNotExist(err) {
enableFederatedAvatar = setting.GetDefaultEnableFederatedAvatar(disableGravatar)
enableFederatedAvatar = setting_module.GetDefaultEnableFederatedAvatar(disableGravatar)
enableFederatedAvatarSetting = &Setting{SettingValue: strconv.FormatBool(enableFederatedAvatar)}
} else if err != nil {
return err
@ -261,20 +265,20 @@ func Init() error {
enableFederatedAvatar = disableGravatarSetting.GetValueBool()
}
if setting.OfflineMode {
if setting_module.OfflineMode {
disableGravatar = true
enableFederatedAvatar = false
}
if disableGravatar || !enableFederatedAvatar {
if enableFederatedAvatar || !disableGravatar {
var err error
GravatarSourceURL, err = url.Parse(setting.GravatarSource)
GravatarSourceURL, err = url.Parse(setting_module.GravatarSource)
if err != nil {
return fmt.Errorf("Failed to parse Gravatar URL(%s): %w", setting.GravatarSource, err)
return fmt.Errorf("Failed to parse Gravatar URL(%s): %w", setting_module.GravatarSource, err)
}
}
if enableFederatedAvatarSetting.GetValueBool() {
if GravatarSourceURL != nil && enableFederatedAvatarSetting.GetValueBool() {
LibravatarService = libravatar.New()
if GravatarSourceURL.Scheme == "https" {
LibravatarService.SetUseHTTPS(true)

View file

@ -33,10 +33,14 @@ func TestSettings(t *testing.T) {
assert.EqualValues(t, newSetting.SettingValue, settings[strings.ToLower(keyName)].SettingValue)
// updated setting
updatedSetting := &system.Setting{SettingKey: keyName, SettingValue: "100", Version: newSetting.Version}
updatedSetting := &system.Setting{SettingKey: keyName, SettingValue: "100", Version: settings[strings.ToLower(keyName)].Version}
err = system.SetSetting(updatedSetting)
assert.NoError(t, err)
value, err := system.GetSetting(keyName)
assert.NoError(t, err)
assert.EqualValues(t, updatedSetting.SettingValue, value)
// get all settings
settings, err = system.GetAllSettings()
assert.NoError(t, err)

View file

@ -64,7 +64,7 @@ func Copy(src, dest string) error {
func CopyDir(srcPath, destPath string, filters ...func(filePath string) bool) error {
// Check if target directory exists.
if _, err := os.Stat(destPath); !errors.Is(err, os.ErrNotExist) {
return errors.New("file or directory already exists: " + destPath)
return util.NewAlreadyExistErrorf("file or directory already exists: %s", destPath)
}
err := os.MkdirAll(destPath, os.ModePerm)

View file

@ -67,9 +67,7 @@ func (u *User) AvatarLinkWithSize(size int) string {
useLocalAvatar := false
autoGenerateAvatar := false
disableGravatarSetting, _ := system_model.GetSetting(system_model.KeyPictureDisableGravatar)
disableGravatar := disableGravatarSetting.GetValueBool()
disableGravatar := system_model.GetSettingBool(system_model.KeyPictureDisableGravatar)
switch {
case u.UseCustomAvatar:

View file

@ -6,7 +6,6 @@ package user
import (
"context"
"errors"
"fmt"
"net/mail"
"regexp"
@ -22,7 +21,7 @@ import (
)
// ErrEmailNotActivated e-mail address has not been activated error
var ErrEmailNotActivated = errors.New("e-mail address has not been activated")
var ErrEmailNotActivated = util.NewInvalidArgumentErrorf("e-mail address has not been activated")
// ErrEmailCharIsNotSupported e-mail address contains unsupported character
type ErrEmailCharIsNotSupported struct {

View file

@ -5,7 +5,6 @@ package user
import (
"context"
"errors"
"fmt"
"code.gitea.io/gitea/models/db"
@ -13,7 +12,7 @@ import (
)
// ErrOpenIDNotExist openid is not known
var ErrOpenIDNotExist = errors.New("OpenID is unknown")
var ErrOpenIDNotExist = util.NewNotExistErrorf("OpenID is unknown")
// UserOpenID is the list of all OpenID identities of a user.
// Since this is a middle table, name it OpenID is not suitable, so we ignore the lint here

View file

@ -53,13 +53,13 @@ func genSettingCacheKey(userID int64, key string) string {
}
// GetSetting returns the setting value via the key
func GetSetting(uid int64, key string) (*Setting, error) {
return cache.Get(genSettingCacheKey(uid, key), func() (*Setting, error) {
func GetSetting(uid int64, key string) (string, error) {
return cache.GetString(genSettingCacheKey(uid, key), func() (string, error) {
res, err := GetSettingNoCache(uid, key)
if err != nil {
return nil, err
return "", err
}
return res, nil
return res.SettingValue, nil
})
}
@ -154,7 +154,7 @@ func SetUserSetting(userID int64, key, value string) error {
return err
}
_, err := cache.Set(genSettingCacheKey(userID, key), func() (string, error) {
_, err := cache.GetString(genSettingCacheKey(userID, key), func() (string, error) {
return value, upsertUserSettingValue(userID, key, value)
})

View file

@ -275,6 +275,15 @@ func (u *User) CanEditGitHook() bool {
return !setting.DisableGitHooks && (u.IsAdmin || u.AllowGitHook)
}
// CanForkRepo returns if user login can fork a repository
// It checks especially that the user can create repos, and potentially more
func (u *User) CanForkRepo() bool {
if setting.Repository.AllowForkWithoutMaximumLimit {
return true
}
return u.CanCreateRepo()
}
// CanImportLocal returns true if user can migrate repository by local path.
func (u *User) CanImportLocal() bool {
if !setting.ImportLocalPaths || u == nil {

View file

@ -12,6 +12,7 @@ import (
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
webhook_module "code.gitea.io/gitea/modules/webhook"
gouuid "github.com/google/uuid"
)
@ -23,69 +24,6 @@ import (
// \___|_ / \____/ \____/|__|_ \ |____| (____ /____ >__|_ \
// \/ \/ \/ \/ \/
// HookEventType is the type of an hook event
type HookEventType string
// Types of hook events
const (
HookEventCreate HookEventType = "create"
HookEventDelete HookEventType = "delete"
HookEventFork HookEventType = "fork"
HookEventPush HookEventType = "push"
HookEventIssues HookEventType = "issues"
HookEventIssueAssign HookEventType = "issue_assign"
HookEventIssueLabel HookEventType = "issue_label"
HookEventIssueMilestone HookEventType = "issue_milestone"
HookEventIssueComment HookEventType = "issue_comment"
HookEventPullRequest HookEventType = "pull_request"
HookEventPullRequestAssign HookEventType = "pull_request_assign"
HookEventPullRequestLabel HookEventType = "pull_request_label"
HookEventPullRequestMilestone HookEventType = "pull_request_milestone"
HookEventPullRequestComment HookEventType = "pull_request_comment"
HookEventPullRequestReviewApproved HookEventType = "pull_request_review_approved"
HookEventPullRequestReviewRejected HookEventType = "pull_request_review_rejected"
HookEventPullRequestReviewComment HookEventType = "pull_request_review_comment"
HookEventPullRequestSync HookEventType = "pull_request_sync"
HookEventWiki HookEventType = "wiki"
HookEventRepository HookEventType = "repository"
HookEventRelease HookEventType = "release"
HookEventPackage HookEventType = "package"
)
// Event returns the HookEventType as an event string
func (h HookEventType) Event() string {
switch h {
case HookEventCreate:
return "create"
case HookEventDelete:
return "delete"
case HookEventFork:
return "fork"
case HookEventPush:
return "push"
case HookEventIssues, HookEventIssueAssign, HookEventIssueLabel, HookEventIssueMilestone:
return "issues"
case HookEventPullRequest, HookEventPullRequestAssign, HookEventPullRequestLabel, HookEventPullRequestMilestone,
HookEventPullRequestSync:
return "pull_request"
case HookEventIssueComment, HookEventPullRequestComment:
return "issue_comment"
case HookEventPullRequestReviewApproved:
return "pull_request_approved"
case HookEventPullRequestReviewRejected:
return "pull_request_rejected"
case HookEventPullRequestReviewComment:
return "pull_request_comment"
case HookEventWiki:
return "wiki"
case HookEventRepository:
return "repository"
case HookEventRelease:
return "release"
}
return ""
}
// HookRequest represents hook task request information.
type HookRequest struct {
URL string `json:"url"`
@ -107,7 +45,7 @@ type HookTask struct {
UUID string `xorm:"unique"`
api.Payloader `xorm:"-"`
PayloadContent string `xorm:"LONGTEXT"`
EventType HookEventType
EventType webhook_module.HookEventType
IsDelivered bool
Delivered int64
DeliveredString string `xorm:"-"`

View file

@ -16,6 +16,7 @@ import (
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
webhook_module "code.gitea.io/gitea/modules/webhook"
"xorm.io/builder"
)
@ -46,7 +47,7 @@ type ErrHookTaskNotExist struct {
UUID string
}
// IsErrWebhookNotExist checks if an error is a ErrWebhookNotExist.
// IsErrHookTaskNotExist checks if an error is a ErrHookTaskNotExist.
func IsErrHookTaskNotExist(err error) bool {
_, ok := err.(ErrHookTaskNotExist)
return ok
@ -117,84 +118,22 @@ func IsValidHookContentType(name string) bool {
return ok
}
// HookEvents is a set of web hook events
type HookEvents struct {
Create bool `json:"create"`
Delete bool `json:"delete"`
Fork bool `json:"fork"`
Issues bool `json:"issues"`
IssueAssign bool `json:"issue_assign"`
IssueLabel bool `json:"issue_label"`
IssueMilestone bool `json:"issue_milestone"`
IssueComment bool `json:"issue_comment"`
Push bool `json:"push"`
PullRequest bool `json:"pull_request"`
PullRequestAssign bool `json:"pull_request_assign"`
PullRequestLabel bool `json:"pull_request_label"`
PullRequestMilestone bool `json:"pull_request_milestone"`
PullRequestComment bool `json:"pull_request_comment"`
PullRequestReview bool `json:"pull_request_review"`
PullRequestSync bool `json:"pull_request_sync"`
Wiki bool `json:"wiki"`
Repository bool `json:"repository"`
Release bool `json:"release"`
Package bool `json:"package"`
}
// HookEvent represents events that will delivery hook.
type HookEvent struct {
PushOnly bool `json:"push_only"`
SendEverything bool `json:"send_everything"`
ChooseEvents bool `json:"choose_events"`
BranchFilter string `json:"branch_filter"`
HookEvents `json:"events"`
}
// HookType is the type of a webhook
type HookType = string
// Types of webhooks
const (
GITEA HookType = "gitea"
GOGS HookType = "gogs"
SLACK HookType = "slack"
DISCORD HookType = "discord"
DINGTALK HookType = "dingtalk"
TELEGRAM HookType = "telegram"
MSTEAMS HookType = "msteams"
FEISHU HookType = "feishu"
MATRIX HookType = "matrix"
WECHATWORK HookType = "wechatwork"
PACKAGIST HookType = "packagist"
)
// HookStatus is the status of a web hook
type HookStatus int
// Possible statuses of a web hook
const (
HookStatusNone = iota
HookStatusSucceed
HookStatusFail
)
// Webhook represents a web hook object.
type Webhook struct {
ID int64 `xorm:"pk autoincr"`
RepoID int64 `xorm:"INDEX"` // An ID of 0 indicates either a default or system webhook
OrgID int64 `xorm:"INDEX"`
IsSystemWebhook bool
URL string `xorm:"url TEXT"`
HTTPMethod string `xorm:"http_method"`
ContentType HookContentType
Secret string `xorm:"TEXT"`
Events string `xorm:"TEXT"`
*HookEvent `xorm:"-"`
IsActive bool `xorm:"INDEX"`
Type HookType `xorm:"VARCHAR(16) 'type'"`
Meta string `xorm:"TEXT"` // store hook-specific attributes
LastStatus HookStatus // Last delivery status
ID int64 `xorm:"pk autoincr"`
RepoID int64 `xorm:"INDEX"` // An ID of 0 indicates either a default or system webhook
OrgID int64 `xorm:"INDEX"`
IsSystemWebhook bool
URL string `xorm:"url TEXT"`
HTTPMethod string `xorm:"http_method"`
ContentType HookContentType
Secret string `xorm:"TEXT"`
Events string `xorm:"TEXT"`
*webhook_module.HookEvent `xorm:"-"`
IsActive bool `xorm:"INDEX"`
Type webhook_module.HookType `xorm:"VARCHAR(16) 'type'"`
Meta string `xorm:"TEXT"` // store hook-specific attributes
LastStatus webhook_module.HookStatus // Last delivery status
// HeaderAuthorizationEncrypted should be accessed using HeaderAuthorization() and SetHeaderAuthorization()
HeaderAuthorizationEncrypted string `xorm:"TEXT"`
@ -209,7 +148,7 @@ func init() {
// AfterLoad updates the webhook object upon setting a column
func (w *Webhook) AfterLoad() {
w.HookEvent = &HookEvent{}
w.HookEvent = &webhook_module.HookEvent{}
if err := json.Unmarshal([]byte(w.Events), w.HookEvent); err != nil {
log.Error("Unmarshal[%d]: %v", w.ID, err)
}
@ -362,34 +301,34 @@ func (w *Webhook) HasPackageEvent() bool {
// EventCheckers returns event checkers
func (w *Webhook) EventCheckers() []struct {
Has func() bool
Type HookEventType
Type webhook_module.HookEventType
} {
return []struct {
Has func() bool
Type HookEventType
Type webhook_module.HookEventType
}{
{w.HasCreateEvent, HookEventCreate},
{w.HasDeleteEvent, HookEventDelete},
{w.HasForkEvent, HookEventFork},
{w.HasPushEvent, HookEventPush},
{w.HasIssuesEvent, HookEventIssues},
{w.HasIssuesAssignEvent, HookEventIssueAssign},
{w.HasIssuesLabelEvent, HookEventIssueLabel},
{w.HasIssuesMilestoneEvent, HookEventIssueMilestone},
{w.HasIssueCommentEvent, HookEventIssueComment},
{w.HasPullRequestEvent, HookEventPullRequest},
{w.HasPullRequestAssignEvent, HookEventPullRequestAssign},
{w.HasPullRequestLabelEvent, HookEventPullRequestLabel},
{w.HasPullRequestMilestoneEvent, HookEventPullRequestMilestone},
{w.HasPullRequestCommentEvent, HookEventPullRequestComment},
{w.HasPullRequestApprovedEvent, HookEventPullRequestReviewApproved},
{w.HasPullRequestRejectedEvent, HookEventPullRequestReviewRejected},
{w.HasPullRequestCommentEvent, HookEventPullRequestReviewComment},
{w.HasPullRequestSyncEvent, HookEventPullRequestSync},
{w.HasWikiEvent, HookEventWiki},
{w.HasRepositoryEvent, HookEventRepository},
{w.HasReleaseEvent, HookEventRelease},
{w.HasPackageEvent, HookEventPackage},
{w.HasCreateEvent, webhook_module.HookEventCreate},
{w.HasDeleteEvent, webhook_module.HookEventDelete},
{w.HasForkEvent, webhook_module.HookEventFork},
{w.HasPushEvent, webhook_module.HookEventPush},
{w.HasIssuesEvent, webhook_module.HookEventIssues},
{w.HasIssuesAssignEvent, webhook_module.HookEventIssueAssign},
{w.HasIssuesLabelEvent, webhook_module.HookEventIssueLabel},
{w.HasIssuesMilestoneEvent, webhook_module.HookEventIssueMilestone},
{w.HasIssueCommentEvent, webhook_module.HookEventIssueComment},
{w.HasPullRequestEvent, webhook_module.HookEventPullRequest},
{w.HasPullRequestAssignEvent, webhook_module.HookEventPullRequestAssign},
{w.HasPullRequestLabelEvent, webhook_module.HookEventPullRequestLabel},
{w.HasPullRequestMilestoneEvent, webhook_module.HookEventPullRequestMilestone},
{w.HasPullRequestCommentEvent, webhook_module.HookEventPullRequestComment},
{w.HasPullRequestApprovedEvent, webhook_module.HookEventPullRequestReviewApproved},
{w.HasPullRequestRejectedEvent, webhook_module.HookEventPullRequestReviewRejected},
{w.HasPullRequestCommentEvent, webhook_module.HookEventPullRequestReviewComment},
{w.HasPullRequestSyncEvent, webhook_module.HookEventPullRequestSync},
{w.HasWikiEvent, webhook_module.HookEventWiki},
{w.HasRepositoryEvent, webhook_module.HookEventRepository},
{w.HasReleaseEvent, webhook_module.HookEventRelease},
{w.HasPackageEvent, webhook_module.HookEventPackage},
}
}
@ -453,7 +392,7 @@ func getWebhook(bean *Webhook) (*Webhook, error) {
if err != nil {
return nil, err
} else if !has {
return nil, ErrWebhookNotExist{bean.ID}
return nil, ErrWebhookNotExist{ID: bean.ID}
}
return bean, nil
}
@ -541,7 +480,7 @@ func GetSystemOrDefaultWebhook(id int64) (*Webhook, error) {
if err != nil {
return nil, err
} else if !has {
return nil, ErrWebhookNotExist{id}
return nil, ErrWebhookNotExist{ID: id}
}
return webhook, nil
}

View file

@ -13,6 +13,7 @@ import (
"code.gitea.io/gitea/modules/json"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/util"
webhook_module "code.gitea.io/gitea/modules/webhook"
"github.com/stretchr/testify/assert"
)
@ -46,11 +47,11 @@ func TestWebhook_History(t *testing.T) {
func TestWebhook_UpdateEvent(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
webhook := unittest.AssertExistsAndLoadBean(t, &Webhook{ID: 1})
hookEvent := &HookEvent{
hookEvent := &webhook_module.HookEvent{
PushOnly: true,
SendEverything: false,
ChooseEvents: false,
HookEvents: HookEvents{
HookEvents: webhook_module.HookEvents{
Create: false,
Push: true,
PullRequest: false,
@ -59,7 +60,7 @@ func TestWebhook_UpdateEvent(t *testing.T) {
webhook.HookEvent = hookEvent
assert.NoError(t, webhook.UpdateEvent())
assert.NotEmpty(t, webhook.Events)
actualHookEvent := &HookEvent{}
actualHookEvent := &webhook_module.HookEvent{}
assert.NoError(t, json.Unmarshal([]byte(webhook.Events), actualHookEvent))
assert.Equal(t, *hookEvent, *actualHookEvent)
}
@ -74,13 +75,13 @@ func TestWebhook_EventsArray(t *testing.T) {
"package",
},
(&Webhook{
HookEvent: &HookEvent{SendEverything: true},
HookEvent: &webhook_module.HookEvent{SendEverything: true},
}).EventsArray(),
)
assert.Equal(t, []string{"push"},
(&Webhook{
HookEvent: &HookEvent{PushOnly: true},
HookEvent: &webhook_module.HookEvent{PushOnly: true},
}).EventsArray(),
)
}

28
modules/avatar/hash.go Normal file
View file

@ -0,0 +1,28 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package avatar
import (
"crypto/sha256"
"encoding/hex"
"strconv"
)
// HashAvatar will generate a unique string, which ensures that when there's a
// different unique ID while the data is the same, it will generate a different
// output. It will generate the output according to:
// HEX(HASH(uniqueID || - || data))
// The hash being used is SHA256.
// The sole purpose of the unique ID is to generate a distinct hash Such that
// two unique IDs with the same data will have a different hash output.
// The "-" byte is important to ensure that data cannot be modified such that
// the first byte is a number, which could lead to a "collision" with the hash
// of another unique ID.
func HashAvatar(uniqueID int64, data []byte) string {
h := sha256.New()
h.Write([]byte(strconv.FormatInt(uniqueID, 10)))
h.Write([]byte{'-'})
h.Write(data)
return hex.EncodeToString(h.Sum(nil))
}

View file

@ -45,39 +45,6 @@ func GetCache() mc.Cache {
return conn
}
// Get returns the key value from cache with callback when no key exists in cache
func Get[V interface{}](key string, getFunc func() (V, error)) (V, error) {
if conn == nil || setting.CacheService.TTL == 0 {
return getFunc()
}
cached := conn.Get(key)
if value, ok := cached.(V); ok {
return value, nil
}
value, err := getFunc()
if err != nil {
return value, err
}
return value, conn.Put(key, value, setting.CacheService.TTLSeconds())
}
// Set updates and returns the key value in the cache with callback. The old value is only removed if the updateFunc() is successful
func Set[V interface{}](key string, valueFunc func() (V, error)) (V, error) {
if conn == nil || setting.CacheService.TTL == 0 {
return valueFunc()
}
value, err := valueFunc()
if err != nil {
return value, err
}
return value, conn.Put(key, value, setting.CacheService.TTLSeconds())
}
// GetString returns the key value from cache with callback when no key exists in cache
func GetString(key string, getFunc func() (string, error)) (string, error) {
if conn == nil || setting.CacheService.TTL == 0 {

View file

@ -219,7 +219,13 @@ func (ctx *APIContext) CheckForOTP() {
func APIAuth(authMethod auth_service.Method) func(*APIContext) {
return func(ctx *APIContext) {
// Get user from session if logged in.
ctx.Doer = authMethod.Verify(ctx.Req, ctx.Resp, ctx, ctx.Session)
var err error
ctx.Doer, err = authMethod.Verify(ctx.Req, ctx.Resp, ctx, ctx.Session)
if err != nil {
ctx.Error(http.StatusUnauthorized, "APIAuth", err)
return
}
if ctx.Doer != nil {
if ctx.Locale.Language() != ctx.Doer.Language {
ctx.Locale = middleware.Locale(ctx.Resp, ctx.Req)
@ -387,7 +393,7 @@ func RepoRefForAPI(next http.Handler) http.Handler {
return
}
ctx.Repo.CommitID = ctx.Repo.Commit.ID.String()
} else if len(refName) == 40 {
} else if len(refName) == git.SHAFullLength {
ctx.Repo.CommitID = refName
ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetCommit(refName)
if err != nil {

View file

@ -662,7 +662,13 @@ func getCsrfOpts() CsrfOptions {
// Auth converts auth.Auth as a middleware
func Auth(authMethod auth.Method) func(*Context) {
return func(ctx *Context) {
ctx.Doer = authMethod.Verify(ctx.Req, ctx.Resp, ctx, ctx.Session)
var err error
ctx.Doer, err = authMethod.Verify(ctx.Req, ctx.Resp, ctx, ctx.Session)
if err != nil {
log.Error("Failed to verify user %v: %v", ctx.Req.RemoteAddr, err)
ctx.Error(http.StatusUnauthorized, "Verify")
return
}
if ctx.Doer != nil {
if ctx.Locale.Language() != ctx.Doer.Language {
ctx.Locale = middleware.Locale(ctx.Resp, ctx.Req)

View file

@ -126,7 +126,7 @@ func (r *Repository) CanCommitToBranch(ctx context.Context, doer *user_model.Use
userCanPush := true
requireSigned := false
if protectedBranch != nil {
userCanPush = protectedBranch.CanUserPush(doer.ID)
userCanPush = protectedBranch.CanUserPush(ctx, doer.ID)
requireSigned = protectedBranch.RequireSignedCommits
}
@ -817,7 +817,7 @@ func getRefName(ctx *Context, pathType RepoRefType) string {
}
// For legacy and API support only full commit sha
parts := strings.Split(path, "/")
if len(parts) > 0 && len(parts[0]) == 40 {
if len(parts) > 0 && len(parts[0]) == git.SHAFullLength {
ctx.Repo.TreePath = strings.Join(parts[1:], "/")
return parts[0]
}
@ -831,7 +831,7 @@ func getRefName(ctx *Context, pathType RepoRefType) string {
if len(ref) == 0 {
// maybe it's a renamed branch
return getRefNameFromPath(ctx, path, func(s string) bool {
b, exist, err := git_model.FindRenamedBranch(ctx.Repo.Repository.ID, s)
b, exist, err := git_model.FindRenamedBranch(ctx, ctx.Repo.Repository.ID, s)
if err != nil {
log.Error("FindRenamedBranch", err)
return false
@ -853,7 +853,7 @@ func getRefName(ctx *Context, pathType RepoRefType) string {
return getRefNameFromPath(ctx, path, ctx.Repo.GitRepo.IsTagExist)
case RepoRefCommit:
parts := strings.Split(path, "/")
if len(parts) > 0 && len(parts[0]) >= 7 && len(parts[0]) <= 40 {
if len(parts) > 0 && len(parts[0]) >= 7 && len(parts[0]) <= git.SHAFullLength {
ctx.Repo.TreePath = strings.Join(parts[1:], "/")
return parts[0]
}
@ -962,7 +962,7 @@ func RepoRefByType(refType RepoRefType, ignoreNotExistErr ...bool) func(*Context
return
}
ctx.Repo.CommitID = ctx.Repo.Commit.ID.String()
} else if len(refName) >= 7 && len(refName) <= 40 {
} else if len(refName) >= 7 && len(refName) <= git.SHAFullLength {
ctx.Repo.IsViewCommit = true
ctx.Repo.CommitID = refName
@ -972,7 +972,7 @@ func RepoRefByType(refType RepoRefType, ignoreNotExistErr ...bool) func(*Context
return
}
// If short commit ID add canonical link header
if len(refName) < 40 {
if len(refName) < git.SHAFullLength {
ctx.RespHeader().Set("Link", fmt.Sprintf("<%s>; rel=\"canonical\"",
util.URLJoin(setting.AppURL, strings.Replace(ctx.Req.URL.RequestURI(), util.PathEscapeSegments(refName), url.PathEscape(ctx.Repo.Commit.ID.String()), 1))))
}

File diff suppressed because it is too large Load diff

View file

@ -9,13 +9,13 @@ import (
activities_model "code.gitea.io/gitea/models/activities"
issues_model "code.gitea.io/gitea/models/issues"
"code.gitea.io/gitea/modules/convert"
"code.gitea.io/gitea/modules/graceful"
"code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/process"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/services/convert"
)
// Init starts this eventsource

View file

@ -9,10 +9,7 @@ import (
"fmt"
"io"
"os"
"os/exec"
"regexp"
"code.gitea.io/gitea/modules/process"
)
// BlamePart represents block of blame - continuous lines with one sha
@ -23,12 +20,11 @@ type BlamePart struct {
// BlameReader returns part of file blame one by one
type BlameReader struct {
cmd *exec.Cmd
output io.ReadCloser
reader *bufio.Reader
lastSha *string
cancel context.CancelFunc // Cancels the context that this reader runs in
finished process.FinishedFunc // Tells the process manager we're finished and it can remove the associated process from the process table
cmd *Command
output io.WriteCloser
reader io.ReadCloser
done chan error
lastSha *string
}
var shaLineRegex = regexp.MustCompile("^([a-z0-9]{40})")
@ -37,7 +33,7 @@ var shaLineRegex = regexp.MustCompile("^([a-z0-9]{40})")
func (r *BlameReader) NextPart() (*BlamePart, error) {
var blamePart *BlamePart
reader := r.reader
reader := bufio.NewReader(r.reader)
if r.lastSha != nil {
blamePart = &BlamePart{*r.lastSha, make([]string, 0)}
@ -99,51 +95,41 @@ func (r *BlameReader) NextPart() (*BlamePart, error) {
// Close BlameReader - don't run NextPart after invoking that
func (r *BlameReader) Close() error {
defer r.finished() // Only remove the process from the process table when the underlying command is closed
r.cancel() // However, first cancel our own context early
err := <-r.done
_ = r.reader.Close()
_ = r.output.Close()
if err := r.cmd.Wait(); err != nil {
return fmt.Errorf("Wait: %w", err)
}
return nil
return err
}
// CreateBlameReader creates reader for given repository, commit and file
func CreateBlameReader(ctx context.Context, repoPath, commitID, file string) (*BlameReader, error) {
return createBlameReader(ctx, repoPath, GitExecutable, "blame", commitID, "--porcelain", "--", file)
}
func createBlameReader(ctx context.Context, dir string, command ...string) (*BlameReader, error) {
// Here we use the provided context - this should be tied to the request performing the blame so that it does not hang around.
ctx, cancel, finished := process.GetManager().AddContext(ctx, fmt.Sprintf("GetBlame [repo_path: %s]", dir))
cmd := exec.CommandContext(ctx, command[0], command[1:]...)
cmd.Dir = dir
cmd.Stderr = os.Stderr
process.SetSysProcAttribute(cmd)
stdout, err := cmd.StdoutPipe()
cmd := NewCommandContextNoGlobals(ctx, "blame", "--porcelain").
AddDynamicArguments(commitID).
AddDashesAndList(file).
SetDescription(fmt.Sprintf("GetBlame [repo_path: %s]", repoPath))
reader, stdout, err := os.Pipe()
if err != nil {
defer finished()
return nil, fmt.Errorf("StdoutPipe: %w", err)
return nil, err
}
if err = cmd.Start(); err != nil {
defer finished()
_ = stdout.Close()
return nil, fmt.Errorf("Start: %w", err)
}
done := make(chan error, 1)
reader := bufio.NewReader(stdout)
go func(cmd *Command, dir string, stdout io.WriteCloser, done chan error) {
if err := cmd.Run(&RunOpts{
UseContextTimeout: true,
Dir: dir,
Stdout: stdout,
Stderr: os.Stderr,
}); err == nil {
stdout.Close()
}
done <- err
}(cmd, repoPath, stdout, done)
return &BlameReader{
cmd: cmd,
output: stdout,
reader: reader,
cancel: cancel,
finished: finished,
cmd: cmd,
output: stdout,
reader: reader,
done: done,
}, nil
}

View file

@ -5,139 +5,36 @@ package git
import (
"context"
"os"
"testing"
"github.com/stretchr/testify/assert"
)
const exampleBlame = `
4b92a6c2df28054ad766bc262f308db9f6066596 1 1 1
author Unknown
author-mail <joe2010xtmf@163.com>
author-time 1392833071
author-tz -0500
committer Unknown
committer-mail <joe2010xtmf@163.com>
committer-time 1392833071
committer-tz -0500
summary Add code of delete user
previous be0ba9ea88aff8a658d0495d36accf944b74888d gogs.go
filename gogs.go
// Copyright 2014 The Gogs Authors. All rights reserved.
ce21ed6c3490cdfad797319cbb1145e2330a8fef 2 2 1
author Joubert RedRat
author-mail <eu+github@redrat.com.br>
author-time 1482322397
author-tz -0200
committer Lunny Xiao
committer-mail <xiaolunwen@gmail.com>
committer-time 1482322397
committer-tz +0800
summary Remove remaining Gogs reference on locales and cmd (#430)
previous 618407c018cdf668ceedde7454c42fb22ba422d8 main.go
filename main.go
// Copyright 2016 The Gitea Authors. All rights reserved.
4b92a6c2df28054ad766bc262f308db9f6066596 2 3 2
author Unknown
author-mail <joe2010xtmf@163.com>
author-time 1392833071
author-tz -0500
committer Unknown
committer-mail <joe2010xtmf@163.com>
committer-time 1392833071
committer-tz -0500
summary Add code of delete user
previous be0ba9ea88aff8a658d0495d36accf944b74888d gogs.go
filename gogs.go
// Use of this source code is governed by a MIT-style
4b92a6c2df28054ad766bc262f308db9f6066596 3 4
author Unknown
author-mail <joe2010xtmf@163.com>
author-time 1392833071
author-tz -0500
committer Unknown
committer-mail <joe2010xtmf@163.com>
committer-time 1392833071
committer-tz -0500
summary Add code of delete user
previous be0ba9ea88aff8a658d0495d36accf944b74888d gogs.go
filename gogs.go
// license that can be found in the LICENSE file.
e2aa991e10ffd924a828ec149951f2f20eecead2 6 6 2
author Lunny Xiao
author-mail <xiaolunwen@gmail.com>
author-time 1478872595
author-tz +0800
committer Sandro Santilli
committer-mail <strk@kbt.io>
committer-time 1478872595
committer-tz +0100
summary ask for go get from code.gitea.io/gitea and change gogs to gitea on main file (#146)
previous 5fc370e332171b8658caed771b48585576f11737 main.go
filename main.go
// Gitea (git with a cup of tea) is a painless self-hosted Git Service.
e2aa991e10ffd924a828ec149951f2f20eecead2 7 7
package main // import "code.gitea.io/gitea"
`
func TestReadingBlameOutput(t *testing.T) {
tempFile, err := os.CreateTemp("", ".txt")
if err != nil {
panic(err)
}
defer tempFile.Close()
if _, err = tempFile.WriteString(exampleBlame); err != nil {
panic(err)
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
blameReader, err := createBlameReader(ctx, "", "cat", tempFile.Name())
if err != nil {
panic(err)
}
blameReader, err := CreateBlameReader(ctx, "./tests/repos/repo5_pulls", "f32b0a9dfd09a60f616f29158f772cedd89942d2", "README.md")
assert.NoError(t, err)
defer blameReader.Close()
parts := []*BlamePart{
{
"4b92a6c2df28054ad766bc262f308db9f6066596",
"72866af952e98d02a73003501836074b286a78f6",
[]string{
"// Copyright 2014 The Gogs Authors. All rights reserved.",
"# test_repo",
"Test repository for testing migration from github to gitea",
},
},
{
"ce21ed6c3490cdfad797319cbb1145e2330a8fef",
[]string{
"// Copyright 2016 The Gitea Authors. All rights reserved.",
},
"f32b0a9dfd09a60f616f29158f772cedd89942d2",
[]string{},
},
{
"4b92a6c2df28054ad766bc262f308db9f6066596",
[]string{
"// Use of this source code is governed by a MIT-style",
"// license that can be found in the LICENSE file.",
"",
},
},
{
"e2aa991e10ffd924a828ec149951f2f20eecead2",
[]string{
"// Gitea (git with a cup of tea) is a painless self-hosted Git Service.",
"package main // import \"code.gitea.io/gitea\"",
},
},
nil,
}
for _, part := range parts {
actualPart, err := blameReader.NextPart()
if err != nil {
panic(err)
}
assert.NoError(t, err)
assert.Equal(t, part, actualPart)
}
}

View file

@ -9,8 +9,6 @@ import (
"fmt"
"io"
"os"
"strconv"
"strings"
"code.gitea.io/gitea/modules/log"
)
@ -288,102 +286,6 @@ func (wr *nulSeparatedAttributeWriter) Close() error {
return nil
}
type lineSeparatedAttributeWriter struct {
tmp []byte
attributes chan attributeTriple
closed chan struct{}
}
func (wr *lineSeparatedAttributeWriter) Write(p []byte) (n int, err error) {
l := len(p)
nlIdx := bytes.IndexByte(p, '\n')
for nlIdx >= 0 {
wr.tmp = append(wr.tmp, p[:nlIdx]...)
if len(wr.tmp) == 0 {
// This should not happen
if len(p) > nlIdx+1 {
wr.tmp = wr.tmp[:0]
p = p[nlIdx+1:]
nlIdx = bytes.IndexByte(p, '\n')
continue
} else {
return l, nil
}
}
working := attributeTriple{}
if wr.tmp[0] == '"' {
sb := new(strings.Builder)
remaining := string(wr.tmp[1:])
for len(remaining) > 0 {
rn, _, tail, err := strconv.UnquoteChar(remaining, '"')
if err != nil {
if len(remaining) > 2 && remaining[0] == '"' && remaining[1] == ':' && remaining[2] == ' ' {
working.Filename = sb.String()
wr.tmp = []byte(remaining[3:])
break
}
return l, fmt.Errorf("unexpected tail %s", remaining)
}
_, _ = sb.WriteRune(rn)
remaining = tail
}
} else {
idx := bytes.IndexByte(wr.tmp, ':')
if idx < 0 {
return l, fmt.Errorf("unexpected input %s", string(wr.tmp))
}
working.Filename = string(wr.tmp[:idx])
if len(wr.tmp) < idx+2 {
return l, fmt.Errorf("unexpected input %s", string(wr.tmp))
}
wr.tmp = wr.tmp[idx+2:]
}
idx := bytes.IndexByte(wr.tmp, ':')
if idx < 0 {
return l, fmt.Errorf("unexpected input %s", string(wr.tmp))
}
working.Attribute = string(wr.tmp[:idx])
if len(wr.tmp) < idx+2 {
return l, fmt.Errorf("unexpected input %s", string(wr.tmp))
}
working.Value = string(wr.tmp[idx+2:])
wr.attributes <- working
wr.tmp = wr.tmp[:0]
if len(p) > nlIdx+1 {
p = p[nlIdx+1:]
nlIdx = bytes.IndexByte(p, '\n')
continue
} else {
return l, nil
}
}
wr.tmp = append(wr.tmp, p...)
return l, nil
}
func (wr *lineSeparatedAttributeWriter) ReadAttribute() <-chan attributeTriple {
return wr.attributes
}
func (wr *lineSeparatedAttributeWriter) Close() error {
select {
case <-wr.closed:
return nil
default:
}
close(wr.attributes)
close(wr.closed)
return nil
}
// Create a check attribute reader for the current repository and provided commit ID
func (repo *Repository) CheckAttributeReader(commitID string) (*CheckAttributeReader, context.CancelFunc) {
indexFilename, worktree, deleteTemporaryFile, err := repo.ReadTreeToTemporaryIndex(commitID)

View file

@ -95,64 +95,3 @@ func Test_nulSeparatedAttributeWriter_ReadAttribute(t *testing.T) {
Value: "unspecified",
}, attr)
}
func Test_lineSeparatedAttributeWriter_ReadAttribute(t *testing.T) {
wr := &lineSeparatedAttributeWriter{
attributes: make(chan attributeTriple, 5),
}
testStr := `".gitignore\"\n": linguist-vendored: unspecified
`
n, err := wr.Write([]byte(testStr))
assert.Equal(t, n, len(testStr))
assert.NoError(t, err)
select {
case attr := <-wr.ReadAttribute():
assert.Equal(t, ".gitignore\"\n", attr.Filename)
assert.Equal(t, "linguist-vendored", attr.Attribute)
assert.Equal(t, "unspecified", attr.Value)
case <-time.After(100 * time.Millisecond):
assert.Fail(t, "took too long to read an attribute from the list")
}
// Write a second attribute again
n, err = wr.Write([]byte(testStr))
assert.Equal(t, n, len(testStr))
assert.NoError(t, err)
select {
case attr := <-wr.ReadAttribute():
assert.Equal(t, ".gitignore\"\n", attr.Filename)
assert.Equal(t, "linguist-vendored", attr.Attribute)
assert.Equal(t, "unspecified", attr.Value)
case <-time.After(100 * time.Millisecond):
assert.Fail(t, "took too long to read an attribute from the list")
}
// Write a partial attribute
_, err = wr.Write([]byte("incomplete-file"))
assert.NoError(t, err)
_, err = wr.Write([]byte("name: "))
assert.NoError(t, err)
select {
case <-wr.ReadAttribute():
assert.Fail(t, "There should not be an attribute ready to read")
case <-time.After(100 * time.Millisecond):
}
_, err = wr.Write([]byte("attribute: "))
assert.NoError(t, err)
select {
case <-wr.ReadAttribute():
assert.Fail(t, "There should not be an attribute ready to read")
case <-time.After(100 * time.Millisecond):
}
_, err = wr.Write([]byte("value\n"))
assert.NoError(t, err)
attr := <-wr.ReadAttribute()
assert.Equal(t, "incomplete-filename", attr.Filename)
assert.Equal(t, "attribute", attr.Attribute)
assert.Equal(t, "value", attr.Value)
}

View file

@ -41,7 +41,7 @@ func (repo *Repository) RemoveReference(name string) error {
// ConvertToSHA1 returns a Hash object from a potential ID string
func (repo *Repository) ConvertToSHA1(commitID string) (SHA1, error) {
if len(commitID) == 40 {
if len(commitID) == SHAFullLength {
sha1, err := NewIDFromString(commitID)
if err == nil {
return sha1, nil

View file

@ -137,7 +137,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 && IsValidSHAPattern(commitID) {
if len(commitID) == SHAFullLength && IsValidSHAPattern(commitID) {
sha1, err := NewIDFromString(commitID)
if err == nil {
return sha1, nil

View file

@ -16,7 +16,7 @@ import (
// ReadTreeToIndex reads a treeish to the index
func (repo *Repository) ReadTreeToIndex(treeish string, indexFilename ...string) error {
if len(treeish) != 40 {
if len(treeish) != SHAFullLength {
res, _, err := NewCommand(repo.Ctx, "rev-parse", "--verify").AddDynamicArguments(treeish).RunStdString(&RunOpts{Dir: repo.Path})
if err != nil {
return err

View file

@ -19,7 +19,7 @@ func (repo *Repository) getTree(id SHA1) (*Tree, error) {
// GetTree find the tree object in the repository.
func (repo *Repository) GetTree(idStr string) (*Tree, error) {
if len(idStr) != 40 {
if len(idStr) != SHAFullLength {
res, _, err := NewCommand(repo.Ctx, "rev-parse", "--verify").AddDynamicArguments(idStr).RunStdString(&RunOpts{Dir: repo.Path})
if err != nil {
return nil, err

View file

@ -66,7 +66,7 @@ func (repo *Repository) getTree(id SHA1) (*Tree, error) {
// GetTree find the tree object in the repository.
func (repo *Repository) GetTree(idStr string) (*Tree, error) {
if len(idStr) != 40 {
if len(idStr) != SHAFullLength {
res, err := repo.GetRefCommitID(idStr)
if err != nil {
return nil, err

View file

@ -17,6 +17,9 @@ const EmptySHA = "0000000000000000000000000000000000000000"
// EmptyTreeSHA is the SHA of an empty tree
const EmptyTreeSHA = "4b825dc642cb6eb9a060e54bf8d69288fbee4904"
// SHAFullLength is the full length of a git SHA
const SHAFullLength = 40
// SHAPattern can be used to determine if a string is an valid sha
var shaPattern = regexp.MustCompile(`^[0-9a-f]{4,40}$`)
@ -50,7 +53,7 @@ func MustIDFromString(s string) SHA1 {
func NewIDFromString(s string) (SHA1, error) {
var id SHA1
s = strings.TrimSpace(s)
if len(s) != 40 {
if len(s) != SHAFullLength {
return id, fmt.Errorf("Length must be 40: %s", s)
}
b, err := hex.DecodeString(s)

View file

@ -289,9 +289,3 @@ func RenderRawString(ctx *markup.RenderContext, content string) (string, error)
}
return buf.String(), nil
}
// IsMarkdownFile reports whether name looks like a Markdown file
// based on its extension.
func IsMarkdownFile(name string) bool {
return markup.IsMarkupFile(name, MarkupName)
}

View file

@ -74,28 +74,6 @@ func TestRender_StandardLinks(t *testing.T) {
`<p><a href="`+lnkWiki+`" rel="nofollow">WikiPage</a></p>`)
}
func TestMisc_IsMarkdownFile(t *testing.T) {
setting.Markdown.FileExtensions = []string{".md", ".markdown", ".mdown", ".mkd"}
trueTestCases := []string{
"test.md",
"wow.MARKDOWN",
"LOL.mDoWn",
}
falseTestCases := []string{
"test",
"abcdefg",
"abcdefghijklmnopqrstuvwxyz",
"test.md.test",
}
for _, testCase := range trueTestCases {
assert.True(t, IsMarkdownFile(testCase))
}
for _, testCase := range falseTestCases {
assert.False(t, IsMarkdownFile(testCase))
}
}
func TestRender_Images(t *testing.T) {
setting.AppURL = AppURL
setting.AppSubURL = AppSubURL

View file

@ -16,7 +16,6 @@ import (
"code.gitea.io/gitea/modules/notification/mail"
"code.gitea.io/gitea/modules/notification/mirror"
"code.gitea.io/gitea/modules/notification/ui"
"code.gitea.io/gitea/modules/notification/webhook"
"code.gitea.io/gitea/modules/repository"
"code.gitea.io/gitea/modules/setting"
)
@ -36,7 +35,6 @@ func NewContext() {
RegisterNotifier(mail.NewNotifier())
}
RegisterNotifier(indexer.NewNotifier())
RegisterNotifier(webhook.NewNotifier())
RegisterNotifier(action.NewNotifier())
RegisterNotifier(mirror.NewNotifier())
}

View file

@ -243,7 +243,7 @@ func (ns *notificationService) NotifyPullReviewRequest(ctx context.Context, doer
}
func (ns *notificationService) NotifyRepoPendingTransfer(ctx context.Context, doer, newOwner *user_model.User, repo *repo_model.Repository) {
err := db.AutoTx(ctx, func(ctx context.Context) error {
err := db.WithTx(ctx, func(ctx context.Context) error {
return activities_model.CreateRepoTransferNotification(ctx, doer, newOwner, repo)
})
if err != nil {

View file

@ -5,12 +5,12 @@ package composer
import (
"archive/zip"
"errors"
"io"
"regexp"
"strings"
"code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/validation"
"github.com/hashicorp/go-version"
@ -21,11 +21,11 @@ const TypeProperty = "composer.type"
var (
// ErrMissingComposerFile indicates a missing composer.json file
ErrMissingComposerFile = errors.New("composer.json file is missing")
ErrMissingComposerFile = util.NewInvalidArgumentErrorf("composer.json file is missing")
// ErrInvalidName indicates an invalid package name
ErrInvalidName = errors.New("package name is invalid")
ErrInvalidName = util.NewInvalidArgumentErrorf("package name is invalid")
// ErrInvalidVersion indicates an invalid package version
ErrInvalidVersion = errors.New("package version is invalid")
ErrInvalidVersion = util.NewInvalidArgumentErrorf("package version is invalid")
)
// Package represents a Composer package

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