From 9607750b5e9001ab379fa8deab0dadbb6219c66e Mon Sep 17 00:00:00 2001 From: Jason Song Date: Mon, 28 Nov 2022 19:19:18 +0800 Subject: [PATCH 001/110] Replace fmt.Sprintf with hex.EncodeToString (#21960) `hex.EncodeToString` has better performance than `fmt.Sprintf("%x", []byte)`, we should use it as much as possible. I'm not an extreme fan of performance, so I think there are some exceptions: - `fmt.Sprintf("%x", func(...)[N]byte())` - We can't slice the function return value directly, and it's not worth adding lines. ```diff func A()[20]byte { ... } - a := fmt.Sprintf("%x", A()) - a := hex.EncodeToString(A()[:]) // invalid + tmp := A() + a := hex.EncodeToString(tmp[:]) ``` - `fmt.Sprintf("%X", []byte)` - `strings.ToUpper(hex.EncodeToString(bytes))` has even worse performance. --- models/auth/twofactor.go | 3 ++- models/migrations/base/hash.go | 4 ++-- models/migrations/v1_14/v166.go | 4 ++-- models/user/user.go | 2 +- modules/packages/hashed_buffer_test.go | 10 +++++----- modules/packages/multi_hasher_test.go | 18 +++++++++--------- routers/api/packages/maven/maven.go | 4 ++-- routers/api/packages/pypi/pypi.go | 4 ++-- services/packages/packages.go | 9 +++++---- 9 files changed, 30 insertions(+), 28 deletions(-) diff --git a/models/auth/twofactor.go b/models/auth/twofactor.go index 179d315364b17..5b3a9d011a099 100644 --- a/models/auth/twofactor.go +++ b/models/auth/twofactor.go @@ -9,6 +9,7 @@ import ( "crypto/subtle" "encoding/base32" "encoding/base64" + "encoding/hex" "fmt" "code.gitea.io/gitea/models/db" @@ -78,7 +79,7 @@ func (t *TwoFactor) GenerateScratchToken() (string, error) { // HashToken return the hashable salt func HashToken(token, salt string) string { tempHash := pbkdf2.Key([]byte(token), []byte(salt), 10000, 50, sha256.New) - return fmt.Sprintf("%x", tempHash) + return hex.EncodeToString(tempHash) } // VerifyScratchToken verifies if the specified scratch token is valid. diff --git a/models/migrations/base/hash.go b/models/migrations/base/hash.go index 164f826b45d0e..00fd1efd4a3ba 100644 --- a/models/migrations/base/hash.go +++ b/models/migrations/base/hash.go @@ -5,12 +5,12 @@ package base import ( "crypto/sha256" - "fmt" + "encoding/hex" "golang.org/x/crypto/pbkdf2" ) func HashToken(token, salt string) string { tempHash := pbkdf2.Key([]byte(token), []byte(salt), 10000, 50, sha256.New) - return fmt.Sprintf("%x", tempHash) + return hex.EncodeToString(tempHash) } diff --git a/models/migrations/v1_14/v166.go b/models/migrations/v1_14/v166.go index 1eb7263347608..f797930d6d5bc 100644 --- a/models/migrations/v1_14/v166.go +++ b/models/migrations/v1_14/v166.go @@ -5,7 +5,7 @@ package v1_14 //nolint import ( "crypto/sha256" - "fmt" + "encoding/hex" "golang.org/x/crypto/argon2" "golang.org/x/crypto/bcrypt" @@ -53,7 +53,7 @@ func RecalculateUserEmptyPWD(x *xorm.Engine) (err error) { tempPasswd = pbkdf2.Key([]byte(passwd), []byte(salt), 10000, 50, sha256.New) } - return fmt.Sprintf("%x", tempPasswd) + return hex.EncodeToString(tempPasswd) } // ValidatePassword checks if given password matches the one belongs to the user. diff --git a/models/user/user.go b/models/user/user.go index 7e3ae388fb303..915e4243cf28b 100644 --- a/models/user/user.go +++ b/models/user/user.go @@ -401,7 +401,7 @@ func hashPassword(passwd, salt, algo string) (string, error) { tempPasswd = pbkdf2.Key([]byte(passwd), saltBytes, 10000, 50, sha256.New) } - return fmt.Sprintf("%x", tempPasswd), nil + return hex.EncodeToString(tempPasswd), nil } // SetPassword hashes a password using the algorithm defined in the config value of PASSWORD_HASH_ALGO diff --git a/modules/packages/hashed_buffer_test.go b/modules/packages/hashed_buffer_test.go index 529262226fae4..e907aa060578a 100644 --- a/modules/packages/hashed_buffer_test.go +++ b/modules/packages/hashed_buffer_test.go @@ -4,7 +4,7 @@ package packages import ( - "fmt" + "encoding/hex" "io" "strings" "testing" @@ -36,10 +36,10 @@ func TestHashedBuffer(t *testing.T) { assert.Equal(t, c.Data, string(data)) hashMD5, hashSHA1, hashSHA256, hashSHA512 := buf.Sums() - assert.Equal(t, c.HashMD5, fmt.Sprintf("%x", hashMD5)) - assert.Equal(t, c.HashSHA1, fmt.Sprintf("%x", hashSHA1)) - assert.Equal(t, c.HashSHA256, fmt.Sprintf("%x", hashSHA256)) - assert.Equal(t, c.HashSHA512, fmt.Sprintf("%x", hashSHA512)) + assert.Equal(t, c.HashMD5, hex.EncodeToString(hashMD5)) + assert.Equal(t, c.HashSHA1, hex.EncodeToString(hashSHA1)) + assert.Equal(t, c.HashSHA256, hex.EncodeToString(hashSHA256)) + assert.Equal(t, c.HashSHA512, hex.EncodeToString(hashSHA512)) assert.NoError(t, buf.Close()) } diff --git a/modules/packages/multi_hasher_test.go b/modules/packages/multi_hasher_test.go index 42c1ef416f4e8..a37debbc95fff 100644 --- a/modules/packages/multi_hasher_test.go +++ b/modules/packages/multi_hasher_test.go @@ -4,7 +4,7 @@ package packages import ( - "fmt" + "encoding/hex" "testing" "github.com/stretchr/testify/assert" @@ -24,10 +24,10 @@ func TestMultiHasherSums(t *testing.T) { hashMD5, hashSHA1, hashSHA256, hashSHA512 := h.Sums() - assert.Equal(t, expectedMD5, fmt.Sprintf("%x", hashMD5)) - assert.Equal(t, expectedSHA1, fmt.Sprintf("%x", hashSHA1)) - assert.Equal(t, expectedSHA256, fmt.Sprintf("%x", hashSHA256)) - assert.Equal(t, expectedSHA512, fmt.Sprintf("%x", hashSHA512)) + assert.Equal(t, expectedMD5, hex.EncodeToString(hashMD5)) + assert.Equal(t, expectedSHA1, hex.EncodeToString(hashSHA1)) + assert.Equal(t, expectedSHA256, hex.EncodeToString(hashSHA256)) + assert.Equal(t, expectedSHA512, hex.EncodeToString(hashSHA512)) }) t.Run("State", func(t *testing.T) { @@ -45,9 +45,9 @@ func TestMultiHasherSums(t *testing.T) { hashMD5, hashSHA1, hashSHA256, hashSHA512 := h2.Sums() - assert.Equal(t, expectedMD5, fmt.Sprintf("%x", hashMD5)) - assert.Equal(t, expectedSHA1, fmt.Sprintf("%x", hashSHA1)) - assert.Equal(t, expectedSHA256, fmt.Sprintf("%x", hashSHA256)) - assert.Equal(t, expectedSHA512, fmt.Sprintf("%x", hashSHA512)) + assert.Equal(t, expectedMD5, hex.EncodeToString(hashMD5)) + assert.Equal(t, expectedSHA1, hex.EncodeToString(hashSHA1)) + assert.Equal(t, expectedSHA256, hex.EncodeToString(hashSHA256)) + assert.Equal(t, expectedSHA512, hex.EncodeToString(hashSHA512)) }) } diff --git a/routers/api/packages/maven/maven.go b/routers/api/packages/maven/maven.go index 0ca3fa179394b..d0c9983cbf1f2 100644 --- a/routers/api/packages/maven/maven.go +++ b/routers/api/packages/maven/maven.go @@ -8,9 +8,9 @@ import ( "crypto/sha1" "crypto/sha256" "crypto/sha512" + "encoding/hex" "encoding/xml" "errors" - "fmt" "io" "net/http" "path/filepath" @@ -128,7 +128,7 @@ func serveMavenMetadata(ctx *context.Context, params parameters) { tmp := sha512.Sum512(xmlMetadataWithHeader) hash = tmp[:] } - ctx.PlainText(http.StatusOK, fmt.Sprintf("%x", hash)) + ctx.PlainText(http.StatusOK, hex.EncodeToString(hash)) return } diff --git a/routers/api/packages/pypi/pypi.go b/routers/api/packages/pypi/pypi.go index 826f58095e704..6cf9329bbb134 100644 --- a/routers/api/packages/pypi/pypi.go +++ b/routers/api/packages/pypi/pypi.go @@ -4,7 +4,7 @@ package pypi import ( - "fmt" + "encoding/hex" "io" "net/http" "regexp" @@ -118,7 +118,7 @@ func UploadPackageFile(ctx *context.Context) { _, _, hashSHA256, _ := buf.Sums() - if !strings.EqualFold(ctx.Req.FormValue("sha256_digest"), fmt.Sprintf("%x", hashSHA256)) { + if !strings.EqualFold(ctx.Req.FormValue("sha256_digest"), hex.EncodeToString(hashSHA256)) { apiError(ctx, http.StatusBadRequest, "hash mismatch") return } diff --git a/services/packages/packages.go b/services/packages/packages.go index f819949c96955..49f5a2fac4e21 100644 --- a/services/packages/packages.go +++ b/services/packages/packages.go @@ -5,6 +5,7 @@ package packages import ( "context" + "encoding/hex" "errors" "fmt" "io" @@ -229,10 +230,10 @@ func NewPackageBlob(hsr packages_module.HashedSizeReader) *packages_model.Packag return &packages_model.PackageBlob{ Size: hsr.Size(), - HashMD5: fmt.Sprintf("%x", hashMD5), - HashSHA1: fmt.Sprintf("%x", hashSHA1), - HashSHA256: fmt.Sprintf("%x", hashSHA256), - HashSHA512: fmt.Sprintf("%x", hashSHA512), + HashMD5: hex.EncodeToString(hashMD5), + HashSHA1: hex.EncodeToString(hashSHA1), + HashSHA256: hex.EncodeToString(hashSHA256), + HashSHA512: hex.EncodeToString(hashSHA512), } } From f047ee0a40b50ab51e10ddcc57040ffa127d9e21 Mon Sep 17 00:00:00 2001 From: Jason Song Date: Mon, 28 Nov 2022 23:37:42 +0800 Subject: [PATCH 002/110] Use random bytes to generate access token (#21959) --- models/auth/token.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/models/auth/token.go b/models/auth/token.go index 763174f08f6c9..0dfcb7629ba9f 100644 --- a/models/auth/token.go +++ b/models/auth/token.go @@ -6,16 +6,15 @@ package auth import ( "crypto/subtle" + "encoding/hex" "fmt" "time" "code.gitea.io/gitea/models/db" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/util" - gouuid "github.com/google/uuid" lru "github.com/hashicorp/golang-lru" ) @@ -100,8 +99,12 @@ func NewAccessToken(t *AccessToken) error { if err != nil { return err } + token, err := util.CryptoRandomBytes(20) + if err != nil { + return err + } t.TokenSalt = salt - t.Token = base.EncodeSha1(gouuid.New().String()) + t.Token = hex.EncodeToString(token) t.TokenHash = HashToken(t.Token, t.TokenSalt) t.TokenLastEight = t.Token[len(t.Token)-8:] _, err = db.GetEngine(db.DefaultContext).Insert(t) From 715cf46dc464fe8b1543b6a6c640e5187ccb5c1a Mon Sep 17 00:00:00 2001 From: Saswat Padhi Date: Mon, 28 Nov 2022 23:30:47 -0800 Subject: [PATCH 003/110] Normalize `AppURL` according to RFC 3986 (#21950) Fixes #21865. Scheme-based normalization ([RFC 3986, section 6.2.3](https://www.rfc-editor.org/rfc/rfc3986#section-6.2.3)) was already implemented, but only for `defaultAppURL`. This PR implements the same for `AppURL`. Signed-off-by: Saswat Padhi Co-authored-by: John Olheiser --- modules/setting/setting.go | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 68892a2198259..f0d7f029271c9 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -748,19 +748,22 @@ func loadFromConf(allowEmpty bool, extraConfig string) { PerWriteTimeout = sec.Key("PER_WRITE_TIMEOUT").MustDuration(PerWriteTimeout) PerWritePerKbTimeout = sec.Key("PER_WRITE_PER_KB_TIMEOUT").MustDuration(PerWritePerKbTimeout) - defaultAppURL := string(Protocol) + "://" + Domain - if (Protocol == HTTP && HTTPPort != "80") || (Protocol == HTTPS && HTTPPort != "443") { - defaultAppURL += ":" + HTTPPort - } - AppURL = sec.Key("ROOT_URL").MustString(defaultAppURL + "/") - // This should be TrimRight to ensure that there is only a single '/' at the end of AppURL. - AppURL = strings.TrimRight(AppURL, "/") + "/" + defaultAppURL := string(Protocol) + "://" + Domain + ":" + HTTPPort + AppURL = sec.Key("ROOT_URL").MustString(defaultAppURL) - // Check if has app suburl. + // Check validity of AppURL appURL, err := url.Parse(AppURL) if err != nil { log.Fatal("Invalid ROOT_URL '%s': %s", AppURL, err) } + // Remove default ports from AppURL. + // (scheme-based URL normalization, RFC 3986 section 6.2.3) + if (appURL.Scheme == string(HTTP) && appURL.Port() == "80") || (appURL.Scheme == string(HTTPS) && appURL.Port() == "443") { + appURL.Host = appURL.Hostname() + } + // This should be TrimRight to ensure that there is only a single '/' at the end of AppURL. + AppURL = strings.TrimRight(appURL.String(), "/") + "/" + // Suburl should start with '/' and end without '/', such as '/{subpath}'. // This value is empty if site does not have sub-url. AppSubURL = strings.TrimSuffix(appURL.Path, "/") From fdfd77f478c40c83131b08b2ee27545790e454d0 Mon Sep 17 00:00:00 2001 From: luzpaz Date: Tue, 29 Nov 2022 19:41:29 -0500 Subject: [PATCH 004/110] Fix typos (#21979) Found via codespell --- custom/conf/app.example.ini | 28 +++++++++---------- .../doc/advanced/config-cheat-sheet.en-us.md | 28 +++++++++---------- options/gitignore/Bazel | 2 +- 3 files changed, 29 insertions(+), 29 deletions(-) diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 5822dc1e4a85d..bee12ffa9b225 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -2378,33 +2378,33 @@ ROUTER = console ;; Path for chunked uploads. Defaults to APP_DATA_PATH + `tmp/package-upload` ;CHUNKED_UPLOAD_PATH = tmp/package-upload ;; -;; Maxmimum count of package versions a single owner can have (`-1` means no limits) +;; Maximum count of package versions a single owner can have (`-1` means no limits) ;LIMIT_TOTAL_OWNER_COUNT = -1 -;; Maxmimum size of packages a single owner can use (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +;; Maximum size of packages a single owner can use (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) ;LIMIT_TOTAL_OWNER_SIZE = -1 -;; Maxmimum size of a Composer upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +;; Maximum size of a Composer upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) ;LIMIT_SIZE_COMPOSER = -1 -;; Maxmimum size of a Conan upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +;; Maximum size of a Conan upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) ;LIMIT_SIZE_CONAN = -1 -;; Maxmimum size of a Container upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +;; Maximum size of a Container upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) ;LIMIT_SIZE_CONTAINER = -1 -;; Maxmimum size of a Generic upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +;; Maximum size of a Generic upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) ;LIMIT_SIZE_GENERIC = -1 -;; Maxmimum size of a Helm upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +;; Maximum size of a Helm upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) ;LIMIT_SIZE_HELM = -1 -;; Maxmimum size of a Maven upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +;; Maximum size of a Maven upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) ;LIMIT_SIZE_MAVEN = -1 -;; Maxmimum size of a npm upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +;; Maximum size of a npm upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) ;LIMIT_SIZE_NPM = -1 -;; Maxmimum size of a NuGet upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +;; Maximum size of a NuGet upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) ;LIMIT_SIZE_NUGET = -1 -;; Maxmimum size of a Pub upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +;; Maximum size of a Pub upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) ;LIMIT_SIZE_PUB = -1 -;; Maxmimum size of a PyPI upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +;; Maximum size of a PyPI upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) ;LIMIT_SIZE_PYPI = -1 -;; Maxmimum size of a RubyGems upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +;; Maximum size of a RubyGems upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) ;LIMIT_SIZE_RUBYGEMS = -1 -;; Maxmimum size of a Vagrant upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +;; Maximum size of a Vagrant upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) ;LIMIT_SIZE_VAGRANT = -1 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index 853f0c67f254c..756ab32256752 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -1179,20 +1179,20 @@ Task queue configuration has been moved to `queue.task`. However, the below conf - `ENABLED`: **true**: Enable/Disable package registry capabilities - `CHUNKED_UPLOAD_PATH`: **tmp/package-upload**: Path for chunked uploads. Defaults to `APP_DATA_PATH` + `tmp/package-upload` -- `LIMIT_TOTAL_OWNER_COUNT`: **-1**: Maxmimum count of package versions a single owner can have (`-1` means no limits) -- `LIMIT_TOTAL_OWNER_SIZE`: **-1**: Maxmimum size of packages a single owner can use (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) -- `LIMIT_SIZE_COMPOSER`: **-1**: Maxmimum size of a Composer upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) -- `LIMIT_SIZE_CONAN`: **-1**: Maxmimum size of a Conan upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) -- `LIMIT_SIZE_CONTAINER`: **-1**: Maxmimum size of a Container upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) -- `LIMIT_SIZE_GENERIC`: **-1**: Maxmimum size of a Generic upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) -- `LIMIT_SIZE_HELM`: **-1**: Maxmimum size of a Helm upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) -- `LIMIT_SIZE_MAVEN`: **-1**: Maxmimum size of a Maven upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) -- `LIMIT_SIZE_NPM`: **-1**: Maxmimum size of a npm upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) -- `LIMIT_SIZE_NUGET`: **-1**: Maxmimum size of a NuGet upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) -- `LIMIT_SIZE_PUB`: **-1**: Maxmimum size of a Pub upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) -- `LIMIT_SIZE_PYPI`: **-1**: Maxmimum size of a PyPI upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) -- `LIMIT_SIZE_RUBYGEMS`: **-1**: Maxmimum size of a RubyGems upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) -- `LIMIT_SIZE_VAGRANT`: **-1**: Maxmimum size of a Vagrant upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +- `LIMIT_TOTAL_OWNER_COUNT`: **-1**: Maximum count of package versions a single owner can have (`-1` means no limits) +- `LIMIT_TOTAL_OWNER_SIZE`: **-1**: Maximum size of packages a single owner can use (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +- `LIMIT_SIZE_COMPOSER`: **-1**: Maximum size of a Composer upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +- `LIMIT_SIZE_CONAN`: **-1**: Maximum size of a Conan upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +- `LIMIT_SIZE_CONTAINER`: **-1**: Maximum size of a Container upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +- `LIMIT_SIZE_GENERIC`: **-1**: Maximum size of a Generic upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +- `LIMIT_SIZE_HELM`: **-1**: Maximum size of a Helm upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +- `LIMIT_SIZE_MAVEN`: **-1**: Maximum size of a Maven upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +- `LIMIT_SIZE_NPM`: **-1**: Maximum size of a npm upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +- `LIMIT_SIZE_NUGET`: **-1**: Maximum size of a NuGet upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +- `LIMIT_SIZE_PUB`: **-1**: Maximum size of a Pub upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +- `LIMIT_SIZE_PYPI`: **-1**: Maximum size of a PyPI upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +- `LIMIT_SIZE_RUBYGEMS`: **-1**: Maximum size of a RubyGems upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +- `LIMIT_SIZE_VAGRANT`: **-1**: Maximum size of a Vagrant upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) ## Mirror (`mirror`) diff --git a/options/gitignore/Bazel b/options/gitignore/Bazel index bc3afc20ba696..4e1d5a2ba0a42 100644 --- a/options/gitignore/Bazel +++ b/options/gitignore/Bazel @@ -6,7 +6,7 @@ /bazel-* # Directories for the Bazel IntelliJ plugin containing the generated -# IntelliJ project files and plugin configuration. Seperate directories are +# IntelliJ project files and plugin configuration. Separate directories are # for the IntelliJ, Android Studio and CLion versions of the plugin. /.ijwb/ /.aswb/ From 7020c4afb74756f60ae5381a05c6511dbf0d72ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8A=B1=E5=A2=A8?= Date: Wed, 30 Nov 2022 17:00:00 +0800 Subject: [PATCH 005/110] Fix leaving organization bug on user settings -> orgs (#21983) Fix #21772 Co-authored-by: wxiaoguang --- options/locale/locale_en-US.ini | 1 + routers/web/org/members.go | 11 +++++++++-- templates/user/settings/organization.tmpl | 18 ++++++++++++++++-- 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 8503cb78d712f..40d041e2cbb3f 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -505,6 +505,7 @@ team_not_exist = The team does not exist. last_org_owner = You cannot remove the last user from the 'owners' team. There must be at least one owner for an organization. cannot_add_org_to_team = An organization cannot be added as a team member. duplicate_invite_to_team = The user was already invited as a team member. +organization_leave_success = You have successfully left the organization %s. invalid_ssh_key = Can not verify your SSH key: %s invalid_gpg_key = Can not verify your GPG key: %s diff --git a/routers/web/org/members.go b/routers/web/org/members.go index 3be2a39c2e363..8361da663211c 100644 --- a/routers/web/org/members.go +++ b/routers/web/org/members.go @@ -107,13 +107,20 @@ func MembersAction(ctx *context.Context) { } case "leave": err = models.RemoveOrgUser(org.ID, ctx.Doer.ID) - if organization.IsErrLastOrgOwner(err) { + if err == nil { + ctx.Flash.Success(ctx.Tr("form.organization_leave_success", org.DisplayName())) + ctx.JSON(http.StatusOK, map[string]interface{}{ + "redirect": "", // keep the user stay on current page, in case they want to do other operations. + }) + } else if organization.IsErrLastOrgOwner(err) { ctx.Flash.Error(ctx.Tr("form.last_org_owner")) ctx.JSON(http.StatusOK, map[string]interface{}{ "redirect": ctx.Org.OrgLink + "/members", }) - return + } else { + log.Error("RemoveOrgUser(%d,%d): %v", org.ID, ctx.Doer.ID, err) } + return } if err != nil { diff --git a/templates/user/settings/organization.tmpl b/templates/user/settings/organization.tmpl index e25d5e7fa6766..703ac8ad8edbe 100644 --- a/templates/user/settings/organization.tmpl +++ b/templates/user/settings/organization.tmpl @@ -17,9 +17,13 @@ {{range .Orgs}}
-
+ {{$.CsrfTokenHtml}} - +
{{avatar . 28 "mini"}} @@ -36,4 +40,14 @@
+ {{template "base/footer" .}} From 67881ae99abc673954d56436730af313c93ee48f Mon Sep 17 00:00:00 2001 From: Jason Song Date: Wed, 30 Nov 2022 21:39:02 +0800 Subject: [PATCH 006/110] Skip initing disabled storages (#21985) If `Attachment` or `Packages` are disabled, we don't have to init the storages for them. --- modules/storage/helper.go | 32 +++++++++++++++++++++ modules/storage/helper_test.go | 50 ++++++++++++++++++++++++++++++++ modules/storage/storage.go | 52 +++++++++++++++++----------------- 3 files changed, 108 insertions(+), 26 deletions(-) create mode 100644 modules/storage/helper_test.go diff --git a/modules/storage/helper.go b/modules/storage/helper.go index 5aaa2a9e6430a..1ab99d98b31bc 100644 --- a/modules/storage/helper.go +++ b/modules/storage/helper.go @@ -4,6 +4,10 @@ package storage import ( + "fmt" + "io" + "net/url" + "os" "reflect" "code.gitea.io/gitea/modules/json" @@ -61,3 +65,31 @@ func toConfig(exemplar, cfg interface{}) (interface{}, error) { } return newVal.Elem().Interface(), nil } + +var uninitializedStorage = discardStorage("uninitialized storage") + +type discardStorage string + +func (s discardStorage) Open(_ string) (Object, error) { + return nil, fmt.Errorf("%s", s) +} + +func (s discardStorage) Save(_ string, _ io.Reader, _ int64) (int64, error) { + return 0, fmt.Errorf("%s", s) +} + +func (s discardStorage) Stat(_ string) (os.FileInfo, error) { + return nil, fmt.Errorf("%s", s) +} + +func (s discardStorage) Delete(_ string) error { + return fmt.Errorf("%s", s) +} + +func (s discardStorage) URL(_, _ string) (*url.URL, error) { + return nil, fmt.Errorf("%s", s) +} + +func (s discardStorage) IterateObjects(_ func(string, Object) error) error { + return fmt.Errorf("%s", s) +} diff --git a/modules/storage/helper_test.go b/modules/storage/helper_test.go new file mode 100644 index 0000000000000..7d74671c544a8 --- /dev/null +++ b/modules/storage/helper_test.go @@ -0,0 +1,50 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package storage + +import ( + "bytes" + "testing" + + "github.com/stretchr/testify/assert" +) + +func Test_discardStorage(t *testing.T) { + tests := []discardStorage{ + uninitializedStorage, + discardStorage("empty"), + } + for _, tt := range tests { + t.Run(string(tt), func(t *testing.T) { + { + got, err := tt.Open("path") + assert.Nil(t, got) + assert.Error(t, err, string(tt)) + } + { + got, err := tt.Save("path", bytes.NewReader([]byte{0}), 1) + assert.Equal(t, int64(0), got) + assert.Error(t, err, string(tt)) + } + { + got, err := tt.Stat("path") + assert.Nil(t, got) + assert.Error(t, err, string(tt)) + } + { + err := tt.Delete("path") + assert.Error(t, err, string(tt)) + } + { + got, err := tt.URL("path", "name") + assert.Nil(t, got) + assert.Errorf(t, err, string(tt)) + } + { + err := tt.IterateObjects(func(_ string, _ Object) error { return nil }) + assert.Error(t, err, string(tt)) + } + }) + } +} diff --git a/modules/storage/storage.go b/modules/storage/storage.go index a7d3b9ce1f69a..35f1527172381 100644 --- a/modules/storage/storage.go +++ b/modules/storage/storage.go @@ -110,46 +110,38 @@ func SaveFrom(objStorage ObjectStorage, p string, callback func(w io.Writer) err var ( // Attachments represents attachments storage - Attachments ObjectStorage + Attachments ObjectStorage = uninitializedStorage // LFS represents lfs storage - LFS ObjectStorage + LFS ObjectStorage = uninitializedStorage // Avatars represents user avatars storage - Avatars ObjectStorage + Avatars ObjectStorage = uninitializedStorage // RepoAvatars represents repository avatars storage - RepoAvatars ObjectStorage + RepoAvatars ObjectStorage = uninitializedStorage // RepoArchives represents repository archives storage - RepoArchives ObjectStorage + RepoArchives ObjectStorage = uninitializedStorage // Packages represents packages storage - Packages ObjectStorage + Packages ObjectStorage = uninitializedStorage ) // Init init the stoarge func Init() error { - if err := initAttachments(); err != nil { - return err - } - - if err := initAvatars(); err != nil { - return err - } - - if err := initRepoAvatars(); err != nil { - return err - } - - if err := initLFS(); err != nil { - return err - } - - if err := initRepoArchives(); err != nil { - return err + for _, f := range []func() error{ + initAttachments, + initAvatars, + initRepoAvatars, + initLFS, + initRepoArchives, + initPackages, + } { + if err := f(); err != nil { + return err + } } - - return initPackages() + return nil } // NewStorage takes a storage type and some config and returns an ObjectStorage or an error @@ -172,6 +164,10 @@ func initAvatars() (err error) { } func initAttachments() (err error) { + if !setting.Attachment.Enabled { + Attachments = discardStorage("Attachment isn't enabled") + return nil + } log.Info("Initialising Attachment storage with type: %s", setting.Attachment.Storage.Type) Attachments, err = NewStorage(setting.Attachment.Storage.Type, &setting.Attachment.Storage) return err @@ -196,6 +192,10 @@ func initRepoArchives() (err error) { } func initPackages() (err error) { + if !setting.Packages.Enabled { + Packages = discardStorage("Packages isn't enabled") + return nil + } log.Info("Initialising Packages storage with type: %s", setting.Packages.Storage.Type) Packages, err = NewStorage(setting.Packages.Storage.Type, &setting.Packages.Storage) return err From b2c4870481329889a76ea2421152647d36dd8374 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Thu, 1 Dec 2022 00:41:49 +0800 Subject: [PATCH 007/110] Fix parallel creating commit status bug with tests (#21911) This PR is a follow up of #21469 Co-authored-by: Lauris BH --- models/db/index.go | 5 -- models/git/commit_status.go | 101 +++++++++---------------- tests/integration/repo_commits_test.go | 31 ++++++++ 3 files changed, 67 insertions(+), 70 deletions(-) diff --git a/models/db/index.go b/models/db/index.go index 46be74e91e7f6..ca664c9cf125a 100644 --- a/models/db/index.go +++ b/models/db/index.go @@ -23,11 +23,6 @@ var ( ErrGetResourceIndexFailed = errors.New("get resource index failed") ) -const ( - // MaxDupIndexAttempts max retry times to create index - MaxDupIndexAttempts = 3 -) - // SyncMaxResourceIndex sync the max index with the resource func SyncMaxResourceIndex(ctx context.Context, tableName string, groupID, maxIndex int64) (err error) { e := GetEngine(ctx) diff --git a/models/git/commit_status.go b/models/git/commit_status.go index 411fbbe536041..6353bb2fa9f97 100644 --- a/models/git/commit_status.go +++ b/models/git/commit_status.go @@ -6,6 +6,7 @@ package git import ( "context" "crypto/sha1" + "errors" "fmt" "net/url" "strings" @@ -48,79 +49,49 @@ func init() { db.RegisterModel(new(CommitStatusIndex)) } -// upsertCommitStatusIndex the function will not return until it acquires the lock or receives an error. -func upsertCommitStatusIndex(ctx context.Context, repoID int64, sha string) (err error) { - // An atomic UPSERT operation (INSERT/UPDATE) is the only operation - // that ensures that the key is actually locked. - switch { - case setting.Database.UseSQLite3 || setting.Database.UsePostgreSQL: - _, err = db.Exec(ctx, "INSERT INTO `commit_status_index` (repo_id, sha, max_index) "+ - "VALUES (?,?,1) ON CONFLICT (repo_id,sha) DO UPDATE SET max_index = `commit_status_index`.max_index+1", - repoID, sha) - case setting.Database.UseMySQL: - _, err = db.Exec(ctx, "INSERT INTO `commit_status_index` (repo_id, sha, max_index) "+ - "VALUES (?,?,1) ON DUPLICATE KEY UPDATE max_index = max_index+1", - repoID, sha) - case setting.Database.UseMSSQL: - // https://weblogs.sqlteam.com/dang/2009/01/31/upsert-race-condition-with-merge/ - _, err = db.Exec(ctx, "MERGE `commit_status_index` WITH (HOLDLOCK) as target "+ - "USING (SELECT ? AS repo_id, ? AS sha) AS src "+ - "ON src.repo_id = target.repo_id AND src.sha = target.sha "+ - "WHEN MATCHED THEN UPDATE SET target.max_index = target.max_index+1 "+ - "WHEN NOT MATCHED THEN INSERT (repo_id, sha, max_index) "+ - "VALUES (src.repo_id, src.sha, 1);", - repoID, sha) - default: - return fmt.Errorf("database type not supported") - } - return err -} - // GetNextCommitStatusIndex retried 3 times to generate a resource index -func GetNextCommitStatusIndex(repoID int64, sha string) (int64, error) { - for i := 0; i < db.MaxDupIndexAttempts; i++ { - idx, err := getNextCommitStatusIndex(repoID, sha) - if err == db.ErrResouceOutdated { - continue - } - if err != nil { - return 0, err - } - return idx, nil - } - return 0, db.ErrGetResourceIndexFailed -} +func GetNextCommitStatusIndex(ctx context.Context, repoID int64, sha string) (int64, error) { + e := db.GetEngine(ctx) -// getNextCommitStatusIndex return the next index -func getNextCommitStatusIndex(repoID int64, sha string) (int64, error) { - ctx, commiter, err := db.TxContext(db.DefaultContext) + // try to update the max_index to next value, and acquire the write-lock for the record + res, err := e.Exec("UPDATE `commit_status_index` SET max_index=max_index+1 WHERE repo_id=? AND sha=?", repoID, sha) if err != nil { return 0, err } - defer commiter.Close() - - var preIdx int64 - _, err = db.GetEngine(ctx).SQL("SELECT max_index FROM `commit_status_index` WHERE repo_id = ? AND sha = ?", repoID, sha).Get(&preIdx) + affected, err := res.RowsAffected() if err != nil { return 0, err } - - if err := upsertCommitStatusIndex(ctx, repoID, sha); err != nil { - return 0, err + if affected == 0 { + // this slow path is only for the first time of creating a resource index + _, errIns := e.Exec("INSERT INTO `commit_status_index` (repo_id, sha, max_index) VALUES (?, ?, 0)", repoID, sha) + res, err = e.Exec("UPDATE `commit_status_index` SET max_index=max_index+1 WHERE repo_id=? AND sha=?", repoID, sha) + if err != nil { + return 0, err + } + affected, err = res.RowsAffected() + if err != nil { + return 0, err + } + // if the update still can not update any records, the record must not exist and there must be some errors (insert error) + if affected == 0 { + if errIns == nil { + return 0, errors.New("impossible error when GetNextCommitStatusIndex, insert and update both succeeded but no record is updated") + } + return 0, errIns + } } - var curIdx int64 - has, err := db.GetEngine(ctx).SQL("SELECT max_index FROM `commit_status_index` WHERE repo_id = ? AND sha = ? AND max_index=?", repoID, sha, preIdx+1).Get(&curIdx) + // now, the new index is in database (protected by the transaction and write-lock) + var newIdx int64 + has, err := e.SQL("SELECT max_index FROM `commit_status_index` WHERE repo_id=? AND sha=?", repoID, sha).Get(&newIdx) if err != nil { return 0, err } if !has { - return 0, db.ErrResouceOutdated + return 0, errors.New("impossible error when GetNextCommitStatusIndex, upsert succeeded but no record can be selected") } - if err := commiter.Commit(); err != nil { - return 0, err - } - return curIdx, nil + return newIdx, nil } func (status *CommitStatus) loadAttributes(ctx context.Context) (err error) { @@ -290,18 +261,18 @@ func NewCommitStatus(opts NewCommitStatusOptions) error { return fmt.Errorf("NewCommitStatus[%s, %s]: no user specified", repoPath, opts.SHA) } - // Get the next Status Index - idx, err := GetNextCommitStatusIndex(opts.Repo.ID, opts.SHA) - if err != nil { - return fmt.Errorf("generate commit status index failed: %w", err) - } - ctx, committer, err := db.TxContext(db.DefaultContext) 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) } defer committer.Close() + // Get the next Status Index + idx, err := GetNextCommitStatusIndex(ctx, opts.Repo.ID, opts.SHA) + if err != nil { + return fmt.Errorf("generate commit status index failed: %w", err) + } + opts.CommitStatus.Description = strings.TrimSpace(opts.CommitStatus.Description) opts.CommitStatus.Context = strings.TrimSpace(opts.CommitStatus.Context) opts.CommitStatus.TargetURL = strings.TrimSpace(opts.CommitStatus.TargetURL) @@ -315,7 +286,7 @@ func NewCommitStatus(opts NewCommitStatusOptions) error { // Insert new CommitStatus if _, err = db.GetEngine(ctx).Insert(opts.CommitStatus); err != nil { - return fmt.Errorf("Insert CommitStatus[%s, %s]: %w", repoPath, opts.SHA, err) + return fmt.Errorf("insert CommitStatus[%s, %s]: %w", repoPath, opts.SHA, err) } return committer.Commit() diff --git a/tests/integration/repo_commits_test.go b/tests/integration/repo_commits_test.go index 438e1c2cc4bb4..3840c508dcebc 100644 --- a/tests/integration/repo_commits_test.go +++ b/tests/integration/repo_commits_test.go @@ -4,9 +4,11 @@ package integration import ( + "fmt" "net/http" "net/http/httptest" "path" + "sync" "testing" "code.gitea.io/gitea/modules/json" @@ -114,3 +116,32 @@ func TestRepoCommitsWithStatusFailure(t *testing.T) { func TestRepoCommitsWithStatusWarning(t *testing.T) { doTestRepoCommitWithStatus(t, "warning", "gitea-exclamation", "yellow") } + +func TestRepoCommitsStatusParallel(t *testing.T) { + defer tests.PrepareTestEnv(t)() + + session := loginUser(t, "user2") + + // Request repository commits page + req := NewRequest(t, "GET", "/user2/repo1/commits/branch/master") + resp := session.MakeRequest(t, req, http.StatusOK) + + doc := NewHTMLParser(t, resp.Body) + // Get first commit URL + commitURL, exists := doc.doc.Find("#commits-table tbody tr td.sha a").Attr("href") + assert.True(t, exists) + assert.NotEmpty(t, commitURL) + + var wg sync.WaitGroup + for i := 0; i < 10; i++ { + wg.Add(1) + go func(t *testing.T, i int) { + t.Run(fmt.Sprintf("ParallelCreateStatus_%d", i), func(t *testing.T) { + runBody := doAPICreateCommitStatus(NewAPITestContext(t, "user2", "repo1"), path.Base(commitURL), api.CommitStatusState("pending")) + runBody(t) + wg.Done() + }) + }(t, i) + } + wg.Wait() +} From 4e5d4d0073df7bffba95107ea969f1fdeb165830 Mon Sep 17 00:00:00 2001 From: Jason Song Date: Thu, 1 Dec 2022 17:02:04 +0800 Subject: [PATCH 008/110] Skip initing LFS storage if disabled (#21996) A complement to #21985. I overlooked it because the name of the switch is `StartServer`, not `Enabled`. I believe the weird name is a legacy, but renaming is out of scope. --- modules/storage/storage.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/modules/storage/storage.go b/modules/storage/storage.go index 35f1527172381..671e0ce56529e 100644 --- a/modules/storage/storage.go +++ b/modules/storage/storage.go @@ -174,6 +174,10 @@ func initAttachments() (err error) { } func initLFS() (err error) { + if !setting.LFS.StartServer { + LFS = discardStorage("LFS isn't enabled") + return nil + } log.Info("Initialising LFS storage with type: %s", setting.LFS.Storage.Type) LFS, err = NewStorage(setting.LFS.Storage.Type, &setting.LFS.Storage) return err From f9cbf5a1bcd38810432e9ca16270e1f7ccc63605 Mon Sep 17 00:00:00 2001 From: Jason Song Date: Thu, 1 Dec 2022 19:56:04 +0800 Subject: [PATCH 009/110] Util type to parse ref name (#21969) Provide a new type to make it easier to parse a ref name. Actually, it's picked up from #21937, to make the origin PR lighter. Co-authored-by: Lunny Xiao --- modules/git/ref.go | 57 ++++++++++++++++++++++++++++++---------------- 1 file changed, 37 insertions(+), 20 deletions(-) diff --git a/modules/git/ref.go b/modules/git/ref.go index cd8d268184951..47cc04b7fbdb7 100644 --- a/modules/git/ref.go +++ b/modules/git/ref.go @@ -55,40 +55,57 @@ func (ref *Reference) Commit() (*Commit, error) { // ShortName returns the short name of the reference func (ref *Reference) ShortName() string { - if ref == nil { - return "" - } - if strings.HasPrefix(ref.Name, BranchPrefix) { - return strings.TrimPrefix(ref.Name, BranchPrefix) + return RefName(ref.Name).ShortName() +} + +// RefGroup returns the group type of the reference +func (ref *Reference) RefGroup() string { + return RefName(ref.Name).RefGroup() +} + +// RefName represents a git reference name +type RefName string + +func (ref RefName) IsBranch() bool { + return strings.HasPrefix(string(ref), BranchPrefix) +} + +func (ref RefName) IsTag() bool { + return strings.HasPrefix(string(ref), TagPrefix) +} + +// ShortName returns the short name of the reference name +func (ref RefName) ShortName() string { + refName := string(ref) + if strings.HasPrefix(refName, BranchPrefix) { + return strings.TrimPrefix(refName, BranchPrefix) } - if strings.HasPrefix(ref.Name, TagPrefix) { - return strings.TrimPrefix(ref.Name, TagPrefix) + if strings.HasPrefix(refName, TagPrefix) { + return strings.TrimPrefix(refName, TagPrefix) } - if strings.HasPrefix(ref.Name, RemotePrefix) { - return strings.TrimPrefix(ref.Name, RemotePrefix) + if strings.HasPrefix(refName, RemotePrefix) { + return strings.TrimPrefix(refName, RemotePrefix) } - if strings.HasPrefix(ref.Name, PullPrefix) && strings.IndexByte(ref.Name[pullLen:], '/') > -1 { - return ref.Name[pullLen : strings.IndexByte(ref.Name[pullLen:], '/')+pullLen] + if strings.HasPrefix(refName, PullPrefix) && strings.IndexByte(refName[pullLen:], '/') > -1 { + return refName[pullLen : strings.IndexByte(refName[pullLen:], '/')+pullLen] } - return ref.Name + return refName } // RefGroup returns the group type of the reference -func (ref *Reference) RefGroup() string { - if ref == nil { - return "" - } - if strings.HasPrefix(ref.Name, BranchPrefix) { +func (ref RefName) RefGroup() string { + refName := string(ref) + if strings.HasPrefix(refName, BranchPrefix) { return "heads" } - if strings.HasPrefix(ref.Name, TagPrefix) { + if strings.HasPrefix(refName, TagPrefix) { return "tags" } - if strings.HasPrefix(ref.Name, RemotePrefix) { + if strings.HasPrefix(refName, RemotePrefix) { return "remotes" } - if strings.HasPrefix(ref.Name, PullPrefix) && strings.IndexByte(ref.Name[pullLen:], '/') > -1 { + if strings.HasPrefix(refName, PullPrefix) && strings.IndexByte(refName[pullLen:], '/') > -1 { return "pull" } return "" From f0bd219a5e153ddcf6806334da700aac46fcefad Mon Sep 17 00:00:00 2001 From: silverwind Date: Thu, 1 Dec 2022 22:44:38 +0100 Subject: [PATCH 010/110] Update chroma to v2.4.0 (#22000) Did a few cursory tests, seems to work well. --- go.mod | 2 +- go.sum | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index ca8c79c689003..5e090a98b4d0b 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,7 @@ require ( github.com/42wim/sshsig v0.0.0-20211121163825-841cf5bbc121 github.com/NYTimes/gziphandler v1.1.1 github.com/PuerkitoBio/goquery v1.8.0 - github.com/alecthomas/chroma/v2 v2.3.0 + github.com/alecthomas/chroma/v2 v2.4.0 github.com/blevesearch/bleve/v2 v2.3.4 github.com/buildkite/terminal-to-html/v3 v3.7.0 github.com/caddyserver/certmagic v0.17.2 diff --git a/go.sum b/go.sum index d6748eae34de6..097d03780cdb3 100644 --- a/go.sum +++ b/go.sum @@ -160,9 +160,10 @@ github.com/acomagu/bufpipe v1.0.3/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c= github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= +github.com/alecthomas/assert/v2 v2.2.0 h1:f6L/b7KE2bfA+9O4FL3CM/xJccDEwPVYd5fALBiuwvw= github.com/alecthomas/chroma/v2 v2.2.0/go.mod h1:vf4zrexSH54oEjJ7EdB65tGNHmH3pGZmVkgTP5RHvAs= -github.com/alecthomas/chroma/v2 v2.3.0 h1:83xfxrnjv8eK+Cf8qZDzNo3PPF9IbTWHs7z28GY6D0U= -github.com/alecthomas/chroma/v2 v2.3.0/go.mod h1:mZxeWZlxP2Dy+/8cBob2PYd8O2DwNAzave5AY7A2eQw= +github.com/alecthomas/chroma/v2 v2.4.0 h1:Loe2ZjT5x3q1bcWwemqyqEi8p11/IV/ncFCeLYDpWC4= +github.com/alecthomas/chroma/v2 v2.4.0/go.mod h1:6kHzqF5O6FUSJzBXW7fXELjb+e+7OXW4UpoPqMO7IBQ= github.com/alecthomas/kingpin v2.2.6+incompatible/go.mod h1:59OFYbFVLKQKq+mqrL6Rw5bR0c3ACQaawgXx0QYndlE= github.com/alecthomas/repr v0.0.0-20220113201626-b1b626ac65ae/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8= github.com/alecthomas/repr v0.1.0 h1:ENn2e1+J3k09gyj2shc0dHr/yjaWSHRlrJ4DPMevDqE= @@ -830,6 +831,7 @@ github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/xstrings v1.0.0/go.mod h1:4qWG/gcEcfX4z/mBDHJ++3ReCw9ibxbsNJbcucJdbSo= github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4= From 64973cf18fcd21179fb7612b15914691ee24c657 Mon Sep 17 00:00:00 2001 From: zeripath Date: Thu, 1 Dec 2022 23:56:51 +0000 Subject: [PATCH 011/110] Use path not filepath in template filenames (#21993) Paths in git are always separated by `/` not `\` - therefore we should `path` and not `filepath` Fix #21987 Signed-off-by: Andrew Thornton Co-authored-by: Lunny Xiao Co-authored-by: Lauris BH --- modules/issue/template/unmarshal.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/issue/template/unmarshal.go b/modules/issue/template/unmarshal.go index f43a83fb62b8c..8cae8d4c4299d 100644 --- a/modules/issue/template/unmarshal.go +++ b/modules/issue/template/unmarshal.go @@ -6,7 +6,7 @@ package template import ( "fmt" "io" - "path/filepath" + "path" "strconv" "code.gitea.io/gitea/modules/git" @@ -43,7 +43,7 @@ func Unmarshal(filename string, content []byte) (*api.IssueTemplate, error) { // UnmarshalFromEntry parses out a valid template from the blob in entry func UnmarshalFromEntry(entry *git.TreeEntry, dir string) (*api.IssueTemplate, error) { - return unmarshalFromEntry(entry, filepath.Join(dir, entry.Name())) + return unmarshalFromEntry(entry, path.Join(dir, entry.Name())) // Filepaths in Git are ALWAYS '/' separated do not use filepath here } // UnmarshalFromCommit parses out a valid template from the commit @@ -108,7 +108,7 @@ func unmarshal(filename string, content []byte) (*api.IssueTemplate, error) { // It could be a valid markdown with two horizontal lines, or an invalid markdown with wrong metadata. it.Content = string(content) - it.Name = filepath.Base(it.FileName) + it.Name = path.Base(it.FileName) // paths in Git are always '/' separated - do not use filepath! it.About, _ = util.SplitStringAtByteN(it.Content, 80) } else { it.Content = templateBody From f7ade6de7c1c4991c650d6b96e6407053e6bdae7 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Fri, 2 Dec 2022 11:15:36 +0800 Subject: [PATCH 012/110] Fix generate index failure possibility on postgres (#21998) @wxiaoguang Please review Co-authored-by: silverwind --- models/db/index.go | 20 ++++++++++++++++++++ models/git/commit_status.go | 18 ++++++++++++++++++ tests/integration/repo_commits_test.go | 4 ++-- 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/models/db/index.go b/models/db/index.go index ca664c9cf125a..f840a62c8913f 100644 --- a/models/db/index.go +++ b/models/db/index.go @@ -7,6 +7,9 @@ import ( "context" "errors" "fmt" + "strconv" + + "code.gitea.io/gitea/modules/setting" ) // ResourceIndex represents a resource index which could be used as issue/release and others @@ -55,8 +58,25 @@ func SyncMaxResourceIndex(ctx context.Context, tableName string, groupID, maxInd return nil } +func postgresGetNextResourceIndex(ctx context.Context, tableName string, groupID int64) (int64, error) { + res, err := GetEngine(ctx).Query(fmt.Sprintf("INSERT INTO %s (group_id, max_index) "+ + "VALUES (?,1) ON CONFLICT (group_id) DO UPDATE SET max_index = %s.max_index+1 RETURNING max_index", + tableName, tableName), groupID) + if err != nil { + return 0, err + } + if len(res) == 0 { + return 0, ErrGetResourceIndexFailed + } + return strconv.ParseInt(string(res[0]["max_index"]), 10, 64) +} + // GetNextResourceIndex generates a resource index, it must run in the same transaction where the resource is created func GetNextResourceIndex(ctx context.Context, tableName string, groupID int64) (int64, error) { + if setting.Database.UsePostgreSQL { + return postgresGetNextResourceIndex(ctx, tableName, groupID) + } + e := GetEngine(ctx) // try to update the max_index to next value, and acquire the write-lock for the record diff --git a/models/git/commit_status.go b/models/git/commit_status.go index 6353bb2fa9f97..928f1771fe939 100644 --- a/models/git/commit_status.go +++ b/models/git/commit_status.go @@ -9,6 +9,7 @@ import ( "errors" "fmt" "net/url" + "strconv" "strings" "time" @@ -49,8 +50,25 @@ func init() { db.RegisterModel(new(CommitStatusIndex)) } +func postgresGetCommitStatusIndex(ctx context.Context, repoID int64, sha string) (int64, error) { + res, err := db.GetEngine(ctx).Query("INSERT INTO `commit_status_index` (repo_id, sha, max_index) "+ + "VALUES (?,?,1) ON CONFLICT (repo_id, sha) DO UPDATE SET max_index = `commit_status_index`.max_index+1 RETURNING max_index", + repoID, sha) + if err != nil { + return 0, err + } + if len(res) == 0 { + return 0, db.ErrGetResourceIndexFailed + } + return strconv.ParseInt(string(res[0]["max_index"]), 10, 64) +} + // GetNextCommitStatusIndex retried 3 times to generate a resource index func GetNextCommitStatusIndex(ctx context.Context, repoID int64, sha string) (int64, error) { + if setting.Database.UsePostgreSQL { + return postgresGetCommitStatusIndex(ctx, repoID, sha) + } + e := db.GetEngine(ctx) // try to update the max_index to next value, and acquire the write-lock for the record diff --git a/tests/integration/repo_commits_test.go b/tests/integration/repo_commits_test.go index 3840c508dcebc..0d794cec757b8 100644 --- a/tests/integration/repo_commits_test.go +++ b/tests/integration/repo_commits_test.go @@ -135,8 +135,8 @@ func TestRepoCommitsStatusParallel(t *testing.T) { var wg sync.WaitGroup for i := 0; i < 10; i++ { wg.Add(1) - go func(t *testing.T, i int) { - t.Run(fmt.Sprintf("ParallelCreateStatus_%d", i), func(t *testing.T) { + go func(parentT *testing.T, i int) { + parentT.Run(fmt.Sprintf("ParallelCreateStatus_%d", i), func(t *testing.T) { runBody := doAPICreateCommitStatus(NewAPITestContext(t, "user2", "repo1"), path.Base(commitURL), api.CommitStatusState("pending")) runBody(t) wg.Done() From 665d02efaf6ebaadf3ffb5b412ea77c4502f0baf Mon Sep 17 00:00:00 2001 From: Mark Ormesher Date: Fri, 2 Dec 2022 03:39:19 +0000 Subject: [PATCH 013/110] Remove duplicate "Actions" label in mobile view (#21974) Closes #21973. The "Actions" button on the commit view page is labelled twice in mobile view. No other buttons on the page have a `mobile-only` extra label, so this PR removes it. Before: ![before](https://user-images.githubusercontent.com/6496999/204540002-75baa08a-6c06-4b39-847b-34272e09d71e.PNG) After: ![after](https://user-images.githubusercontent.com/6496999/204539991-a0607765-d5e2-4b1a-84c9-a3e16cbc674e.PNG) Co-authored-by: Lunny Xiao --- templates/repo/commit_page.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/repo/commit_page.tmpl b/templates/repo/commit_page.tmpl index 2dcd02ad98dfd..d4839e8930e84 100644 --- a/templates/repo/commit_page.tmpl +++ b/templates/repo/commit_page.tmpl @@ -27,7 +27,7 @@ {{if and ($.Permission.CanWrite $.UnitTypeCode) (not $.Repository.IsArchived) (not .IsDeleted)}}{{- /* */ -}} diff --git a/templates/repo/migrate/gitbucket.tmpl b/templates/repo/migrate/gitbucket.tmpl index 06912b27f52e5..5e6b3b4528394 100644 --- a/templates/repo/migrate/gitbucket.tmpl +++ b/templates/repo/migrate/gitbucket.tmpl @@ -123,7 +123,6 @@ - {{.locale.Tr "cancel"}} diff --git a/templates/repo/migrate/gitea.tmpl b/templates/repo/migrate/gitea.tmpl index 3bc615631684d..f56f9df5ec7ae 100644 --- a/templates/repo/migrate/gitea.tmpl +++ b/templates/repo/migrate/gitea.tmpl @@ -119,7 +119,6 @@ - {{.locale.Tr "cancel"}} diff --git a/templates/repo/migrate/github.tmpl b/templates/repo/migrate/github.tmpl index a5b1f195061f0..c4249f8904b80 100644 --- a/templates/repo/migrate/github.tmpl +++ b/templates/repo/migrate/github.tmpl @@ -121,7 +121,6 @@ - {{.locale.Tr "cancel"}} diff --git a/templates/repo/migrate/gitlab.tmpl b/templates/repo/migrate/gitlab.tmpl index fa68cee8914d4..a959833e96684 100644 --- a/templates/repo/migrate/gitlab.tmpl +++ b/templates/repo/migrate/gitlab.tmpl @@ -118,7 +118,6 @@ - {{.locale.Tr "cancel"}} diff --git a/templates/repo/migrate/gogs.tmpl b/templates/repo/migrate/gogs.tmpl index 01936e028bbfd..6d331b9e8fe6a 100644 --- a/templates/repo/migrate/gogs.tmpl +++ b/templates/repo/migrate/gogs.tmpl @@ -121,7 +121,6 @@ - {{.locale.Tr "cancel"}} diff --git a/templates/repo/migrate/onedev.tmpl b/templates/repo/migrate/onedev.tmpl index e411d47760189..18256aca5dc16 100644 --- a/templates/repo/migrate/onedev.tmpl +++ b/templates/repo/migrate/onedev.tmpl @@ -107,7 +107,6 @@ - {{.locale.Tr "cancel"}} diff --git a/templates/repo/pulls/fork.tmpl b/templates/repo/pulls/fork.tmpl index 0172e1b708298..28ba8e2e2527c 100644 --- a/templates/repo/pulls/fork.tmpl +++ b/templates/repo/pulls/fork.tmpl @@ -61,7 +61,6 @@ - {{.locale.Tr "cancel"}} diff --git a/templates/user/project.tmpl b/templates/user/project.tmpl index 3db9d19eede11..d38d84d95cfb7 100644 --- a/templates/user/project.tmpl +++ b/templates/user/project.tmpl @@ -60,7 +60,6 @@ - {{.locale.Tr "cancel"}} From 74874d065f39bb381ce6f703388eb4a7dd936509 Mon Sep 17 00:00:00 2001 From: Jason Song Date: Tue, 6 Dec 2022 15:53:09 +0800 Subject: [PATCH 031/110] Fix issue/PR numbers (#22037) When deleting a closed issue, we should update both `NumIssues`and `NumClosedIssues`, or `NumOpenIssues`(`= NumIssues -NumClosedIssues`) will be wrong. It's the same for pull requests. Releated to #21557. Alse fixed two harmless problems: - The SQL to check issue/PR total numbers is wrong, that means it will update the numbers even if they are correct. - Replace legacy `num_issues = num_issues + 1` operations with `UpdateRepoIssueNumbers`. --- models/issues/issue.go | 7 +------ models/repo.go | 4 ++-- services/issue/issue.go | 9 ++++++++- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/models/issues/issue.go b/models/issues/issue.go index 1d66996ee002c..3ab6d204ba09a 100644 --- a/models/issues/issue.go +++ b/models/issues/issue.go @@ -997,12 +997,7 @@ func NewIssueWithIndex(ctx context.Context, doer *user_model.User, opts NewIssue } } - if opts.IsPull { - _, err = e.Exec("UPDATE `repository` SET num_pulls = num_pulls + 1 WHERE id = ?", opts.Issue.RepoID) - } else { - _, err = e.Exec("UPDATE `repository` SET num_issues = num_issues + 1 WHERE id = ?", opts.Issue.RepoID) - } - if err != nil { + if err := repo_model.UpdateRepoIssueNumbers(ctx, opts.Issue.RepoID, opts.IsPull, false); err != nil { return err } diff --git a/models/repo.go b/models/repo.go index 5d333a3aee44e..9af600c9ba4a7 100644 --- a/models/repo.go +++ b/models/repo.go @@ -443,7 +443,7 @@ func CheckRepoStats(ctx context.Context) error { }, // Repository.NumIssues { - statsQuery("SELECT repo.id FROM `repository` repo WHERE repo.num_issues!=(SELECT COUNT(*) FROM `issue` WHERE repo_id=repo.id AND is_closed=? AND is_pull=?)", false, false), + statsQuery("SELECT repo.id FROM `repository` repo WHERE repo.num_issues!=(SELECT COUNT(*) FROM `issue` WHERE repo_id=repo.id AND is_pull=?)", false), repoStatsCorrectNumIssues, "repository count 'num_issues'", }, @@ -455,7 +455,7 @@ func CheckRepoStats(ctx context.Context) error { }, // Repository.NumPulls { - statsQuery("SELECT repo.id FROM `repository` repo WHERE repo.num_pulls!=(SELECT COUNT(*) FROM `issue` WHERE repo_id=repo.id AND is_closed=? AND is_pull=?)", false, true), + statsQuery("SELECT repo.id FROM `repository` repo WHERE repo.num_pulls!=(SELECT COUNT(*) FROM `issue` WHERE repo_id=repo.id AND is_pull=?)", true), repoStatsCorrectNumPulls, "repository count 'num_pulls'", }, diff --git a/services/issue/issue.go b/services/issue/issue.go index 5073dff819190..b91ee4fc18b07 100644 --- a/services/issue/issue.go +++ b/services/issue/issue.go @@ -218,9 +218,16 @@ func deleteIssue(issue *issues_model.Issue) error { return err } - if err := repo_model.UpdateRepoIssueNumbers(ctx, issue.RepoID, issue.IsPull, issue.IsClosed); err != nil { + // update the total issue numbers + if err := repo_model.UpdateRepoIssueNumbers(ctx, issue.RepoID, issue.IsPull, false); err != nil { return err } + // if the issue is closed, update the closed issue numbers + if issue.IsClosed { + if err := repo_model.UpdateRepoIssueNumbers(ctx, issue.RepoID, issue.IsPull, true); err != nil { + return err + } + } if err := issues_model.UpdateMilestoneCounters(ctx, issue.MilestoneID); err != nil { return fmt.Errorf("error updating counters for milestone id %d: %w", From e2fa84fddc80368c0315616870b8c75592397422 Mon Sep 17 00:00:00 2001 From: silverwind Date: Tue, 6 Dec 2022 14:15:46 +0100 Subject: [PATCH 032/110] Release and Tag List tweaks (#21712) - Reduce font size on tag list and add muted links - Move Release tag to right side on release list - Move Release edit button to far-right and make it icon-only - Add styles for error dropdowns, seen on release edit page - Make the release page slightly more mobile-friendly Screen Shot 2022-11-07 at 22 10 44 Screen Shot 2022-11-07 at 22 27 14 Screen Shot 2022-11-07 at 22 27 27 Screen Shot 2022-11-07 at 22 42 10 Screen Shot 2022-11-07 at 22 42 27 image Screen Shot 2022-11-07 at 22 21 36 Co-authored-by: Lunny Xiao --- templates/repo/release/list.tmpl | 73 ++++++++++++++---------- tests/integration/release_test.go | 2 +- web_src/less/_base.less | 31 +++++++++- web_src/less/_repository.less | 13 ++--- web_src/less/themes/theme-arc-green.less | 2 + 5 files changed, 80 insertions(+), 41 deletions(-) diff --git a/templates/repo/release/list.tmpl b/templates/repo/release/list.tmpl index 6abb240cc34b3..5f668d74a9f68 100644 --- a/templates/repo/release/list.tmpl +++ b/templates/repo/release/list.tmpl @@ -36,21 +36,21 @@ @@ -69,19 +69,10 @@ {{if .IsTag}} {{if .CreatedUnix}}{{TimeSinceUnix .CreatedUnix $.locale}}{{end}} {{else}} - {{if .IsDraft}} - {{$.locale.Tr "repo.release.draft"}} - {{else if .IsPrerelease}} - {{$.locale.Tr "repo.release.prerelease"}} - {{else}} - {{$.locale.Tr "repo.release.stable"}} - {{end}} - - {{svg "octicon-tag" 16 "mr-2"}}{{.TagName}} - + {{svg "octicon-tag" 16 "mr-2"}}{{.TagName}} {{if .Sha1}} - {{svg "octicon-git-commit" 16 "mr-2"}}{{ShortSha .Sha1}} + {{svg "octicon-git-commit" 16 "mr-2"}}{{ShortSha .Sha1}} {{template "repo/branch_dropdown" dict "root" $ "release" .}} {{end}} @@ -89,36 +80,56 @@
{{if .IsTag}} -

- {{svg "octicon-tag" 16 "mr-2"}}{{.TagName}} -

+

{{if gt .Publisher.ID 0}} {{avatar .Publisher 20}} {{.Publisher.Name}} + + {{$.locale.Tr "repo.released_this"}} + + {{if .CreatedUnix}} + {{TimeSinceUnix .CreatedUnix $.locale}} + {{end}} + | {{end}} {{$.locale.Tr "repo.release.ahead.commits" .NumCommitsBehind | Str2html}} {{$.locale.Tr "repo.release.ahead.target" $.DefaultBranch}}

{{else}} -

- {{.Title}} - {{if $.CanCreateRelease}} - - ({{$.locale.Tr "repo.release.edit"}}) - - {{end}} -

+
+

+ {{.Title}} + {{if .IsDraft}} + {{$.locale.Tr "repo.release.draft"}} + {{else if .IsPrerelease}} + {{$.locale.Tr "repo.release.prerelease"}} + {{else if not .IsTag}} + {{$.locale.Tr "repo.release.stable"}} + {{end}} +

+
+ {{if $.CanCreateRelease}} + + {{svg "octicon-pencil"}} + + {{end}} +
+

{{if .OriginalAuthor}} diff --git a/tests/integration/release_test.go b/tests/integration/release_test.go index b4f7560fa33b1..3fcd4a5b5e8e8 100644 --- a/tests/integration/release_test.go +++ b/tests/integration/release_test.go @@ -53,7 +53,7 @@ func checkLatestReleaseAndCount(t *testing.T, session *TestSession, repoURL, ver resp := session.MakeRequest(t, req, http.StatusOK) htmlDoc := NewHTMLParser(t, resp.Body) - labelText := htmlDoc.doc.Find("#release-list > li .meta .label").First().Text() + labelText := htmlDoc.doc.Find("#release-list > li .detail .label").First().Text() assert.EqualValues(t, label, labelText) titleText := htmlDoc.doc.Find("#release-list > li .detail h4 a").First().Text() assert.EqualValues(t, version, titleText) diff --git a/web_src/less/_base.less b/web_src/less/_base.less index e156ccd6cc0ad..022afcea927e7 100644 --- a/web_src/less/_base.less +++ b/web_src/less/_base.less @@ -108,6 +108,8 @@ --color-diff-inactive: #f2f2f2; --color-error-border: #e0b4b4; --color-error-bg: #fff6f6; + --color-error-bg-active: #fbb; + --color-error-bg-hover: #fdd; --color-error-text: #9f3a38; --color-success-border: #a3c293; --color-success-bg: #fcfff5; @@ -1293,6 +1295,11 @@ a.ui.card:hover, .ui.form .fields.error .field input[type="text"], .ui.form .fields.error .field input[type="file"], .ui.form .fields.error .field input[type="url"], +.ui.form .fields.error .field .ui.dropdown, +.ui.form .fields.error .field .ui.dropdown .item, +.ui.form .field.error .ui.dropdown, +.ui.form .field.error .ui.dropdown .text, +.ui.form .field.error .ui.dropdown .item, .ui.form .field.error textarea, .ui.form .field.error select, .ui.form .field.error input:not([type]), @@ -1321,10 +1328,32 @@ a.ui.card:hover, .ui.form .field.error input[type="file"]:focus, .ui.form .field.error input[type="url"]:focus { background-color: var(--color-error-bg); - border: 1px solid var(--color-error-border); + border-color: var(--color-error-border); color: var(--color-error-text); } +.ui.form .fields.error .field .ui.dropdown, +.ui.form .field.error .ui.dropdown, +.ui.form .fields.error .field .ui.dropdown:hover, +.ui.form .field.error .ui.dropdown:hover { + border-color: var(--color-error-border) !important; +} + +.ui.form .fields.error .field .ui.dropdown .menu .item:hover, +.ui.form .field.error .ui.dropdown .menu .item:hover { + background-color: var(--color-error-bg-hover); +} + +.ui.form .fields.error .field .ui.dropdown .menu .active.item, +.ui.form .field.error .ui.dropdown .menu .active.item { + background-color: var(--color-error-bg-active) !important; +} + +.ui.form .fields.error .dropdown .menu, +.ui.form .field.error .dropdown .menu { + border-color: var(--color-error-border) !important; +} + .ui.loading.loading.input > i.icon svg { visibility: hidden; } diff --git a/web_src/less/_repository.less b/web_src/less/_repository.less index 3eb0178d373d6..0f318fa53cdab 100644 --- a/web_src/less/_repository.less +++ b/web_src/less/_repository.less @@ -1855,11 +1855,13 @@ border-top: 1px solid var(--color-secondary); margin-top: 20px; padding-top: 15px; + padding-left: 0; .release-list-title { font-size: 2rem; font-weight: normal; - margin-top: -6px; + margin-top: -4px; + margin-bottom: 0; } > li { @@ -1879,11 +1881,6 @@ margin-right: 0; } - .tag:not(.icon) { - display: block; - margin-top: 15px; - } - .commit { display: block; margin-top: 10px; @@ -1903,7 +1900,7 @@ .author { img { - margin-bottom: -3px; + margin-bottom: 3px; } } @@ -1966,7 +1963,7 @@ } .release-tag-name { - font-size: 20px; + font-size: 18px; font-weight: normal; } } diff --git a/web_src/less/themes/theme-arc-green.less b/web_src/less/themes/theme-arc-green.less index 8c05ad278f4cb..2f06f33aca705 100644 --- a/web_src/less/themes/theme-arc-green.less +++ b/web_src/less/themes/theme-arc-green.less @@ -97,6 +97,8 @@ --color-diff-inactive: #353846; --color-error-border: #a04141; --color-error-bg: #522; + --color-error-bg-active: #744; + --color-error-bg-hover: #633; --color-error-text: #f9cbcb; --color-success-border: #458a57; --color-success-bg: #284034; From 0a85537c79b65f3b10a4b66265a23a8de46a2e43 Mon Sep 17 00:00:00 2001 From: Jason Song Date: Wed, 7 Dec 2022 23:58:31 +0800 Subject: [PATCH 033/110] Support disabling database auto migration (#22053) Gitea will migrate the database model version automatically, but it should be able to be disabled and keep Gitea shutdown if the version is not matched. --- custom/conf/app.example.ini | 3 +++ .../doc/advanced/config-cheat-sheet.en-us.md | 1 + modules/doctor/dbversion.go | 1 + modules/setting/database.go | 2 ++ routers/common/db.go | 21 ++++++++++++++++++- 5 files changed, 27 insertions(+), 1 deletion(-) diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index bee12ffa9b225..03f004ee90196 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -403,6 +403,9 @@ LOG_SQL = false ; if unset defaults to true ;; ;; Database maximum number of open connections, default is 0 meaning no maximum ;MAX_OPEN_CONNS = 0 +;; +;; Whether execute database models migrations automatically +;AUTO_MIGRATION = true ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index 756ab32256752..37f03b42ea724 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -444,6 +444,7 @@ The following configuration set `Content-Type: application/vnd.android.package-a - `MAX_OPEN_CONNS` **0**: Database maximum open connections - default is 0, meaning there is no limit. - `MAX_IDLE_CONNS` **2**: Max idle database connections on connection pool, default is 2 - this will be capped to `MAX_OPEN_CONNS`. - `CONN_MAX_LIFETIME` **0 or 3s**: Sets the maximum amount of time a DB connection may be reused - default is 0, meaning there is no limit (except on MySQL where it is 3s - see #6804 & #7071). +- `AUTO_MIGRATION` **true**: Whether execute database models migrations automatically. Please see #8540 & #8273 for further discussion of the appropriate values for `MAX_OPEN_CONNS`, `MAX_IDLE_CONNS` & `CONN_MAX_LIFETIME` and their relation to port exhaustion. diff --git a/modules/doctor/dbversion.go b/modules/doctor/dbversion.go index 3ddca92fb34c9..2b20cb2340641 100644 --- a/modules/doctor/dbversion.go +++ b/modules/doctor/dbversion.go @@ -12,6 +12,7 @@ import ( ) func checkDBVersion(ctx context.Context, logger log.Logger, autofix bool) error { + logger.Info("Expected database version: %d", migrations.ExpectedVersion()) if err := db.InitEngineWithMigration(ctx, migrations.EnsureUpToDate); err != nil { if !autofix { logger.Critical("Error: %v during ensure up to date", err) diff --git a/modules/setting/database.go b/modules/setting/database.go index be06c47478fd4..5480f9dffd905 100644 --- a/modules/setting/database.go +++ b/modules/setting/database.go @@ -49,6 +49,7 @@ var ( MaxOpenConns int ConnMaxLifetime time.Duration IterateBufferSize int + AutoMigration bool }{ Timeout: 500, IterateBufferSize: 50, @@ -105,6 +106,7 @@ func InitDBConfig() { Database.LogSQL = sec.Key("LOG_SQL").MustBool(true) Database.DBConnectRetries = sec.Key("DB_RETRIES").MustInt(10) Database.DBConnectBackoff = sec.Key("DB_RETRY_BACKOFF").MustDuration(3 * time.Second) + Database.AutoMigration = sec.Key("AUTO_MIGRATION").MustBool(true) } // DBConnStr returns database connection string diff --git a/routers/common/db.go b/routers/common/db.go index ac082ab36f99f..2e86fbd0fd42c 100644 --- a/routers/common/db.go +++ b/routers/common/db.go @@ -12,6 +12,8 @@ import ( "code.gitea.io/gitea/models/migrations" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" + + "xorm.io/xorm" ) // InitDBEngine In case of problems connecting to DB, retry connection. Eg, PGSQL in Docker Container on Synology @@ -24,7 +26,7 @@ func InitDBEngine(ctx context.Context) (err error) { default: } log.Info("ORM engine initialization attempt #%d/%d...", i+1, setting.Database.DBConnectRetries) - if err = db.InitEngineWithMigration(ctx, migrations.Migrate); err == nil { + if err = db.InitEngineWithMigration(ctx, migrateWithSetting); err == nil { break } else if i == setting.Database.DBConnectRetries-1 { return err @@ -36,3 +38,20 @@ func InitDBEngine(ctx context.Context) (err error) { db.HasEngine = true return nil } + +func migrateWithSetting(x *xorm.Engine) error { + if setting.Database.AutoMigration { + return migrations.Migrate(x) + } + + if current, err := migrations.GetCurrentDBVersion(x); err != nil { + return err + } else if current < 0 { + // execute migrations when the database isn't initialized even if AutoMigration is false + return migrations.Migrate(x) + } else if expected := migrations.ExpectedVersion(); current != expected { + log.Fatal(`"database.AUTO_MIGRATION" is disabled, but current database version %d is not equal to the expected version %d.`+ + `You can set "database.AUTO_MIGRATION" to true or migrate manually by running "gitea [--config /path/to/app.ini] migrate"`, current, expected) + } + return nil +} From cf27403e189f674d9a1e02cb71bc1ac13a5ba23d Mon Sep 17 00:00:00 2001 From: hr-98 Date: Thu, 8 Dec 2022 02:47:47 +0000 Subject: [PATCH 034/110] Round language stats percentage using largest remainder (#22026) Fix #22023 I've changed how the percentages for the language statistics are rounded because they did not always add up to 100% Now it's done with the largest remainder method, which makes sure that total is 100% Co-authored-by: Lauris BH --- models/repo/language_stats.go | 40 +++++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/models/repo/language_stats.go b/models/repo/language_stats.go index f8f5dd041fa1c..2da16814bd8f1 100644 --- a/models/repo/language_stats.go +++ b/models/repo/language_stats.go @@ -6,6 +6,7 @@ package repo import ( "context" "math" + "sort" "strings" "code.gitea.io/gitea/models/db" @@ -43,7 +44,7 @@ func (stats LanguageStatList) LoadAttributes() { func (stats LanguageStatList) getLanguagePercentages() map[string]float32 { langPerc := make(map[string]float32) - var otherPerc float32 = 100 + var otherPerc float32 var total int64 for _, stat := range stats { @@ -51,21 +52,52 @@ func (stats LanguageStatList) getLanguagePercentages() map[string]float32 { } if total > 0 { for _, stat := range stats { - perc := float32(math.Round(float64(stat.Size)/float64(total)*1000) / 10) + perc := float32(float64(stat.Size) / float64(total) * 100) if perc <= 0.1 { + otherPerc += perc continue } - otherPerc -= perc langPerc[stat.Language] = perc } - otherPerc = float32(math.Round(float64(otherPerc)*10) / 10) } if otherPerc > 0 { langPerc["other"] = otherPerc } + roundByLargestRemainder(langPerc, 100) return langPerc } +// Rounds to 1 decimal point, target should be the expected sum of percs +func roundByLargestRemainder(percs map[string]float32, target float32) { + leftToDistribute := int(target * 10) + + keys := make([]string, 0, len(percs)) + + for k, v := range percs { + percs[k] = v * 10 + floored := math.Floor(float64(percs[k])) + leftToDistribute -= int(floored) + keys = append(keys, k) + } + + // Sort the keys by the largest remainder + sort.SliceStable(keys, func(i, j int) bool { + _, remainderI := math.Modf(float64(percs[keys[i]])) + _, remainderJ := math.Modf(float64(percs[keys[j]])) + return remainderI > remainderJ + }) + + // Increment the values in order of largest remainder + for _, k := range keys { + percs[k] = float32(math.Floor(float64(percs[k]))) + if leftToDistribute > 0 { + percs[k]++ + leftToDistribute-- + } + percs[k] /= 10 + } +} + // GetLanguageStats returns the language statistics for a repository func GetLanguageStats(ctx context.Context, repo *Repository) (LanguageStatList, error) { stats := make(LanguageStatList, 0, 6) From 0585ac3ac6ff4f59e8455cb5f4cbe42c4b79c965 Mon Sep 17 00:00:00 2001 From: silverwind Date: Thu, 8 Dec 2022 09:21:37 +0100 Subject: [PATCH 035/110] Update go dev dependencies (#22064) `golangci-lint` [deprecated](https://github.com/golangci/golangci-lint/issues/1841) a bunch of linters, removed them. --- .golangci.yml | 34 ++++++++++++++-------------- Makefile | 12 +++++----- models/db/context.go | 6 +++-- models/migrations/v1_17/main_test.go | 2 +- models/migrations/v1_17/v211.go | 2 +- models/migrations/v1_17/v212.go | 2 +- models/migrations/v1_17/v213.go | 2 +- models/migrations/v1_17/v214.go | 2 +- models/migrations/v1_17/v215.go | 2 +- models/migrations/v1_17/v216.go | 2 +- models/migrations/v1_17/v217.go | 2 +- models/migrations/v1_17/v218.go | 2 +- models/migrations/v1_17/v219.go | 2 +- models/migrations/v1_17/v220.go | 2 +- models/migrations/v1_17/v221.go | 2 +- models/migrations/v1_17/v221_test.go | 2 +- models/migrations/v1_17/v222.go | 2 +- models/migrations/v1_17/v223.go | 2 +- models/migrations/v1_18/main_test.go | 2 +- models/migrations/v1_18/v224.go | 2 +- models/migrations/v1_18/v225.go | 2 +- models/migrations/v1_18/v226.go | 2 +- models/migrations/v1_18/v227.go | 2 +- models/migrations/v1_18/v228.go | 2 +- models/migrations/v1_18/v230.go | 2 +- models/migrations/v1_19/main_test.go | 2 +- models/migrations/v1_19/v232.go | 2 +- models/migrations/v1_6/v70.go | 2 +- models/migrations/v1_6/v71.go | 2 +- models/migrations/v1_6/v72.go | 2 +- models/migrations/v1_7/v73.go | 2 +- models/migrations/v1_7/v74.go | 2 +- models/migrations/v1_7/v75.go | 2 +- models/migrations/v1_8/v76.go | 2 +- models/migrations/v1_8/v77.go | 2 +- models/migrations/v1_8/v78.go | 2 +- models/migrations/v1_8/v79.go | 2 +- models/migrations/v1_8/v80.go | 2 +- models/migrations/v1_8/v81.go | 2 +- models/migrations/v1_9/v82.go | 2 +- modules/charset/escape_stream.go | 2 +- modules/log/groutinelabel.go | 2 +- modules/setting/setting.go | 2 +- routers/api/packages/pypi/pypi.go | 6 +++-- 44 files changed, 71 insertions(+), 67 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 99133badd9b86..130ad286b507a 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,28 +1,28 @@ linters: enable: - - gosimple - - deadcode - - typecheck - - govet - - errcheck - - staticcheck - - unused - - structcheck - - varcheck + - bidichk + # - deadcode # deprecated - https://github.com/golangci/golangci-lint/issues/1841 + - depguard - dupl - #- gocyclo # The cyclomatic complexety of a lot of functions is too high, we should refactor those another time. - - gofmt + - errcheck - gocritic - - bidichk - - ineffassign - - revive + # - gocyclo # The cyclomatic complexety of a lot of functions is too high, we should refactor those another time. + - gofmt - gofumpt - - depguard + - gosimple + - govet + - ineffassign - nakedret - - unconvert - - wastedassign - nolintlint + - revive + - staticcheck + # - structcheck # deprecated - https://github.com/golangci/golangci-lint/issues/1841 - stylecheck + - typecheck + - unconvert + - unused + # - varcheck # deprecated - https://github.com/golangci/golangci-lint/issues/1841 + # - wastedassign # disabled - https://github.com/golangci/golangci-lint/issues/2649 enable-all: false disable-all: true fast: false diff --git a/Makefile b/Makefile index 4d78944de152c..d1122984a7d8d 100644 --- a/Makefile +++ b/Makefile @@ -26,15 +26,15 @@ COMMA := , XGO_VERSION := go-1.19.x AIR_PACKAGE ?= github.com/cosmtrek/air@v1.40.4 -EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/cmd/editorconfig-checker@2.5.0 -ERRCHECK_PACKAGE ?= github.com/kisielk/errcheck@v1.6.1 -GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.3.1 -GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.47.0 +EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/cmd/editorconfig-checker@2.6.0 +ERRCHECK_PACKAGE ?= github.com/kisielk/errcheck@v1.6.2 +GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.4.0 +GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.50.1 GXZ_PAGAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.10 MISSPELL_PACKAGE ?= github.com/client9/misspell/cmd/misspell@v0.3.4 -SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@v0.30.0 +SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@v0.30.3 XGO_PACKAGE ?= src.techknowlogick.com/xgo@latest -GO_LICENSES_PACKAGE ?= github.com/google/go-licenses@v1.3.0 +GO_LICENSES_PACKAGE ?= github.com/google/go-licenses@v1.5.0 GOVULNCHECK_PACKAGE ?= golang.org/x/vuln/cmd/govulncheck@latest DOCKER_IMAGE ?= gitea/gitea diff --git a/models/db/context.go b/models/db/context.go index fb95e94c931df..c8ad0c1aa2739 100644 --- a/models/db/context.go +++ b/models/db/context.go @@ -21,8 +21,10 @@ type contextKey struct { } // enginedContextKey is a context key. It is used with context.Value() to get the current Engined for the context -var enginedContextKey = &contextKey{"engined"} -var _ Engined = &Context{} +var ( + enginedContextKey = &contextKey{"engined"} + _ Engined = &Context{} +) // Context represents a db context type Context struct { diff --git a/models/migrations/v1_17/main_test.go b/models/migrations/v1_17/main_test.go index e6871cacf2e06..79cb3fa078863 100644 --- a/models/migrations/v1_17/main_test.go +++ b/models/migrations/v1_17/main_test.go @@ -1,7 +1,7 @@ // Copyright 2021 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_17 // nolint +package v1_17 //nolint import ( "testing" diff --git a/models/migrations/v1_17/v211.go b/models/migrations/v1_17/v211.go index 227de4984fc50..16ec51849366d 100644 --- a/models/migrations/v1_17/v211.go +++ b/models/migrations/v1_17/v211.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_17 // nolint +package v1_17 //nolint import ( "fmt" diff --git a/models/migrations/v1_17/v212.go b/models/migrations/v1_17/v212.go index a00d29cd2fd06..536ba0a2c42d4 100644 --- a/models/migrations/v1_17/v212.go +++ b/models/migrations/v1_17/v212.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_17 // nolint +package v1_17 //nolint import ( "code.gitea.io/gitea/modules/timeutil" diff --git a/models/migrations/v1_17/v213.go b/models/migrations/v1_17/v213.go index 2ed56104cf7e7..8607fdba47f24 100644 --- a/models/migrations/v1_17/v213.go +++ b/models/migrations/v1_17/v213.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_17 // nolint +package v1_17 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_17/v214.go b/models/migrations/v1_17/v214.go index e619b805a619c..3b2351d160407 100644 --- a/models/migrations/v1_17/v214.go +++ b/models/migrations/v1_17/v214.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_17 // nolint +package v1_17 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_17/v215.go b/models/migrations/v1_17/v215.go index 43e5b636c9bfa..0244be216c446 100644 --- a/models/migrations/v1_17/v215.go +++ b/models/migrations/v1_17/v215.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_17 // nolint +package v1_17 //nolint import ( "code.gitea.io/gitea/models/pull" diff --git a/models/migrations/v1_17/v216.go b/models/migrations/v1_17/v216.go index 388cb971e7055..59b21d9b2c465 100644 --- a/models/migrations/v1_17/v216.go +++ b/models/migrations/v1_17/v216.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_17 // nolint +package v1_17 //nolint // This migration added non-ideal indices to the action table which on larger datasets slowed things down // it has been superceded by v218.go diff --git a/models/migrations/v1_17/v217.go b/models/migrations/v1_17/v217.go index bbb40251fbe8c..3ca9215f09378 100644 --- a/models/migrations/v1_17/v217.go +++ b/models/migrations/v1_17/v217.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_17 // nolint +package v1_17 //nolint import ( "code.gitea.io/gitea/modules/setting" diff --git a/models/migrations/v1_17/v218.go b/models/migrations/v1_17/v218.go index 4d5e77070bbc7..675fd1df94fb3 100644 --- a/models/migrations/v1_17/v218.go +++ b/models/migrations/v1_17/v218.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_17 // nolint +package v1_17 //nolint import ( "code.gitea.io/gitea/modules/setting" diff --git a/models/migrations/v1_17/v219.go b/models/migrations/v1_17/v219.go index c8aa2378c30a8..a2165212cc9b2 100644 --- a/models/migrations/v1_17/v219.go +++ b/models/migrations/v1_17/v219.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_17 // nolint +package v1_17 //nolint import ( "time" diff --git a/models/migrations/v1_17/v220.go b/models/migrations/v1_17/v220.go index 31158509b87d6..904ddc5192935 100644 --- a/models/migrations/v1_17/v220.go +++ b/models/migrations/v1_17/v220.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_17 // nolint +package v1_17 //nolint import ( packages_model "code.gitea.io/gitea/models/packages" diff --git a/models/migrations/v1_17/v221.go b/models/migrations/v1_17/v221.go index ceb079f369d09..8a58b0f1056d3 100644 --- a/models/migrations/v1_17/v221.go +++ b/models/migrations/v1_17/v221.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_17 // nolint +package v1_17 //nolint import ( "encoding/base32" diff --git a/models/migrations/v1_17/v221_test.go b/models/migrations/v1_17/v221_test.go index 3215d74915f15..9ca54142e2d59 100644 --- a/models/migrations/v1_17/v221_test.go +++ b/models/migrations/v1_17/v221_test.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_17 // nolint +package v1_17 //nolint import ( "encoding/base32" diff --git a/models/migrations/v1_17/v222.go b/models/migrations/v1_17/v222.go index 558c0d9adcd22..d1b77d845d164 100644 --- a/models/migrations/v1_17/v222.go +++ b/models/migrations/v1_17/v222.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_17 // nolint +package v1_17 //nolint import ( "context" diff --git a/models/migrations/v1_17/v223.go b/models/migrations/v1_17/v223.go index c83deb255fe00..a23d9916b383a 100644 --- a/models/migrations/v1_17/v223.go +++ b/models/migrations/v1_17/v223.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_17 // nolint +package v1_17 //nolint import ( "context" diff --git a/models/migrations/v1_18/main_test.go b/models/migrations/v1_18/main_test.go index aec48845bf7f1..f71a21d1fb24b 100644 --- a/models/migrations/v1_18/main_test.go +++ b/models/migrations/v1_18/main_test.go @@ -1,7 +1,7 @@ // Copyright 2021 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_18 // nolint +package v1_18 //nolint import ( "testing" diff --git a/models/migrations/v1_18/v224.go b/models/migrations/v1_18/v224.go index f37b773effa19..afd34a5db09cc 100644 --- a/models/migrations/v1_18/v224.go +++ b/models/migrations/v1_18/v224.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_18 // nolint +package v1_18 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_18/v225.go b/models/migrations/v1_18/v225.go index 2ff5f4c7f7c62..786772c143bd0 100644 --- a/models/migrations/v1_18/v225.go +++ b/models/migrations/v1_18/v225.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_18 // nolint +package v1_18 //nolint import ( "code.gitea.io/gitea/modules/setting" diff --git a/models/migrations/v1_18/v226.go b/models/migrations/v1_18/v226.go index 536346a97a6b1..f87e24b11de9f 100644 --- a/models/migrations/v1_18/v226.go +++ b/models/migrations/v1_18/v226.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_18 // nolint +package v1_18 //nolint import ( "xorm.io/builder" diff --git a/models/migrations/v1_18/v227.go b/models/migrations/v1_18/v227.go index b4da88ee0aedc..c938028323fd7 100644 --- a/models/migrations/v1_18/v227.go +++ b/models/migrations/v1_18/v227.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_18 // nolint +package v1_18 //nolint import ( "fmt" diff --git a/models/migrations/v1_18/v228.go b/models/migrations/v1_18/v228.go index 3144310507f01..58d3257528ae9 100644 --- a/models/migrations/v1_18/v228.go +++ b/models/migrations/v1_18/v228.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_18 // nolint +package v1_18 //nolint import ( "code.gitea.io/gitea/modules/timeutil" diff --git a/models/migrations/v1_18/v230.go b/models/migrations/v1_18/v230.go index 2d2248fcb384d..cf94926be17ca 100644 --- a/models/migrations/v1_18/v230.go +++ b/models/migrations/v1_18/v230.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_18 // nolint +package v1_18 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_19/main_test.go b/models/migrations/v1_19/main_test.go index 3d08ec2f5e96f..59f42af111623 100644 --- a/models/migrations/v1_19/main_test.go +++ b/models/migrations/v1_19/main_test.go @@ -1,7 +1,7 @@ // Copyright 2021 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_19 // nolint +package v1_19 //nolint import ( "testing" diff --git a/models/migrations/v1_19/v232.go b/models/migrations/v1_19/v232.go index 9feb5343bcd85..89b595c54375f 100644 --- a/models/migrations/v1_19/v232.go +++ b/models/migrations/v1_19/v232.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_19 // nolint +package v1_19 //nolint import ( "code.gitea.io/gitea/modules/setting" diff --git a/models/migrations/v1_6/v70.go b/models/migrations/v1_6/v70.go index 166772ad700ac..fec88266ba6e8 100644 --- a/models/migrations/v1_6/v70.go +++ b/models/migrations/v1_6/v70.go @@ -1,7 +1,7 @@ // Copyright 2018 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_6 // nolint +package v1_6 //nolint import ( "fmt" diff --git a/models/migrations/v1_6/v71.go b/models/migrations/v1_6/v71.go index 57586c5c32650..effd2ebf99595 100644 --- a/models/migrations/v1_6/v71.go +++ b/models/migrations/v1_6/v71.go @@ -1,7 +1,7 @@ // Copyright 2018 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_6 // nolint +package v1_6 //nolint import ( "fmt" diff --git a/models/migrations/v1_6/v72.go b/models/migrations/v1_6/v72.go index b7428150bef77..ce963eb371480 100644 --- a/models/migrations/v1_6/v72.go +++ b/models/migrations/v1_6/v72.go @@ -1,7 +1,7 @@ // Copyright 2018 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_6 // nolint +package v1_6 //nolint import ( "fmt" diff --git a/models/migrations/v1_7/v73.go b/models/migrations/v1_7/v73.go index 0c5775c2b2ddc..1013daedbd635 100644 --- a/models/migrations/v1_7/v73.go +++ b/models/migrations/v1_7/v73.go @@ -1,7 +1,7 @@ // Copyright 2018 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_7 // nolint +package v1_7 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_7/v74.go b/models/migrations/v1_7/v74.go index aeca5448e106e..bdd89d1f342a4 100644 --- a/models/migrations/v1_7/v74.go +++ b/models/migrations/v1_7/v74.go @@ -1,7 +1,7 @@ // Copyright 2018 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_7 // nolint +package v1_7 //nolint import "xorm.io/xorm" diff --git a/models/migrations/v1_7/v75.go b/models/migrations/v1_7/v75.go index bad8010090a85..fa7430970c91d 100644 --- a/models/migrations/v1_7/v75.go +++ b/models/migrations/v1_7/v75.go @@ -1,7 +1,7 @@ // Copyright 2018 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_7 // nolint +package v1_7 //nolint import ( "xorm.io/builder" diff --git a/models/migrations/v1_8/v76.go b/models/migrations/v1_8/v76.go index 4512689386024..f35856cc606cc 100644 --- a/models/migrations/v1_8/v76.go +++ b/models/migrations/v1_8/v76.go @@ -1,7 +1,7 @@ // Copyright 2018 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_8 // nolint +package v1_8 //nolint import ( "fmt" diff --git a/models/migrations/v1_8/v77.go b/models/migrations/v1_8/v77.go index f92dfed882dd1..2305984c129ed 100644 --- a/models/migrations/v1_8/v77.go +++ b/models/migrations/v1_8/v77.go @@ -1,7 +1,7 @@ // Copyright 2019 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_8 // nolint +package v1_8 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_8/v78.go b/models/migrations/v1_8/v78.go index 8bc0221412e79..637db451f5b8f 100644 --- a/models/migrations/v1_8/v78.go +++ b/models/migrations/v1_8/v78.go @@ -1,7 +1,7 @@ // Copyright 2019 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_8 // nolint +package v1_8 //nolint import ( "code.gitea.io/gitea/models/migrations/base" diff --git a/models/migrations/v1_8/v79.go b/models/migrations/v1_8/v79.go index 9cebca1853764..e708d7229464e 100644 --- a/models/migrations/v1_8/v79.go +++ b/models/migrations/v1_8/v79.go @@ -1,7 +1,7 @@ // Copyright 2019 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_8 // nolint +package v1_8 //nolint import ( "code.gitea.io/gitea/modules/setting" diff --git a/models/migrations/v1_8/v80.go b/models/migrations/v1_8/v80.go index ec9726d889201..7f2e0ff72bf09 100644 --- a/models/migrations/v1_8/v80.go +++ b/models/migrations/v1_8/v80.go @@ -1,7 +1,7 @@ // Copyright 2019 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_8 // nolint +package v1_8 //nolint import "xorm.io/xorm" diff --git a/models/migrations/v1_8/v81.go b/models/migrations/v1_8/v81.go index ff050386b43cc..a100dc1ef71f1 100644 --- a/models/migrations/v1_8/v81.go +++ b/models/migrations/v1_8/v81.go @@ -1,7 +1,7 @@ // Copyright 2019 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_8 // nolint +package v1_8 //nolint import ( "fmt" diff --git a/models/migrations/v1_9/v82.go b/models/migrations/v1_9/v82.go index b0dffe6035f6a..26806dd64505d 100644 --- a/models/migrations/v1_9/v82.go +++ b/models/migrations/v1_9/v82.go @@ -1,7 +1,7 @@ // Copyright 2019 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_9 // nolint +package v1_9 //nolint import ( "fmt" diff --git a/modules/charset/escape_stream.go b/modules/charset/escape_stream.go index d29e393ab4d79..823b635137ebf 100644 --- a/modules/charset/escape_stream.go +++ b/modules/charset/escape_stream.go @@ -239,7 +239,7 @@ func (counts runeCountType) needsEscape() bool { type runeType int const ( - basicASCIIRuneType runeType = iota //nolint // <- This is technically deadcode but its self-documenting so it should stay + basicASCIIRuneType runeType = iota // <- This is technically deadcode but its self-documenting so it should stay brokenRuneType nonBasicASCIIRuneType ambiguousRuneType diff --git a/modules/log/groutinelabel.go b/modules/log/groutinelabel.go index 829c217574e84..56d7af42da3fb 100644 --- a/modules/log/groutinelabel.go +++ b/modules/log/groutinelabel.go @@ -6,7 +6,7 @@ package log import "unsafe" //go:linkname runtime_getProfLabel runtime/pprof.runtime_getProfLabel -func runtime_getProfLabel() unsafe.Pointer // nolint +func runtime_getProfLabel() unsafe.Pointer //nolint type labelMap map[string]string diff --git a/modules/setting/setting.go b/modules/setting/setting.go index f0d7f029271c9..9f2f0933d4eae 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -941,7 +941,7 @@ func loadFromConf(allowEmpty bool, extraConfig string) { if SecretKey == "" { // FIXME: https://github.com/go-gitea/gitea/issues/16832 // Until it supports rotating an existing secret key, we shouldn't move users off of the widely used default value - SecretKey = "!#@FDEWREWR&*(" // nolint:gosec + SecretKey = "!#@FDEWREWR&*(" //nolint:gosec } CookieRememberName = sec.Key("COOKIE_REMEMBER_NAME").MustString("gitea_incredible") diff --git a/routers/api/packages/pypi/pypi.go b/routers/api/packages/pypi/pypi.go index 6cf9329bbb134..609c63dc64f5a 100644 --- a/routers/api/packages/pypi/pypi.go +++ b/routers/api/packages/pypi/pypi.go @@ -21,8 +21,10 @@ import ( ) // https://peps.python.org/pep-0426/#name -var normalizer = strings.NewReplacer(".", "-", "_", "-") -var nameMatcher = regexp.MustCompile(`\A(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\.\-_]*[a-zA-Z0-9])\z`) +var ( + normalizer = strings.NewReplacer(".", "-", "_", "-") + nameMatcher = regexp.MustCompile(`\A(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\.\-_]*[a-zA-Z0-9])\z`) +) // https://peps.python.org/pep-0440/#appendix-b-parsing-version-strings-with-regular-expressions var versionMatcher = regexp.MustCompile(`\Av?` + From 8fb1e53ca2bea37d9d6b89a47cb13e253355829b Mon Sep 17 00:00:00 2001 From: Jason Song Date: Thu, 8 Dec 2022 21:14:09 +0800 Subject: [PATCH 036/110] Rename actions to operations on UI (#22067) Use "operations" to indicate "some something can be done", to prevent users from confusing it with CICD. Releated to: #13539. Snapshots: image image image I'm not a native English speaker, but I think "operations" may be good enough, and Gitea already uses this word: image --- options/locale/locale_en-US.ini | 6 +++--- templates/admin/notice.tmpl | 2 +- templates/repo/commit_page.tmpl | 4 ++-- templates/repo/home.tmpl | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 40d041e2cbb3f..70f982b8dcc59 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -1018,7 +1018,7 @@ unstar = Unstar star = Star fork = Fork download_archive = Download Repository -more_actions = More Actions +more_operations = More Operations no_desc = No Description quick_guide = Quick Guide @@ -1173,7 +1173,7 @@ commits.signed_by_untrusted_user_unmatched = Signed by untrusted user who does n commits.gpg_key_id = GPG Key ID commits.ssh_key_fingerprint = SSH Key Fingerprint -commit.actions = Actions +commit.operations = Operations commit.revert = Revert commit.revert-header = Revert: %s commit.revert-content = Select branch to revert onto: @@ -2989,7 +2989,7 @@ monitor.queue.pool.cancel_desc = Leaving a queue without any worker groups may c notices.system_notice_list = System Notices notices.view_detail_header = View Notice Details -notices.actions = Actions +notices.operations = Operations notices.select_all = Select All notices.deselect_all = Deselect All notices.inverse_selection = Inverse Selection diff --git a/templates/admin/notice.tmpl b/templates/admin/notice.tmpl index 2777741efbe9d..36752d47b26e4 100644 --- a/templates/admin/notice.tmpl +++ b/templates/admin/notice.tmpl @@ -46,7 +46,7 @@

diff --git a/templates/org/settings/navbar.tmpl b/templates/org/settings/navbar.tmpl index 7df1c85903c9c..9ff30ae4ff57a 100644 --- a/templates/org/settings/navbar.tmpl +++ b/templates/org/settings/navbar.tmpl @@ -1,28 +1,28 @@
diff --git a/templates/repo/header.tmpl b/templates/repo/header.tmpl index e6bd839f5704e..c706e00777b48 100644 --- a/templates/repo/header.tmpl +++ b/templates/repo/header.tmpl @@ -154,13 +154,13 @@ {{if not (or .Repository.IsBeingCreated .Repository.IsBroken)}} diff --git a/templates/repo/issue/list.tmpl b/templates/repo/issue/list.tmpl index 3df7dbca696fd..ad0ce50ec15fb 100644 --- a/templates/repo/issue/list.tmpl +++ b/templates/repo/issue/list.tmpl @@ -123,12 +123,12 @@ {{svg "octicon-triangle-down" 14 "dropdown icon"}}
@@ -141,14 +141,14 @@ {{svg "octicon-triangle-down" 14 "dropdown icon"}} diff --git a/templates/repo/issue/milestone_issues.tmpl b/templates/repo/issue/milestone_issues.tmpl index ba229cb5e8971..f3e28208adb9a 100644 --- a/templates/repo/issue/milestone_issues.tmpl +++ b/templates/repo/issue/milestone_issues.tmpl @@ -108,11 +108,11 @@ {{svg "octicon-triangle-down" 14 "dropdown icon"}} {{end}} @@ -124,12 +124,12 @@ {{svg "octicon-triangle-down" 14 "dropdown icon"}} diff --git a/templates/repo/issue/milestones.tmpl b/templates/repo/issue/milestones.tmpl index 641dc6c9187ef..3282e895ebc47 100644 --- a/templates/repo/issue/milestones.tmpl +++ b/templates/repo/issue/milestones.tmpl @@ -46,12 +46,12 @@ {{svg "octicon-triangle-down" 14 "dropdown icon"}} diff --git a/templates/repo/issue/navbar.tmpl b/templates/repo/issue/navbar.tmpl index 9a963cd8228ed..1e576796579e0 100644 --- a/templates/repo/issue/navbar.tmpl +++ b/templates/repo/issue/navbar.tmpl @@ -1,4 +1,4 @@ diff --git a/templates/repo/issue/openclose.tmpl b/templates/repo/issue/openclose.tmpl index ccfb40684c3f7..758fc447ce609 100644 --- a/templates/repo/issue/openclose.tmpl +++ b/templates/repo/issue/openclose.tmpl @@ -1,5 +1,5 @@ diff --git a/templates/repo/release/list.tmpl b/templates/repo/release/list.tmpl index 5f668d74a9f68..f8c54bf7f6e0d 100644 --- a/templates/repo/release/list.tmpl +++ b/templates/repo/release/list.tmpl @@ -5,10 +5,10 @@ {{template "base/alert" .}} {{if (and .CanCreateRelease (not .PageIsTagList))}} diff --git a/templates/repo/settings/navbar.tmpl b/templates/repo/settings/navbar.tmpl index 2a9202cf4048c..e2b741b8d032b 100644 --- a/templates/repo/settings/navbar.tmpl +++ b/templates/repo/settings/navbar.tmpl @@ -1,34 +1,34 @@ {{$reactions := .Reactions.GroupByType}} diff --git a/templates/repo/issue/view_content/context_menu.tmpl b/templates/repo/issue/view_content/context_menu.tmpl index 45dd08bf61035..7459623a54d9e 100644 --- a/templates/repo/issue/view_content/context_menu.tmpl +++ b/templates/repo/issue/view_content/context_menu.tmpl @@ -11,9 +11,9 @@ {{$referenceUrl = Printf "%s/files#%s" .ctx.Issue.HTMLURL .item.HashTag}} {{end}}
{{.ctx.locale.Tr "repo.issues.context.copy_link"}}
-
{{.ctx.locale.Tr "repo.issues.context.quote_reply"}}
+
{{.ctx.locale.Tr "repo.issues.context.quote_reply"}}
{{if not .ctx.UnitIssuesGlobalDisabled}} -
{{.ctx.locale.Tr "repo.issues.context.reference_issue"}}
+
{{.ctx.locale.Tr "repo.issues.context.reference_issue"}}
{{end}} {{if or .ctx.Permission.IsAdmin .IsCommentPoster .ctx.HasIssuesOrPullsWritePermission}}
diff --git a/web_src/js/features/repo-issue.js b/web_src/js/features/repo-issue.js index 54cdeb383b8f9..ca5d69c5a6d7a 100644 --- a/web_src/js/features/repo-issue.js +++ b/web_src/js/features/repo-issue.js @@ -553,7 +553,7 @@ export function initRepoIssueReferenceIssue() { const $this = $(this); $this.closest('.dropdown').find('.menu').toggle('visible'); - const content = $(`#comment-${$this.data('target')}`).text(); + const content = $(`#${$this.data('target')}`).text(); const poster = $this.data('poster-username'); const reference = $this.data('reference'); const $modal = $($this.data('modal')); diff --git a/web_src/js/features/repo-legacy.js b/web_src/js/features/repo-legacy.js index d438186c5f5ae..910d4bb56c8db 100644 --- a/web_src/js/features/repo-legacy.js +++ b/web_src/js/features/repo-legacy.js @@ -566,7 +566,7 @@ function initRepoIssueCommentEdit() { $(document).on('click', '.quote-reply', function (event) { $(this).closest('.dropdown').find('.menu').toggle('visible'); const target = $(this).data('target'); - const quote = $(`#comment-${target}`).text().replace(/\n/g, '\n> '); + const quote = $(`#${target}`).text().replace(/\n/g, '\n> '); const content = `> ${quote}\n\n`; let easyMDE; if ($(this).hasClass('quote-reply-diff')) { From 68704532c28cf09db96c988291b2f82c5e615984 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sat, 10 Dec 2022 10:46:31 +0800 Subject: [PATCH 040/110] Rename almost all Ctx functions (#22071) --- cmd/admin.go | 1 + models/issues/assignees.go | 2 +- models/issues/comment.go | 208 +----------------- models/issues/comment_test.go | 2 +- models/issues/issue.go | 24 +- models/issues/issue_list.go | 2 +- models/issues/issue_lock.go | 2 +- models/issues/issue_project.go | 2 +- models/issues/issue_xref.go | 2 +- models/issues/label.go | 4 +- models/issues/review.go | 16 +- models/issues/stopwatch.go | 6 +- models/issues/tracked_time.go | 6 +- models/organization/org.go | 2 +- models/organization/org_user.go | 4 +- models/organization/team.go | 12 +- models/perm/access/repo_permission.go | 2 +- models/project/project.go | 54 ++--- models/repo/collaboration.go | 69 +++--- models/repo/collaboration_test.go | 6 +- models/repo/issue.go | 23 +- models/repo/release.go | 4 +- models/repo/repo.go | 22 +- models/repo_transfer.go | 94 ++++---- models/repo_transfer_test.go | 15 +- modules/context/package.go | 2 +- modules/context/repo.go | 14 +- modules/convert/issue_comment.go | 2 +- modules/convert/repository.go | 23 +- modules/repository/collaborator.go | 45 ++-- modules/repository/collaborator_test.go | 16 +- modules/repository/create.go | 6 +- routers/api/v1/repo/collaborators.go | 4 +- routers/api/v1/repo/issue_comment.go | 8 +- .../api/v1/repo/issue_comment_attachment.go | 4 +- routers/api/v1/repo/issue_tracked_time.go | 12 +- routers/api/v1/repo/repo.go | 10 +- routers/api/v1/repo/transfer.go | 8 +- routers/private/serv.go | 2 +- routers/web/repo/cherry_pick.go | 2 +- routers/web/repo/compare.go | 2 +- routers/web/repo/editor.go | 6 +- routers/web/repo/http.go | 2 +- routers/web/repo/issue.go | 16 +- routers/web/repo/milestone.go | 2 +- routers/web/repo/patch.go | 2 +- routers/web/repo/projects.go | 2 +- routers/web/repo/release.go | 2 +- routers/web/repo/repo.go | 6 +- routers/web/repo/setting.go | 9 +- routers/web/repo/wiki.go | 2 +- routers/web/user/home.go | 2 +- services/agit/agit.go | 2 +- services/{comments => issue}/comments.go | 54 ++++- services/issue/commit.go | 2 +- services/issue/milestone.go | 2 +- services/pull/check.go | 2 +- services/pull/comment.go | 162 ++++++++++++++ services/pull/merge.go | 8 +- services/pull/patch.go | 2 +- services/pull/pull.go | 6 +- services/pull/review.go | 5 +- services/pull/update.go | 2 +- services/repository/repository.go | 2 +- services/repository/transfer.go | 29 +-- services/repository/transfer_test.go | 4 +- templates/admin/config.tmpl | 2 +- templates/org/team/new.tmpl | 8 +- templates/org/team/sidebar.tmpl | 6 +- templates/repo/editor/commit_form.tmpl | 4 +- templates/repo/graph/commits.tmpl | 2 +- templates/repo/header.tmpl | 2 +- templates/repo/issue/view_content/pull.tmpl | 2 +- .../repo/issue/view_content/sidebar.tmpl | 4 +- templates/repo/settings/collaboration.tmpl | 2 +- templates/repo/settings/options.tmpl | 46 ++-- tests/integration/api_repo_edit_test.go | 11 +- tests/integration/mirror_pull_test.go | 7 +- 78 files changed, 562 insertions(+), 611 deletions(-) rename services/{comments => issue}/comments.go (63%) create mode 100644 services/pull/comment.go diff --git a/cmd/admin.go b/cmd/admin.go index e4210213cdeae..7463b21d81ab6 100644 --- a/cmd/admin.go +++ b/cmd/admin.go @@ -778,6 +778,7 @@ func runRepoSyncReleases(_ *cli.Context) error { func getReleaseCount(id int64) (int64, error) { return repo_model.GetReleaseCountByRepoID( + db.DefaultContext, id, repo_model.FindReleasesOptions{ IncludeTags: true, diff --git a/models/issues/assignees.go b/models/issues/assignees.go index d3a1f5ffe836a..159086bd01052 100644 --- a/models/issues/assignees.go +++ b/models/issues/assignees.go @@ -102,7 +102,7 @@ func toggleIssueAssignee(ctx context.Context, issue *Issue, doer *user_model.Use AssigneeID: assigneeID, } // Comment - comment, err = CreateCommentCtx(ctx, opts) + comment, err = CreateComment(ctx, opts) if err != nil { return false, nil, fmt.Errorf("createComment: %w", err) } diff --git a/models/issues/comment.go b/models/issues/comment.go index 2abe692a6f70b..612f17aa5af68 100644 --- a/models/issues/comment.go +++ b/models/issues/comment.go @@ -779,8 +779,8 @@ func (c *Comment) LoadPushCommits(ctx context.Context) (err error) { return err } -// CreateCommentCtx creates comment with context -func CreateCommentCtx(ctx context.Context, opts *CreateCommentOptions) (_ *Comment, err error) { +// CreateComment creates comment with context +func CreateComment(ctx context.Context, opts *CreateCommentOptions) (_ *Comment, err error) { e := db.GetEngine(ctx) var LabelID int64 if opts.Label != nil { @@ -915,7 +915,7 @@ func createDeadlineComment(ctx context.Context, doer *user_model.User, issue *Is Issue: issue, Content: content, } - comment, err := CreateCommentCtx(ctx, opts) + comment, err := CreateComment(ctx, opts) if err != nil { return nil, err } @@ -940,7 +940,7 @@ func createIssueDependencyComment(ctx context.Context, doer *user_model.User, is Issue: issue, DependentIssueID: dependentIssue.ID, } - if _, err = CreateCommentCtx(ctx, opts); err != nil { + if _, err = CreateComment(ctx, opts); err != nil { return } @@ -951,7 +951,7 @@ func createIssueDependencyComment(ctx context.Context, doer *user_model.User, is Issue: dependentIssue, DependentIssueID: issue.ID, } - _, err = CreateCommentCtx(ctx, opts) + _, err = CreateComment(ctx, opts) return err } @@ -993,55 +993,6 @@ type CreateCommentOptions struct { Invalidated bool } -// CreateComment creates comment of issue or commit. -func CreateComment(opts *CreateCommentOptions) (comment *Comment, err error) { - ctx, committer, err := db.TxContext(db.DefaultContext) - if err != nil { - return nil, err - } - defer committer.Close() - - comment, err = CreateCommentCtx(ctx, opts) - if err != nil { - return nil, err - } - - if err = committer.Commit(); err != nil { - return nil, err - } - - return comment, nil -} - -// CreateRefComment creates a commit reference comment to issue. -func CreateRefComment(doer *user_model.User, repo *repo_model.Repository, issue *Issue, content, commitSHA string) error { - if len(commitSHA) == 0 { - return fmt.Errorf("cannot create reference with empty commit SHA") - } - - // Check if same reference from same commit has already existed. - has, err := db.GetEngine(db.DefaultContext).Get(&Comment{ - Type: CommentTypeCommitRef, - IssueID: issue.ID, - CommitSHA: commitSHA, - }) - if err != nil { - return fmt.Errorf("check reference comment: %w", err) - } else if has { - return nil - } - - _, err = CreateComment(&CreateCommentOptions{ - Type: CommentTypeCommitRef, - Doer: doer, - Repo: repo, - Issue: issue, - CommitSHA: commitSHA, - Content: content, - }) - return err -} - // GetCommentByID returns the comment by given ID. func GetCommentByID(ctx context.Context, id int64) (*Comment, error) { c := new(Comment) @@ -1317,39 +1268,6 @@ func UpdateCommentsMigrationsByType(tp structs.GitServiceType, originalAuthorID return err } -// CreatePushPullComment create push code to pull base comment -func CreatePushPullComment(ctx context.Context, pusher *user_model.User, pr *PullRequest, oldCommitID, newCommitID string) (comment *Comment, err error) { - if pr.HasMerged || oldCommitID == "" || newCommitID == "" { - return nil, nil - } - - ops := &CreateCommentOptions{ - Type: CommentTypePullRequestPush, - Doer: pusher, - Repo: pr.BaseRepo, - } - - var data PushActionContent - - data.CommitIDs, data.IsForcePush, err = getCommitIDsFromRepo(ctx, pr.BaseRepo, oldCommitID, newCommitID, pr.BaseBranch) - if err != nil { - return nil, err - } - - ops.Issue = pr.Issue - - dataJSON, err := json.Marshal(data) - if err != nil { - return nil, err - } - - ops.Content = string(dataJSON) - - comment, err = CreateComment(ops) - - return comment, err -} - // CreateAutoMergeComment is a internal function, only use it for CommentTypePRScheduledToAutoMerge and CommentTypePRUnScheduledToAutoMerge CommentTypes func CreateAutoMergeComment(ctx context.Context, typ CommentType, pr *PullRequest, doer *user_model.User) (comment *Comment, err error) { if typ != CommentTypePRScheduledToAutoMerge && typ != CommentTypePRUnScheduledToAutoMerge { @@ -1363,7 +1281,7 @@ func CreateAutoMergeComment(ctx context.Context, typ CommentType, pr *PullReques return } - comment, err = CreateCommentCtx(ctx, &CreateCommentOptions{ + comment, err = CreateComment(ctx, &CreateCommentOptions{ Type: typ, Doer: doer, Repo: pr.BaseRepo, @@ -1372,120 +1290,6 @@ func CreateAutoMergeComment(ctx context.Context, typ CommentType, pr *PullReques return comment, err } -// getCommitsFromRepo get commit IDs from repo in between oldCommitID and newCommitID -// isForcePush will be true if oldCommit isn't on the branch -// Commit on baseBranch will skip -func getCommitIDsFromRepo(ctx context.Context, repo *repo_model.Repository, oldCommitID, newCommitID, baseBranch string) (commitIDs []string, isForcePush bool, err error) { - repoPath := repo.RepoPath() - gitRepo, closer, err := git.RepositoryFromContextOrOpen(ctx, repoPath) - if err != nil { - return nil, false, err - } - defer closer.Close() - - oldCommit, err := gitRepo.GetCommit(oldCommitID) - if err != nil { - return nil, false, err - } - - if err = oldCommit.LoadBranchName(); err != nil { - return nil, false, err - } - - if len(oldCommit.Branch) == 0 { - commitIDs = make([]string, 2) - commitIDs[0] = oldCommitID - commitIDs[1] = newCommitID - - return commitIDs, true, err - } - - newCommit, err := gitRepo.GetCommit(newCommitID) - if err != nil { - return nil, false, err - } - - commits, err := newCommit.CommitsBeforeUntil(oldCommitID) - if err != nil { - return nil, false, err - } - - commitIDs = make([]string, 0, len(commits)) - commitChecks := make(map[string]*commitBranchCheckItem) - - for _, commit := range commits { - commitChecks[commit.ID.String()] = &commitBranchCheckItem{ - Commit: commit, - Checked: false, - } - } - - if err = commitBranchCheck(gitRepo, newCommit, oldCommitID, baseBranch, commitChecks); err != nil { - return - } - - for i := len(commits) - 1; i >= 0; i-- { - commitID := commits[i].ID.String() - if item, ok := commitChecks[commitID]; ok && item.Checked { - commitIDs = append(commitIDs, commitID) - } - } - - return commitIDs, isForcePush, err -} - -type commitBranchCheckItem struct { - Commit *git.Commit - Checked bool -} - -func commitBranchCheck(gitRepo *git.Repository, startCommit *git.Commit, endCommitID, baseBranch string, commitList map[string]*commitBranchCheckItem) error { - if startCommit.ID.String() == endCommitID { - return nil - } - - checkStack := make([]string, 0, 10) - checkStack = append(checkStack, startCommit.ID.String()) - - for len(checkStack) > 0 { - commitID := checkStack[0] - checkStack = checkStack[1:] - - item, ok := commitList[commitID] - if !ok { - continue - } - - if item.Commit.ID.String() == endCommitID { - continue - } - - if err := item.Commit.LoadBranchName(); err != nil { - return err - } - - if item.Commit.Branch == baseBranch { - continue - } - - if item.Checked { - continue - } - - item.Checked = true - - parentNum := item.Commit.ParentCount() - for i := 0; i < parentNum; i++ { - parentCommit, err := item.Commit.Parent(i) - if err != nil { - return err - } - checkStack = append(checkStack, parentCommit.ID.String()) - } - } - return nil -} - // RemapExternalUser ExternalUserRemappable interface func (c *Comment) RemapExternalUser(externalName string, externalID, userID int64) error { c.OriginalAuthor = externalName diff --git a/models/issues/comment_test.go b/models/issues/comment_test.go index 6a647474dca51..0d0570ae34d68 100644 --- a/models/issues/comment_test.go +++ b/models/issues/comment_test.go @@ -24,7 +24,7 @@ func TestCreateComment(t *testing.T) { doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) now := time.Now().Unix() - comment, err := issues_model.CreateComment(&issues_model.CreateCommentOptions{ + comment, err := issues_model.CreateComment(db.DefaultContext, &issues_model.CreateCommentOptions{ Type: issues_model.CommentTypeComment, Doer: doer, Repo: repo, diff --git a/models/issues/issue.go b/models/issues/issue.go index 3ab6d204ba09a..fc93fcf45465c 100644 --- a/models/issues/issue.go +++ b/models/issues/issue.go @@ -202,16 +202,12 @@ func (issue *Issue) LoadRepo(ctx context.Context) (err error) { } // IsTimetrackerEnabled returns true if the repo enables timetracking -func (issue *Issue) IsTimetrackerEnabled() bool { - return issue.isTimetrackerEnabled(db.DefaultContext) -} - -func (issue *Issue) isTimetrackerEnabled(ctx context.Context) bool { +func (issue *Issue) IsTimetrackerEnabled(ctx context.Context) bool { if err := issue.LoadRepo(ctx); err != nil { log.Error(fmt.Sprintf("loadRepo: %v", err)) return false } - return issue.Repo.IsTimetrackerEnabledCtx(ctx) + return issue.Repo.IsTimetrackerEnabled(ctx) } // GetPullRequest returns the issue pull request @@ -404,7 +400,7 @@ func (issue *Issue) LoadAttributes(ctx context.Context) (err error) { if err = CommentList(issue.Comments).loadAttributes(ctx); err != nil { return err } - if issue.isTimetrackerEnabled(ctx) { + if issue.IsTimetrackerEnabled(ctx) { if err = issue.LoadTotalTimes(ctx); err != nil { return err } @@ -673,7 +669,7 @@ func changeIssueStatus(ctx context.Context, issue *Issue, doer *user_model.User, func doChangeIssueStatus(ctx context.Context, issue *Issue, doer *user_model.User, isMergePull bool) (*Comment, error) { // Check for open dependencies - if issue.IsClosed && issue.Repo.IsDependenciesEnabledCtx(ctx) { + if issue.IsClosed && issue.Repo.IsDependenciesEnabled(ctx) { // only check if dependencies are enabled and we're about to close an issue, otherwise reopening an issue would fail when there are unsatisfied dependencies noDeps, err := IssueNoDependenciesLeft(ctx, issue) if err != nil { @@ -725,7 +721,7 @@ func doChangeIssueStatus(ctx context.Context, issue *Issue, doer *user_model.Use cmtType = CommentTypeMergePull } - return CreateCommentCtx(ctx, &CreateCommentOptions{ + return CreateComment(ctx, &CreateCommentOptions{ Type: cmtType, Doer: doer, Repo: issue.Repo, @@ -769,7 +765,7 @@ func ChangeIssueTitle(issue *Issue, doer *user_model.User, oldTitle string) (err OldTitle: oldTitle, NewTitle: issue.Title, } - if _, err = CreateCommentCtx(ctx, opts); err != nil { + if _, err = CreateComment(ctx, opts); err != nil { return fmt.Errorf("createComment: %w", err) } if err = issue.AddCrossReferences(ctx, doer, true); err != nil { @@ -805,7 +801,7 @@ func ChangeIssueRef(issue *Issue, doer *user_model.User, oldRef string) (err err OldRef: oldRefFriendly, NewRef: newRefFriendly, } - if _, err = CreateCommentCtx(ctx, opts); err != nil { + if _, err = CreateComment(ctx, opts); err != nil { return fmt.Errorf("createComment: %w", err) } @@ -825,7 +821,7 @@ func AddDeletePRBranchComment(ctx context.Context, doer *user_model.User, repo * Issue: issue, OldRef: branchName, } - _, err = CreateCommentCtx(ctx, opts) + _, err = CreateComment(ctx, opts) return err } @@ -992,7 +988,7 @@ func NewIssueWithIndex(ctx context.Context, doer *user_model.User, opts NewIssue OldMilestoneID: 0, MilestoneID: opts.Issue.MilestoneID, } - if _, err = CreateCommentCtx(ctx, opts); err != nil { + if _, err = CreateComment(ctx, opts); err != nil { return err } } @@ -2000,7 +1996,7 @@ func UpdateIssueByAPI(issue *Issue, doer *user_model.User) (statusChangeComment OldTitle: currentIssue.Title, NewTitle: issue.Title, } - _, err := CreateCommentCtx(ctx, opts) + _, err := CreateComment(ctx, opts) if err != nil { return nil, false, fmt.Errorf("createComment: %w", err) } diff --git a/models/issues/issue_list.go b/models/issues/issue_list.go index 35a0c1f0e3a7c..e22e48c0bb4bd 100644 --- a/models/issues/issue_list.go +++ b/models/issues/issue_list.go @@ -461,7 +461,7 @@ func (issues IssueList) loadTotalTrackedTimes(ctx context.Context) (err error) { ids := make([]int64, 0, len(issues)) for _, issue := range issues { - if issue.Repo.IsTimetrackerEnabled() { + if issue.Repo.IsTimetrackerEnabled(ctx) { ids = append(ids, issue.ID) } } diff --git a/models/issues/issue_lock.go b/models/issues/issue_lock.go index 1376ffcadad35..19cd6d316757f 100644 --- a/models/issues/issue_lock.go +++ b/models/issues/issue_lock.go @@ -56,7 +56,7 @@ func updateIssueLock(opts *IssueLockOptions, lock bool) error { Type: commentType, Content: opts.Reason, } - if _, err := CreateCommentCtx(ctx, opt); err != nil { + if _, err := CreateComment(ctx, opt); err != nil { return err } diff --git a/models/issues/issue_project.go b/models/issues/issue_project.go index a366a92fad04c..8e559f13c92c5 100644 --- a/models/issues/issue_project.go +++ b/models/issues/issue_project.go @@ -145,7 +145,7 @@ func addUpdateIssueProject(ctx context.Context, issue *Issue, doer *user_model.U } if oldProjectID > 0 || newProjectID > 0 { - if _, err := CreateCommentCtx(ctx, &CreateCommentOptions{ + if _, err := CreateComment(ctx, &CreateCommentOptions{ Type: CommentTypeProject, Doer: doer, Repo: issue.Repo, diff --git a/models/issues/issue_xref.go b/models/issues/issue_xref.go index 267ccc73a03da..21ee24210f838 100644 --- a/models/issues/issue_xref.go +++ b/models/issues/issue_xref.go @@ -121,7 +121,7 @@ func (issue *Issue) createCrossReferences(stdCtx context.Context, ctx *crossRefe RefAction: xref.Action, RefIsPull: ctx.OrigIssue.IsPull, } - _, err := CreateCommentCtx(stdCtx, opts) + _, err := CreateComment(stdCtx, opts) if err != nil { return err } diff --git a/models/issues/label.go b/models/issues/label.go index e5583ff00f618..dbb7a139effdf 100644 --- a/models/issues/label.go +++ b/models/issues/label.go @@ -613,7 +613,7 @@ func newIssueLabel(ctx context.Context, issue *Issue, label *Label, doer *user_m Label: label, Content: "1", } - if _, err = CreateCommentCtx(ctx, opts); err != nil { + if _, err = CreateComment(ctx, opts); err != nil { return err } @@ -714,7 +714,7 @@ func deleteIssueLabel(ctx context.Context, issue *Issue, label *Label, doer *use Issue: issue, Label: label, } - if _, err = CreateCommentCtx(ctx, opts); err != nil { + if _, err = CreateComment(ctx, opts); err != nil { return err } diff --git a/models/issues/review.go b/models/issues/review.go index db2d2686cb6a0..7dee28fe976dc 100644 --- a/models/issues/review.go +++ b/models/issues/review.go @@ -294,7 +294,7 @@ func IsOfficialReviewerTeam(ctx context.Context, issue *Issue, team *organizatio } if !pr.ProtectedBranch.EnableApprovalsWhitelist { - return team.UnitAccessModeCtx(ctx, unit.TypeCode) >= perm.AccessModeWrite, nil + return team.UnitAccessMode(ctx, unit.TypeCode) >= perm.AccessModeWrite, nil } return base.Int64sContains(pr.ProtectedBranch.ApprovalsWhitelistTeamIDs, team.ID), nil @@ -436,7 +436,7 @@ func SubmitReview(doer *user_model.User, issue *Issue, reviewType ReviewType, co } } - comm, err := CreateCommentCtx(ctx, &CreateCommentOptions{ + comm, err := CreateComment(ctx, &CreateCommentOptions{ Type: CommentTypeReview, Doer: doer, Content: review.Content, @@ -692,7 +692,7 @@ func AddReviewRequest(issue *Issue, reviewer, doer *user_model.User) (*Comment, return nil, err } - comment, err := CreateCommentCtx(ctx, &CreateCommentOptions{ + comment, err := CreateComment(ctx, &CreateCommentOptions{ Type: CommentTypeReviewRequest, Doer: doer, Repo: issue.Repo, @@ -746,7 +746,7 @@ func RemoveReviewRequest(issue *Issue, reviewer, doer *user_model.User) (*Commen } } - comment, err := CreateCommentCtx(ctx, &CreateCommentOptions{ + comment, err := CreateComment(ctx, &CreateCommentOptions{ Type: CommentTypeReviewRequest, Doer: doer, Repo: issue.Repo, @@ -804,7 +804,7 @@ func AddTeamReviewRequest(issue *Issue, reviewer *organization.Team, doer *user_ } } - comment, err := CreateCommentCtx(ctx, &CreateCommentOptions{ + comment, err := CreateComment(ctx, &CreateCommentOptions{ Type: CommentTypeReviewRequest, Doer: doer, Repo: issue.Repo, @@ -814,7 +814,7 @@ func AddTeamReviewRequest(issue *Issue, reviewer *organization.Team, doer *user_ ReviewID: review.ID, }) if err != nil { - return nil, fmt.Errorf("CreateCommentCtx(): %w", err) + return nil, fmt.Errorf("CreateComment(): %w", err) } return comment, committer.Commit() @@ -864,7 +864,7 @@ func RemoveTeamReviewRequest(issue *Issue, reviewer *organization.Team, doer *us return nil, committer.Commit() } - comment, err := CreateCommentCtx(ctx, &CreateCommentOptions{ + comment, err := CreateComment(ctx, &CreateCommentOptions{ Type: CommentTypeReviewRequest, Doer: doer, Repo: issue.Repo, @@ -873,7 +873,7 @@ func RemoveTeamReviewRequest(issue *Issue, reviewer *organization.Team, doer *us AssigneeTeamID: reviewer.ID, // Use AssigneeTeamID as reviewer team ID }) if err != nil { - return nil, fmt.Errorf("CreateCommentCtx(): %w", err) + return nil, fmt.Errorf("CreateComment(): %w", err) } return comment, committer.Commit() diff --git a/models/issues/stopwatch.go b/models/issues/stopwatch.go index 8a8fdca339cf6..6bf936c5d41b1 100644 --- a/models/issues/stopwatch.go +++ b/models/issues/stopwatch.go @@ -196,7 +196,7 @@ func FinishIssueStopwatch(ctx context.Context, user *user_model.User, issue *Iss return err } - if _, err := CreateCommentCtx(ctx, &CreateCommentOptions{ + if _, err := CreateComment(ctx, &CreateCommentOptions{ Doer: user, Issue: issue, Repo: issue.Repo, @@ -246,7 +246,7 @@ func CreateIssueStopwatch(ctx context.Context, user *user_model.User, issue *Iss return err } - if _, err := CreateCommentCtx(ctx, &CreateCommentOptions{ + if _, err := CreateComment(ctx, &CreateCommentOptions{ Doer: user, Issue: issue, Repo: issue.Repo, @@ -287,7 +287,7 @@ func cancelStopwatch(ctx context.Context, user *user_model.User, issue *Issue) e return err } - if _, err := CreateCommentCtx(ctx, &CreateCommentOptions{ + if _, err := CreateComment(ctx, &CreateCommentOptions{ Doer: user, Issue: issue, Repo: issue.Repo, diff --git a/models/issues/tracked_time.go b/models/issues/tracked_time.go index 554b01bd407cc..ac65d654f20a3 100644 --- a/models/issues/tracked_time.go +++ b/models/issues/tracked_time.go @@ -172,7 +172,7 @@ func AddTime(user *user_model.User, issue *Issue, amount int64, created time.Tim return nil, err } - if _, err := CreateCommentCtx(ctx, &CreateCommentOptions{ + if _, err := CreateComment(ctx, &CreateCommentOptions{ Issue: issue, Repo: issue.Repo, Doer: user, @@ -250,7 +250,7 @@ func DeleteIssueUserTimes(issue *Issue, user *user_model.User) error { if err := issue.LoadRepo(ctx); err != nil { return err } - if _, err := CreateCommentCtx(ctx, &CreateCommentOptions{ + if _, err := CreateComment(ctx, &CreateCommentOptions{ Issue: issue, Repo: issue.Repo, Doer: user, @@ -279,7 +279,7 @@ func DeleteTime(t *TrackedTime) error { return err } - if _, err := CreateCommentCtx(ctx, &CreateCommentOptions{ + if _, err := CreateComment(ctx, &CreateCommentOptions{ Issue: t.Issue, Repo: t.Issue.Repo, Doer: t.User, diff --git a/models/organization/org.go b/models/organization/org.go index a5b07d5aae87a..b3d77b4ec6967 100644 --- a/models/organization/org.go +++ b/models/organization/org.go @@ -106,7 +106,7 @@ func (org *Organization) IsOrgMember(uid int64) (bool, error) { // CanCreateOrgRepo returns true if given user can create repo in organization func (org *Organization) CanCreateOrgRepo(uid int64) (bool, error) { - return CanCreateOrgRepo(org.ID, uid) + return CanCreateOrgRepo(db.DefaultContext, org.ID, uid) } func (org *Organization) getTeam(ctx context.Context, name string) (*Team, error) { diff --git a/models/organization/org_user.go b/models/organization/org_user.go index d514e401ba6ad..e5cbfe6c0f3ea 100644 --- a/models/organization/org_user.go +++ b/models/organization/org_user.go @@ -73,8 +73,8 @@ func IsPublicMembership(orgID, uid int64) (bool, error) { } // CanCreateOrgRepo returns true if user can create repo in organization -func CanCreateOrgRepo(orgID, uid int64) (bool, error) { - return db.GetEngine(db.DefaultContext). +func CanCreateOrgRepo(ctx context.Context, orgID, uid int64) (bool, error) { + return db.GetEngine(ctx). Where(builder.Eq{"team.can_create_org_repo": true}). Join("INNER", "team_user", "team_user.team_id = team.id"). And("team_user.uid = ?", uid). diff --git a/models/organization/team.go b/models/organization/team.go index 86ea30c801051..55d3f1727665e 100644 --- a/models/organization/team.go +++ b/models/organization/team.go @@ -242,18 +242,12 @@ func (t *Team) LoadMembers(ctx context.Context) (err error) { } // UnitEnabled returns if the team has the given unit type enabled -func (t *Team) UnitEnabled(tp unit.Type) bool { - return t.UnitAccessMode(tp) > perm.AccessModeNone +func (t *Team) UnitEnabled(ctx context.Context, tp unit.Type) bool { + return t.UnitAccessMode(ctx, tp) > perm.AccessModeNone } // UnitAccessMode returns if the team has the given unit type enabled -// it is called in templates, should not be replaced by `UnitAccessModeCtx(ctx ...)` -func (t *Team) UnitAccessMode(tp unit.Type) perm.AccessMode { // Notice: It will be used in template, don't remove it directly - return t.UnitAccessModeCtx(db.DefaultContext, tp) -} - -// UnitAccessModeCtx returns if the team has the given unit type enabled -func (t *Team) UnitAccessModeCtx(ctx context.Context, tp unit.Type) perm.AccessMode { +func (t *Team) UnitAccessMode(ctx context.Context, tp unit.Type) perm.AccessMode { if err := t.getUnits(ctx); err != nil { log.Warn("Error loading team (ID: %d) units: %s", t.ID, err.Error()) } diff --git a/models/perm/access/repo_permission.go b/models/perm/access/repo_permission.go index 88437dc4b2510..a6bf9b6744a52 100644 --- a/models/perm/access/repo_permission.go +++ b/models/perm/access/repo_permission.go @@ -244,7 +244,7 @@ func GetUserRepoPermission(ctx context.Context, repo *repo_model.Repository, use for _, u := range repo.Units { var found bool for _, team := range teams { - teamMode := team.UnitAccessModeCtx(ctx, u.Type) + teamMode := team.UnitAccessMode(ctx, u.Type) if teamMode > perm_model.AccessModeNone { m := perm.UnitsMode[u.Type] if m < teamMode { diff --git a/models/project/project.go b/models/project/project.go index 384f51c5ac2a8..bcf1166408f85 100644 --- a/models/project/project.go +++ b/models/project/project.go @@ -298,44 +298,32 @@ func changeProjectStatus(ctx context.Context, p *Project, isClosed bool) error { return updateRepositoryProjectCount(ctx, p.RepoID) } -// DeleteProjectByID deletes a project from a repository. -func DeleteProjectByID(id int64) error { - ctx, committer, err := db.TxContext(db.DefaultContext) - if err != nil { - return err - } - defer committer.Close() - - if err := DeleteProjectByIDCtx(ctx, id); err != nil { - return err - } - - return committer.Commit() -} - -// DeleteProjectByIDCtx deletes a project from a repository. -func DeleteProjectByIDCtx(ctx context.Context, id int64) error { - p, err := GetProjectByID(ctx, id) - if err != nil { - if IsErrProjectNotExist(err) { - return nil +// 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 { + p, err := GetProjectByID(ctx, id) + if err != nil { + if IsErrProjectNotExist(err) { + return nil + } + return err } - return err - } - if err := deleteProjectIssuesByProjectID(ctx, id); err != nil { - return err - } + if err := deleteProjectIssuesByProjectID(ctx, id); err != nil { + return err + } - if err := deleteBoardByProjectID(ctx, id); err != nil { - return err - } + if err := deleteBoardByProjectID(ctx, id); err != nil { + return err + } - if _, err = db.GetEngine(ctx).ID(p.ID).Delete(new(Project)); err != nil { - return err - } + if _, err = db.GetEngine(ctx).ID(p.ID).Delete(new(Project)); err != nil { + return err + } - return updateRepositoryProjectCount(ctx, p.RepoID) + return updateRepositoryProjectCount(ctx, p.RepoID) + }) } func DeleteProjectByRepoID(ctx context.Context, repoID int64) error { diff --git a/models/repo/collaboration.go b/models/repo/collaboration.go index bd49b9aec9af4..29bcab70f36a3 100644 --- a/models/repo/collaboration.go +++ b/models/repo/collaboration.go @@ -99,55 +99,42 @@ func getCollaborations(ctx context.Context, repoID int64, listOptions db.ListOpt } // ChangeCollaborationAccessMode sets new access mode for the collaboration. -func ChangeCollaborationAccessModeCtx(ctx context.Context, repo *Repository, uid int64, mode perm.AccessMode) error { +func ChangeCollaborationAccessMode(ctx context.Context, repo *Repository, uid int64, mode perm.AccessMode) error { // Discard invalid input if mode <= perm.AccessModeNone || mode > perm.AccessModeOwner { return nil } - e := db.GetEngine(ctx) - - collaboration := &Collaboration{ - RepoID: repo.ID, - UserID: uid, - } - has, err := e.Get(collaboration) - if err != nil { - return fmt.Errorf("get collaboration: %w", err) - } else if !has { - return nil - } - - if collaboration.Mode == mode { - return nil - } - collaboration.Mode = mode - - if _, err = e. - ID(collaboration.ID). - Cols("mode"). - Update(collaboration); err != nil { - return fmt.Errorf("update collaboration: %w", err) - } else if _, err = e.Exec("UPDATE access SET mode = ? WHERE user_id = ? AND repo_id = ?", mode, uid, repo.ID); err != nil { - return fmt.Errorf("update access table: %w", err) - } + return db.AutoTx(ctx, func(ctx context.Context) error { + e := db.GetEngine(ctx) - return nil -} - -// ChangeCollaborationAccessMode sets new access mode for the collaboration. -func ChangeCollaborationAccessMode(repo *Repository, uid int64, mode perm.AccessMode) error { - ctx, committer, err := db.TxContext(db.DefaultContext) - if err != nil { - return err - } - defer committer.Close() + collaboration := &Collaboration{ + RepoID: repo.ID, + UserID: uid, + } + has, err := e.Get(collaboration) + if err != nil { + return fmt.Errorf("get collaboration: %w", err) + } else if !has { + return nil + } - if err := ChangeCollaborationAccessModeCtx(ctx, repo, uid, mode); err != nil { - return err - } + if collaboration.Mode == mode { + return nil + } + collaboration.Mode = mode + + if _, err = e. + ID(collaboration.ID). + Cols("mode"). + Update(collaboration); err != nil { + return fmt.Errorf("update collaboration: %w", err) + } else if _, err = e.Exec("UPDATE access SET mode = ? WHERE user_id = ? AND repo_id = ?", mode, uid, repo.ID); err != nil { + return fmt.Errorf("update access table: %w", err) + } - return committer.Commit() + return nil + }) } // IsOwnerMemberCollaborator checks if a provided user is the owner, a collaborator or a member of a team in a repository diff --git a/models/repo/collaboration_test.go b/models/repo/collaboration_test.go index d240e9cbef04f..0a6444de858ac 100644 --- a/models/repo/collaboration_test.go +++ b/models/repo/collaboration_test.go @@ -54,7 +54,7 @@ func TestRepository_ChangeCollaborationAccessMode(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4}) - assert.NoError(t, repo_model.ChangeCollaborationAccessMode(repo, 4, perm.AccessModeAdmin)) + assert.NoError(t, repo_model.ChangeCollaborationAccessMode(db.DefaultContext, repo, 4, perm.AccessModeAdmin)) collaboration := unittest.AssertExistsAndLoadBean(t, &repo_model.Collaboration{RepoID: repo.ID, UserID: 4}) assert.EqualValues(t, perm.AccessModeAdmin, collaboration.Mode) @@ -62,9 +62,9 @@ func TestRepository_ChangeCollaborationAccessMode(t *testing.T) { access := unittest.AssertExistsAndLoadBean(t, &access_model.Access{UserID: 4, RepoID: repo.ID}) assert.EqualValues(t, perm.AccessModeAdmin, access.Mode) - assert.NoError(t, repo_model.ChangeCollaborationAccessMode(repo, 4, perm.AccessModeAdmin)) + assert.NoError(t, repo_model.ChangeCollaborationAccessMode(db.DefaultContext, repo, 4, perm.AccessModeAdmin)) - assert.NoError(t, repo_model.ChangeCollaborationAccessMode(repo, unittest.NonexistentID, perm.AccessModeAdmin)) + assert.NoError(t, repo_model.ChangeCollaborationAccessMode(db.DefaultContext, repo, unittest.NonexistentID, perm.AccessModeAdmin)) unittest.CheckConsistencyFor(t, &repo_model.Repository{ID: repo.ID}) } diff --git a/models/repo/issue.go b/models/repo/issue.go index e27179caf51f7..6f6b565a00cfd 100644 --- a/models/repo/issue.go +++ b/models/repo/issue.go @@ -6,7 +6,6 @@ package repo import ( "context" - "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" @@ -26,44 +25,34 @@ func (repo *Repository) CanEnableTimetracker() bool { } // IsTimetrackerEnabled returns whether or not the timetracker is enabled. It returns the default value from config if an error occurs. -func (repo *Repository) IsTimetrackerEnabled() bool { // Notice: It will be used in template so don't remove directly - return repo.IsTimetrackerEnabledCtx(db.DefaultContext) -} - -// IsTimetrackerEnabledCtx returns whether or not the timetracker is enabled. It returns the default value from config if an error occurs. -func (repo *Repository) IsTimetrackerEnabledCtx(ctx context.Context) bool { +func (repo *Repository) IsTimetrackerEnabled(ctx context.Context) bool { if !setting.Service.EnableTimetracking { return false } var u *RepoUnit var err error - if u, err = repo.GetUnitCtx(ctx, unit.TypeIssues); err != nil { + if u, err = repo.GetUnit(ctx, unit.TypeIssues); err != nil { return setting.Service.DefaultEnableTimetracking } return u.IssuesConfig().EnableTimetracker } // AllowOnlyContributorsToTrackTime returns value of IssuesConfig or the default value -func (repo *Repository) AllowOnlyContributorsToTrackTime() bool { +func (repo *Repository) AllowOnlyContributorsToTrackTime(ctx context.Context) bool { var u *RepoUnit var err error - if u, err = repo.GetUnit(unit.TypeIssues); err != nil { + if u, err = repo.GetUnit(ctx, unit.TypeIssues); err != nil { return setting.Service.DefaultAllowOnlyContributorsToTrackTime } return u.IssuesConfig().AllowOnlyContributorsToTrackTime } // IsDependenciesEnabled returns if dependencies are enabled and returns the default setting if not set. -func (repo *Repository) IsDependenciesEnabled() bool { - return repo.IsDependenciesEnabledCtx(db.DefaultContext) -} - -// IsDependenciesEnabledCtx returns if dependencies are enabled and returns the default setting if not set. -func (repo *Repository) IsDependenciesEnabledCtx(ctx context.Context) bool { +func (repo *Repository) IsDependenciesEnabled(ctx context.Context) bool { var u *RepoUnit var err error - if u, err = repo.GetUnitCtx(ctx, unit.TypeIssues); err != nil { + if u, err = repo.GetUnit(ctx, unit.TypeIssues); err != nil { log.Trace("%s", err) return setting.Service.DefaultEnableDependencies } diff --git a/models/repo/release.go b/models/repo/release.go index c6cb755344540..25eba10e05dff 100644 --- a/models/repo/release.go +++ b/models/repo/release.go @@ -286,8 +286,8 @@ func GetReleasesByRepoIDAndNames(ctx context.Context, repoID int64, tagNames []s } // GetReleaseCountByRepoID returns the count of releases of repository -func GetReleaseCountByRepoID(repoID int64, opts FindReleasesOptions) (int64, error) { - return db.GetEngine(db.DefaultContext).Where(opts.toConds(repoID)).Count(&Release{}) +func GetReleaseCountByRepoID(ctx context.Context, repoID int64, opts FindReleasesOptions) (int64, error) { + return db.GetEngine(ctx).Where(opts.toConds(repoID)).Count(&Release{}) } type releaseMetaSearch struct { diff --git a/models/repo/repo.go b/models/repo/repo.go index 7cb7138523ff2..e5e1ac43b41fd 100644 --- a/models/repo/repo.go +++ b/models/repo/repo.go @@ -315,12 +315,7 @@ func (repo *Repository) LoadUnits(ctx context.Context) (err error) { } // UnitEnabled if this repository has the given unit enabled -func (repo *Repository) UnitEnabled(tp unit.Type) (result bool) { // Notice: Don't remove this function directly, because it has been used in go template. - return repo.UnitEnabledCtx(db.DefaultContext, tp) -} - -// UnitEnabled if this repository has the given unit enabled -func (repo *Repository) UnitEnabledCtx(ctx context.Context, tp unit.Type) bool { +func (repo *Repository) UnitEnabled(ctx context.Context, tp unit.Type) bool { if err := repo.LoadUnits(ctx); err != nil { log.Warn("Error loading repository (ID: %d) units: %s", repo.ID, err.Error()) } @@ -333,8 +328,8 @@ func (repo *Repository) UnitEnabledCtx(ctx context.Context, tp unit.Type) bool { } // MustGetUnit always returns a RepoUnit object -func (repo *Repository) MustGetUnit(tp unit.Type) *RepoUnit { - ru, err := repo.GetUnit(tp) +func (repo *Repository) MustGetUnit(ctx context.Context, tp unit.Type) *RepoUnit { + ru, err := repo.GetUnit(ctx, tp) if err == nil { return ru } @@ -367,12 +362,7 @@ func (repo *Repository) MustGetUnit(tp unit.Type) *RepoUnit { } // GetUnit returns a RepoUnit object -func (repo *Repository) GetUnit(tp unit.Type) (*RepoUnit, error) { - return repo.GetUnitCtx(db.DefaultContext, tp) -} - -// GetUnitCtx returns a RepoUnit object -func (repo *Repository) GetUnitCtx(ctx context.Context, tp unit.Type) (*RepoUnit, error) { +func (repo *Repository) GetUnit(ctx context.Context, tp unit.Type) (*RepoUnit, error) { if err := repo.LoadUnits(ctx); err != nil { return nil, err } @@ -419,7 +409,7 @@ func (repo *Repository) ComposeMetas() map[string]string { "mode": "comment", } - unit, err := repo.GetUnit(unit.TypeExternalTracker) + unit, err := repo.GetUnit(db.DefaultContext, unit.TypeExternalTracker) if err == nil { metas["format"] = unit.ExternalTrackerConfig().ExternalTrackerFormat switch unit.ExternalTrackerConfig().ExternalTrackerStyle { @@ -518,7 +508,7 @@ func (repo *Repository) CanEnablePulls() bool { // AllowsPulls returns true if repository meets the requirements of accepting pulls and has them enabled. func (repo *Repository) AllowsPulls() bool { - return repo.CanEnablePulls() && repo.UnitEnabled(unit.TypePullRequests) + return repo.CanEnablePulls() && repo.UnitEnabled(db.DefaultContext, unit.TypePullRequests) } // CanEnableEditor returns true if repository meets the requirements of web editor. diff --git a/models/repo_transfer.go b/models/repo_transfer.go index 362253bdc8ae2..19e6c0662727f 100644 --- a/models/repo_transfer.go +++ b/models/repo_transfer.go @@ -39,9 +39,9 @@ func init() { } // LoadAttributes fetches the transfer recipient from the database -func (r *RepoTransfer) LoadAttributes() error { +func (r *RepoTransfer) LoadAttributes(ctx context.Context) error { if r.Recipient == nil { - u, err := user_model.GetUserByID(db.DefaultContext, r.RecipientID) + u, err := user_model.GetUserByID(ctx, r.RecipientID) if err != nil { return err } @@ -51,7 +51,7 @@ func (r *RepoTransfer) LoadAttributes() error { if r.Recipient.IsOrganization() && len(r.TeamIDs) != len(r.Teams) { for _, v := range r.TeamIDs { - team, err := organization.GetTeamByID(db.DefaultContext, v) + team, err := organization.GetTeamByID(ctx, v) if err != nil { return err } @@ -65,7 +65,7 @@ func (r *RepoTransfer) LoadAttributes() error { } if r.Doer == nil { - u, err := user_model.GetUserByID(db.DefaultContext, r.DoerID) + u, err := user_model.GetUserByID(ctx, r.DoerID) if err != nil { return err } @@ -80,7 +80,7 @@ func (r *RepoTransfer) LoadAttributes() error { // For user, it checks if it's himself // For organizations, it checks if the user is able to create repos func (r *RepoTransfer) CanUserAcceptTransfer(u *user_model.User) bool { - if err := r.LoadAttributes(); err != nil { + if err := r.LoadAttributes(db.DefaultContext); err != nil { log.Error("LoadAttributes: %v", err) return false } @@ -89,7 +89,7 @@ func (r *RepoTransfer) CanUserAcceptTransfer(u *user_model.User) bool { return r.RecipientID == u.ID } - allowed, err := organization.CanCreateOrgRepo(r.RecipientID, u.ID) + allowed, err := organization.CanCreateOrgRepo(db.DefaultContext, r.RecipientID, u.ID) if err != nil { log.Error("CanCreateOrgRepo: %v", err) return false @@ -100,10 +100,10 @@ func (r *RepoTransfer) CanUserAcceptTransfer(u *user_model.User) bool { // GetPendingRepositoryTransfer fetches the most recent and ongoing transfer // process for the repository -func GetPendingRepositoryTransfer(repo *repo_model.Repository) (*RepoTransfer, error) { +func GetPendingRepositoryTransfer(ctx context.Context, repo *repo_model.Repository) (*RepoTransfer, error) { transfer := new(RepoTransfer) - has, err := db.GetEngine(db.DefaultContext).Where("repo_id = ? ", repo.ID).Get(transfer) + has, err := db.GetEngine(ctx).Where("repo_id = ? ", repo.ID).Get(transfer) if err != nil { return nil, err } @@ -154,56 +154,48 @@ 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(doer, newOwner *user_model.User, repoID int64, teams []*organization.Team) error { - ctx, committer, err := db.TxContext(db.DefaultContext) - if err != nil { - return err - } - defer committer.Close() - - repo, err := repo_model.GetRepositoryByID(ctx, repoID) - if err != nil { - return err - } - - // Make sure repo is ready to transfer - if err := TestRepositoryReadyForTransfer(repo.Status); err != nil { - return err - } +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 { + repo, err := repo_model.GetRepositoryByID(ctx, repoID) + if err != nil { + return err + } - repo.Status = repo_model.RepositoryPendingTransfer - if err := repo_model.UpdateRepositoryCols(ctx, repo, "status"); err != nil { - return err - } + // Make sure repo is ready to transfer + if err := TestRepositoryReadyForTransfer(repo.Status); err != nil { + return err + } - // Check if new owner has repository with same name. - if has, err := repo_model.IsRepositoryExist(ctx, newOwner, repo.Name); err != nil { - return fmt.Errorf("IsRepositoryExist: %w", err) - } else if has { - return repo_model.ErrRepoAlreadyExist{ - Uname: newOwner.LowerName, - Name: repo.Name, + repo.Status = repo_model.RepositoryPendingTransfer + if err := repo_model.UpdateRepositoryCols(ctx, repo, "status"); err != nil { + return err } - } - transfer := &RepoTransfer{ - RepoID: repo.ID, - RecipientID: newOwner.ID, - CreatedUnix: timeutil.TimeStampNow(), - UpdatedUnix: timeutil.TimeStampNow(), - DoerID: doer.ID, - TeamIDs: make([]int64, 0, len(teams)), - } + // Check if new owner has repository with same name. + if has, err := repo_model.IsRepositoryExist(ctx, newOwner, repo.Name); err != nil { + return fmt.Errorf("IsRepositoryExist: %w", err) + } else if has { + return repo_model.ErrRepoAlreadyExist{ + Uname: newOwner.LowerName, + Name: repo.Name, + } + } - for k := range teams { - transfer.TeamIDs = append(transfer.TeamIDs, teams[k].ID) - } + transfer := &RepoTransfer{ + RepoID: repo.ID, + RecipientID: newOwner.ID, + CreatedUnix: timeutil.TimeStampNow(), + UpdatedUnix: timeutil.TimeStampNow(), + DoerID: doer.ID, + TeamIDs: make([]int64, 0, len(teams)), + } - if err := db.Insert(ctx, transfer); err != nil { - return err - } + for k := range teams { + transfer.TeamIDs = append(transfer.TeamIDs, teams[k].ID) + } - return committer.Commit() + return db.Insert(ctx, transfer) + }) } // TransferOwnership transfers all corresponding repository items from old user to new one. diff --git a/models/repo_transfer_test.go b/models/repo_transfer_test.go index 9720071a989b9..8352adc94892e 100644 --- a/models/repo_transfer_test.go +++ b/models/repo_transfer_test.go @@ -6,6 +6,7 @@ package models import ( "testing" + "code.gitea.io/gitea/models/db" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" @@ -19,36 +20,36 @@ func TestRepositoryTransfer(t *testing.T) { doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}) repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}) - transfer, err := GetPendingRepositoryTransfer(repo) + transfer, err := GetPendingRepositoryTransfer(db.DefaultContext, repo) assert.NoError(t, err) assert.NotNil(t, transfer) // Cancel transfer assert.NoError(t, CancelRepositoryTransfer(repo)) - transfer, err = GetPendingRepositoryTransfer(repo) + transfer, err = GetPendingRepositoryTransfer(db.DefaultContext, repo) assert.Error(t, err) assert.Nil(t, transfer) assert.True(t, IsErrNoPendingTransfer(err)) user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) - assert.NoError(t, CreatePendingRepositoryTransfer(doer, user2, repo.ID, nil)) + assert.NoError(t, CreatePendingRepositoryTransfer(db.DefaultContext, doer, user2, repo.ID, nil)) - transfer, err = GetPendingRepositoryTransfer(repo) + transfer, err = GetPendingRepositoryTransfer(db.DefaultContext, repo) assert.Nil(t, err) - assert.NoError(t, transfer.LoadAttributes()) + assert.NoError(t, transfer.LoadAttributes(db.DefaultContext)) assert.Equal(t, "user2", transfer.Recipient.Name) user6 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // Only transfer can be started at any given time - err = CreatePendingRepositoryTransfer(doer, user6, repo.ID, nil) + err = CreatePendingRepositoryTransfer(db.DefaultContext, doer, user6, repo.ID, nil) assert.Error(t, err) assert.True(t, IsErrRepoTransferInProgress(err)) // Unknown user - err = CreatePendingRepositoryTransfer(doer, &user_model.User{ID: 1000, LowerName: "user1000"}, repo.ID, nil) + err = CreatePendingRepositoryTransfer(db.DefaultContext, doer, &user_model.User{ID: 1000, LowerName: "user1000"}, repo.ID, nil) assert.Error(t, err) // Cancel transfer diff --git a/modules/context/package.go b/modules/context/package.go index 65a9d74b77528..2a55db3a77fa6 100644 --- a/modules/context/package.go +++ b/modules/context/package.go @@ -110,7 +110,7 @@ func determineAccessMode(ctx *Context) (perm.AccessMode, error) { return accessMode, err } for _, t := range teams { - perm := t.UnitAccessModeCtx(ctx, unit.TypePackages) + perm := t.UnitAccessMode(ctx, unit.TypePackages) if accessMode < perm { accessMode = perm } diff --git a/modules/context/repo.go b/modules/context/repo.go index a50cb15abe25a..71a2b3c0c6ef2 100644 --- a/modules/context/repo.go +++ b/modules/context/repo.go @@ -163,13 +163,13 @@ func (r *Repository) CanUseTimetracker(issue *issues_model.Issue, user *user_mod // 1. Is timetracker enabled // 2. Is the user a contributor, admin, poster or assignee and do the repository policies require this? isAssigned, _ := issues_model.IsUserAssignedToIssue(db.DefaultContext, issue, user) - return r.Repository.IsTimetrackerEnabled() && (!r.Repository.AllowOnlyContributorsToTrackTime() || + return r.Repository.IsTimetrackerEnabled(db.DefaultContext) && (!r.Repository.AllowOnlyContributorsToTrackTime(db.DefaultContext) || r.Permission.CanWriteIssuesOrPulls(issue.IsPull) || issue.IsPoster(user.ID) || isAssigned) } // CanCreateIssueDependencies returns whether or not a user can create dependencies. func (r *Repository) CanCreateIssueDependencies(user *user_model.User, isPull bool) bool { - return r.Repository.IsDependenciesEnabled() && r.Permission.CanWriteIssuesOrPulls(isPull) + return r.Repository.IsDependenciesEnabled(db.DefaultContext) && r.Permission.CanWriteIssuesOrPulls(isPull) } // GetCommitsCount returns cached commit count for current view @@ -528,12 +528,12 @@ func RepoAssignment(ctx *Context) (cancel context.CancelFunc) { ctx.Data["RepoLink"] = ctx.Repo.RepoLink ctx.Data["RepoRelPath"] = ctx.Repo.Owner.Name + "/" + ctx.Repo.Repository.Name - unit, err := ctx.Repo.Repository.GetUnit(unit_model.TypeExternalTracker) + unit, err := ctx.Repo.Repository.GetUnit(ctx, unit_model.TypeExternalTracker) if err == nil { ctx.Data["RepoExternalIssuesLink"] = unit.ExternalTrackerConfig().ExternalTrackerURL } - ctx.Data["NumTags"], err = repo_model.GetReleaseCountByRepoID(ctx.Repo.Repository.ID, repo_model.FindReleasesOptions{ + ctx.Data["NumTags"], err = repo_model.GetReleaseCountByRepoID(ctx, ctx.Repo.Repository.ID, repo_model.FindReleasesOptions{ IncludeDrafts: true, IncludeTags: true, HasSha1: util.OptionalBoolTrue, // only draft releases which are created with existing tags @@ -542,7 +542,7 @@ func RepoAssignment(ctx *Context) (cancel context.CancelFunc) { ctx.ServerError("GetReleaseCountByRepoID", err) return } - ctx.Data["NumReleases"], err = repo_model.GetReleaseCountByRepoID(ctx.Repo.Repository.ID, repo_model.FindReleasesOptions{}) + ctx.Data["NumReleases"], err = repo_model.GetReleaseCountByRepoID(ctx, ctx.Repo.Repository.ID, repo_model.FindReleasesOptions{}) if err != nil { ctx.ServerError("GetReleaseCountByRepoID", err) return @@ -723,13 +723,13 @@ func RepoAssignment(ctx *Context) (cancel context.CancelFunc) { ctx.Data["PullRequestCtx"] = ctx.Repo.PullRequest if ctx.Repo.Repository.Status == repo_model.RepositoryPendingTransfer { - repoTransfer, err := models.GetPendingRepositoryTransfer(ctx.Repo.Repository) + repoTransfer, err := models.GetPendingRepositoryTransfer(ctx, ctx.Repo.Repository) if err != nil { ctx.ServerError("GetPendingRepositoryTransfer", err) return } - if err := repoTransfer.LoadAttributes(); err != nil { + if err := repoTransfer.LoadAttributes(ctx); err != nil { ctx.ServerError("LoadRecipient", err) return } diff --git a/modules/convert/issue_comment.go b/modules/convert/issue_comment.go index 983354438ae42..6044cbcf61343 100644 --- a/modules/convert/issue_comment.go +++ b/modules/convert/issue_comment.go @@ -149,7 +149,7 @@ func ToTimelineComment(ctx context.Context, c *issues_model.Comment, doer *user_ var err error repo, err = repo_model.GetRepositoryByID(ctx, c.Label.RepoID) if err != nil { - log.Error("GetRepositoryByIDCtx(%d): %v", c.Label.RepoID, err) + log.Error("GetRepositoryByID(%d): %v", c.Label.RepoID, err) return nil } } diff --git a/modules/convert/repository.go b/modules/convert/repository.go index 843556e1b1203..ce53a6669237c 100644 --- a/modules/convert/repository.go +++ b/modules/convert/repository.go @@ -8,7 +8,6 @@ import ( "time" "code.gitea.io/gitea/models" - "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/perm" repo_model "code.gitea.io/gitea/models/repo" unit_model "code.gitea.io/gitea/models/unit" @@ -44,7 +43,7 @@ func innerToRepo(ctx context.Context, repo *repo_model.Repository, mode perm.Acc hasIssues := false var externalTracker *api.ExternalTracker var internalTracker *api.InternalTracker - if unit, err := repo.GetUnit(unit_model.TypeIssues); err == nil { + if unit, err := repo.GetUnit(ctx, unit_model.TypeIssues); err == nil { config := unit.IssuesConfig() hasIssues = true internalTracker = &api.InternalTracker{ @@ -52,7 +51,7 @@ func innerToRepo(ctx context.Context, repo *repo_model.Repository, mode perm.Acc AllowOnlyContributorsToTrackTime: config.AllowOnlyContributorsToTrackTime, EnableIssueDependencies: config.EnableDependencies, } - } else if unit, err := repo.GetUnit(unit_model.TypeExternalTracker); err == nil { + } else if unit, err := repo.GetUnit(ctx, unit_model.TypeExternalTracker); err == nil { config := unit.ExternalTrackerConfig() hasIssues = true externalTracker = &api.ExternalTracker{ @@ -64,9 +63,9 @@ func innerToRepo(ctx context.Context, repo *repo_model.Repository, mode perm.Acc } hasWiki := false var externalWiki *api.ExternalWiki - if _, err := repo.GetUnit(unit_model.TypeWiki); err == nil { + if _, err := repo.GetUnit(ctx, unit_model.TypeWiki); err == nil { hasWiki = true - } else if unit, err := repo.GetUnit(unit_model.TypeExternalWiki); err == nil { + } else if unit, err := repo.GetUnit(ctx, unit_model.TypeExternalWiki); err == nil { hasWiki = true config := unit.ExternalWikiConfig() externalWiki = &api.ExternalWiki{ @@ -82,7 +81,7 @@ func innerToRepo(ctx context.Context, repo *repo_model.Repository, mode perm.Acc allowRebaseUpdate := false defaultDeleteBranchAfterMerge := false defaultMergeStyle := repo_model.MergeStyleMerge - if unit, err := repo.GetUnit(unit_model.TypePullRequests); err == nil { + if unit, err := repo.GetUnit(ctx, unit_model.TypePullRequests); err == nil { config := unit.PullRequestsConfig() hasPullRequests = true ignoreWhitespaceConflicts = config.IgnoreWhitespaceConflicts @@ -95,21 +94,21 @@ func innerToRepo(ctx context.Context, repo *repo_model.Repository, mode perm.Acc defaultMergeStyle = config.GetDefaultMergeStyle() } hasProjects := false - if _, err := repo.GetUnit(unit_model.TypeProjects); err == nil { + if _, err := repo.GetUnit(ctx, unit_model.TypeProjects); err == nil { hasProjects = true } - if err := repo.GetOwner(db.DefaultContext); err != nil { + if err := repo.GetOwner(ctx); err != nil { return nil } - numReleases, _ := repo_model.GetReleaseCountByRepoID(repo.ID, repo_model.FindReleasesOptions{IncludeDrafts: false, IncludeTags: false}) + numReleases, _ := repo_model.GetReleaseCountByRepoID(ctx, repo.ID, repo_model.FindReleasesOptions{IncludeDrafts: false, IncludeTags: false}) mirrorInterval := "" var mirrorUpdated time.Time if repo.IsMirror { var err error - repo.Mirror, err = repo_model.GetMirrorByRepoID(db.DefaultContext, repo.ID) + repo.Mirror, err = repo_model.GetMirrorByRepoID(ctx, repo.ID) if err == nil { mirrorInterval = repo.Mirror.Interval.String() mirrorUpdated = repo.Mirror.UpdatedUnix.AsTime() @@ -118,11 +117,11 @@ func innerToRepo(ctx context.Context, repo *repo_model.Repository, mode perm.Acc var transfer *api.RepoTransfer if repo.Status == repo_model.RepositoryPendingTransfer { - t, err := models.GetPendingRepositoryTransfer(repo) + t, err := models.GetPendingRepositoryTransfer(ctx, repo) if err != nil && !models.IsErrNoPendingTransfer(err) { log.Warn("GetPendingRepositoryTransfer: %v", err) } else { - if err := t.LoadAttributes(); err != nil { + if err := t.LoadAttributes(ctx); err != nil { log.Warn("LoadAttributes of RepoTransfer: %v", err) } else { transfer = ToRepoTransfer(t) diff --git a/modules/repository/collaborator.go b/modules/repository/collaborator.go index 44c03f999ee7d..f2b95151879ff 100644 --- a/modules/repository/collaborator.go +++ b/modules/repository/collaborator.go @@ -13,30 +13,25 @@ import ( user_model "code.gitea.io/gitea/models/user" ) -func addCollaborator(ctx context.Context, repo *repo_model.Repository, u *user_model.User) error { - collaboration := &repo_model.Collaboration{ - RepoID: repo.ID, - UserID: u.ID, - } - - has, err := db.GetByBean(ctx, collaboration) - if err != nil { - return err - } else if has { - return nil - } - collaboration.Mode = perm.AccessModeWrite - - if err = db.Insert(ctx, collaboration); err != nil { - return err - } - - return access_model.RecalculateUserAccess(ctx, repo, u.ID) -} - -// AddCollaborator adds new collaboration to a repository with default access mode. -func AddCollaborator(repo *repo_model.Repository, u *user_model.User) error { - return db.WithTx(db.DefaultContext, func(ctx context.Context) error { - return addCollaborator(ctx, repo, u) +func AddCollaborator(ctx context.Context, repo *repo_model.Repository, u *user_model.User) error { + return db.AutoTx(ctx, func(ctx context.Context) error { + collaboration := &repo_model.Collaboration{ + RepoID: repo.ID, + UserID: u.ID, + } + + has, err := db.GetByBean(ctx, collaboration) + if err != nil { + return err + } else if has { + return nil + } + collaboration.Mode = perm.AccessModeWrite + + if err = db.Insert(ctx, collaboration); err != nil { + return err + } + + return access_model.RecalculateUserAccess(ctx, repo, u.ID) }) } diff --git a/modules/repository/collaborator_test.go b/modules/repository/collaborator_test.go index ad835ae4d428c..6cf239d0eadae 100644 --- a/modules/repository/collaborator_test.go +++ b/modules/repository/collaborator_test.go @@ -25,7 +25,7 @@ func TestRepository_AddCollaborator(t *testing.T) { repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID}) assert.NoError(t, repo.GetOwner(db.DefaultContext)) user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: userID}) - assert.NoError(t, AddCollaborator(repo, user)) + assert.NoError(t, AddCollaborator(db.DefaultContext, repo, user)) unittest.CheckConsistencyFor(t, &repo_model.Repository{ID: repoID}, &user_model.User{ID: userID}) } testSuccess(1, 4) @@ -50,7 +50,7 @@ func TestRepoPermissionPublicNonOrgRepo(t *testing.T) { } // change to collaborator - assert.NoError(t, AddCollaborator(repo, user)) + assert.NoError(t, AddCollaborator(db.DefaultContext, repo, user)) perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, user) assert.NoError(t, err) for _, unit := range repo.Units { @@ -103,7 +103,7 @@ func TestRepoPermissionPrivateNonOrgRepo(t *testing.T) { } // change to collaborator to default write access - assert.NoError(t, AddCollaborator(repo, user)) + assert.NoError(t, AddCollaborator(db.DefaultContext, repo, user)) perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, user) assert.NoError(t, err) for _, unit := range repo.Units { @@ -111,7 +111,7 @@ func TestRepoPermissionPrivateNonOrgRepo(t *testing.T) { assert.True(t, perm.CanWrite(unit.Type)) } - assert.NoError(t, repo_model.ChangeCollaborationAccessMode(repo, user.ID, perm_model.AccessModeRead)) + assert.NoError(t, repo_model.ChangeCollaborationAccessMode(db.DefaultContext, repo, user.ID, perm_model.AccessModeRead)) perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, user) assert.NoError(t, err) for _, unit := range repo.Units { @@ -155,7 +155,7 @@ func TestRepoPermissionPublicOrgRepo(t *testing.T) { } // change to collaborator to default write access - assert.NoError(t, AddCollaborator(repo, user)) + assert.NoError(t, AddCollaborator(db.DefaultContext, repo, user)) perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, user) assert.NoError(t, err) for _, unit := range repo.Units { @@ -163,7 +163,7 @@ func TestRepoPermissionPublicOrgRepo(t *testing.T) { assert.True(t, perm.CanWrite(unit.Type)) } - assert.NoError(t, repo_model.ChangeCollaborationAccessMode(repo, user.ID, perm_model.AccessModeRead)) + assert.NoError(t, repo_model.ChangeCollaborationAccessMode(db.DefaultContext, repo, user.ID, perm_model.AccessModeRead)) perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, user) assert.NoError(t, err) for _, unit := range repo.Units { @@ -217,7 +217,7 @@ func TestRepoPermissionPrivateOrgRepo(t *testing.T) { } // change to collaborator to default write access - assert.NoError(t, AddCollaborator(repo, user)) + assert.NoError(t, AddCollaborator(db.DefaultContext, repo, user)) perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, user) assert.NoError(t, err) for _, unit := range repo.Units { @@ -225,7 +225,7 @@ func TestRepoPermissionPrivateOrgRepo(t *testing.T) { assert.True(t, perm.CanWrite(unit.Type)) } - assert.NoError(t, repo_model.ChangeCollaborationAccessMode(repo, user.ID, perm_model.AccessModeRead)) + assert.NoError(t, repo_model.ChangeCollaborationAccessMode(db.DefaultContext, repo, user.ID, perm_model.AccessModeRead)) perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, user) assert.NoError(t, err) for _, unit := range repo.Units { diff --git a/modules/repository/create.go b/modules/repository/create.go index 8bee890aadb23..1e157ec85eff8 100644 --- a/modules/repository/create.go +++ b/modules/repository/create.go @@ -125,10 +125,10 @@ func CreateRepositoryByExample(ctx context.Context, doer, u *user_model.User, re return fmt.Errorf("IsUserRepoAdmin: %w", err) } else if !isAdmin { // Make creator repo admin if it wasn't assigned automatically - if err = addCollaborator(ctx, repo, doer); err != nil { - return fmt.Errorf("addCollaborator: %w", err) + if err = AddCollaborator(ctx, repo, doer); err != nil { + return fmt.Errorf("AddCollaborator: %w", err) } - if err = repo_model.ChangeCollaborationAccessModeCtx(ctx, repo, doer.ID, perm.AccessModeAdmin); err != nil { + if err = repo_model.ChangeCollaborationAccessMode(ctx, repo, doer.ID, perm.AccessModeAdmin); err != nil { return fmt.Errorf("ChangeCollaborationAccessModeCtx: %w", err) } } diff --git a/routers/api/v1/repo/collaborators.go b/routers/api/v1/repo/collaborators.go index 383193daa71be..202418bd2bec5 100644 --- a/routers/api/v1/repo/collaborators.go +++ b/routers/api/v1/repo/collaborators.go @@ -174,13 +174,13 @@ func AddCollaborator(ctx *context.APIContext) { return } - if err := repo_module.AddCollaborator(ctx.Repo.Repository, collaborator); err != nil { + if err := repo_module.AddCollaborator(ctx, ctx.Repo.Repository, collaborator); err != nil { ctx.Error(http.StatusInternalServerError, "AddCollaborator", err) return } if form.Permission != nil { - if err := repo_model.ChangeCollaborationAccessMode(ctx.Repo.Repository, collaborator.ID, perm.ParseAccessMode(*form.Permission)); err != nil { + if err := repo_model.ChangeCollaborationAccessMode(ctx, ctx.Repo.Repository, collaborator.ID, perm.ParseAccessMode(*form.Permission)); err != nil { ctx.Error(http.StatusInternalServerError, "ChangeCollaborationAccessMode", err) return } diff --git a/routers/api/v1/repo/issue_comment.go b/routers/api/v1/repo/issue_comment.go index a584a7a174ab9..9097004186f4a 100644 --- a/routers/api/v1/repo/issue_comment.go +++ b/routers/api/v1/repo/issue_comment.go @@ -18,7 +18,7 @@ import ( api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/api/v1/utils" - comment_service "code.gitea.io/gitea/services/comments" + issue_service "code.gitea.io/gitea/services/issue" ) // ListIssueComments list all the comments of an issue @@ -362,7 +362,7 @@ func CreateIssueComment(ctx *context.APIContext) { return } - comment, err := comment_service.CreateIssueComment(ctx, ctx.Doer, ctx.Repo.Repository, issue, form.Body, nil) + comment, err := issue_service.CreateIssueComment(ctx, ctx.Doer, ctx.Repo.Repository, issue, form.Body, nil) if err != nil { ctx.Error(http.StatusInternalServerError, "CreateIssueComment", err) return @@ -556,7 +556,7 @@ func editIssueComment(ctx *context.APIContext, form api.EditIssueCommentOption) oldContent := comment.Content comment.Content = form.Body - if err := comment_service.UpdateComment(ctx, comment, ctx.Doer, oldContent); err != nil { + if err := issue_service.UpdateComment(ctx, comment, ctx.Doer, oldContent); err != nil { ctx.Error(http.StatusInternalServerError, "UpdateComment", err) return } @@ -655,7 +655,7 @@ func deleteIssueComment(ctx *context.APIContext) { return } - if err = comment_service.DeleteComment(ctx, ctx.Doer, comment); err != nil { + if err = issue_service.DeleteComment(ctx, ctx.Doer, comment); err != nil { ctx.Error(http.StatusInternalServerError, "DeleteCommentByID", err) return } diff --git a/routers/api/v1/repo/issue_comment_attachment.go b/routers/api/v1/repo/issue_comment_attachment.go index 60ea8d1b832ed..2198a6a33d51d 100644 --- a/routers/api/v1/repo/issue_comment_attachment.go +++ b/routers/api/v1/repo/issue_comment_attachment.go @@ -15,7 +15,7 @@ import ( api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/services/attachment" - comment_service "code.gitea.io/gitea/services/comments" + issue_service "code.gitea.io/gitea/services/issue" ) // GetIssueCommentAttachment gets a single attachment of the comment @@ -196,7 +196,7 @@ func CreateIssueCommentAttachment(ctx *context.APIContext) { return } - if err = comment_service.UpdateComment(ctx, comment, ctx.Doer, comment.Content); err != nil { + if err = issue_service.UpdateComment(ctx, comment, ctx.Doer, comment.Content); err != nil { ctx.ServerError("UpdateComment", err) return } diff --git a/routers/api/v1/repo/issue_tracked_time.go b/routers/api/v1/repo/issue_tracked_time.go index 6786d23a93269..ede60a2ed810b 100644 --- a/routers/api/v1/repo/issue_tracked_time.go +++ b/routers/api/v1/repo/issue_tracked_time.go @@ -71,7 +71,7 @@ func ListTrackedTimes(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - if !ctx.Repo.Repository.IsTimetrackerEnabled() { + if !ctx.Repo.Repository.IsTimetrackerEnabled(ctx) { ctx.NotFound("Timetracker is disabled") return } @@ -190,7 +190,7 @@ func AddTime(ctx *context.APIContext) { } if !ctx.Repo.CanUseTimetracker(issue, ctx.Doer) { - if !ctx.Repo.Repository.IsTimetrackerEnabled() { + if !ctx.Repo.Repository.IsTimetrackerEnabled(ctx) { ctx.Error(http.StatusBadRequest, "", "time tracking disabled") return } @@ -271,7 +271,7 @@ func ResetIssueTime(ctx *context.APIContext) { } if !ctx.Repo.CanUseTimetracker(issue, ctx.Doer) { - if !ctx.Repo.Repository.IsTimetrackerEnabled() { + if !ctx.Repo.Repository.IsTimetrackerEnabled(ctx) { ctx.JSON(http.StatusBadRequest, struct{ Message string }{Message: "time tracking disabled"}) return } @@ -342,7 +342,7 @@ func DeleteTime(ctx *context.APIContext) { } if !ctx.Repo.CanUseTimetracker(issue, ctx.Doer) { - if !ctx.Repo.Repository.IsTimetrackerEnabled() { + if !ctx.Repo.Repository.IsTimetrackerEnabled(ctx) { ctx.JSON(http.StatusBadRequest, struct{ Message string }{Message: "time tracking disabled"}) return } @@ -410,7 +410,7 @@ func ListTrackedTimesByUser(ctx *context.APIContext) { // "403": // "$ref": "#/responses/forbidden" - if !ctx.Repo.Repository.IsTimetrackerEnabled() { + if !ctx.Repo.Repository.IsTimetrackerEnabled(ctx) { ctx.Error(http.StatusBadRequest, "", "time tracking disabled") return } @@ -498,7 +498,7 @@ func ListTrackedTimesByRepository(ctx *context.APIContext) { // "403": // "$ref": "#/responses/forbidden" - if !ctx.Repo.Repository.IsTimetrackerEnabled() { + if !ctx.Repo.Repository.IsTimetrackerEnabled(ctx) { ctx.Error(http.StatusBadRequest, "", "time tracking disabled") return } diff --git a/routers/api/v1/repo/repo.go b/routers/api/v1/repo/repo.go index 3b55b496a905b..349040507810b 100644 --- a/routers/api/v1/repo/repo.go +++ b/routers/api/v1/repo/repo.go @@ -731,7 +731,7 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error { var units []repo_model.RepoUnit var deleteUnitTypes []unit_model.Type - currHasIssues := repo.UnitEnabledCtx(ctx, unit_model.TypeIssues) + currHasIssues := repo.UnitEnabled(ctx, unit_model.TypeIssues) newHasIssues := currHasIssues if opts.HasIssues != nil { newHasIssues = *opts.HasIssues @@ -771,7 +771,7 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error { AllowOnlyContributorsToTrackTime: opts.InternalTracker.AllowOnlyContributorsToTrackTime, EnableDependencies: opts.InternalTracker.EnableIssueDependencies, } - } else if unit, err := repo.GetUnit(unit_model.TypeIssues); err != nil { + } else if unit, err := repo.GetUnit(ctx, unit_model.TypeIssues); err != nil { // Unit type doesn't exist so we make a new config file with default values config = &repo_model.IssuesConfig{ EnableTimetracker: true, @@ -798,7 +798,7 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error { } } - currHasWiki := repo.UnitEnabledCtx(ctx, unit_model.TypeWiki) + currHasWiki := repo.UnitEnabled(ctx, unit_model.TypeWiki) newHasWiki := currHasWiki if opts.HasWiki != nil { newHasWiki = *opts.HasWiki @@ -838,7 +838,7 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error { } } - currHasPullRequests := repo.UnitEnabledCtx(ctx, unit_model.TypePullRequests) + currHasPullRequests := repo.UnitEnabled(ctx, unit_model.TypePullRequests) newHasPullRequests := currHasPullRequests if opts.HasPullRequests != nil { newHasPullRequests = *opts.HasPullRequests @@ -848,7 +848,7 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error { // We do allow setting individual PR settings through the API, so // we get the config settings and then set them // if those settings were provided in the opts. - unit, err := repo.GetUnit(unit_model.TypePullRequests) + unit, err := repo.GetUnit(ctx, unit_model.TypePullRequests) var config *repo_model.PullRequestsConfig if err != nil { // Unit type doesn't exist so we make a new config file with default values diff --git a/routers/api/v1/repo/transfer.go b/routers/api/v1/repo/transfer.go index fb15566a4b5a5..5154c5afa3cbb 100644 --- a/routers/api/v1/repo/transfer.go +++ b/routers/api/v1/repo/transfer.go @@ -105,7 +105,7 @@ func Transfer(ctx *context.APIContext) { oldFullname := ctx.Repo.Repository.FullName() - if err := repo_service.StartRepositoryTransfer(ctx.Doer, newOwner, ctx.Repo.Repository, teams); err != nil { + if err := repo_service.StartRepositoryTransfer(ctx, ctx.Doer, newOwner, ctx.Repo.Repository, teams); err != nil { if models.IsErrRepoTransferInProgress(err) { ctx.Error(http.StatusConflict, "StartRepositoryTransfer", err) return @@ -207,7 +207,7 @@ func RejectTransfer(ctx *context.APIContext) { } func acceptOrRejectRepoTransfer(ctx *context.APIContext, accept bool) error { - repoTransfer, err := models.GetPendingRepositoryTransfer(ctx.Repo.Repository) + repoTransfer, err := models.GetPendingRepositoryTransfer(ctx, ctx.Repo.Repository) if err != nil { if models.IsErrNoPendingTransfer(err) { ctx.NotFound() @@ -216,7 +216,7 @@ func acceptOrRejectRepoTransfer(ctx *context.APIContext, accept bool) error { return err } - if err := repoTransfer.LoadAttributes(); err != nil { + if err := repoTransfer.LoadAttributes(ctx); err != nil { return err } @@ -226,7 +226,7 @@ func acceptOrRejectRepoTransfer(ctx *context.APIContext, accept bool) error { } if accept { - return repo_service.TransferOwnership(repoTransfer.Doer, repoTransfer.Recipient, ctx.Repo.Repository, repoTransfer.Teams) + return repo_service.TransferOwnership(ctx, repoTransfer.Doer, repoTransfer.Recipient, ctx.Repo.Repository, repoTransfer.Teams) } return models.CancelRepositoryTransfer(ctx.Repo.Repository) diff --git a/routers/private/serv.go b/routers/private/serv.go index a86f6c057928b..17f966e3e40a7 100644 --- a/routers/private/serv.go +++ b/routers/private/serv.go @@ -382,7 +382,7 @@ func ServCommand(ctx *context.PrivateContext) { if results.IsWiki { // Ensure the wiki is enabled before we allow access to it - if _, err := repo.GetUnit(unit.TypeWiki); err != nil { + if _, err := repo.GetUnit(ctx, unit.TypeWiki); err != nil { if repo_model.IsErrUnitTypeNotExist(err) { ctx.JSON(http.StatusForbidden, private.ErrServCommand{ Results: results, diff --git a/routers/web/repo/cherry_pick.go b/routers/web/repo/cherry_pick.go index 2056ad1b379bf..48bc6959e075f 100644 --- a/routers/web/repo/cherry_pick.go +++ b/routers/web/repo/cherry_pick.go @@ -177,7 +177,7 @@ func CherryPickPost(ctx *context.Context) { } } - if form.CommitChoice == frmCommitChoiceNewBranch && ctx.Repo.Repository.UnitEnabled(unit.TypePullRequests) { + if form.CommitChoice == frmCommitChoiceNewBranch && ctx.Repo.Repository.UnitEnabled(ctx, unit.TypePullRequests) { ctx.Redirect(ctx.Repo.RepoLink + "/compare/" + util.PathEscapeSegments(ctx.Repo.BranchName) + "..." + util.PathEscapeSegments(form.NewBranchName)) } else { ctx.Redirect(ctx.Repo.RepoLink + "/src/branch/" + util.PathEscapeSegments(branchName)) diff --git a/routers/web/repo/compare.go b/routers/web/repo/compare.go index b2d8f8645df15..d95eeaecc9774 100644 --- a/routers/web/repo/compare.go +++ b/routers/web/repo/compare.go @@ -577,7 +577,7 @@ func PrepareCompareDiff( if (headCommitID == ci.CompareInfo.MergeBase && !ci.DirectComparison) || headCommitID == ci.CompareInfo.BaseCommitID { ctx.Data["IsNothingToCompare"] = true - if unit, err := repo.GetUnit(unit.TypePullRequests); err == nil { + if unit, err := repo.GetUnit(ctx, unit.TypePullRequests); err == nil { config := unit.PullRequestsConfig() if !config.AutodetectManualMerge { diff --git a/routers/web/repo/editor.go b/routers/web/repo/editor.go index 7b064adfc5e97..e5ba4ad2c1398 100644 --- a/routers/web/repo/editor.go +++ b/routers/web/repo/editor.go @@ -328,7 +328,7 @@ func editFilePost(ctx *context.Context, form forms.EditRepoFileForm, isNewFile b } } - if form.CommitChoice == frmCommitChoiceNewBranch && ctx.Repo.Repository.UnitEnabled(unit.TypePullRequests) { + if form.CommitChoice == frmCommitChoiceNewBranch && ctx.Repo.Repository.UnitEnabled(ctx, unit.TypePullRequests) { ctx.Redirect(ctx.Repo.RepoLink + "/compare/" + util.PathEscapeSegments(ctx.Repo.BranchName) + "..." + util.PathEscapeSegments(form.NewBranchName)) } else { ctx.Redirect(ctx.Repo.RepoLink + "/src/branch/" + util.PathEscapeSegments(branchName) + "/" + util.PathEscapeSegments(form.TreePath)) @@ -514,7 +514,7 @@ func DeleteFilePost(ctx *context.Context) { } ctx.Flash.Success(ctx.Tr("repo.editor.file_delete_success", ctx.Repo.TreePath)) - if form.CommitChoice == frmCommitChoiceNewBranch && ctx.Repo.Repository.UnitEnabled(unit.TypePullRequests) { + if form.CommitChoice == frmCommitChoiceNewBranch && ctx.Repo.Repository.UnitEnabled(ctx, unit.TypePullRequests) { ctx.Redirect(ctx.Repo.RepoLink + "/compare/" + util.PathEscapeSegments(ctx.Repo.BranchName) + "..." + util.PathEscapeSegments(form.NewBranchName)) } else { treePath := path.Dir(ctx.Repo.TreePath) @@ -717,7 +717,7 @@ func UploadFilePost(ctx *context.Context) { return } - if form.CommitChoice == frmCommitChoiceNewBranch && ctx.Repo.Repository.UnitEnabled(unit.TypePullRequests) { + if form.CommitChoice == frmCommitChoiceNewBranch && ctx.Repo.Repository.UnitEnabled(ctx, unit.TypePullRequests) { ctx.Redirect(ctx.Repo.RepoLink + "/compare/" + util.PathEscapeSegments(ctx.Repo.BranchName) + "..." + util.PathEscapeSegments(form.NewBranchName)) } else { ctx.Redirect(ctx.Repo.RepoLink + "/src/branch/" + util.PathEscapeSegments(branchName) + "/" + util.PathEscapeSegments(form.TreePath)) diff --git a/routers/web/repo/http.go b/routers/web/repo/http.go index d2450066e3418..b2a49e3e3a103 100644 --- a/routers/web/repo/http.go +++ b/routers/web/repo/http.go @@ -258,7 +258,7 @@ func httpBase(ctx *context.Context) (h *serviceHandler) { if isWiki { // Ensure the wiki is enabled before we allow access to it - if _, err := repo.GetUnit(unit.TypeWiki); err != nil { + if _, err := repo.GetUnit(ctx, unit.TypeWiki); err != nil { if repo_model.IsErrUnitTypeNotExist(err) { ctx.PlainText(http.StatusForbidden, "repository wiki is disabled") return diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go index b11cc58e41190..d315525dac879 100644 --- a/routers/web/repo/issue.go +++ b/routers/web/repo/issue.go @@ -47,7 +47,6 @@ import ( "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/utils" asymkey_service "code.gitea.io/gitea/services/asymkey" - comment_service "code.gitea.io/gitea/services/comments" "code.gitea.io/gitea/services/forms" issue_service "code.gitea.io/gitea/services/issue" pull_service "code.gitea.io/gitea/services/pull" @@ -114,7 +113,7 @@ func MustEnableIssues(ctx *context.Context) { return } - unit, err := ctx.Repo.Repository.GetUnit(unit.TypeExternalTracker) + unit, err := ctx.Repo.Repository.GetUnit(ctx, unit.TypeExternalTracker) if err == nil { ctx.Redirect(unit.ExternalTrackerConfig().ExternalTrackerURL) return @@ -1174,7 +1173,7 @@ func getBranchData(ctx *context.Context, issue *issues_model.Issue) { func ViewIssue(ctx *context.Context) { if ctx.Params(":type") == "issues" { // If issue was requested we check if repo has external tracker and redirect - extIssueUnit, err := ctx.Repo.Repository.GetUnit(unit.TypeExternalTracker) + extIssueUnit, err := ctx.Repo.Repository.GetUnit(ctx, unit.TypeExternalTracker) if err == nil && extIssueUnit != nil { if extIssueUnit.ExternalTrackerConfig().ExternalTrackerStyle == markup.IssueNameStyleNumeric || extIssueUnit.ExternalTrackerConfig().ExternalTrackerStyle == "" { metas := ctx.Repo.Repository.ComposeMetas() @@ -1375,7 +1374,7 @@ func ViewIssue(ctx *context.Context) { comment *issues_model.Comment participants = make([]*user_model.User, 1, 10) ) - if ctx.Repo.Repository.IsTimetrackerEnabled() { + if ctx.Repo.Repository.IsTimetrackerEnabled(ctx) { if ctx.IsSigned { // Deal with the stopwatch ctx.Data["IsStopwatchRunning"] = issues_model.StopwatchExists(ctx.Doer.ID, issue.ID) @@ -1636,7 +1635,7 @@ func ViewIssue(ctx *context.Context) { } } - prUnit, err := repo.GetUnit(unit.TypePullRequests) + prUnit, err := repo.GetUnit(ctx, unit.TypePullRequests) if err != nil { ctx.ServerError("GetUnit", err) return @@ -2709,7 +2708,7 @@ func NewComment(ctx *context.Context) { return } - comment, err := comment_service.CreateIssueComment(ctx, ctx.Doer, ctx.Repo.Repository, issue, form.Content, attachments) + comment, err := issue_service.CreateIssueComment(ctx, ctx.Doer, ctx.Repo.Repository, issue, form.Content, attachments) if err != nil { ctx.ServerError("CreateIssueComment", err) return @@ -2749,8 +2748,7 @@ func UpdateCommentContent(ctx *context.Context) { }) return } - - if err = comment_service.UpdateComment(ctx, comment, ctx.Doer, oldContent); err != nil { + if err = issue_service.UpdateComment(ctx, comment, ctx.Doer, oldContent); err != nil { ctx.ServerError("UpdateComment", err) return } @@ -2806,7 +2804,7 @@ func DeleteComment(ctx *context.Context) { return } - if err = comment_service.DeleteComment(ctx, ctx.Doer, comment); err != nil { + if err = issue_service.DeleteComment(ctx, ctx.Doer, comment); err != nil { ctx.ServerError("DeleteComment", err) return } diff --git a/routers/web/repo/milestone.go b/routers/web/repo/milestone.go index 04271563973fa..d712df1001bc3 100644 --- a/routers/web/repo/milestone.go +++ b/routers/web/repo/milestone.go @@ -73,7 +73,7 @@ func Milestones(ctx *context.Context) { ctx.ServerError("GetMilestones", err) return } - if ctx.Repo.Repository.IsTimetrackerEnabled() { + if ctx.Repo.Repository.IsTimetrackerEnabled(ctx) { if err := miles.LoadTotalTrackedTimes(); err != nil { ctx.ServerError("LoadTotalTrackedTimes", err) return diff --git a/routers/web/repo/patch.go b/routers/web/repo/patch.go index 27199ba41096d..12b26f38e9013 100644 --- a/routers/web/repo/patch.go +++ b/routers/web/repo/patch.go @@ -108,7 +108,7 @@ func NewDiffPatchPost(ctx *context.Context) { } } - if form.CommitChoice == frmCommitChoiceNewBranch && ctx.Repo.Repository.UnitEnabled(unit.TypePullRequests) { + if form.CommitChoice == frmCommitChoiceNewBranch && ctx.Repo.Repository.UnitEnabled(ctx, unit.TypePullRequests) { ctx.Redirect(ctx.Repo.RepoLink + "/compare/" + util.PathEscapeSegments(ctx.Repo.BranchName) + "..." + util.PathEscapeSegments(form.NewBranchName)) } else { ctx.Redirect(ctx.Repo.RepoLink + "/src/branch/" + util.PathEscapeSegments(branchName) + "/" + util.PathEscapeSegments(form.TreePath)) diff --git a/routers/web/repo/projects.go b/routers/web/repo/projects.go index 73f0916346b4d..75cd290b8f0cb 100644 --- a/routers/web/repo/projects.go +++ b/routers/web/repo/projects.go @@ -196,7 +196,7 @@ func DeleteProject(ctx *context.Context) { return } - if err := project_model.DeleteProjectByID(p.ID); err != nil { + if err := project_model.DeleteProjectByID(ctx, p.ID); err != nil { ctx.Flash.Error("DeleteProjectByID: " + err.Error()) } else { ctx.Flash.Success(ctx.Tr("repo.projects.deletion_success")) diff --git a/routers/web/repo/release.go b/routers/web/repo/release.go index 0aa1fde8de575..2047a1cfb9c8f 100644 --- a/routers/web/repo/release.go +++ b/routers/web/repo/release.go @@ -135,7 +135,7 @@ func releasesOrTags(ctx *context.Context, isTagList bool) { return } - count, err := repo_model.GetReleaseCountByRepoID(ctx.Repo.Repository.ID, opts) + count, err := repo_model.GetReleaseCountByRepoID(ctx, ctx.Repo.Repository.ID, opts) if err != nil { ctx.ServerError("GetReleaseCountByRepoID", err) return diff --git a/routers/web/repo/repo.go b/routers/web/repo/repo.go index c57564d3340c6..8856ee662684e 100644 --- a/routers/web/repo/repo.go +++ b/routers/web/repo/repo.go @@ -314,12 +314,12 @@ func Action(ctx *context.Context) { } func acceptOrRejectRepoTransfer(ctx *context.Context, accept bool) error { - repoTransfer, err := models.GetPendingRepositoryTransfer(ctx.Repo.Repository) + repoTransfer, err := models.GetPendingRepositoryTransfer(ctx, ctx.Repo.Repository) if err != nil { return err } - if err := repoTransfer.LoadAttributes(); err != nil { + if err := repoTransfer.LoadAttributes(ctx); err != nil { return err } @@ -333,7 +333,7 @@ func acceptOrRejectRepoTransfer(ctx *context.Context, accept bool) error { ctx.Repo.GitRepo = nil } - if err := repo_service.TransferOwnership(repoTransfer.Doer, repoTransfer.Recipient, ctx.Repo.Repository, repoTransfer.Teams); err != nil { + if err := repo_service.TransferOwnership(ctx, repoTransfer.Doer, repoTransfer.Recipient, ctx.Repo.Repository, repoTransfer.Teams); err != nil { return err } ctx.Flash.Success(ctx.Tr("repo.settings.transfer.success")) diff --git a/routers/web/repo/setting.go b/routers/web/repo/setting.go index 9e47d0bb12487..8ba5fc9e349da 100644 --- a/routers/web/repo/setting.go +++ b/routers/web/repo/setting.go @@ -689,7 +689,7 @@ func SettingsPost(ctx *context.Context) { ctx.Repo.GitRepo = nil } - if err := repo_service.StartRepositoryTransfer(ctx.Doer, newOwner, repo, nil); err != nil { + if err := repo_service.StartRepositoryTransfer(ctx, ctx.Doer, newOwner, repo, nil); err != nil { if repo_model.IsErrRepoAlreadyExist(err) { ctx.RenderWithErr(ctx.Tr("repo.settings.new_owner_has_same_repo"), tplSettingsOptions, nil) } else if models.IsErrRepoTransferInProgress(err) { @@ -711,7 +711,7 @@ func SettingsPost(ctx *context.Context) { return } - repoTransfer, err := models.GetPendingRepositoryTransfer(ctx.Repo.Repository) + repoTransfer, err := models.GetPendingRepositoryTransfer(ctx, ctx.Repo.Repository) if err != nil { if models.IsErrNoPendingTransfer(err) { ctx.Flash.Error("repo.settings.transfer_abort_invalid") @@ -723,7 +723,7 @@ func SettingsPost(ctx *context.Context) { return } - if err := repoTransfer.LoadAttributes(); err != nil { + if err := repoTransfer.LoadAttributes(ctx); err != nil { ctx.ServerError("LoadRecipient", err) return } @@ -929,7 +929,7 @@ func CollaborationPost(ctx *context.Context) { } } - if err = repo_module.AddCollaborator(ctx.Repo.Repository, u); err != nil { + if err = repo_module.AddCollaborator(ctx, ctx.Repo.Repository, u); err != nil { ctx.ServerError("AddCollaborator", err) return } @@ -945,6 +945,7 @@ func CollaborationPost(ctx *context.Context) { // ChangeCollaborationAccessMode response for changing access of a collaboration func ChangeCollaborationAccessMode(ctx *context.Context) { if err := repo_model.ChangeCollaborationAccessMode( + ctx, ctx.Repo.Repository, ctx.FormInt64("uid"), perm.AccessMode(ctx.FormInt("mode"))); err != nil { diff --git a/routers/web/repo/wiki.go b/routers/web/repo/wiki.go index 885f84543c83e..b50a4be802043 100644 --- a/routers/web/repo/wiki.go +++ b/routers/web/repo/wiki.go @@ -59,7 +59,7 @@ func MustEnableWiki(ctx *context.Context) { return } - unit, err := ctx.Repo.Repository.GetUnit(unit.TypeExternalWiki) + unit, err := ctx.Repo.Repository.GetUnit(ctx, unit.TypeExternalWiki) if err == nil { ctx.Redirect(unit.ExternalWikiConfig().ExternalWikiURL) return diff --git a/routers/web/user/home.go b/routers/web/user/home.go index fc4c919de3550..36d9d4f019f7d 100644 --- a/routers/web/user/home.go +++ b/routers/web/user/home.go @@ -231,7 +231,7 @@ func Milestones(ctx *context.Context) { return } - if milestones[i].Repo.IsTimetrackerEnabled() { + if milestones[i].Repo.IsTimetrackerEnabled(ctx) { err := milestones[i].LoadTotalTrackedTime() if err != nil { ctx.ServerError("LoadTotalTrackedTime", err) diff --git a/services/agit/agit.go b/services/agit/agit.go index b4f4438791cb4..b61cb6f3f5692 100644 --- a/services/agit/agit.go +++ b/services/agit/agit.go @@ -206,7 +206,7 @@ func ProcReceive(ctx context.Context, repo *repo_model.Repository, gitRepo *git. if err != nil { return nil, fmt.Errorf("Failed to load pull issue. Error: %w", err) } - comment, err := issues_model.CreatePushPullComment(ctx, pusher, pr, oldCommitID, opts.NewCommitIDs[i]) + comment, err := pull_service.CreatePushPullComment(ctx, pusher, pr, oldCommitID, opts.NewCommitIDs[i]) if err == nil && comment != nil { notification.NotifyPullRequestPushCommits(ctx, pusher, pr, comment) } diff --git a/services/comments/comments.go b/services/issue/comments.go similarity index 63% rename from services/comments/comments.go rename to services/issue/comments.go index 21640d90b4eab..46c0daf70a336 100644 --- a/services/comments/comments.go +++ b/services/issue/comments.go @@ -1,10 +1,11 @@ // Copyright 2019 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package comments +package issue import ( "context" + "fmt" "code.gitea.io/gitea/models/db" issues_model "code.gitea.io/gitea/models/issues" @@ -14,9 +15,58 @@ import ( "code.gitea.io/gitea/modules/timeutil" ) +// CreateComment creates comment of issue or commit. +func CreateComment(opts *issues_model.CreateCommentOptions) (comment *issues_model.Comment, err error) { + ctx, committer, err := db.TxContext(db.DefaultContext) + if err != nil { + return nil, err + } + defer committer.Close() + + comment, err = issues_model.CreateComment(ctx, opts) + if err != nil { + return nil, err + } + + if err = committer.Commit(); err != nil { + return nil, err + } + + return comment, nil +} + +// CreateRefComment creates a commit reference comment to issue. +func CreateRefComment(doer *user_model.User, repo *repo_model.Repository, issue *issues_model.Issue, content, commitSHA string) error { + if len(commitSHA) == 0 { + return fmt.Errorf("cannot create reference with empty commit SHA") + } + + // Check if same reference from same commit has already existed. + has, err := db.GetEngine(db.DefaultContext).Get(&issues_model.Comment{ + Type: issues_model.CommentTypeCommitRef, + IssueID: issue.ID, + CommitSHA: commitSHA, + }) + if err != nil { + return fmt.Errorf("check reference comment: %w", err) + } else if has { + return nil + } + + _, err = CreateComment(&issues_model.CreateCommentOptions{ + Type: issues_model.CommentTypeCommitRef, + Doer: doer, + Repo: repo, + Issue: issue, + CommitSHA: commitSHA, + Content: content, + }) + return err +} + // CreateIssueComment creates a plain issue comment. func CreateIssueComment(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, issue *issues_model.Issue, content string, attachments []string) (*issues_model.Comment, error) { - comment, err := issues_model.CreateComment(&issues_model.CreateCommentOptions{ + comment, err := CreateComment(&issues_model.CreateCommentOptions{ Type: issues_model.CommentTypeComment, Doer: doer, Repo: repo, diff --git a/services/issue/commit.go b/services/issue/commit.go index efbcd639a59e5..db31fc66bb3b0 100644 --- a/services/issue/commit.go +++ b/services/issue/commit.go @@ -158,7 +158,7 @@ func UpdateIssuesCommit(doer *user_model.User, repo *repo_model.Repository, comm } message := fmt.Sprintf(`%s`, html.EscapeString(repo.Link()), html.EscapeString(url.PathEscape(c.Sha1)), html.EscapeString(strings.SplitN(c.Message, "\n", 2)[0])) - if err = issues_model.CreateRefComment(doer, refRepo, refIssue, message, c.Sha1); err != nil { + if err = CreateRefComment(doer, refRepo, refIssue, message, c.Sha1); err != nil { return err } diff --git a/services/issue/milestone.go b/services/issue/milestone.go index 6019a28a99851..a9be8bd887871 100644 --- a/services/issue/milestone.go +++ b/services/issue/milestone.go @@ -54,7 +54,7 @@ func changeMilestoneAssign(ctx context.Context, doer *user_model.User, issue *is OldMilestoneID: oldMilestoneID, MilestoneID: issue.MilestoneID, } - if _, err := issues_model.CreateCommentCtx(ctx, opts); err != nil { + if _, err := issues_model.CreateComment(ctx, opts); err != nil { return err } } diff --git a/services/pull/check.go b/services/pull/check.go index 4f720f0a0cf06..ed4b18107caf7 100644 --- a/services/pull/check.go +++ b/services/pull/check.go @@ -236,7 +236,7 @@ func manuallyMerged(ctx context.Context, pr *issues_model.PullRequest) bool { return false } - if unit, err := pr.BaseRepo.GetUnit(unit.TypePullRequests); err == nil { + if unit, err := pr.BaseRepo.GetUnit(ctx, unit.TypePullRequests); err == nil { config := unit.PullRequestsConfig() if !config.AutodetectManualMerge { return false diff --git a/services/pull/comment.go b/services/pull/comment.go new file mode 100644 index 0000000000000..068aca6cd128b --- /dev/null +++ b/services/pull/comment.go @@ -0,0 +1,162 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package pull + +import ( + "context" + + issues_model "code.gitea.io/gitea/models/issues" + repo_model "code.gitea.io/gitea/models/repo" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/json" + issue_service "code.gitea.io/gitea/services/issue" +) + +type commitBranchCheckItem struct { + Commit *git.Commit + Checked bool +} + +func commitBranchCheck(gitRepo *git.Repository, startCommit *git.Commit, endCommitID, baseBranch string, commitList map[string]*commitBranchCheckItem) error { + if startCommit.ID.String() == endCommitID { + return nil + } + + checkStack := make([]string, 0, 10) + checkStack = append(checkStack, startCommit.ID.String()) + + for len(checkStack) > 0 { + commitID := checkStack[0] + checkStack = checkStack[1:] + + item, ok := commitList[commitID] + if !ok { + continue + } + + if item.Commit.ID.String() == endCommitID { + continue + } + + if err := item.Commit.LoadBranchName(); err != nil { + return err + } + + if item.Commit.Branch == baseBranch { + continue + } + + if item.Checked { + continue + } + + item.Checked = true + + parentNum := item.Commit.ParentCount() + for i := 0; i < parentNum; i++ { + parentCommit, err := item.Commit.Parent(i) + if err != nil { + return err + } + checkStack = append(checkStack, parentCommit.ID.String()) + } + } + return nil +} + +// getCommitIDsFromRepo get commit IDs from repo in between oldCommitID and newCommitID +// isForcePush will be true if oldCommit isn't on the branch +// Commit on baseBranch will skip +func getCommitIDsFromRepo(ctx context.Context, repo *repo_model.Repository, oldCommitID, newCommitID, baseBranch string) (commitIDs []string, isForcePush bool, err error) { + repoPath := repo.RepoPath() + gitRepo, closer, err := git.RepositoryFromContextOrOpen(ctx, repoPath) + if err != nil { + return nil, false, err + } + defer closer.Close() + + oldCommit, err := gitRepo.GetCommit(oldCommitID) + if err != nil { + return nil, false, err + } + + if err = oldCommit.LoadBranchName(); err != nil { + return nil, false, err + } + + if len(oldCommit.Branch) == 0 { + commitIDs = make([]string, 2) + commitIDs[0] = oldCommitID + commitIDs[1] = newCommitID + + return commitIDs, true, err + } + + newCommit, err := gitRepo.GetCommit(newCommitID) + if err != nil { + return nil, false, err + } + + commits, err := newCommit.CommitsBeforeUntil(oldCommitID) + if err != nil { + return nil, false, err + } + + commitIDs = make([]string, 0, len(commits)) + commitChecks := make(map[string]*commitBranchCheckItem) + + for _, commit := range commits { + commitChecks[commit.ID.String()] = &commitBranchCheckItem{ + Commit: commit, + Checked: false, + } + } + + if err = commitBranchCheck(gitRepo, newCommit, oldCommitID, baseBranch, commitChecks); err != nil { + return + } + + for i := len(commits) - 1; i >= 0; i-- { + commitID := commits[i].ID.String() + if item, ok := commitChecks[commitID]; ok && item.Checked { + commitIDs = append(commitIDs, commitID) + } + } + + return commitIDs, isForcePush, err +} + +// CreatePushPullComment create push code to pull base comment +func CreatePushPullComment(ctx context.Context, pusher *user_model.User, pr *issues_model.PullRequest, oldCommitID, newCommitID string) (comment *issues_model.Comment, err error) { + if pr.HasMerged || oldCommitID == "" || newCommitID == "" { + return nil, nil + } + + ops := &issues_model.CreateCommentOptions{ + Type: issues_model.CommentTypePullRequestPush, + Doer: pusher, + Repo: pr.BaseRepo, + } + + var data issues_model.PushActionContent + + data.CommitIDs, data.IsForcePush, err = getCommitIDsFromRepo(ctx, pr.BaseRepo, oldCommitID, newCommitID, pr.BaseBranch) + if err != nil { + return nil, err + } + + ops.Issue = pr.Issue + + dataJSON, err := json.Marshal(data) + if err != nil { + return nil, err + } + + ops.Content = string(dataJSON) + + comment, err = issue_service.CreateComment(ops) + + return comment, err +} diff --git a/services/pull/merge.go b/services/pull/merge.go index 9270fb8cbc2bf..1c42c1c17b8b7 100644 --- a/services/pull/merge.go +++ b/services/pull/merge.go @@ -54,7 +54,7 @@ func GetDefaultMergeMessage(ctx context.Context, baseGitRepo *git.Repository, pr return "", err } - isExternalTracker := pr.BaseRepo.UnitEnabled(unit.TypeExternalTracker) + isExternalTracker := pr.BaseRepo.UnitEnabled(ctx, unit.TypeExternalTracker) issueReference := "#" if isExternalTracker { issueReference = "!" @@ -145,11 +145,11 @@ func Merge(ctx context.Context, pr *issues_model.PullRequest, doer *user_model.U defer pullWorkingPool.CheckOut(fmt.Sprint(pr.ID)) // Removing an auto merge pull and ignore if not exist - if err := pull_model.DeleteScheduledAutoMerge(db.DefaultContext, pr.ID); err != nil && !db.IsErrNotExist(err) { + if err := pull_model.DeleteScheduledAutoMerge(ctx, pr.ID); err != nil && !db.IsErrNotExist(err) { return err } - prUnit, err := pr.BaseRepo.GetUnit(unit.TypePullRequests) + prUnit, err := pr.BaseRepo.GetUnit(ctx, unit.TypePullRequests) if err != nil { log.Error("pr.BaseRepo.GetUnit(unit.TypePullRequests): %v", err) return err @@ -828,7 +828,7 @@ func MergedManually(pr *issues_model.PullRequest, doer *user_model.User, baseGit defer pullWorkingPool.CheckOut(fmt.Sprint(pr.ID)) if err := db.WithTx(db.DefaultContext, func(ctx context.Context) error { - prUnit, err := pr.BaseRepo.GetUnitCtx(ctx, unit.TypePullRequests) + prUnit, err := pr.BaseRepo.GetUnit(ctx, unit.TypePullRequests) if err != nil { return err } diff --git a/services/pull/patch.go b/services/pull/patch.go index 2d495a3d72d56..809b75e6b4536 100644 --- a/services/pull/patch.go +++ b/services/pull/patch.go @@ -354,7 +354,7 @@ func checkConflicts(ctx context.Context, pr *issues_model.PullRequest, gitRepo * } // 5. Now get the pull request configuration to check if we need to ignore whitespace - prUnit, err := pr.BaseRepo.GetUnit(unit.TypePullRequests) + prUnit, err := pr.BaseRepo.GetUnit(ctx, unit.TypePullRequests) if err != nil { return false, err } diff --git a/services/pull/pull.go b/services/pull/pull.go index fd907491d447c..afb0fa244244b 100644 --- a/services/pull/pull.go +++ b/services/pull/pull.go @@ -123,7 +123,7 @@ func NewPullRequest(ctx context.Context, repo *repo_model.Repository, pull *issu Content: string(dataJSON), } - _, _ = issues_model.CreateComment(ops) + _, _ = issue_service.CreateComment(ops) } return nil @@ -222,7 +222,7 @@ func ChangeTargetBranch(ctx context.Context, pr *issues_model.PullRequest, doer OldRef: oldBranch, NewRef: targetBranch, } - if _, err = issues_model.CreateComment(options); err != nil { + if _, err = issue_service.CreateComment(options); err != nil { return fmt.Errorf("CreateChangeTargetBranchComment: %w", err) } @@ -317,7 +317,7 @@ func AddTestPullRequestTask(doer *user_model.User, repoID int64, branch string, } AddToTaskQueue(pr) - comment, err := issues_model.CreatePushPullComment(ctx, doer, pr, oldCommitID, newCommitID) + comment, err := CreatePushPullComment(ctx, doer, pr, oldCommitID, newCommitID) if err == nil && comment != nil { notification.NotifyPullRequestPushCommits(ctx, doer, pr, comment) } diff --git a/services/pull/review.go b/services/pull/review.go index 1f2bc77e2cd10..67a10d7aad61c 100644 --- a/services/pull/review.go +++ b/services/pull/review.go @@ -20,6 +20,7 @@ import ( "code.gitea.io/gitea/modules/notification" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" + issue_service "code.gitea.io/gitea/services/issue" ) // CreateCodeComment creates a comment on the code line @@ -202,7 +203,7 @@ func createCodeComment(ctx context.Context, doer *user_model.User, repo *repo_mo return nil, err } } - return issues_model.CreateComment(&issues_model.CreateCommentOptions{ + return issue_service.CreateComment(&issues_model.CreateCommentOptions{ Type: issues_model.CommentTypeCode, Doer: doer, Repo: repo, @@ -322,7 +323,7 @@ func DismissReview(ctx context.Context, reviewID, repoID int64, message string, return } - comment, err = issues_model.CreateComment(&issues_model.CreateCommentOptions{ + comment, err = issue_service.CreateComment(&issues_model.CreateCommentOptions{ Doer: doer, Content: message, Type: issues_model.CommentTypeDismissReview, diff --git a/services/pull/update.go b/services/pull/update.go index bd6a37b277e02..e09dbf624457a 100644 --- a/services/pull/update.go +++ b/services/pull/update.go @@ -106,7 +106,7 @@ func IsUserAllowedToUpdate(ctx context.Context, pull *issues_model.PullRequest, // can't do rebase on protected branch because need force push if pr.ProtectedBranch == nil { - prUnit, err := pr.BaseRepo.GetUnit(unit.TypePullRequests) + prUnit, err := pr.BaseRepo.GetUnit(ctx, unit.TypePullRequests) if err != nil { log.Error("pr.BaseRepo.GetUnit(unit.TypePullRequests): %v", err) return false, false, err diff --git a/services/repository/repository.go b/services/repository/repository.go index 41fae4b4cf69f..3c3e7e82c3f8f 100644 --- a/services/repository/repository.go +++ b/services/repository/repository.go @@ -58,7 +58,7 @@ func DeleteRepository(ctx context.Context, doer *user_model.User, repo *repo_mod func PushCreateRepo(authUser, owner *user_model.User, repoName string) (*repo_model.Repository, error) { if !authUser.IsAdmin { if owner.IsOrganization() { - if ok, err := organization.CanCreateOrgRepo(owner.ID, authUser.ID); err != nil { + if ok, err := organization.CanCreateOrgRepo(db.DefaultContext, owner.ID, authUser.ID); err != nil { return nil, err } else if !ok { return nil, fmt.Errorf("cannot push-create repository for org") diff --git a/services/repository/transfer.go b/services/repository/transfer.go index 9fba9c44ebc32..f4afb7e2dec28 100644 --- a/services/repository/transfer.go +++ b/services/repository/transfer.go @@ -4,6 +4,7 @@ package repository import ( + "context" "fmt" "code.gitea.io/gitea/models" @@ -24,8 +25,8 @@ import ( var repoWorkingPool = sync.NewExclusivePool() // TransferOwnership transfers all corresponding setting from old user to new one. -func TransferOwnership(doer, newOwner *user_model.User, repo *repo_model.Repository, teams []*organization.Team) error { - if err := repo.GetOwner(db.DefaultContext); err != nil { +func TransferOwnership(ctx context.Context, doer, newOwner *user_model.User, repo *repo_model.Repository, teams []*organization.Team) error { + if err := repo.GetOwner(ctx); err != nil { return err } for _, team := range teams { @@ -43,18 +44,18 @@ func TransferOwnership(doer, newOwner *user_model.User, repo *repo_model.Reposit } repoWorkingPool.CheckOut(fmt.Sprint(repo.ID)) - newRepo, err := repo_model.GetRepositoryByID(db.DefaultContext, repo.ID) + newRepo, err := repo_model.GetRepositoryByID(ctx, repo.ID) if err != nil { return err } for _, team := range teams { - if err := models.AddRepository(db.DefaultContext, team, newRepo); err != nil { + if err := models.AddRepository(ctx, team, newRepo); err != nil { return err } } - notification.NotifyTransferRepository(db.DefaultContext, doer, repo, oldOwner.Name) + notification.NotifyTransferRepository(ctx, doer, repo, oldOwner.Name) return nil } @@ -84,49 +85,49 @@ func ChangeRepositoryName(doer *user_model.User, repo *repo_model.Repository, ne // StartRepositoryTransfer transfer a repo from one owner to a new one. // it make repository into pending transfer state, if doer can not create repo for new owner. -func StartRepositoryTransfer(doer, newOwner *user_model.User, repo *repo_model.Repository, teams []*organization.Team) error { +func StartRepositoryTransfer(ctx context.Context, doer, newOwner *user_model.User, repo *repo_model.Repository, teams []*organization.Team) error { if err := models.TestRepositoryReadyForTransfer(repo.Status); err != nil { return err } // Admin is always allowed to transfer || user transfer repo back to his account if doer.IsAdmin || doer.ID == newOwner.ID { - return TransferOwnership(doer, newOwner, repo, teams) + return TransferOwnership(ctx, doer, newOwner, repo, teams) } // If new owner is an org and user can create repos he can transfer directly too if newOwner.IsOrganization() { - allowed, err := organization.CanCreateOrgRepo(newOwner.ID, doer.ID) + allowed, err := organization.CanCreateOrgRepo(ctx, newOwner.ID, doer.ID) if err != nil { return err } if allowed { - return TransferOwnership(doer, newOwner, repo, teams) + return TransferOwnership(ctx, doer, newOwner, repo, teams) } } // In case the new owner would not have sufficient access to the repo, give access rights for read - hasAccess, err := access_model.HasAccess(db.DefaultContext, newOwner.ID, repo) + hasAccess, err := access_model.HasAccess(ctx, newOwner.ID, repo) if err != nil { return err } if !hasAccess { - if err := repo_module.AddCollaborator(repo, newOwner); err != nil { + if err := repo_module.AddCollaborator(ctx, repo, newOwner); err != nil { return err } - if err := repo_model.ChangeCollaborationAccessMode(repo, newOwner.ID, perm.AccessModeRead); err != nil { + if err := repo_model.ChangeCollaborationAccessMode(ctx, repo, newOwner.ID, perm.AccessModeRead); err != nil { return err } } // Make repo as pending for transfer repo.Status = repo_model.RepositoryPendingTransfer - if err := models.CreatePendingRepositoryTransfer(doer, newOwner, repo.ID, teams); err != nil { + if err := models.CreatePendingRepositoryTransfer(ctx, doer, newOwner, repo.ID, teams); err != nil { return err } // notify users who are able to accept / reject transfer - notification.NotifyRepoPendingTransfer(db.DefaultContext, doer, newOwner, repo) + notification.NotifyRepoPendingTransfer(ctx, doer, newOwner, repo) return nil } diff --git a/services/repository/transfer_test.go b/services/repository/transfer_test.go index 2bbc5abbd257b..1299e66be2781 100644 --- a/services/repository/transfer_test.go +++ b/services/repository/transfer_test.go @@ -37,7 +37,7 @@ func TestTransferOwnership(t *testing.T) { doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}) repo.Owner = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) - assert.NoError(t, TransferOwnership(doer, doer, repo, nil)) + assert.NoError(t, TransferOwnership(db.DefaultContext, doer, doer, repo, nil)) transferredRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}) assert.EqualValues(t, 2, transferredRepo.OwnerID) @@ -70,7 +70,7 @@ func TestStartRepositoryTransferSetPermission(t *testing.T) { assert.NoError(t, err) assert.False(t, hasAccess) - assert.NoError(t, StartRepositoryTransfer(doer, recipient, repo, nil)) + assert.NoError(t, StartRepositoryTransfer(db.DefaultContext, doer, recipient, repo, nil)) hasAccess, err = access_model.HasAccess(db.DefaultContext, recipient.ID, repo) assert.NoError(t, err) diff --git a/templates/admin/config.tmpl b/templates/admin/config.tmpl index 982cfb2800815..de33c6c553868 100644 --- a/templates/admin/config.tmpl +++ b/templates/admin/config.tmpl @@ -177,7 +177,7 @@
{{.locale.Tr "admin.config.default_enable_timetracking"}}
{{if .Service.DefaultEnableTimetracking}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}
{{.locale.Tr "admin.config.default_allow_only_contributors_to_track_time"}}
-
{{if .Service.DefaultAllowOnlyContributorsToTrackTime}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}
+
{{if .Service.DefaultAllowOnlyContributorsToTrackTime $.Context}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}
{{end}}
{{.locale.Tr "admin.config.default_visibility_organization"}}
{{.Service.DefaultOrgVisibility}}
diff --git a/templates/org/team/new.tmpl b/templates/org/team/new.tmpl index f6786f3d8d519..10b5abda31457 100644 --- a/templates/org/team/new.tmpl +++ b/templates/org/team/new.tmpl @@ -99,17 +99,17 @@
- +
- +
- +
@@ -121,7 +121,7 @@ {{if lt $unit.MaxPerm 2}}
- + {{$.locale.Tr $unit.DescKey}}
diff --git a/templates/org/team/sidebar.tmpl b/templates/org/team/sidebar.tmpl index 5d952b501e262..ab118a7e263f4 100644 --- a/templates/org/team/sidebar.tmpl +++ b/templates/org/team/sidebar.tmpl @@ -61,11 +61,11 @@ {{if and (lt $unit.MaxPerm 2) (not $unit.Type.UnitGlobalDisabled)}} {{$.locale.Tr $unit.NameKey}} - {{if eq ($.Team.UnitAccessMode $unit.Type) 0 -}} + {{if eq ($.Team.UnitAccessMode $.Context $unit.Type) 0 -}} {{$.locale.Tr "org.teams.none_access"}} - {{- else if or (eq $.Team.ID 0) (eq ($.Team.UnitAccessMode $unit.Type) 1) -}} + {{- else if or (eq $.Team.ID 0) (eq ($.Team.UnitAccessMode $.Context $unit.Type) 1) -}} {{$.locale.Tr "org.teams.read_access"}} - {{- else if eq ($.Team.UnitAccessMode $unit.Type) 2 -}} + {{- else if eq ($.Team.UnitAccessMode $.Context $unit.Type) 2 -}} {{$.locale.Tr "org.teams.write_access"}} {{- end}} diff --git a/templates/repo/editor/commit_form.tmpl b/templates/repo/editor/commit_form.tmpl index 95fcf2b8555be..8700f7740151e 100644 --- a/templates/repo/editor/commit_form.tmpl +++ b/templates/repo/editor/commit_form.tmpl @@ -40,8 +40,8 @@
- {{$pullRequestEnabled := .Repository.UnitEnabled $.UnitTypePullRequests}} - {{$prUnit := .Repository.MustGetUnit $.UnitTypePullRequests}} + {{$pullRequestEnabled := .Repository.UnitEnabled $.Context $.UnitTypePullRequests}} + {{$prUnit := .Repository.MustGetUnit $.Context $.UnitTypePullRequests}}
{{if $pullRequestEnabled}} diff --git a/templates/repo/graph/commits.tmpl b/templates/repo/graph/commits.tmpl index 357c99b2b85f6..fc4b1a1ea36a2 100644 --- a/templates/repo/graph/commits.tmpl +++ b/templates/repo/graph/commits.tmpl @@ -37,7 +37,7 @@ {{if eq $refGroup "pull"}} {{if or (not $.HidePRRefs) (containGeneric $.SelectedBranches .Name)}} - + {{svg "octicon-git-pull-request" 16 "mr-2"}}#{{.ShortName}} {{end}} diff --git a/templates/repo/header.tmpl b/templates/repo/header.tmpl index c706e00777b48..4da91e424df9d 100644 --- a/templates/repo/header.tmpl +++ b/templates/repo/header.tmpl @@ -208,7 +208,7 @@ {{end}} {{if or (.Permission.CanRead $.UnitTypeWiki) (.Permission.CanRead $.UnitTypeExternalWiki)}} - + {{svg "octicon-book"}} {{.locale.Tr "repo.wiki"}} {{end}} diff --git a/templates/repo/issue/view_content/pull.tmpl b/templates/repo/issue/view_content/pull.tmpl index 9e0909064de1a..d68f3e5414399 100644 --- a/templates/repo/issue/view_content/pull.tmpl +++ b/templates/repo/issue/view_content/pull.tmpl @@ -330,7 +330,7 @@ {{end}} {{if .AllowMerge}} {{/* user is allowed to merge */}} - {{$prUnit := .Repository.MustGetUnit $.UnitTypePullRequests}} + {{$prUnit := .Repository.MustGetUnit $.Context $.UnitTypePullRequests}} {{$approvers := .Issue.PullRequest.GetApprovers}} {{if or $prUnit.PullRequestsConfig.AllowMerge $prUnit.PullRequestsConfig.AllowRebase $prUnit.PullRequestsConfig.AllowRebaseMerge $prUnit.PullRequestsConfig.AllowSquash}} {{$hasPendingPullRequestMergeTip := ""}} diff --git a/templates/repo/issue/view_content/sidebar.tmpl b/templates/repo/issue/view_content/sidebar.tmpl index af648387db58b..63b99136a8ed5 100644 --- a/templates/repo/issue/view_content/sidebar.tmpl +++ b/templates/repo/issue/view_content/sidebar.tmpl @@ -337,7 +337,7 @@
{{end}} - {{if .Repository.IsTimetrackerEnabled}} + {{if .Repository.IsTimetrackerEnabled $.Context}} {{if and .CanUseTimetracker (not .Repository.IsArchived)}}
@@ -444,7 +444,7 @@ {{end}}
- {{if .Repository.IsDependenciesEnabled}} + {{if .Repository.IsDependenciesEnabled $.Context}}
diff --git a/templates/repo/settings/collaboration.tmpl b/templates/repo/settings/collaboration.tmpl index 342b260db6c0e..2f932b4c3958e 100644 --- a/templates/repo/settings/collaboration.tmpl +++ b/templates/repo/settings/collaboration.tmpl @@ -74,7 +74,7 @@ {{if or (eq .AccessMode 1) (eq .AccessMode 2)}} {{$first := true}}
- Sections: {{range $u, $unit := $.Units}}{{if and ($.Repo.UnitEnabled $unit.Type) ($team.UnitEnabled $unit.Type)}}{{if $first}}{{$first = false}}{{else}}, {{end}}{{$.locale.Tr $unit.NameKey}}{{end}}{{end}} {{if $first}}None{{end}} + Sections: {{range $u, $unit := $.Units}}{{if and ($.Repo.UnitEnabled $.Context $unit.Type) ($team.UnitEnabled $.Context $unit.Type)}}{{if $first}}{{$first = false}}{{else}}, {{end}}{{$.locale.Tr $unit.NameKey}}{{end}}{{end}} {{if $first}}None{{end}}
{{end}}
diff --git a/templates/repo/settings/options.tmpl b/templates/repo/settings/options.tmpl index 3c5996e903a73..aa79f75617e73 100644 --- a/templates/repo/settings/options.tmpl +++ b/templates/repo/settings/options.tmpl @@ -249,7 +249,7 @@ {{.CsrfTokenHtml}} - {{$isWikiEnabled := or (.Repository.UnitEnabled $.UnitTypeWiki) (.Repository.UnitEnabled $.UnitTypeExternalWiki)}} + {{$isWikiEnabled := or (.Repository.UnitEnabled $.Context $.UnitTypeWiki) (.Repository.UnitEnabled $.Context $.UnitTypeExternalWiki)}}
{{if and (.UnitTypeWiki.UnitGlobalDisabled) (.UnitTypeExternalWiki.UnitGlobalDisabled)}} @@ -268,7 +268,7 @@ {{else}}
{{end}} - +
@@ -278,20 +278,20 @@ {{else}}
{{end}} - +
-
+
- +

{{.locale.Tr "repo.settings.external_wiki_url_desc"}}

- {{$isIssuesEnabled := or (.Repository.UnitEnabled $.UnitTypeIssues) (.Repository.UnitEnabled $.UnitTypeExternalTracker)}} + {{$isIssuesEnabled := or (.Repository.UnitEnabled $.Context $.UnitTypeIssues) (.Repository.UnitEnabled $.Context $.UnitTypeExternalTracker)}}
{{if and (.UnitTypeIssues.UnitGlobalDisabled) (.UnitTypeExternalTracker.UnitGlobalDisabled)}} @@ -310,28 +310,28 @@ {{else}}
{{end}} - +
-
+
{{if .Repository.CanEnableTimetracker}}
- +
-
+
- +
{{end}}
- +
@@ -346,26 +346,26 @@ {{else}}
{{end}} - +
-
+
- +

{{.locale.Tr "repo.settings.external_tracker_url_desc"}}

- +

{{.locale.Tr "repo.settings.tracker_url_format_desc" | Str2html}}

- {{$externalTracker := (.Repository.MustGetUnit $.UnitTypeExternalTracker)}} + {{$externalTracker := (.Repository.MustGetUnit $.Context $.UnitTypeExternalTracker)}} {{$externalTrackerStyle := $externalTracker.ExternalTrackerConfig.ExternalTrackerStyle}} @@ -386,7 +386,7 @@
- +

{{.locale.Tr "repo.settings.tracker_issue_style.regexp_pattern_desc" | Str2html}}

@@ -394,7 +394,7 @@
- {{$isProjectsEnabled := .Repository.UnitEnabled $.UnitTypeProjects}} + {{$isProjectsEnabled := .Repository.UnitEnabled $.Context $.UnitTypeProjects}}
{{if .UnitTypeProjects.UnitGlobalDisabled}} @@ -407,7 +407,7 @@
- {{$isPackagesEnabled := .Repository.UnitEnabled $.UnitTypePackages}} + {{$isPackagesEnabled := .Repository.UnitEnabled $.Context $.UnitTypePackages}}
{{if .UnitTypePackages.UnitGlobalDisabled}} @@ -422,8 +422,8 @@ {{if not .IsMirror}}
- {{$pullRequestEnabled := .Repository.UnitEnabled $.UnitTypePullRequests}} - {{$prUnit := .Repository.MustGetUnit $.UnitTypePullRequests}} + {{$pullRequestEnabled := .Repository.UnitEnabled $.Context $.UnitTypePullRequests}} + {{$prUnit := .Repository.MustGetUnit $.Context $.UnitTypePullRequests}}
{{if .UnitTypePullRequests.UnitGlobalDisabled}} @@ -880,7 +880,7 @@
- {{if .Repository.UnitEnabled $.UnitTypeWiki}} + {{if .Repository.UnitEnabled $.Context $.UnitTypeWiki}}